2026-04-06 10:58:59 -05:00
|
|
|
// @vitest-environment jsdom
|
|
|
|
|
|
|
|
|
|
import { act } from "react";
|
|
|
|
|
import type { ComponentProps, ReactNode } from "react";
|
|
|
|
|
import { createRoot } from "react-dom/client";
|
[codex] Improve workspace navigation and runtime UI (#4089)
## Thinking Path
> - Paperclip agents do real work in project and execution workspaces.
> - Operators need workspace state to be visible, navigable, and
copyable without digging through raw run logs.
> - The branch included related workspace cards, navigation, runtime
controls, stale-service handling, and issue-property visibility.
> - These changes share the workspace UI and runtime-control surfaces
and can stand alone from unrelated access/profile work.
> - This pull request groups the workspace experience changes into one
standalone branch.
> - The benefit is a clearer workspace overview, better metadata copy
flows, and more accurate runtime service controls.
## What Changed
- Polished project workspace summary cards and made workspace metadata
copyable.
- Added a workspace navigation overview and extracted reusable project
workspace content.
- Squared and polished the execution workspace configuration page.
- Fixed stale workspace command matching and hid stopped stale services
in runtime controls.
- Showed live workspace service context in issue properties.
## Verification
- `pnpm install --frozen-lockfile`
- `pnpm exec vitest run
ui/src/components/ProjectWorkspaceSummaryCard.test.tsx
ui/src/lib/project-workspaces-tab.test.ts
ui/src/components/Sidebar.test.tsx
ui/src/components/WorkspaceRuntimeControls.test.tsx
ui/src/components/IssueProperties.test.tsx`
- `pnpm exec vitest run packages/shared/src/workspace-commands.test.ts
--config /dev/null` because the root Vitest project config does not
currently include `packages/shared` tests.
- Split integration check: merged after runtime/governance,
dev-infra/backups, and access/profiles with no merge conflicts.
- Confirmed this branch does not include `pnpm-lock.yaml`.
## Risks
- Medium risk: touches workspace navigation, runtime controls, and issue
property rendering.
- Visual layout changes may need browser QA, especially around smaller
screens and dense workspace metadata.
- No database migrations are included.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5.4 tool-enabled coding model, agentic
code-editing/runtime with local shell and GitHub CLI access; exact
context window and reasoning mode are not exposed by the Paperclip
harness.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-20 06:14:32 -05:00
|
|
|
import type {
|
|
|
|
|
ExecutionWorkspace,
|
|
|
|
|
IssueExecutionPolicy,
|
|
|
|
|
IssueExecutionState,
|
[codex] Polish issue board workflows (#4224)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Human operators supervise that work through issue lists, issue
detail, comments, inbox groups, markdown references, and
profile/activity surfaces
> - The branch had many small UI fixes that improve the operator loop
but do not need to ship with backend runtime migrations
> - These changes belong together as board workflow polish because they
affect scanning, navigation, issue context, comment state, and markdown
clarity
> - This pull request groups the UI-only slice so it can merge
independently from runtime/backend changes
> - The benefit is a clearer board experience with better issue context,
steadier optimistic updates, and more predictable keyboard navigation
## What Changed
- Improves issue properties, sub-issue actions, blocker chips, and issue
list/detail refresh behavior.
- Adds blocker context above the issue composer and stabilizes
queued/interrupted comment UI state.
- Improves markdown issue/GitHub link rendering and opens external
markdown links in a new tab.
- Adds inbox group keyboard navigation and fold/unfold support.
- Polishes activity/avatar/profile/settings/workspace presentation
details.
## Verification
- `pnpm exec vitest run ui/src/components/IssueProperties.test.tsx
ui/src/components/IssueChatThread.test.tsx
ui/src/components/MarkdownBody.test.tsx ui/src/lib/inbox.test.ts
ui/src/lib/optimistic-issue-comments.test.ts`
## Risks
- Low to medium risk: changes are UI-focused but cover high-traffic
issue and inbox surfaces.
- This branch intentionally does not include the backend runtime changes
from the companion PR; where UI calls newer API filters, unsupported
servers should continue to fail visibly through existing API error
handling.
- Visual screenshots were not captured in this heartbeat; targeted
component/helper tests cover the changed behavior.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5-based coding agent runtime, shell/git tool use
enabled. Exact hosted model build and context window are not exposed in
this Paperclip heartbeat environment.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-04-21 12:25:34 -05:00
|
|
|
IssueLabel,
|
[codex] Improve workspace navigation and runtime UI (#4089)
## Thinking Path
> - Paperclip agents do real work in project and execution workspaces.
> - Operators need workspace state to be visible, navigable, and
copyable without digging through raw run logs.
> - The branch included related workspace cards, navigation, runtime
controls, stale-service handling, and issue-property visibility.
> - These changes share the workspace UI and runtime-control surfaces
and can stand alone from unrelated access/profile work.
> - This pull request groups the workspace experience changes into one
standalone branch.
> - The benefit is a clearer workspace overview, better metadata copy
flows, and more accurate runtime service controls.
## What Changed
- Polished project workspace summary cards and made workspace metadata
copyable.
- Added a workspace navigation overview and extracted reusable project
workspace content.
- Squared and polished the execution workspace configuration page.
- Fixed stale workspace command matching and hid stopped stale services
in runtime controls.
- Showed live workspace service context in issue properties.
## Verification
- `pnpm install --frozen-lockfile`
- `pnpm exec vitest run
ui/src/components/ProjectWorkspaceSummaryCard.test.tsx
ui/src/lib/project-workspaces-tab.test.ts
ui/src/components/Sidebar.test.tsx
ui/src/components/WorkspaceRuntimeControls.test.tsx
ui/src/components/IssueProperties.test.tsx`
- `pnpm exec vitest run packages/shared/src/workspace-commands.test.ts
--config /dev/null` because the root Vitest project config does not
currently include `packages/shared` tests.
- Split integration check: merged after runtime/governance,
dev-infra/backups, and access/profiles with no merge conflicts.
- Confirmed this branch does not include `pnpm-lock.yaml`.
## Risks
- Medium risk: touches workspace navigation, runtime controls, and issue
property rendering.
- Visual layout changes may need browser QA, especially around smaller
screens and dense workspace metadata.
- No database migrations are included.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5.4 tool-enabled coding model, agentic
code-editing/runtime with local shell and GitHub CLI access; exact
context window and reasoning mode are not exposed by the Paperclip
harness.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-20 06:14:32 -05:00
|
|
|
Project,
|
|
|
|
|
WorkspaceRuntimeService,
|
|
|
|
|
} from "@paperclipai/shared";
|
2026-04-06 10:58:59 -05:00
|
|
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
|
|
|
import type { Issue } from "@paperclipai/shared";
|
|
|
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
|
import { IssueProperties } from "./IssueProperties";
|
|
|
|
|
|
|
|
|
|
const mockAgentsApi = vi.hoisted(() => ({
|
|
|
|
|
list: vi.fn(),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
const mockProjectsApi = vi.hoisted(() => ({
|
|
|
|
|
list: vi.fn(),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
const mockIssuesApi = vi.hoisted(() => ({
|
2026-04-10 22:26:21 -05:00
|
|
|
list: vi.fn(),
|
2026-04-06 10:58:59 -05:00
|
|
|
listLabels: vi.fn(),
|
[codex] Polish issue board workflows (#4224)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Human operators supervise that work through issue lists, issue
detail, comments, inbox groups, markdown references, and
profile/activity surfaces
> - The branch had many small UI fixes that improve the operator loop
but do not need to ship with backend runtime migrations
> - These changes belong together as board workflow polish because they
affect scanning, navigation, issue context, comment state, and markdown
clarity
> - This pull request groups the UI-only slice so it can merge
independently from runtime/backend changes
> - The benefit is a clearer board experience with better issue context,
steadier optimistic updates, and more predictable keyboard navigation
## What Changed
- Improves issue properties, sub-issue actions, blocker chips, and issue
list/detail refresh behavior.
- Adds blocker context above the issue composer and stabilizes
queued/interrupted comment UI state.
- Improves markdown issue/GitHub link rendering and opens external
markdown links in a new tab.
- Adds inbox group keyboard navigation and fold/unfold support.
- Polishes activity/avatar/profile/settings/workspace presentation
details.
## Verification
- `pnpm exec vitest run ui/src/components/IssueProperties.test.tsx
ui/src/components/IssueChatThread.test.tsx
ui/src/components/MarkdownBody.test.tsx ui/src/lib/inbox.test.ts
ui/src/lib/optimistic-issue-comments.test.ts`
## Risks
- Low to medium risk: changes are UI-focused but cover high-traffic
issue and inbox surfaces.
- This branch intentionally does not include the backend runtime changes
from the companion PR; where UI calls newer API filters, unsupported
servers should continue to fail visibly through existing API error
handling.
- Visual screenshots were not captured in this heartbeat; targeted
component/helper tests cover the changed behavior.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5-based coding agent runtime, shell/git tool use
enabled. Exact hosted model build and context window are not exposed in
this Paperclip heartbeat environment.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-04-21 12:25:34 -05:00
|
|
|
createLabel: vi.fn(),
|
2026-04-06 10:58:59 -05:00
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
const mockAuthApi = vi.hoisted(() => ({
|
|
|
|
|
getSession: vi.fn(),
|
|
|
|
|
}));
|
|
|
|
|
|
[codex] Polish issue board workflows (#4224)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Human operators supervise that work through issue lists, issue
detail, comments, inbox groups, markdown references, and
profile/activity surfaces
> - The branch had many small UI fixes that improve the operator loop
but do not need to ship with backend runtime migrations
> - These changes belong together as board workflow polish because they
affect scanning, navigation, issue context, comment state, and markdown
clarity
> - This pull request groups the UI-only slice so it can merge
independently from runtime/backend changes
> - The benefit is a clearer board experience with better issue context,
steadier optimistic updates, and more predictable keyboard navigation
## What Changed
- Improves issue properties, sub-issue actions, blocker chips, and issue
list/detail refresh behavior.
- Adds blocker context above the issue composer and stabilizes
queued/interrupted comment UI state.
- Improves markdown issue/GitHub link rendering and opens external
markdown links in a new tab.
- Adds inbox group keyboard navigation and fold/unfold support.
- Polishes activity/avatar/profile/settings/workspace presentation
details.
## Verification
- `pnpm exec vitest run ui/src/components/IssueProperties.test.tsx
ui/src/components/IssueChatThread.test.tsx
ui/src/components/MarkdownBody.test.tsx ui/src/lib/inbox.test.ts
ui/src/lib/optimistic-issue-comments.test.ts`
## Risks
- Low to medium risk: changes are UI-focused but cover high-traffic
issue and inbox surfaces.
- This branch intentionally does not include the backend runtime changes
from the companion PR; where UI calls newer API filters, unsupported
servers should continue to fail visibly through existing API error
handling.
- Visual screenshots were not captured in this heartbeat; targeted
component/helper tests cover the changed behavior.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5-based coding agent runtime, shell/git tool use
enabled. Exact hosted model build and context window are not exposed in
this Paperclip heartbeat environment.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-04-21 12:25:34 -05:00
|
|
|
const mockInstanceSettingsApi = vi.hoisted(() => ({
|
|
|
|
|
getExperimental: vi.fn(),
|
|
|
|
|
}));
|
|
|
|
|
|
2026-04-06 10:58:59 -05:00
|
|
|
vi.mock("../context/CompanyContext", () => ({
|
|
|
|
|
useCompany: () => ({
|
|
|
|
|
selectedCompanyId: "company-1",
|
|
|
|
|
}),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
vi.mock("../api/agents", () => ({
|
|
|
|
|
agentsApi: mockAgentsApi,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
vi.mock("../api/projects", () => ({
|
|
|
|
|
projectsApi: mockProjectsApi,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
vi.mock("../api/issues", () => ({
|
|
|
|
|
issuesApi: mockIssuesApi,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
vi.mock("../api/auth", () => ({
|
|
|
|
|
authApi: mockAuthApi,
|
|
|
|
|
}));
|
|
|
|
|
|
[codex] Polish issue board workflows (#4224)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Human operators supervise that work through issue lists, issue
detail, comments, inbox groups, markdown references, and
profile/activity surfaces
> - The branch had many small UI fixes that improve the operator loop
but do not need to ship with backend runtime migrations
> - These changes belong together as board workflow polish because they
affect scanning, navigation, issue context, comment state, and markdown
clarity
> - This pull request groups the UI-only slice so it can merge
independently from runtime/backend changes
> - The benefit is a clearer board experience with better issue context,
steadier optimistic updates, and more predictable keyboard navigation
## What Changed
- Improves issue properties, sub-issue actions, blocker chips, and issue
list/detail refresh behavior.
- Adds blocker context above the issue composer and stabilizes
queued/interrupted comment UI state.
- Improves markdown issue/GitHub link rendering and opens external
markdown links in a new tab.
- Adds inbox group keyboard navigation and fold/unfold support.
- Polishes activity/avatar/profile/settings/workspace presentation
details.
## Verification
- `pnpm exec vitest run ui/src/components/IssueProperties.test.tsx
ui/src/components/IssueChatThread.test.tsx
ui/src/components/MarkdownBody.test.tsx ui/src/lib/inbox.test.ts
ui/src/lib/optimistic-issue-comments.test.ts`
## Risks
- Low to medium risk: changes are UI-focused but cover high-traffic
issue and inbox surfaces.
- This branch intentionally does not include the backend runtime changes
from the companion PR; where UI calls newer API filters, unsupported
servers should continue to fail visibly through existing API error
handling.
- Visual screenshots were not captured in this heartbeat; targeted
component/helper tests cover the changed behavior.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5-based coding agent runtime, shell/git tool use
enabled. Exact hosted model build and context window are not exposed in
this Paperclip heartbeat environment.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-04-21 12:25:34 -05:00
|
|
|
vi.mock("../api/instanceSettings", () => ({
|
|
|
|
|
instanceSettingsApi: mockInstanceSettingsApi,
|
|
|
|
|
}));
|
|
|
|
|
|
2026-04-06 10:58:59 -05:00
|
|
|
vi.mock("../hooks/useProjectOrder", () => ({
|
|
|
|
|
useProjectOrder: ({ projects }: { projects: unknown[] }) => ({
|
|
|
|
|
orderedProjects: projects,
|
|
|
|
|
}),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
vi.mock("../lib/recent-assignees", () => ({
|
|
|
|
|
getRecentAssigneeIds: () => [],
|
[codex] Polish issue and operator workflow UI (#4090)
## Thinking Path
> - Paperclip operators spend much of their time in issues, inboxes,
selectors, and rich comment threads.
> - Small interaction problems in those surfaces slow down supervision
of AI-agent work.
> - The branch included related operator quality-of-life fixes for issue
layout, inbox actions, recent selectors, mobile inputs, and chat
rendering stability.
> - These changes are UI-focused and can land independently from
workspace navigation and access-profile work.
> - This pull request groups the operator QoL fixes into one standalone
branch.
> - The benefit is a more stable and efficient board workflow for issue
triage and task editing.
## What Changed
- Widened issue detail content and added a desktop inbox archive action.
- Fixed mobile text-field zoom by keeping touch input font sizes at
16px.
- Prioritized recent picker selections for assignees/projects in issue
and routine flows.
- Showed actionable approvals in the Mine inbox model.
- Fixed issue chat renderer state crashes and hardened tests.
## Verification
- `pnpm install --frozen-lockfile`
- `pnpm exec vitest run ui/src/components/IssueChatThread.test.tsx
ui/src/lib/inbox.test.ts ui/src/lib/recent-selections.test.ts`
- Split integration check: merged last after the other
[PAP-1614](/PAP/issues/PAP-1614) branches with no merge conflicts.
- Confirmed this branch does not include `pnpm-lock.yaml`.
## Risks
- Low to medium risk: mostly UI state, layout, and selection-priority
behavior.
- Visual layout and mobile zoom behavior may need browser/device QA
beyond component tests.
- No database migrations are included.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5.4 tool-enabled coding model, agentic
code-editing/runtime with local shell and GitHub CLI access; exact
context window and reasoning mode are not exposed by the Paperclip
harness.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-20 06:16:41 -05:00
|
|
|
getRecentAssigneeSelectionIds: () => [],
|
2026-04-06 10:58:59 -05:00
|
|
|
sortAgentsByRecency: (agents: unknown[]) => agents,
|
|
|
|
|
trackRecentAssignee: vi.fn(),
|
[codex] Polish issue and operator workflow UI (#4090)
## Thinking Path
> - Paperclip operators spend much of their time in issues, inboxes,
selectors, and rich comment threads.
> - Small interaction problems in those surfaces slow down supervision
of AI-agent work.
> - The branch included related operator quality-of-life fixes for issue
layout, inbox actions, recent selectors, mobile inputs, and chat
rendering stability.
> - These changes are UI-focused and can land independently from
workspace navigation and access-profile work.
> - This pull request groups the operator QoL fixes into one standalone
branch.
> - The benefit is a more stable and efficient board workflow for issue
triage and task editing.
## What Changed
- Widened issue detail content and added a desktop inbox archive action.
- Fixed mobile text-field zoom by keeping touch input font sizes at
16px.
- Prioritized recent picker selections for assignees/projects in issue
and routine flows.
- Showed actionable approvals in the Mine inbox model.
- Fixed issue chat renderer state crashes and hardened tests.
## Verification
- `pnpm install --frozen-lockfile`
- `pnpm exec vitest run ui/src/components/IssueChatThread.test.tsx
ui/src/lib/inbox.test.ts ui/src/lib/recent-selections.test.ts`
- Split integration check: merged last after the other
[PAP-1614](/PAP/issues/PAP-1614) branches with no merge conflicts.
- Confirmed this branch does not include `pnpm-lock.yaml`.
## Risks
- Low to medium risk: mostly UI state, layout, and selection-priority
behavior.
- Visual layout and mobile zoom behavior may need browser/device QA
beyond component tests.
- No database migrations are included.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5.4 tool-enabled coding model, agentic
code-editing/runtime with local shell and GitHub CLI access; exact
context window and reasoning mode are not exposed by the Paperclip
harness.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-20 06:16:41 -05:00
|
|
|
trackRecentAssigneeUser: vi.fn(),
|
2026-04-06 10:58:59 -05:00
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
vi.mock("../lib/assignees", () => ({
|
|
|
|
|
formatAssigneeUserLabel: () => "Me",
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
vi.mock("./StatusIcon", () => ({
|
2026-04-24 15:50:32 -05:00
|
|
|
StatusIcon: ({ status, blockerAttention }: { status: string; blockerAttention?: Issue["blockerAttention"] }) => (
|
|
|
|
|
<span data-status-icon-state={blockerAttention?.state}>{status}</span>
|
|
|
|
|
),
|
2026-04-06 10:58:59 -05:00
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
vi.mock("./PriorityIcon", () => ({
|
|
|
|
|
PriorityIcon: ({ priority }: { priority: string }) => <span>{priority}</span>,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
vi.mock("./Identity", () => ({
|
|
|
|
|
Identity: ({ name }: { name: string }) => <span>{name}</span>,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
vi.mock("./AgentIconPicker", () => ({
|
|
|
|
|
AgentIcon: () => null,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
vi.mock("@/lib/router", () => ({
|
|
|
|
|
Link: ({ children, to, ...props }: { children: ReactNode; to: string } & ComponentProps<"a">) => <a href={to} {...props}>{children}</a>,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
vi.mock("@/components/ui/separator", () => ({
|
|
|
|
|
Separator: () => <hr />,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
vi.mock("@/components/ui/popover", () => ({
|
|
|
|
|
Popover: ({ children }: { children: ReactNode }) => <div>{children}</div>,
|
|
|
|
|
PopoverTrigger: ({ children }: { children: ReactNode }) => <>{children}</>,
|
|
|
|
|
PopoverContent: ({ children }: { children: ReactNode }) => <div>{children}</div>,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
|
(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true;
|
|
|
|
|
|
|
|
|
|
async function flush() {
|
|
|
|
|
await act(async () => {
|
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createIssue(overrides: Partial<Issue> = {}): Issue {
|
|
|
|
|
return {
|
|
|
|
|
id: "issue-1",
|
|
|
|
|
companyId: "company-1",
|
|
|
|
|
projectId: null,
|
|
|
|
|
projectWorkspaceId: null,
|
|
|
|
|
goalId: null,
|
|
|
|
|
parentId: null,
|
|
|
|
|
title: "Parent issue",
|
|
|
|
|
description: null,
|
|
|
|
|
status: "todo",
|
|
|
|
|
priority: "medium",
|
|
|
|
|
assigneeAgentId: null,
|
|
|
|
|
assigneeUserId: null,
|
|
|
|
|
checkoutRunId: null,
|
|
|
|
|
executionRunId: null,
|
|
|
|
|
executionAgentNameKey: null,
|
|
|
|
|
executionLockedAt: null,
|
|
|
|
|
createdByAgentId: null,
|
|
|
|
|
createdByUserId: "user-1",
|
|
|
|
|
issueNumber: 1,
|
|
|
|
|
identifier: "PAP-1",
|
|
|
|
|
requestDepth: 0,
|
|
|
|
|
billingCode: null,
|
|
|
|
|
assigneeAdapterOverrides: null,
|
|
|
|
|
executionWorkspaceId: null,
|
|
|
|
|
executionWorkspacePreference: null,
|
|
|
|
|
executionWorkspaceSettings: null,
|
|
|
|
|
startedAt: null,
|
|
|
|
|
completedAt: null,
|
|
|
|
|
cancelledAt: null,
|
|
|
|
|
hiddenAt: null,
|
|
|
|
|
labels: [],
|
|
|
|
|
labelIds: [],
|
|
|
|
|
blockedBy: [],
|
|
|
|
|
blocks: [],
|
|
|
|
|
createdAt: new Date("2026-04-06T12:00:00.000Z"),
|
|
|
|
|
updatedAt: new Date("2026-04-06T12:05:00.000Z"),
|
|
|
|
|
...overrides,
|
Add planning mode for issue work (#5353)
## Thinking Path
> - Paperclip is a control plane for autonomous AI companies.
> - Issues are the core unit of work, and issue comments are how board
users and agents coordinate execution.
> - Some issue conversations need to produce plans and approvals instead
of immediate implementation work.
> - The existing issue contract did not distinguish standard execution
comments from planning-oriented issue work.
> - This pull request adds an issue work-mode contract and board UI
affordances for standard vs planning mode.
> - The benefit is that planning-mode issues can be created, displayed,
discussed, and carried through agent heartbeat context without losing
the normal issue workflow.
## What Changed
- Added `standard` / `planning` issue work-mode contracts across DB,
shared validators/types, server issue flows, plugin protocol, and
adapter heartbeat payloads.
- Added an idempotent `0081_optimal_dormammu` migration for
`issues.work_mode`, ordered after current `public-gh/master` migrations.
- Updated heartbeat/context summaries and issue-thread interaction
behavior so planning work mode is preserved when creating suggested
follow-up issues.
- Added UI support for planning-mode issue creation, issue rows, detail
composer styling, and composer work-mode toggles.
- Added focused server/shared/UI tests plus a Playwright visual
verification spec for planning-mode surfaces.
- Rebased the branch onto current `public-gh/master` and added durable
planning-mode screenshots under `doc/assets/pap-3368/`.
## Verification
- `pnpm --filter @paperclipai/db run check:migrations`
- `pnpm exec vitest run --project @paperclipai/shared
packages/shared/src/validators/issue.test.ts`
- `pnpm exec vitest run --project @paperclipai/server
server/src/__tests__/heartbeat-context-summary.test.ts
server/src/__tests__/issue-thread-interactions-service.test.ts
server/src/__tests__/issues-goal-context-routes.test.ts --pool=forks
--poolOptions.forks.isolate=true`
- `pnpm exec vitest run --project @paperclipai/ui
ui/src/components/IssueChatThread.test.tsx
ui/src/components/NewIssueDialog.test.tsx
ui/src/components/IssueRow.test.tsx ui/src/pages/IssueDetail.test.tsx`
- `pnpm exec vitest run --project @paperclipai/adapter-utils
packages/adapter-utils/src/server-utils.test.ts`
- `PAPERCLIP_E2E_SKIP_LLM=true npx playwright test --config
tests/e2e/playwright.config.ts
tests/e2e/planning-mode-visual-verification.spec.ts`
## Screenshots
Desktop planning detail:

Desktop planning row:

Desktop staged standard toggle:

Mobile planning detail:

Mobile planning row:

## Risks
- Medium migration risk: this adds a non-null issue column. The
migration uses `ADD COLUMN IF NOT EXISTS` so installations that applied
an older branch-local migration number can still apply the final
numbered migration safely.
- Medium contract risk: issue payloads, plugin payloads, and adapter
heartbeat payloads now include work mode; compatibility is handled by
defaulting missing values to `standard`.
- UI risk is moderate because composer controls changed; focused
component tests and visual e2e coverage exercise standard vs planning
display and toggle behavior.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5 coding agent in a local Paperclip worktree, with
shell/tool use. Exact context-window size is not exposed in this
runtime.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-05-06 07:01:28 -05:00
|
|
|
workMode: overrides.workMode ?? "standard",
|
2026-04-06 10:58:59 -05:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
[codex] Polish issue board workflows (#4224)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Human operators supervise that work through issue lists, issue
detail, comments, inbox groups, markdown references, and
profile/activity surfaces
> - The branch had many small UI fixes that improve the operator loop
but do not need to ship with backend runtime migrations
> - These changes belong together as board workflow polish because they
affect scanning, navigation, issue context, comment state, and markdown
clarity
> - This pull request groups the UI-only slice so it can merge
independently from runtime/backend changes
> - The benefit is a clearer board experience with better issue context,
steadier optimistic updates, and more predictable keyboard navigation
## What Changed
- Improves issue properties, sub-issue actions, blocker chips, and issue
list/detail refresh behavior.
- Adds blocker context above the issue composer and stabilizes
queued/interrupted comment UI state.
- Improves markdown issue/GitHub link rendering and opens external
markdown links in a new tab.
- Adds inbox group keyboard navigation and fold/unfold support.
- Polishes activity/avatar/profile/settings/workspace presentation
details.
## Verification
- `pnpm exec vitest run ui/src/components/IssueProperties.test.tsx
ui/src/components/IssueChatThread.test.tsx
ui/src/components/MarkdownBody.test.tsx ui/src/lib/inbox.test.ts
ui/src/lib/optimistic-issue-comments.test.ts`
## Risks
- Low to medium risk: changes are UI-focused but cover high-traffic
issue and inbox surfaces.
- This branch intentionally does not include the backend runtime changes
from the companion PR; where UI calls newer API filters, unsupported
servers should continue to fail visibly through existing API error
handling.
- Visual screenshots were not captured in this heartbeat; targeted
component/helper tests cover the changed behavior.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5-based coding agent runtime, shell/git tool use
enabled. Exact hosted model build and context window are not exposed in
this Paperclip heartbeat environment.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-04-21 12:25:34 -05:00
|
|
|
function createLabel(overrides: Partial<IssueLabel> = {}): IssueLabel {
|
|
|
|
|
return {
|
|
|
|
|
id: "label-1",
|
|
|
|
|
companyId: "company-1",
|
|
|
|
|
name: "Bug",
|
|
|
|
|
color: "#ef4444",
|
|
|
|
|
createdAt: new Date("2026-04-06T12:00:00.000Z"),
|
|
|
|
|
updatedAt: new Date("2026-04-06T12:00:00.000Z"),
|
|
|
|
|
...overrides,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
[codex] Improve workspace navigation and runtime UI (#4089)
## Thinking Path
> - Paperclip agents do real work in project and execution workspaces.
> - Operators need workspace state to be visible, navigable, and
copyable without digging through raw run logs.
> - The branch included related workspace cards, navigation, runtime
controls, stale-service handling, and issue-property visibility.
> - These changes share the workspace UI and runtime-control surfaces
and can stand alone from unrelated access/profile work.
> - This pull request groups the workspace experience changes into one
standalone branch.
> - The benefit is a clearer workspace overview, better metadata copy
flows, and more accurate runtime service controls.
## What Changed
- Polished project workspace summary cards and made workspace metadata
copyable.
- Added a workspace navigation overview and extracted reusable project
workspace content.
- Squared and polished the execution workspace configuration page.
- Fixed stale workspace command matching and hid stopped stale services
in runtime controls.
- Showed live workspace service context in issue properties.
## Verification
- `pnpm install --frozen-lockfile`
- `pnpm exec vitest run
ui/src/components/ProjectWorkspaceSummaryCard.test.tsx
ui/src/lib/project-workspaces-tab.test.ts
ui/src/components/Sidebar.test.tsx
ui/src/components/WorkspaceRuntimeControls.test.tsx
ui/src/components/IssueProperties.test.tsx`
- `pnpm exec vitest run packages/shared/src/workspace-commands.test.ts
--config /dev/null` because the root Vitest project config does not
currently include `packages/shared` tests.
- Split integration check: merged after runtime/governance,
dev-infra/backups, and access/profiles with no merge conflicts.
- Confirmed this branch does not include `pnpm-lock.yaml`.
## Risks
- Medium risk: touches workspace navigation, runtime controls, and issue
property rendering.
- Visual layout changes may need browser QA, especially around smaller
screens and dense workspace metadata.
- No database migrations are included.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5.4 tool-enabled coding model, agentic
code-editing/runtime with local shell and GitHub CLI access; exact
context window and reasoning mode are not exposed by the Paperclip
harness.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-20 06:14:32 -05:00
|
|
|
function createRuntimeService(overrides: Partial<WorkspaceRuntimeService> = {}): WorkspaceRuntimeService {
|
|
|
|
|
return {
|
|
|
|
|
id: "service-1",
|
|
|
|
|
companyId: "company-1",
|
|
|
|
|
projectId: "project-1",
|
|
|
|
|
projectWorkspaceId: "workspace-main",
|
|
|
|
|
executionWorkspaceId: "workspace-1",
|
|
|
|
|
issueId: "issue-1",
|
|
|
|
|
scopeType: "execution_workspace",
|
|
|
|
|
scopeId: "workspace-1",
|
|
|
|
|
serviceName: "web",
|
|
|
|
|
status: "running",
|
|
|
|
|
lifecycle: "shared",
|
|
|
|
|
reuseKey: null,
|
|
|
|
|
command: "pnpm dev",
|
|
|
|
|
cwd: "/tmp/paperclip",
|
|
|
|
|
port: 62475,
|
|
|
|
|
url: "http://127.0.0.1:62475",
|
|
|
|
|
provider: "local_process",
|
|
|
|
|
providerRef: null,
|
|
|
|
|
ownerAgentId: null,
|
|
|
|
|
startedByRunId: null,
|
|
|
|
|
lastUsedAt: new Date("2026-04-06T12:03:00.000Z"),
|
|
|
|
|
startedAt: new Date("2026-04-06T12:02:00.000Z"),
|
|
|
|
|
stoppedAt: null,
|
|
|
|
|
stopPolicy: null,
|
|
|
|
|
healthStatus: "healthy",
|
|
|
|
|
createdAt: new Date("2026-04-06T12:02:00.000Z"),
|
|
|
|
|
updatedAt: new Date("2026-04-06T12:03:00.000Z"),
|
|
|
|
|
...overrides,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createExecutionWorkspace(overrides: Partial<ExecutionWorkspace> = {}): ExecutionWorkspace {
|
|
|
|
|
return {
|
|
|
|
|
id: "workspace-1",
|
|
|
|
|
companyId: "company-1",
|
|
|
|
|
projectId: "project-1",
|
|
|
|
|
projectWorkspaceId: "workspace-main",
|
|
|
|
|
sourceIssueId: "issue-1",
|
|
|
|
|
mode: "isolated_workspace",
|
|
|
|
|
strategyType: "git_worktree",
|
|
|
|
|
name: "PAP-1 workspace",
|
|
|
|
|
status: "active",
|
|
|
|
|
cwd: "/tmp/paperclip/PAP-1",
|
|
|
|
|
repoUrl: null,
|
|
|
|
|
baseRef: "master",
|
|
|
|
|
branchName: "pap-1-workspace",
|
|
|
|
|
providerType: "git_worktree",
|
|
|
|
|
providerRef: "/tmp/paperclip/PAP-1",
|
|
|
|
|
derivedFromExecutionWorkspaceId: null,
|
|
|
|
|
lastUsedAt: new Date("2026-04-06T12:04:00.000Z"),
|
|
|
|
|
openedAt: new Date("2026-04-06T12:01:00.000Z"),
|
|
|
|
|
closedAt: null,
|
|
|
|
|
cleanupEligibleAt: null,
|
|
|
|
|
cleanupReason: null,
|
|
|
|
|
config: null,
|
|
|
|
|
metadata: null,
|
|
|
|
|
runtimeServices: [createRuntimeService()],
|
|
|
|
|
createdAt: new Date("2026-04-06T12:01:00.000Z"),
|
|
|
|
|
updatedAt: new Date("2026-04-06T12:04:00.000Z"),
|
|
|
|
|
...overrides,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createProject(overrides: Partial<Project> = {}): Project {
|
|
|
|
|
const primaryWorkspace = {
|
|
|
|
|
id: "workspace-main",
|
|
|
|
|
companyId: "company-1",
|
|
|
|
|
projectId: "project-1",
|
|
|
|
|
name: "Main",
|
|
|
|
|
sourceType: "local_path" as const,
|
|
|
|
|
cwd: "/tmp/paperclip",
|
|
|
|
|
repoUrl: null,
|
|
|
|
|
repoRef: null,
|
|
|
|
|
defaultRef: "master",
|
|
|
|
|
visibility: "default" as const,
|
|
|
|
|
setupCommand: null,
|
|
|
|
|
cleanupCommand: null,
|
|
|
|
|
remoteProvider: null,
|
|
|
|
|
remoteWorkspaceRef: null,
|
|
|
|
|
sharedWorkspaceKey: null,
|
|
|
|
|
metadata: null,
|
|
|
|
|
runtimeConfig: null,
|
|
|
|
|
isPrimary: true,
|
|
|
|
|
runtimeServices: [],
|
|
|
|
|
createdAt: new Date("2026-04-06T12:00:00.000Z"),
|
|
|
|
|
updatedAt: new Date("2026-04-06T12:00:00.000Z"),
|
|
|
|
|
};
|
|
|
|
|
return {
|
|
|
|
|
id: "project-1",
|
|
|
|
|
companyId: "company-1",
|
|
|
|
|
urlKey: "project-1",
|
|
|
|
|
goalId: null,
|
|
|
|
|
goalIds: [],
|
|
|
|
|
goals: [],
|
|
|
|
|
name: "Project",
|
|
|
|
|
description: null,
|
|
|
|
|
status: "in_progress",
|
|
|
|
|
leadAgentId: null,
|
|
|
|
|
targetDate: null,
|
|
|
|
|
color: "#6366f1",
|
|
|
|
|
env: null,
|
|
|
|
|
pauseReason: null,
|
|
|
|
|
pausedAt: null,
|
|
|
|
|
executionWorkspacePolicy: null,
|
|
|
|
|
codebase: {
|
|
|
|
|
workspaceId: "workspace-main",
|
|
|
|
|
repoUrl: null,
|
|
|
|
|
repoRef: null,
|
|
|
|
|
defaultRef: "master",
|
|
|
|
|
repoName: null,
|
|
|
|
|
localFolder: "/tmp/paperclip",
|
|
|
|
|
managedFolder: "/tmp/paperclip",
|
|
|
|
|
effectiveLocalFolder: "/tmp/paperclip",
|
|
|
|
|
origin: "local_folder",
|
|
|
|
|
},
|
|
|
|
|
workspaces: [primaryWorkspace],
|
|
|
|
|
primaryWorkspace,
|
|
|
|
|
archivedAt: null,
|
|
|
|
|
createdAt: new Date("2026-04-06T12:00:00.000Z"),
|
|
|
|
|
updatedAt: new Date("2026-04-06T12:00:00.000Z"),
|
|
|
|
|
...overrides,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-08 17:00:57 -05:00
|
|
|
function createExecutionPolicy(overrides: Partial<IssueExecutionPolicy> = {}): IssueExecutionPolicy {
|
|
|
|
|
return {
|
|
|
|
|
mode: "normal",
|
|
|
|
|
commentRequired: true,
|
|
|
|
|
stages: [],
|
|
|
|
|
...overrides,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createExecutionState(overrides: Partial<IssueExecutionState> = {}): IssueExecutionState {
|
|
|
|
|
return {
|
|
|
|
|
status: "changes_requested",
|
|
|
|
|
currentStageId: "stage-1",
|
|
|
|
|
currentStageIndex: 0,
|
|
|
|
|
currentStageType: "review",
|
|
|
|
|
currentParticipant: { type: "agent", agentId: "agent-1", userId: null },
|
|
|
|
|
returnAssignee: { type: "agent", agentId: "agent-2", userId: null },
|
[codex] Improve issue thread review flow (#4381)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Issue detail is where operators coordinate review, approvals, and
follow-up work with active runs
> - That thread UI needs to surface blockers, descendants, review
handoffs, and reply ergonomics clearly enough for humans to guide agent
work
> - Several small gaps in the issue-thread flow were making review and
navigation clunkier than necessary
> - This pull request improves the reply composer, descendant/blocker
presentation, interaction folding, and review-request handoff plumbing
together as one cohesive issue-thread workflow slice
> - The benefit is a cleaner operator review loop without changing the
broader task model
## What Changed
- restored and refined the floating reply composer behavior in the issue
thread
- folded expired confirmation interactions and improved post-submit
thread scrolling behavior
- surfaced descendant issue context and inline blocker/paused-assignee
notices on the issue detail view
- tightened large-board first paint behavior in `IssuesList`
- added loose review-request handoffs through the issue
execution-policy/update path and covered them with tests
## Verification
- `pnpm vitest run ui/src/pages/IssueDetail.test.tsx`
- `pnpm vitest run server/src/__tests__/issues-service.test.ts
server/src/__tests__/issue-execution-policy.test.ts`
- `pnpm exec vitest run --project @paperclipai/ui
ui/src/components/IssueChatThread.test.tsx
ui/src/components/IssueProperties.test.tsx
ui/src/components/IssuesList.test.tsx ui/src/lib/issue-tree.test.ts
ui/src/api/issues.test.ts`
- `pnpm exec vitest run --project @paperclipai/adapter-utils
packages/adapter-utils/src/server-utils.test.ts`
- `pnpm exec vitest run --project @paperclipai/server
server/src/__tests__/issue-comment-reopen-routes.test.ts -t "coerces
executor handoff patches into workflow-controlled review wakes|wakes the
return assignee with execution_changes_requested"`
- `pnpm exec vitest run --project @paperclipai/server
server/src/__tests__/issue-execution-policy.test.ts
server/src/__tests__/issues-service.test.ts`
## Visual Evidence
- UI layout changes are covered by the focused issue-thread component
and issue-detail tests listed above. Browser screenshots were not
attachable from this automated greploop environment, so reviewers should
use the running preview for final visual confirmation.
## Risks
- Moderate UI-flow risk: these changes touch the issue detail experience
in multiple spots, so regressions would most likely show up as
thread-layout quirks or incorrect review-handoff behavior
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex GPT-5-based coding agent with tool use and code execution
in the Codex CLI environment
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots or documented the visual verification path
- [ ] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-24 08:02:45 -05:00
|
|
|
reviewRequest: null,
|
2026-04-08 17:00:57 -05:00
|
|
|
completedStageIds: [],
|
|
|
|
|
lastDecisionId: null,
|
|
|
|
|
lastDecisionOutcome: "changes_requested",
|
|
|
|
|
...overrides,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-06 10:58:59 -05:00
|
|
|
function renderProperties(container: HTMLDivElement, props: ComponentProps<typeof IssueProperties>) {
|
|
|
|
|
const queryClient = new QueryClient({
|
|
|
|
|
defaultOptions: {
|
|
|
|
|
queries: { retry: false },
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
const root = createRoot(container);
|
|
|
|
|
act(() => {
|
|
|
|
|
root.render(
|
|
|
|
|
<QueryClientProvider client={queryClient}>
|
|
|
|
|
<IssueProperties {...props} />
|
|
|
|
|
</QueryClientProvider>,
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
return root;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
describe("IssueProperties", () => {
|
|
|
|
|
let container: HTMLDivElement;
|
|
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
container = document.createElement("div");
|
|
|
|
|
document.body.appendChild(container);
|
|
|
|
|
mockAgentsApi.list.mockResolvedValue([]);
|
|
|
|
|
mockProjectsApi.list.mockResolvedValue([]);
|
2026-04-10 22:26:21 -05:00
|
|
|
mockIssuesApi.list.mockResolvedValue([]);
|
2026-04-06 10:58:59 -05:00
|
|
|
mockIssuesApi.listLabels.mockResolvedValue([]);
|
[codex] Polish issue board workflows (#4224)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Human operators supervise that work through issue lists, issue
detail, comments, inbox groups, markdown references, and
profile/activity surfaces
> - The branch had many small UI fixes that improve the operator loop
but do not need to ship with backend runtime migrations
> - These changes belong together as board workflow polish because they
affect scanning, navigation, issue context, comment state, and markdown
clarity
> - This pull request groups the UI-only slice so it can merge
independently from runtime/backend changes
> - The benefit is a clearer board experience with better issue context,
steadier optimistic updates, and more predictable keyboard navigation
## What Changed
- Improves issue properties, sub-issue actions, blocker chips, and issue
list/detail refresh behavior.
- Adds blocker context above the issue composer and stabilizes
queued/interrupted comment UI state.
- Improves markdown issue/GitHub link rendering and opens external
markdown links in a new tab.
- Adds inbox group keyboard navigation and fold/unfold support.
- Polishes activity/avatar/profile/settings/workspace presentation
details.
## Verification
- `pnpm exec vitest run ui/src/components/IssueProperties.test.tsx
ui/src/components/IssueChatThread.test.tsx
ui/src/components/MarkdownBody.test.tsx ui/src/lib/inbox.test.ts
ui/src/lib/optimistic-issue-comments.test.ts`
## Risks
- Low to medium risk: changes are UI-focused but cover high-traffic
issue and inbox surfaces.
- This branch intentionally does not include the backend runtime changes
from the companion PR; where UI calls newer API filters, unsupported
servers should continue to fail visibly through existing API error
handling.
- Visual screenshots were not captured in this heartbeat; targeted
component/helper tests cover the changed behavior.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5-based coding agent runtime, shell/git tool use
enabled. Exact hosted model build and context window are not exposed in
this Paperclip heartbeat environment.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-04-21 12:25:34 -05:00
|
|
|
mockIssuesApi.createLabel.mockResolvedValue(createLabel({
|
|
|
|
|
id: "label-new",
|
|
|
|
|
name: "New label",
|
|
|
|
|
color: "#6366f1",
|
|
|
|
|
}));
|
2026-04-06 10:58:59 -05:00
|
|
|
mockAuthApi.getSession.mockResolvedValue({ user: { id: "user-1" } });
|
[codex] Polish issue board workflows (#4224)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Human operators supervise that work through issue lists, issue
detail, comments, inbox groups, markdown references, and
profile/activity surfaces
> - The branch had many small UI fixes that improve the operator loop
but do not need to ship with backend runtime migrations
> - These changes belong together as board workflow polish because they
affect scanning, navigation, issue context, comment state, and markdown
clarity
> - This pull request groups the UI-only slice so it can merge
independently from runtime/backend changes
> - The benefit is a clearer board experience with better issue context,
steadier optimistic updates, and more predictable keyboard navigation
## What Changed
- Improves issue properties, sub-issue actions, blocker chips, and issue
list/detail refresh behavior.
- Adds blocker context above the issue composer and stabilizes
queued/interrupted comment UI state.
- Improves markdown issue/GitHub link rendering and opens external
markdown links in a new tab.
- Adds inbox group keyboard navigation and fold/unfold support.
- Polishes activity/avatar/profile/settings/workspace presentation
details.
## Verification
- `pnpm exec vitest run ui/src/components/IssueProperties.test.tsx
ui/src/components/IssueChatThread.test.tsx
ui/src/components/MarkdownBody.test.tsx ui/src/lib/inbox.test.ts
ui/src/lib/optimistic-issue-comments.test.ts`
## Risks
- Low to medium risk: changes are UI-focused but cover high-traffic
issue and inbox surfaces.
- This branch intentionally does not include the backend runtime changes
from the companion PR; where UI calls newer API filters, unsupported
servers should continue to fail visibly through existing API error
handling.
- Visual screenshots were not captured in this heartbeat; targeted
component/helper tests cover the changed behavior.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5-based coding agent runtime, shell/git tool use
enabled. Exact hosted model build and context window are not exposed in
this Paperclip heartbeat environment.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-04-21 12:25:34 -05:00
|
|
|
mockInstanceSettingsApi.getExperimental.mockResolvedValue({ enableIsolatedWorkspaces: false });
|
2026-04-06 10:58:59 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
afterEach(() => {
|
|
|
|
|
document.body.innerHTML = "";
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("always exposes the add sub-issue action", async () => {
|
|
|
|
|
const onAddSubIssue = vi.fn();
|
|
|
|
|
const root = renderProperties(container, {
|
|
|
|
|
issue: createIssue(),
|
|
|
|
|
childIssues: [],
|
|
|
|
|
onAddSubIssue,
|
|
|
|
|
onUpdate: vi.fn(),
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
expect(container.textContent).toContain("Sub-issues");
|
|
|
|
|
expect(container.textContent).toContain("Add sub-issue");
|
|
|
|
|
|
|
|
|
|
const addButton = Array.from(container.querySelectorAll("button"))
|
|
|
|
|
.find((button) => button.textContent?.includes("Add sub-issue"));
|
|
|
|
|
expect(addButton).not.toBeUndefined();
|
|
|
|
|
|
|
|
|
|
await act(async () => {
|
|
|
|
|
addButton!.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
expect(onAddSubIssue).toHaveBeenCalledTimes(1);
|
|
|
|
|
|
|
|
|
|
act(() => root.unmount());
|
|
|
|
|
});
|
2026-04-08 17:00:57 -05:00
|
|
|
|
2026-04-24 15:50:32 -05:00
|
|
|
it("passes blocker attention to the sidebar status icon", async () => {
|
|
|
|
|
const root = renderProperties(container, {
|
|
|
|
|
issue: createIssue({
|
|
|
|
|
status: "blocked",
|
|
|
|
|
blockerAttention: {
|
|
|
|
|
state: "covered",
|
|
|
|
|
reason: "active_child",
|
|
|
|
|
unresolvedBlockerCount: 1,
|
|
|
|
|
coveredBlockerCount: 1,
|
2026-04-26 21:17:38 -05:00
|
|
|
stalledBlockerCount: 0,
|
2026-04-24 15:50:32 -05:00
|
|
|
attentionBlockerCount: 0,
|
|
|
|
|
sampleBlockerIdentifier: "PAP-2",
|
2026-04-26 21:17:38 -05:00
|
|
|
sampleStalledBlockerIdentifier: null,
|
2026-04-24 15:50:32 -05:00
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
childIssues: [],
|
|
|
|
|
onUpdate: vi.fn(),
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
expect(container.querySelector('[data-status-icon-state="covered"]')?.textContent).toBe("blocked");
|
|
|
|
|
|
|
|
|
|
act(() => root.unmount());
|
|
|
|
|
});
|
|
|
|
|
|
[codex] Polish issue board workflows (#4224)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Human operators supervise that work through issue lists, issue
detail, comments, inbox groups, markdown references, and
profile/activity surfaces
> - The branch had many small UI fixes that improve the operator loop
but do not need to ship with backend runtime migrations
> - These changes belong together as board workflow polish because they
affect scanning, navigation, issue context, comment state, and markdown
clarity
> - This pull request groups the UI-only slice so it can merge
independently from runtime/backend changes
> - The benefit is a clearer board experience with better issue context,
steadier optimistic updates, and more predictable keyboard navigation
## What Changed
- Improves issue properties, sub-issue actions, blocker chips, and issue
list/detail refresh behavior.
- Adds blocker context above the issue composer and stabilizes
queued/interrupted comment UI state.
- Improves markdown issue/GitHub link rendering and opens external
markdown links in a new tab.
- Adds inbox group keyboard navigation and fold/unfold support.
- Polishes activity/avatar/profile/settings/workspace presentation
details.
## Verification
- `pnpm exec vitest run ui/src/components/IssueProperties.test.tsx
ui/src/components/IssueChatThread.test.tsx
ui/src/components/MarkdownBody.test.tsx ui/src/lib/inbox.test.ts
ui/src/lib/optimistic-issue-comments.test.ts`
## Risks
- Low to medium risk: changes are UI-focused but cover high-traffic
issue and inbox surfaces.
- This branch intentionally does not include the backend runtime changes
from the companion PR; where UI calls newer API filters, unsupported
servers should continue to fail visibly through existing API error
handling.
- Visual screenshots were not captured in this heartbeat; targeted
component/helper tests cover the changed behavior.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5-based coding agent runtime, shell/git tool use
enabled. Exact hosted model build and context window are not exposed in
this Paperclip heartbeat environment.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-04-21 12:25:34 -05:00
|
|
|
it("renders blocked-by issues as direct chips and edits them from an add action", async () => {
|
|
|
|
|
const onUpdate = vi.fn();
|
|
|
|
|
mockIssuesApi.list.mockResolvedValue([
|
|
|
|
|
createIssue({ id: "issue-3", identifier: "PAP-3", title: "New blocker", status: "todo" }),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
const root = renderProperties(container, {
|
|
|
|
|
issue: createIssue({
|
|
|
|
|
blockedBy: [
|
|
|
|
|
{
|
|
|
|
|
id: "issue-2",
|
|
|
|
|
identifier: "PAP-2",
|
|
|
|
|
title: "Existing blocker",
|
|
|
|
|
status: "in_progress",
|
|
|
|
|
priority: "medium",
|
|
|
|
|
assigneeAgentId: null,
|
|
|
|
|
assigneeUserId: null,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
}),
|
|
|
|
|
childIssues: [],
|
|
|
|
|
onUpdate,
|
|
|
|
|
inline: true,
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
const blockerLink = container.querySelector('a[href="/issues/PAP-2"]');
|
|
|
|
|
expect(blockerLink).not.toBeNull();
|
|
|
|
|
expect(blockerLink?.textContent).toContain("PAP-2");
|
|
|
|
|
expect(blockerLink?.closest("button")).toBeNull();
|
|
|
|
|
expect(container.textContent).toContain("Add blocker");
|
|
|
|
|
expect(container.querySelector('input[placeholder="Search issues..."]')).toBeNull();
|
|
|
|
|
|
|
|
|
|
const addButton = Array.from(container.querySelectorAll("button"))
|
|
|
|
|
.find((button) => button.textContent?.includes("Add blocker"));
|
|
|
|
|
expect(addButton).not.toBeUndefined();
|
|
|
|
|
|
|
|
|
|
await act(async () => {
|
|
|
|
|
addButton!.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
expect(container.querySelector('input[placeholder="Search issues..."]')).not.toBeNull();
|
|
|
|
|
|
|
|
|
|
const candidateButton = Array.from(container.querySelectorAll("button"))
|
|
|
|
|
.find((button) => button.textContent?.includes("PAP-3 New blocker"));
|
|
|
|
|
expect(candidateButton).not.toBeUndefined();
|
|
|
|
|
|
|
|
|
|
await act(async () => {
|
|
|
|
|
candidateButton!.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
expect(onUpdate).toHaveBeenCalledWith({ blockedByIssueIds: ["issue-2", "issue-3"] });
|
|
|
|
|
|
|
|
|
|
act(() => root.unmount());
|
|
|
|
|
});
|
|
|
|
|
|
Improve operator workflow QoL (#5291)
## Thinking Path
> - Paperclip is a control plane operators use repeatedly to supervise
agent companies.
> - Common operator workflows depend on fast scanning of inboxes, issue
sidebars, workspaces, cost totals, and runtime services.
> - Several small UI and service gaps made those workflows slower or
less clear.
> - This pull request groups the operator-facing QoL changes that can
stand alone from recovery and adapter work.
> - The benefit is a denser, clearer board experience for issue triage
and workspace operation.
## What Changed
- Added inbox assignee/project grouping and issue list token/runtime
totals.
- Improved issue properties with removable blocker chips and workspace
task links.
- Improved execution workspace layout, runtime controls, issues tab
default, and stopped-port reuse behavior.
- Added mobile markdown/routine dialog fixes, page title company names,
sidebar polish, and dashboard run task label cleanup.
## Verification
- `pnpm install --frozen-lockfile`
- `pnpm exec vitest run ui/src/lib/inbox.test.ts
ui/src/components/IssueProperties.test.tsx
ui/src/components/WorkspaceRuntimeControls.test.tsx
server/src/__tests__/workspace-runtime.test.ts
server/src/__tests__/costs-service.test.ts`
## Risks
- Medium UI risk because this touches several operator surfaces. The
branch is intentionally grouped around workflow/QoL files and keeps the
file count below the Greptile limit.
## Model Used
- OpenAI GPT-5 Codex via Paperclip `codex_local` adapter, with
shell/git/GitHub CLI tool use.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-05-06 06:30:44 -05:00
|
|
|
it("removes a blocked-by issue from the chip remove action after confirmation", async () => {
|
|
|
|
|
const onUpdate = vi.fn();
|
|
|
|
|
const root = renderProperties(container, {
|
|
|
|
|
issue: createIssue({
|
|
|
|
|
blockedBy: [
|
|
|
|
|
{
|
|
|
|
|
id: "issue-2",
|
|
|
|
|
identifier: "PAP-2",
|
|
|
|
|
title: "Existing blocker",
|
|
|
|
|
status: "in_progress",
|
|
|
|
|
priority: "medium",
|
|
|
|
|
assigneeAgentId: null,
|
|
|
|
|
assigneeUserId: null,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: "issue-4",
|
|
|
|
|
identifier: "PAP-4",
|
|
|
|
|
title: "Keep blocker",
|
|
|
|
|
status: "todo",
|
|
|
|
|
priority: "medium",
|
|
|
|
|
assigneeAgentId: null,
|
|
|
|
|
assigneeUserId: null,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
}),
|
|
|
|
|
childIssues: [],
|
|
|
|
|
onUpdate,
|
|
|
|
|
inline: true,
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
const removeButton = container.querySelector('button[aria-label="Remove PAP-2 as blocker"]');
|
|
|
|
|
expect(removeButton).not.toBeNull();
|
|
|
|
|
|
|
|
|
|
await act(async () => {
|
|
|
|
|
removeButton!.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
expect(document.body.textContent).toContain("Remove PAP-2: Existing blocker as a blocker for this issue.");
|
|
|
|
|
const confirmButton = Array.from(document.body.querySelectorAll("button"))
|
|
|
|
|
.find((button) => button.textContent?.includes("Remove blocker"));
|
|
|
|
|
expect(confirmButton).not.toBeUndefined();
|
|
|
|
|
|
|
|
|
|
await act(async () => {
|
|
|
|
|
confirmButton!.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
expect(onUpdate).toHaveBeenCalledWith({ blockedByIssueIds: ["issue-4"] });
|
|
|
|
|
|
|
|
|
|
act(() => root.unmount());
|
|
|
|
|
});
|
|
|
|
|
|
[codex] Improve workspace navigation and runtime UI (#4089)
## Thinking Path
> - Paperclip agents do real work in project and execution workspaces.
> - Operators need workspace state to be visible, navigable, and
copyable without digging through raw run logs.
> - The branch included related workspace cards, navigation, runtime
controls, stale-service handling, and issue-property visibility.
> - These changes share the workspace UI and runtime-control surfaces
and can stand alone from unrelated access/profile work.
> - This pull request groups the workspace experience changes into one
standalone branch.
> - The benefit is a clearer workspace overview, better metadata copy
flows, and more accurate runtime service controls.
## What Changed
- Polished project workspace summary cards and made workspace metadata
copyable.
- Added a workspace navigation overview and extracted reusable project
workspace content.
- Squared and polished the execution workspace configuration page.
- Fixed stale workspace command matching and hid stopped stale services
in runtime controls.
- Showed live workspace service context in issue properties.
## Verification
- `pnpm install --frozen-lockfile`
- `pnpm exec vitest run
ui/src/components/ProjectWorkspaceSummaryCard.test.tsx
ui/src/lib/project-workspaces-tab.test.ts
ui/src/components/Sidebar.test.tsx
ui/src/components/WorkspaceRuntimeControls.test.tsx
ui/src/components/IssueProperties.test.tsx`
- `pnpm exec vitest run packages/shared/src/workspace-commands.test.ts
--config /dev/null` because the root Vitest project config does not
currently include `packages/shared` tests.
- Split integration check: merged after runtime/governance,
dev-infra/backups, and access/profiles with no merge conflicts.
- Confirmed this branch does not include `pnpm-lock.yaml`.
## Risks
- Medium risk: touches workspace navigation, runtime controls, and issue
property rendering.
- Visual layout changes may need browser QA, especially around smaller
screens and dense workspace metadata.
- No database migrations are included.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5.4 tool-enabled coding model, agentic
code-editing/runtime with local shell and GitHub CLI access; exact
context window and reasoning mode are not exposed by the Paperclip
harness.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-20 06:14:32 -05:00
|
|
|
it("shows a green service link above the workspace row for a live non-main workspace", async () => {
|
|
|
|
|
mockProjectsApi.list.mockResolvedValue([createProject()]);
|
|
|
|
|
const serviceUrl = "http://127.0.0.1:62475";
|
|
|
|
|
const root = renderProperties(container, {
|
|
|
|
|
issue: createIssue({
|
|
|
|
|
projectId: "project-1",
|
|
|
|
|
projectWorkspaceId: "workspace-main",
|
|
|
|
|
executionWorkspaceId: "workspace-1",
|
|
|
|
|
currentExecutionWorkspace: createExecutionWorkspace({
|
|
|
|
|
mode: "isolated_workspace",
|
|
|
|
|
runtimeServices: [createRuntimeService({ url: serviceUrl, status: "running" })],
|
|
|
|
|
}),
|
|
|
|
|
}),
|
|
|
|
|
childIssues: [],
|
|
|
|
|
onUpdate: vi.fn(),
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
const serviceLink = container.querySelector(`a[href="${serviceUrl}"]`);
|
|
|
|
|
expect(serviceLink).not.toBeNull();
|
|
|
|
|
expect(serviceLink?.getAttribute("target")).toBe("_blank");
|
|
|
|
|
expect(serviceLink?.className).toContain("text-emerald");
|
|
|
|
|
expect((container.textContent ?? "").indexOf("Service")).toBeLessThan(
|
|
|
|
|
(container.textContent ?? "").indexOf("Workspace"),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
act(() => root.unmount());
|
|
|
|
|
});
|
|
|
|
|
|
[codex] Polish issue board workflows (#4224)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Human operators supervise that work through issue lists, issue
detail, comments, inbox groups, markdown references, and
profile/activity surfaces
> - The branch had many small UI fixes that improve the operator loop
but do not need to ship with backend runtime migrations
> - These changes belong together as board workflow polish because they
affect scanning, navigation, issue context, comment state, and markdown
clarity
> - This pull request groups the UI-only slice so it can merge
independently from runtime/backend changes
> - The benefit is a clearer board experience with better issue context,
steadier optimistic updates, and more predictable keyboard navigation
## What Changed
- Improves issue properties, sub-issue actions, blocker chips, and issue
list/detail refresh behavior.
- Adds blocker context above the issue composer and stabilizes
queued/interrupted comment UI state.
- Improves markdown issue/GitHub link rendering and opens external
markdown links in a new tab.
- Adds inbox group keyboard navigation and fold/unfold support.
- Polishes activity/avatar/profile/settings/workspace presentation
details.
## Verification
- `pnpm exec vitest run ui/src/components/IssueProperties.test.tsx
ui/src/components/IssueChatThread.test.tsx
ui/src/components/MarkdownBody.test.tsx ui/src/lib/inbox.test.ts
ui/src/lib/optimistic-issue-comments.test.ts`
## Risks
- Low to medium risk: changes are UI-focused but cover high-traffic
issue and inbox surfaces.
- This branch intentionally does not include the backend runtime changes
from the companion PR; where UI calls newer API filters, unsupported
servers should continue to fail visibly through existing API error
handling.
- Visual screenshots were not captured in this heartbeat; targeted
component/helper tests cover the changed behavior.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5-based coding agent runtime, shell/git tool use
enabled. Exact hosted model build and context window are not exposed in
this Paperclip heartbeat environment.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-04-21 12:25:34 -05:00
|
|
|
it("shows a workspace tasks link for non-default workspaces when isolated workspaces are enabled", async () => {
|
|
|
|
|
mockProjectsApi.list.mockResolvedValue([createProject()]);
|
|
|
|
|
mockInstanceSettingsApi.getExperimental.mockResolvedValue({ enableIsolatedWorkspaces: true });
|
|
|
|
|
const root = renderProperties(container, {
|
|
|
|
|
issue: createIssue({
|
|
|
|
|
projectId: "project-1",
|
|
|
|
|
projectWorkspaceId: "workspace-main",
|
|
|
|
|
executionWorkspaceId: "workspace-1",
|
|
|
|
|
currentExecutionWorkspace: createExecutionWorkspace({
|
|
|
|
|
mode: "isolated_workspace",
|
|
|
|
|
}),
|
|
|
|
|
}),
|
|
|
|
|
childIssues: [],
|
|
|
|
|
onUpdate: vi.fn(),
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
const tasksLink = Array.from(container.querySelectorAll("a")).find(
|
|
|
|
|
(link) => link.textContent?.includes("View workspace tasks"),
|
|
|
|
|
);
|
|
|
|
|
const workspaceLink = Array.from(container.querySelectorAll("a")).find(
|
|
|
|
|
(link) => link.textContent?.trim() === "View workspace",
|
|
|
|
|
);
|
|
|
|
|
expect(tasksLink).not.toBeUndefined();
|
Improve operator workflow QoL (#5291)
## Thinking Path
> - Paperclip is a control plane operators use repeatedly to supervise
agent companies.
> - Common operator workflows depend on fast scanning of inboxes, issue
sidebars, workspaces, cost totals, and runtime services.
> - Several small UI and service gaps made those workflows slower or
less clear.
> - This pull request groups the operator-facing QoL changes that can
stand alone from recovery and adapter work.
> - The benefit is a denser, clearer board experience for issue triage
and workspace operation.
## What Changed
- Added inbox assignee/project grouping and issue list token/runtime
totals.
- Improved issue properties with removable blocker chips and workspace
task links.
- Improved execution workspace layout, runtime controls, issues tab
default, and stopped-port reuse behavior.
- Added mobile markdown/routine dialog fixes, page title company names,
sidebar polish, and dashboard run task label cleanup.
## Verification
- `pnpm install --frozen-lockfile`
- `pnpm exec vitest run ui/src/lib/inbox.test.ts
ui/src/components/IssueProperties.test.tsx
ui/src/components/WorkspaceRuntimeControls.test.tsx
server/src/__tests__/workspace-runtime.test.ts
server/src/__tests__/costs-service.test.ts`
## Risks
- Medium UI risk because this touches several operator surfaces. The
branch is intentionally grouped around workflow/QoL files and keeps the
file count below the Greptile limit.
## Model Used
- OpenAI GPT-5 Codex via Paperclip `codex_local` adapter, with
shell/git/GitHub CLI tool use.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-05-06 06:30:44 -05:00
|
|
|
expect(tasksLink?.getAttribute("href")).toBe("/execution-workspaces/workspace-1/issues");
|
[codex] Polish issue board workflows (#4224)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Human operators supervise that work through issue lists, issue
detail, comments, inbox groups, markdown references, and
profile/activity surfaces
> - The branch had many small UI fixes that improve the operator loop
but do not need to ship with backend runtime migrations
> - These changes belong together as board workflow polish because they
affect scanning, navigation, issue context, comment state, and markdown
clarity
> - This pull request groups the UI-only slice so it can merge
independently from runtime/backend changes
> - The benefit is a clearer board experience with better issue context,
steadier optimistic updates, and more predictable keyboard navigation
## What Changed
- Improves issue properties, sub-issue actions, blocker chips, and issue
list/detail refresh behavior.
- Adds blocker context above the issue composer and stabilizes
queued/interrupted comment UI state.
- Improves markdown issue/GitHub link rendering and opens external
markdown links in a new tab.
- Adds inbox group keyboard navigation and fold/unfold support.
- Polishes activity/avatar/profile/settings/workspace presentation
details.
## Verification
- `pnpm exec vitest run ui/src/components/IssueProperties.test.tsx
ui/src/components/IssueChatThread.test.tsx
ui/src/components/MarkdownBody.test.tsx ui/src/lib/inbox.test.ts
ui/src/lib/optimistic-issue-comments.test.ts`
## Risks
- Low to medium risk: changes are UI-focused but cover high-traffic
issue and inbox surfaces.
- This branch intentionally does not include the backend runtime changes
from the companion PR; where UI calls newer API filters, unsupported
servers should continue to fail visibly through existing API error
handling.
- Visual screenshots were not captured in this heartbeat; targeted
component/helper tests cover the changed behavior.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5-based coding agent runtime, shell/git tool use
enabled. Exact hosted model build and context window are not exposed in
this Paperclip heartbeat environment.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-04-21 12:25:34 -05:00
|
|
|
expect(workspaceLink).not.toBeUndefined();
|
|
|
|
|
expect(workspaceLink?.getAttribute("href")).toBe("/execution-workspaces/workspace-1");
|
|
|
|
|
|
|
|
|
|
act(() => root.unmount());
|
|
|
|
|
});
|
|
|
|
|
|
[codex] Improve workspace navigation and runtime UI (#4089)
## Thinking Path
> - Paperclip agents do real work in project and execution workspaces.
> - Operators need workspace state to be visible, navigable, and
copyable without digging through raw run logs.
> - The branch included related workspace cards, navigation, runtime
controls, stale-service handling, and issue-property visibility.
> - These changes share the workspace UI and runtime-control surfaces
and can stand alone from unrelated access/profile work.
> - This pull request groups the workspace experience changes into one
standalone branch.
> - The benefit is a clearer workspace overview, better metadata copy
flows, and more accurate runtime service controls.
## What Changed
- Polished project workspace summary cards and made workspace metadata
copyable.
- Added a workspace navigation overview and extracted reusable project
workspace content.
- Squared and polished the execution workspace configuration page.
- Fixed stale workspace command matching and hid stopped stale services
in runtime controls.
- Showed live workspace service context in issue properties.
## Verification
- `pnpm install --frozen-lockfile`
- `pnpm exec vitest run
ui/src/components/ProjectWorkspaceSummaryCard.test.tsx
ui/src/lib/project-workspaces-tab.test.ts
ui/src/components/Sidebar.test.tsx
ui/src/components/WorkspaceRuntimeControls.test.tsx
ui/src/components/IssueProperties.test.tsx`
- `pnpm exec vitest run packages/shared/src/workspace-commands.test.ts
--config /dev/null` because the root Vitest project config does not
currently include `packages/shared` tests.
- Split integration check: merged after runtime/governance,
dev-infra/backups, and access/profiles with no merge conflicts.
- Confirmed this branch does not include `pnpm-lock.yaml`.
## Risks
- Medium risk: touches workspace navigation, runtime controls, and issue
property rendering.
- Visual layout changes may need browser QA, especially around smaller
screens and dense workspace metadata.
- No database migrations are included.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5.4 tool-enabled coding model, agentic
code-editing/runtime with local shell and GitHub CLI access; exact
context window and reasoning mode are not exposed by the Paperclip
harness.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-20 06:14:32 -05:00
|
|
|
it("does not show a service link for the main shared workspace", async () => {
|
|
|
|
|
mockProjectsApi.list.mockResolvedValue([createProject()]);
|
|
|
|
|
const serviceUrl = "http://127.0.0.1:62475";
|
|
|
|
|
const root = renderProperties(container, {
|
|
|
|
|
issue: createIssue({
|
|
|
|
|
projectId: "project-1",
|
|
|
|
|
projectWorkspaceId: "workspace-main",
|
|
|
|
|
executionWorkspaceId: "workspace-1",
|
|
|
|
|
currentExecutionWorkspace: createExecutionWorkspace({
|
|
|
|
|
mode: "shared_workspace",
|
|
|
|
|
projectWorkspaceId: "workspace-main",
|
|
|
|
|
runtimeServices: [createRuntimeService({ url: serviceUrl, status: "running" })],
|
|
|
|
|
}),
|
|
|
|
|
}),
|
|
|
|
|
childIssues: [],
|
|
|
|
|
onUpdate: vi.fn(),
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
expect(container.querySelector(`a[href="${serviceUrl}"]`)).toBeNull();
|
[codex] Polish issue board workflows (#4224)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Human operators supervise that work through issue lists, issue
detail, comments, inbox groups, markdown references, and
profile/activity surfaces
> - The branch had many small UI fixes that improve the operator loop
but do not need to ship with backend runtime migrations
> - These changes belong together as board workflow polish because they
affect scanning, navigation, issue context, comment state, and markdown
clarity
> - This pull request groups the UI-only slice so it can merge
independently from runtime/backend changes
> - The benefit is a clearer board experience with better issue context,
steadier optimistic updates, and more predictable keyboard navigation
## What Changed
- Improves issue properties, sub-issue actions, blocker chips, and issue
list/detail refresh behavior.
- Adds blocker context above the issue composer and stabilizes
queued/interrupted comment UI state.
- Improves markdown issue/GitHub link rendering and opens external
markdown links in a new tab.
- Adds inbox group keyboard navigation and fold/unfold support.
- Polishes activity/avatar/profile/settings/workspace presentation
details.
## Verification
- `pnpm exec vitest run ui/src/components/IssueProperties.test.tsx
ui/src/components/IssueChatThread.test.tsx
ui/src/components/MarkdownBody.test.tsx ui/src/lib/inbox.test.ts
ui/src/lib/optimistic-issue-comments.test.ts`
## Risks
- Low to medium risk: changes are UI-focused but cover high-traffic
issue and inbox surfaces.
- This branch intentionally does not include the backend runtime changes
from the companion PR; where UI calls newer API filters, unsupported
servers should continue to fail visibly through existing API error
handling.
- Visual screenshots were not captured in this heartbeat; targeted
component/helper tests cover the changed behavior.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5-based coding agent runtime, shell/git tool use
enabled. Exact hosted model build and context window are not exposed in
this Paperclip heartbeat environment.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-04-21 12:25:34 -05:00
|
|
|
expect(container.textContent).not.toContain("View workspace tasks");
|
|
|
|
|
expect(Array.from(container.querySelectorAll("a")).some(
|
|
|
|
|
(link) => link.textContent?.trim() === "View workspace",
|
|
|
|
|
)).toBe(false);
|
[codex] Improve workspace navigation and runtime UI (#4089)
## Thinking Path
> - Paperclip agents do real work in project and execution workspaces.
> - Operators need workspace state to be visible, navigable, and
copyable without digging through raw run logs.
> - The branch included related workspace cards, navigation, runtime
controls, stale-service handling, and issue-property visibility.
> - These changes share the workspace UI and runtime-control surfaces
and can stand alone from unrelated access/profile work.
> - This pull request groups the workspace experience changes into one
standalone branch.
> - The benefit is a clearer workspace overview, better metadata copy
flows, and more accurate runtime service controls.
## What Changed
- Polished project workspace summary cards and made workspace metadata
copyable.
- Added a workspace navigation overview and extracted reusable project
workspace content.
- Squared and polished the execution workspace configuration page.
- Fixed stale workspace command matching and hid stopped stale services
in runtime controls.
- Showed live workspace service context in issue properties.
## Verification
- `pnpm install --frozen-lockfile`
- `pnpm exec vitest run
ui/src/components/ProjectWorkspaceSummaryCard.test.tsx
ui/src/lib/project-workspaces-tab.test.ts
ui/src/components/Sidebar.test.tsx
ui/src/components/WorkspaceRuntimeControls.test.tsx
ui/src/components/IssueProperties.test.tsx`
- `pnpm exec vitest run packages/shared/src/workspace-commands.test.ts
--config /dev/null` because the root Vitest project config does not
currently include `packages/shared` tests.
- Split integration check: merged after runtime/governance,
dev-infra/backups, and access/profiles with no merge conflicts.
- Confirmed this branch does not include `pnpm-lock.yaml`.
## Risks
- Medium risk: touches workspace navigation, runtime controls, and issue
property rendering.
- Visual layout changes may need browser QA, especially around smaller
screens and dense workspace metadata.
- No database migrations are included.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5.4 tool-enabled coding model, agentic
code-editing/runtime with local shell and GitHub CLI access; exact
context window and reasoning mode are not exposed by the Paperclip
harness.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-20 06:14:32 -05:00
|
|
|
|
|
|
|
|
act(() => root.unmount());
|
|
|
|
|
});
|
|
|
|
|
|
Add first-class issue references (#4214)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies.
> - Operators and agents coordinate through company-scoped issues,
comments, documents, and task relationships.
> - Issue text can mention other tickets, but those references were
previously plain markdown/text without durable relationship data.
> - That made it harder to understand related work, surface backlinks,
and keep cross-ticket context visible in the board.
> - This pull request adds first-class issue reference extraction,
storage, API responses, and UI surfaces.
> - The benefit is that issue references become queryable, navigable,
and visible without relying on ad hoc text scanning.
## What Changed
- Added shared issue-reference parsing utilities and exported
reference-related types/constants.
- Added an `issue_reference_mentions` table, idempotent migration DDL,
schema exports, and database documentation.
- Added server-side issue reference services, route integration,
activity summaries, and a backfill command for existing issue content.
- Added UI reference pills, related-work panels, markdown/editor mention
handling, and issue detail/property rendering updates.
- Added focused shared, server, and UI tests for parsing, persistence,
display, and related-work behavior.
- Rebased `PAP-735-first-class-task-references` cleanly onto
`public-gh/master`; no `pnpm-lock.yaml` changes are included.
## Verification
- `pnpm -r typecheck`
- `pnpm test:run packages/shared/src/issue-references.test.ts
server/src/__tests__/issue-references-service.test.ts
ui/src/components/IssueRelatedWorkPanel.test.tsx
ui/src/components/IssueProperties.test.tsx
ui/src/components/MarkdownBody.test.tsx`
## Risks
- Medium risk because this adds a new issue-reference persistence path
that touches shared parsing, database schema, server routes, and UI
rendering.
- Migration risk is mitigated by `CREATE TABLE IF NOT EXISTS`, guarded
foreign-key creation, and `CREATE INDEX IF NOT EXISTS` statements so
users who have applied an older local version of the numbered migration
can re-run safely.
- UI risk is limited by focused component coverage, but reviewers should
still manually inspect issue detail pages containing ticket references
before merge.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5-based coding agent, tool-using shell workflow with
repository inspection, git rebase/push, typecheck, and focused Vitest
verification.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: dotta <dotta@example.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-21 10:02:52 -05:00
|
|
|
it("shows related task references below sub-issues", async () => {
|
|
|
|
|
const root = renderProperties(container, {
|
|
|
|
|
issue: createIssue({
|
|
|
|
|
relatedWork: {
|
|
|
|
|
outbound: [
|
|
|
|
|
{
|
|
|
|
|
issue: {
|
|
|
|
|
id: "issue-22",
|
|
|
|
|
identifier: "PAP-22",
|
|
|
|
|
title: "Related task",
|
|
|
|
|
status: "todo",
|
|
|
|
|
priority: "medium",
|
|
|
|
|
assigneeAgentId: null,
|
|
|
|
|
assigneeUserId: null,
|
|
|
|
|
},
|
|
|
|
|
mentionCount: 1,
|
|
|
|
|
sources: [{ kind: "description", sourceRecordId: null, label: "description", matchedText: "PAP-22" }],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
inbound: [],
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
childIssues: [],
|
|
|
|
|
onUpdate: vi.fn(),
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
expect(container.textContent).not.toContain("Task ids");
|
|
|
|
|
expect(container.textContent).toContain("Related Tasks");
|
|
|
|
|
expect(container.textContent).toContain("PAP-22");
|
|
|
|
|
|
|
|
|
|
act(() => root.unmount());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("hides related task references already covered by blockers, blocking, and sub-issues", async () => {
|
|
|
|
|
const root = renderProperties(container, {
|
|
|
|
|
issue: createIssue({
|
|
|
|
|
blockedBy: [
|
|
|
|
|
{
|
|
|
|
|
id: "issue-22",
|
|
|
|
|
identifier: "PAP-22",
|
|
|
|
|
title: "Blocker",
|
|
|
|
|
status: "todo",
|
|
|
|
|
priority: "medium",
|
|
|
|
|
assigneeAgentId: null,
|
|
|
|
|
assigneeUserId: null,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
blocks: [
|
|
|
|
|
{
|
|
|
|
|
id: "issue-33",
|
|
|
|
|
identifier: "PAP-33",
|
|
|
|
|
title: "Blocked issue",
|
|
|
|
|
status: "todo",
|
|
|
|
|
priority: "medium",
|
|
|
|
|
assigneeAgentId: null,
|
|
|
|
|
assigneeUserId: null,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
relatedWork: {
|
|
|
|
|
outbound: [
|
|
|
|
|
{
|
|
|
|
|
issue: {
|
|
|
|
|
id: "issue-22",
|
|
|
|
|
identifier: "PAP-22",
|
|
|
|
|
title: "Blocker",
|
|
|
|
|
status: "todo",
|
|
|
|
|
priority: "medium",
|
|
|
|
|
assigneeAgentId: null,
|
|
|
|
|
assigneeUserId: null,
|
|
|
|
|
},
|
|
|
|
|
mentionCount: 1,
|
|
|
|
|
sources: [{ kind: "description", sourceRecordId: null, label: "description", matchedText: "PAP-22" }],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
issue: {
|
|
|
|
|
id: "issue-33",
|
|
|
|
|
identifier: "PAP-33",
|
|
|
|
|
title: "Blocked issue",
|
|
|
|
|
status: "todo",
|
|
|
|
|
priority: "medium",
|
|
|
|
|
assigneeAgentId: null,
|
|
|
|
|
assigneeUserId: null,
|
|
|
|
|
},
|
|
|
|
|
mentionCount: 1,
|
|
|
|
|
sources: [{ kind: "description", sourceRecordId: null, label: "description", matchedText: "PAP-33" }],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
issue: {
|
|
|
|
|
id: "child-44",
|
|
|
|
|
identifier: "PAP-44",
|
|
|
|
|
title: "Child issue",
|
|
|
|
|
status: "todo",
|
|
|
|
|
priority: "medium",
|
|
|
|
|
assigneeAgentId: null,
|
|
|
|
|
assigneeUserId: null,
|
|
|
|
|
},
|
|
|
|
|
mentionCount: 1,
|
|
|
|
|
sources: [{ kind: "description", sourceRecordId: null, label: "description", matchedText: "PAP-44" }],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
inbound: [],
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
childIssues: [
|
|
|
|
|
createIssue({
|
|
|
|
|
id: "child-44",
|
|
|
|
|
identifier: "PAP-44",
|
|
|
|
|
title: "Child issue",
|
|
|
|
|
}),
|
|
|
|
|
],
|
|
|
|
|
onUpdate: vi.fn(),
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
expect(container.textContent).not.toContain("Related Tasks");
|
|
|
|
|
|
|
|
|
|
act(() => root.unmount());
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-10 22:26:21 -05:00
|
|
|
it("shows an add-label button when labels already exist and opens the picker", async () => {
|
|
|
|
|
const root = renderProperties(container, {
|
|
|
|
|
issue: createIssue({
|
|
|
|
|
labels: [{ id: "label-1", companyId: "company-1", name: "Bug", color: "#ef4444", createdAt: new Date("2026-04-06T12:00:00.000Z"), updatedAt: new Date("2026-04-06T12:00:00.000Z") }],
|
|
|
|
|
labelIds: ["label-1"],
|
|
|
|
|
}),
|
|
|
|
|
childIssues: [],
|
|
|
|
|
onUpdate: vi.fn(),
|
|
|
|
|
inline: true,
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
const addLabelButton = container.querySelector('button[aria-label="Add label"]');
|
|
|
|
|
expect(addLabelButton).not.toBeNull();
|
|
|
|
|
expect(container.querySelector('input[placeholder="Search labels..."]')).toBeNull();
|
|
|
|
|
|
|
|
|
|
await act(async () => {
|
|
|
|
|
addLabelButton!.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
expect(container.querySelector('input[placeholder="Search labels..."]')).not.toBeNull();
|
|
|
|
|
expect(container.querySelector('button[title="Delete Bug"]')).toBeNull();
|
|
|
|
|
|
|
|
|
|
act(() => root.unmount());
|
|
|
|
|
});
|
|
|
|
|
|
[codex] Polish issue board workflows (#4224)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Human operators supervise that work through issue lists, issue
detail, comments, inbox groups, markdown references, and
profile/activity surfaces
> - The branch had many small UI fixes that improve the operator loop
but do not need to ship with backend runtime migrations
> - These changes belong together as board workflow polish because they
affect scanning, navigation, issue context, comment state, and markdown
clarity
> - This pull request groups the UI-only slice so it can merge
independently from runtime/backend changes
> - The benefit is a clearer board experience with better issue context,
steadier optimistic updates, and more predictable keyboard navigation
## What Changed
- Improves issue properties, sub-issue actions, blocker chips, and issue
list/detail refresh behavior.
- Adds blocker context above the issue composer and stabilizes
queued/interrupted comment UI state.
- Improves markdown issue/GitHub link rendering and opens external
markdown links in a new tab.
- Adds inbox group keyboard navigation and fold/unfold support.
- Polishes activity/avatar/profile/settings/workspace presentation
details.
## Verification
- `pnpm exec vitest run ui/src/components/IssueProperties.test.tsx
ui/src/components/IssueChatThread.test.tsx
ui/src/components/MarkdownBody.test.tsx ui/src/lib/inbox.test.ts
ui/src/lib/optimistic-issue-comments.test.ts`
## Risks
- Low to medium risk: changes are UI-focused but cover high-traffic
issue and inbox surfaces.
- This branch intentionally does not include the backend runtime changes
from the companion PR; where UI calls newer API filters, unsupported
servers should continue to fail visibly through existing API error
handling.
- Visual screenshots were not captured in this heartbeat; targeted
component/helper tests cover the changed behavior.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5-based coding agent runtime, shell/git tool use
enabled. Exact hosted model build and context window are not exposed in
this Paperclip heartbeat environment.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-04-21 12:25:34 -05:00
|
|
|
it("shows selected labels from labelIds even before the issue labels relation refreshes", async () => {
|
|
|
|
|
mockIssuesApi.listLabels.mockResolvedValue([createLabel()]);
|
|
|
|
|
|
|
|
|
|
const root = renderProperties(container, {
|
|
|
|
|
issue: createIssue({
|
|
|
|
|
labels: [],
|
|
|
|
|
labelIds: ["label-1"],
|
|
|
|
|
}),
|
|
|
|
|
childIssues: [],
|
|
|
|
|
onUpdate: vi.fn(),
|
|
|
|
|
inline: true,
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
expect(container.textContent).toContain("Bug");
|
|
|
|
|
expect(container.textContent).not.toContain("No labels");
|
|
|
|
|
|
|
|
|
|
act(() => root.unmount());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("shows a checkmark on selected labels in the picker", async () => {
|
|
|
|
|
mockIssuesApi.listLabels.mockResolvedValue([
|
|
|
|
|
createLabel(),
|
|
|
|
|
createLabel({ id: "label-2", name: "Feature", color: "#22c55e" }),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
const root = renderProperties(container, {
|
|
|
|
|
issue: createIssue({
|
|
|
|
|
labels: [createLabel()],
|
|
|
|
|
labelIds: ["label-1"],
|
|
|
|
|
}),
|
|
|
|
|
childIssues: [],
|
|
|
|
|
onUpdate: vi.fn(),
|
|
|
|
|
inline: true,
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
const addLabelButton = container.querySelector('button[aria-label="Add label"]');
|
|
|
|
|
expect(addLabelButton).not.toBeNull();
|
|
|
|
|
await act(async () => {
|
|
|
|
|
addLabelButton!.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
const labelButtons = Array.from(container.querySelectorAll("button"))
|
|
|
|
|
.filter((button) => button.textContent?.includes("Bug") || button.textContent?.includes("Feature"));
|
|
|
|
|
const bugButton = labelButtons.find((button) => button.textContent?.includes("Bug") && button.querySelector("svg"));
|
|
|
|
|
const featureButton = labelButtons.find((button) => button.textContent?.includes("Feature"));
|
|
|
|
|
expect(bugButton).not.toBeUndefined();
|
|
|
|
|
expect(featureButton?.querySelector("svg")).toBeNull();
|
|
|
|
|
|
|
|
|
|
act(() => root.unmount());
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-10 22:26:21 -05:00
|
|
|
it("allows setting and clearing a parent issue from the properties pane", async () => {
|
|
|
|
|
const onUpdate = vi.fn();
|
|
|
|
|
mockIssuesApi.list.mockResolvedValue([
|
|
|
|
|
createIssue({ id: "issue-2", identifier: "PAP-2", title: "Candidate parent", status: "in_progress" }),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
const root = renderProperties(container, {
|
|
|
|
|
issue: createIssue(),
|
|
|
|
|
childIssues: [],
|
|
|
|
|
onUpdate,
|
|
|
|
|
inline: true,
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
const parentTrigger = Array.from(container.querySelectorAll("button"))
|
|
|
|
|
.find((button) => button.textContent?.includes("No parent"));
|
|
|
|
|
expect(parentTrigger).not.toBeUndefined();
|
|
|
|
|
|
|
|
|
|
await act(async () => {
|
|
|
|
|
parentTrigger!.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
const candidateButton = Array.from(container.querySelectorAll("button"))
|
|
|
|
|
.find((button) => button.textContent?.includes("PAP-2 Candidate parent"));
|
|
|
|
|
expect(candidateButton).not.toBeUndefined();
|
|
|
|
|
|
|
|
|
|
await act(async () => {
|
|
|
|
|
candidateButton!.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
expect(onUpdate).toHaveBeenCalledWith({ parentId: "issue-2" });
|
|
|
|
|
|
|
|
|
|
onUpdate.mockClear();
|
|
|
|
|
const rerenderedIssue = createIssue({
|
|
|
|
|
parentId: "issue-2",
|
|
|
|
|
ancestors: [
|
|
|
|
|
{
|
|
|
|
|
id: "issue-2",
|
|
|
|
|
identifier: "PAP-2",
|
|
|
|
|
title: "Candidate parent",
|
|
|
|
|
description: null,
|
|
|
|
|
status: "in_progress",
|
|
|
|
|
priority: "medium",
|
|
|
|
|
assigneeAgentId: null,
|
|
|
|
|
assigneeUserId: null,
|
|
|
|
|
projectId: null,
|
|
|
|
|
goalId: null,
|
|
|
|
|
project: null,
|
|
|
|
|
goal: null,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
act(() => root.unmount());
|
|
|
|
|
|
|
|
|
|
const rerenderedRoot = renderProperties(container, {
|
|
|
|
|
issue: rerenderedIssue,
|
|
|
|
|
childIssues: [],
|
|
|
|
|
onUpdate,
|
|
|
|
|
inline: true,
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
const selectedParentTrigger = Array.from(container.querySelectorAll("button"))
|
|
|
|
|
.find((button) => button.textContent?.includes("PAP-2 Candidate parent"));
|
|
|
|
|
expect(selectedParentTrigger).not.toBeUndefined();
|
[codex] improve issue and routine UI responsiveness (#3744)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Operators rely on issue, inbox, and routine views to understand what
the company is doing in real time
> - Those views need to stay fast and readable even when issue lists,
markdown comments, and run metadata get large
> - The current branch had a coherent set of UI and live-update
improvements spread across issue search, issue detail rendering, routine
affordances, and workspace lookups
> - This pull request groups those board-facing changes into one
standalone branch that can merge independently of the heartbeat/runtime
work
> - The benefit is a faster, clearer issue and routine workflow without
changing the underlying task model
## What Changed
- Show routine execution issues by default and rename the filter to
`Hide routine runs` so the default state no longer looks like an active
filter.
- Show the routine name in the run dialog and tighten the issue
properties pane with a workspace link, copy-on-click behavior, and an
inline parent arrow.
- Reduce issue detail rerenders, keep queued issue chat mounted, improve
issues page search responsiveness, and speed up issues first paint.
- Add inbox "other search results", refresh visible issue runs after
status updates, and optimize workspace lookups through summary-mode
execution workspace queries.
- Improve markdown wrapping and scrolling behavior for long strings and
self-comment code blocks.
- Relax the markdown sanitizer assertion so the test still validates
safety after the new wrap-friendly inline styles.
## Verification
- `pnpm vitest run ui/src/components/IssuesList.test.tsx
ui/src/lib/inbox.test.ts ui/src/pages/Issues.test.tsx
ui/src/context/BreadcrumbContext.test.tsx
ui/src/context/LiveUpdatesProvider.test.ts
ui/src/components/MarkdownBody.test.tsx
ui/src/api/execution-workspaces.test.ts
server/src/__tests__/execution-workspaces-routes.test.ts`
## Risks
- This touches several issue-facing UI surfaces at once, so regressions
would most likely show up as stale rendering, search result mismatches,
or small markdown presentation differences.
- The workspace lookup optimization depends on the summary-mode route
shape staying aligned between server and UI.
## Model Used
- OpenAI Codex, GPT-5-based coding agent in the Codex CLI environment.
Exact backend model deployment ID was not exposed in-session.
Tool-assisted editing and shell execution were used.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-15 15:54:05 -05:00
|
|
|
const parentLink = container.querySelector('a[href="/issues/PAP-2"]');
|
|
|
|
|
expect(parentLink).not.toBeNull();
|
|
|
|
|
expect(selectedParentTrigger!.contains(parentLink)).toBe(false);
|
2026-04-10 22:26:21 -05:00
|
|
|
|
|
|
|
|
await act(async () => {
|
|
|
|
|
selectedParentTrigger!.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
const clearParentButton = Array.from(container.querySelectorAll("button"))
|
|
|
|
|
.find((button) => button.textContent?.includes("No parent"));
|
|
|
|
|
expect(clearParentButton).not.toBeUndefined();
|
|
|
|
|
|
|
|
|
|
await act(async () => {
|
|
|
|
|
clearParentButton!.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
expect(onUpdate).toHaveBeenCalledWith({ parentId: null });
|
|
|
|
|
|
|
|
|
|
act(() => rerenderedRoot.unmount());
|
|
|
|
|
});
|
2026-04-08 17:00:57 -05:00
|
|
|
it("shows a run review action after reviewers are configured and starts execution explicitly when clicked", async () => {
|
|
|
|
|
const onUpdate = vi.fn();
|
|
|
|
|
const root = renderProperties(container, {
|
|
|
|
|
issue: createIssue({
|
|
|
|
|
executionPolicy: createExecutionPolicy({
|
|
|
|
|
stages: [
|
|
|
|
|
{
|
|
|
|
|
id: "review-stage",
|
|
|
|
|
type: "review",
|
|
|
|
|
approvalsNeeded: 1,
|
|
|
|
|
participants: [{ id: "participant-1", type: "agent", agentId: "agent-1", userId: null }],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
}),
|
|
|
|
|
}),
|
|
|
|
|
childIssues: [],
|
|
|
|
|
onUpdate,
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
const runReviewButton = Array.from(container.querySelectorAll("button"))
|
|
|
|
|
.find((button) => button.textContent?.includes("Run review now"));
|
|
|
|
|
expect(runReviewButton).not.toBeUndefined();
|
|
|
|
|
|
|
|
|
|
await act(async () => {
|
|
|
|
|
runReviewButton!.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
expect(onUpdate).toHaveBeenCalledWith({ status: "in_review" });
|
|
|
|
|
|
|
|
|
|
act(() => root.unmount());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("shows a run approval action when approval is the next runnable stage", async () => {
|
|
|
|
|
const root = renderProperties(container, {
|
|
|
|
|
issue: createIssue({
|
|
|
|
|
executionPolicy: createExecutionPolicy({
|
|
|
|
|
stages: [
|
|
|
|
|
{
|
|
|
|
|
id: "approval-stage",
|
|
|
|
|
type: "approval",
|
|
|
|
|
approvalsNeeded: 1,
|
|
|
|
|
participants: [{ id: "participant-2", type: "user", agentId: null, userId: "user-1" }],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
}),
|
|
|
|
|
}),
|
|
|
|
|
childIssues: [],
|
|
|
|
|
onUpdate: vi.fn(),
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
expect(container.textContent).toContain("Run approval now");
|
|
|
|
|
expect(container.textContent).not.toContain("Run review now");
|
|
|
|
|
|
|
|
|
|
act(() => root.unmount());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("keeps the run review action available after changes are requested", async () => {
|
|
|
|
|
const root = renderProperties(container, {
|
|
|
|
|
issue: createIssue({
|
|
|
|
|
status: "in_progress",
|
|
|
|
|
executionPolicy: createExecutionPolicy({
|
|
|
|
|
stages: [
|
|
|
|
|
{
|
|
|
|
|
id: "review-stage",
|
|
|
|
|
type: "review",
|
|
|
|
|
approvalsNeeded: 1,
|
|
|
|
|
participants: [{ id: "participant-1", type: "agent", agentId: "agent-1", userId: null }],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
}),
|
|
|
|
|
executionState: createExecutionState(),
|
|
|
|
|
}),
|
|
|
|
|
childIssues: [],
|
|
|
|
|
onUpdate: vi.fn(),
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
expect(container.textContent).toContain("Run review now");
|
|
|
|
|
|
|
|
|
|
act(() => root.unmount());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("hides the run action while an execution stage is already pending", async () => {
|
|
|
|
|
const root = renderProperties(container, {
|
|
|
|
|
issue: createIssue({
|
|
|
|
|
status: "in_review",
|
|
|
|
|
executionPolicy: createExecutionPolicy({
|
|
|
|
|
stages: [
|
|
|
|
|
{
|
|
|
|
|
id: "review-stage",
|
|
|
|
|
type: "review",
|
|
|
|
|
approvalsNeeded: 1,
|
|
|
|
|
participants: [{ id: "participant-1", type: "agent", agentId: "agent-1", userId: null }],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
}),
|
|
|
|
|
executionState: createExecutionState({
|
|
|
|
|
status: "pending",
|
|
|
|
|
currentStageType: "review",
|
|
|
|
|
lastDecisionOutcome: null,
|
|
|
|
|
}),
|
|
|
|
|
}),
|
|
|
|
|
childIssues: [],
|
|
|
|
|
onUpdate: vi.fn(),
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
expect(container.textContent).not.toContain("Run review now");
|
|
|
|
|
expect(container.textContent).not.toContain("Run approval now");
|
|
|
|
|
|
|
|
|
|
act(() => root.unmount());
|
|
|
|
|
});
|
[codex] Add issue monitor liveness controls (#4988)
## Thinking Path
> - Paperclip is a control plane for autonomous AI companies where work
must stay observable, governable, and recoverable.
> - The task/heartbeat subsystem owns agent execution continuity, issue
state transitions, and visible recovery behavior.
> - Waiting on an external service is not the same as being blocked when
the assignee still owns a future check.
> - The gap was that agents had no first-class one-shot monitor state
for external-service waits, so recovery could look stalled or require ad
hoc comments.
> - This pull request adds bounded issue monitors that can wake the
owner, clear exhausted waits, and produce explicit recovery behavior.
> - It also surfaces monitor status in the board UI and documents when
to use monitors versus `blocked`.
> - The benefit is clearer liveness semantics for asynchronous waits
without weakening single-assignee task ownership.
## What Changed
- Added issue monitor fields, shared types, validators, constants, and
an idempotent `0075` migration for scheduled monitor state.
- Added server-side monitor scheduling, dispatch, recovery bounds,
activity logging, and external-ref redaction.
- Added board/agent route coverage for monitor permissions and child
monitor scheduling.
- Added issue detail/property UI for monitor state, a monitor activity
card, and Storybook stories for review surfaces.
- Documented monitor semantics and recovery policy behavior in
`doc/execution-semantics.md`.
- Addressed Greptile review feedback by preserving monitor state in
skipped-stage builders and making board monitor saves send `scheduledBy:
"board"`.
## Verification
- `pnpm install --frozen-lockfile`
- `pnpm run preflight:workspace-links && pnpm exec vitest run
server/src/__tests__/issue-execution-policy-routes.test.ts
server/src/__tests__/issue-execution-policy.test.ts
server/src/__tests__/issue-monitor-scheduler.test.ts
server/src/__tests__/recovery-classifiers.test.ts
ui/src/components/IssueMonitorActivityCard.test.tsx
ui/src/components/IssueProperties.test.tsx
ui/src/lib/activity-format.test.ts`
- First run passed 5 files and failed to collect 2 server suites because
the worktree was missing the optional `acpx/runtime` dependency.
- After `pnpm install --frozen-lockfile`, reran the 2 failed suites
successfully.
- `pnpm exec vitest run
server/src/__tests__/issue-monitor-scheduler.test.ts
server/src/__tests__/recovery-classifiers.test.ts`
- `pnpm --filter @paperclipai/shared typecheck && pnpm --filter
@paperclipai/db typecheck && pnpm --filter @paperclipai/server typecheck
&& pnpm --filter @paperclipai/ui typecheck`
- `pnpm exec vitest run
server/src/__tests__/issue-execution-policy.test.ts
ui/src/components/IssueProperties.test.tsx`
- `pnpm --filter @paperclipai/server typecheck && pnpm --filter
@paperclipai/ui typecheck`
- `pnpm exec vitest run
ui/src/components/IssueMonitorActivityCard.test.tsx
ui/src/components/IssueProperties.test.tsx`
- `pnpm --filter @paperclipai/ui typecheck`
- Storybook screenshot captured from
`http://127.0.0.1:6006/iframe.html?viewMode=story&id=product-issue-monitor-surfaces--monitor-surfaces`
with Playwright.
## Screenshots

## Risks
- Medium: this changes heartbeat recovery behavior for scheduled
external-service waits, so regressions could affect wake timing or
recovery issue creation.
- Migration risk is reduced by using `IF NOT EXISTS` for the new issue
monitor columns and index.
- External monitor references are treated as secret-adjacent and are
intentionally omitted from visible activity/wake payloads.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- OpenAI Codex, GPT-5 coding agent with repository tool use and terminal
execution.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots or Storybook review surfaces
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-05-03 08:58:53 -05:00
|
|
|
|
|
|
|
|
it("renders monitor controls and clears an existing monitor", async () => {
|
|
|
|
|
const onUpdate = vi.fn();
|
|
|
|
|
const root = renderProperties(container, {
|
|
|
|
|
issue: createIssue({
|
|
|
|
|
status: "in_progress",
|
|
|
|
|
assigneeAgentId: "agent-1",
|
|
|
|
|
executionPolicy: createExecutionPolicy({
|
|
|
|
|
monitor: {
|
|
|
|
|
nextCheckAt: "2026-04-11T12:30:00.000Z",
|
|
|
|
|
notes: "Check deployment",
|
|
|
|
|
scheduledBy: "board",
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
executionState: createExecutionState({
|
|
|
|
|
status: "idle",
|
|
|
|
|
currentStageId: null,
|
|
|
|
|
currentStageIndex: null,
|
|
|
|
|
currentStageType: null,
|
|
|
|
|
currentParticipant: null,
|
|
|
|
|
returnAssignee: null,
|
|
|
|
|
lastDecisionOutcome: null,
|
|
|
|
|
monitor: {
|
|
|
|
|
status: "scheduled",
|
|
|
|
|
nextCheckAt: "2026-04-11T12:30:00.000Z",
|
|
|
|
|
lastTriggeredAt: null,
|
|
|
|
|
attemptCount: 0,
|
|
|
|
|
notes: "Check deployment",
|
|
|
|
|
scheduledBy: "board",
|
|
|
|
|
clearedAt: null,
|
|
|
|
|
clearReason: null,
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
}),
|
|
|
|
|
childIssues: [],
|
|
|
|
|
onUpdate,
|
|
|
|
|
inline: true,
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
expect(container.textContent).toContain("Monitor");
|
|
|
|
|
expect(container.textContent).toContain("Next check");
|
|
|
|
|
expect(container.querySelector('input[type="datetime-local"]')).toBeNull();
|
|
|
|
|
expect(container.querySelector('input[placeholder="What should the agent re-check?"]')).toBeNull();
|
|
|
|
|
|
|
|
|
|
const monitorTrigger = Array.from(container.querySelectorAll("button"))
|
|
|
|
|
.find((button) => button.textContent?.includes("Next check"));
|
|
|
|
|
expect(monitorTrigger).not.toBeUndefined();
|
|
|
|
|
|
|
|
|
|
await act(async () => {
|
|
|
|
|
monitorTrigger!.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
|
|
|
});
|
|
|
|
|
await flush();
|
|
|
|
|
|
|
|
|
|
const inputs = Array.from(container.querySelectorAll("input"));
|
|
|
|
|
const datetimeInput = inputs.find((input) => input.getAttribute("type") === "datetime-local");
|
|
|
|
|
const textInput = inputs.find((input) => input.getAttribute("placeholder") === "What should the agent re-check?");
|
|
|
|
|
const clearButton = Array.from(container.querySelectorAll("button"))
|
|
|
|
|
.find((button) => button.textContent?.includes("Clear"));
|
|
|
|
|
|
|
|
|
|
expect(datetimeInput).toBeTruthy();
|
|
|
|
|
expect(textInput).toBeTruthy();
|
|
|
|
|
expect(clearButton).toBeTruthy();
|
|
|
|
|
expect(datetimeInput!.value).toBeTruthy();
|
|
|
|
|
expect(textInput!.value).toBe("Check deployment");
|
|
|
|
|
|
|
|
|
|
act(() => {
|
|
|
|
|
clearButton!.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
expect(onUpdate).toHaveBeenCalledWith({
|
|
|
|
|
executionPolicy: {
|
|
|
|
|
mode: "normal",
|
|
|
|
|
commentRequired: true,
|
|
|
|
|
stages: [],
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
act(() => root.unmount());
|
|
|
|
|
});
|
2026-04-06 10:58:59 -05:00
|
|
|
});
|