Commit Graph
987 Commits
Author SHA1 Message Date
DottaandPaperclip 3afc37ef40 test: harden low-trust route cleanup
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 18:31:08 +00:00
DottaandPaperclip da1778fbf8 fix: close low-trust self detail bypass
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 18:25:20 +00:00
DottaandPaperclip 0a2a16a26d fix: address greptile low-trust review gaps
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 18:06:39 +00:00
DottaandPaperclip 18fd6e262c fix: propagate denied low-trust issue policy
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 18:06:39 +00:00
DottaandPaperclip 2b2f525352 fix: clean up heartbeat rebase conflict
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 18:06:39 +00:00
DottaandPaperclip 323618b453 fix: update auth route test fixtures
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 18:06:39 +00:00
DottaandPaperclip 8bd6659ec2 fix: align low-trust count and ancestry limits
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 18:06:39 +00:00
DottaandPaperclip 325b67ca29 fix: close low-trust greptile auth gaps
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 18:06:39 +00:00
DottaandPaperclip 3d2cf8fa71 fix: align low-trust workspace boundary ancestry
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 18:06:39 +00:00
DottaandPaperclip af9e2503f6 fix: close low-trust greptile cleanup gaps
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 18:06:39 +00:00
DottaandPaperclip 711a29338d fix: include run policy in low-trust self checks
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 18:06:39 +00:00
DottaandPaperclip 4ad567c728 fix: tag low-trust issue creates atomically
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 18:06:39 +00:00
DottaandPaperclip a5f2d64e27 fix: enforce low-trust runtime issue context
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 18:06:39 +00:00
DottaandPaperclip 89945fd23d fix: address low-trust review feedback
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 18:06:39 +00:00
DottaandPaperclip 4cbfc64ff8 fix: pass monitor guard context for plan decomposition
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 18:06:39 +00:00
Dotta e91849ed4a test: add low-trust wake quarantine harness 2026-06-05 18:06:39 +00:00
Dotta 028a8942a2 Add low-trust HTTP regression suite 2026-06-05 18:06:39 +00:00
Dotta af975b4d5d Fix low-trust promotion authorization 2026-06-05 18:06:39 +00:00
Dotta d78bd3b9a5 Preflight low-trust before workspace resolution 2026-06-05 18:06:39 +00:00
Dotta 0e636a4030 Add low-trust preset UI 2026-06-05 18:06:39 +00:00
Dotta e8c17bec49 Fix low-trust sandbox preflight ordering 2026-06-05 18:06:39 +00:00
DottaandPaperclip 468b52a3e9 Implement low-trust containment
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 18:06:39 +00:00
DottaandPaperclip 516f79dee9 Implement low-trust preset resolver
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 18:06:39 +00:00
fff3832a01 [codex] Add teams catalog extraction (#7550)
Fixes #7551

## Thinking Path

> - Paperclip is the control plane for AI-agent companies, and reusable
company/team setup is part of making those companies faster to launch.
> - The teams catalog work introduces app-shipped team templates that
can be browsed, previewed, and installed into a company.
> - Catalog installation crosses several contracts: bundled package
contents, shared API types, server import/install behavior, CLI
workflows, and the board UI.
> - Agents also need a safe path through catalog installs: scoped
company selection, explicit source policy, approval fallback for agent
creation, and preserved catalog provenance.
> - This pull request extracts the completed teams catalog branch into
one reviewable PR on top of `public-gh/master`.
> - The benefit is a reusable teams catalog foundation with server, CLI,
package, docs, and hidden UI surfaces kept in sync.

## What Changed

- Added the `@paperclipai/teams-catalog` package with bundled/optional
team definitions, generated manifest, validators, catalog builder tests,
and migration notes.
- Added shared teams catalog types/validators plus server routes and
services for listing, previewing, and installing catalog teams.
- Integrated catalog install with company portability, skill/source
policy checks, provenance metadata, origin hashes, target-manager
reparenting, and installed/out-of-date detection.
- Added CLI `teams` commands and agent-safe company selection behavior,
including `company current` and approval fallback for forbidden
agent-run installs.
- Added hidden Team Catalog UI/API/query surfaces, Storybook fixtures,
and targeted UI tests while keeping the UI route out of primary
navigation.
- Added docs for CLI/company/teams catalog behavior and removed
generated screenshot artifacts from the PR diff.

## Verification

- `pnpm exec vitest run cli/src/__tests__/company.test.ts
cli/src/__tests__/teams.test.ts
packages/teams-catalog/src/catalog-builder.test.ts
packages/teams-catalog/src/shipped-catalog.test.ts
server/src/__tests__/agent-permissions-service.test.ts
server/src/__tests__/company-portability.test.ts
server/src/__tests__/company-skills-service.test.ts
server/src/__tests__/teams-catalog-routes.test.ts
server/src/__tests__/teams-catalog-service.test.ts
server/src/__tests__/teams-catalog-install-no-overrides.test.ts
ui/src/lib/company-routes.test.ts ui/src/pages/TeamCard.test.tsx
ui/src/pages/TeamCatalog.test.tsx
ui/src/pages/useInstallTeamCatalogEntry.test.tsx`
- `pnpm --filter @paperclipai/shared typecheck && pnpm --filter
@paperclipai/teams-catalog typecheck && pnpm --filter paperclipai
typecheck && pnpm --filter @paperclipai/server typecheck && pnpm
--filter @paperclipai/ui typecheck`
- Confirmed branch is rebased onto `public-gh/master` (`78dc3625a`) and
`public-gh/master` is an ancestor of `HEAD`.
- Confirmed PR diff excludes `pnpm-lock.yaml`, `.github/workflows/*`,
generated screenshot images, and screenshot helper scripts.

## Risks

- Medium review surface: this crosses package generation, shared
contracts, server install behavior, CLI, docs, and hidden UI code.
- Catalog install behavior creates agents/projects/tasks/skills and must
keep company scoping, permissions, source policy, and provenance checks
strict.
- `pnpm-lock.yaml` is intentionally excluded per repo policy;
CI/default-branch automation owns lockfile refresh.
- The Team Catalog UI is included but hidden from primary navigation, so
future enablement should re-check visual QA before exposure.

> 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`.
>
> ROADMAP checked: this aligns with reusable companies/templates and
plugin-adjacent onboarding work. This PR packages work already developed
on the Paperclip task branch for review.

## Model Used

- OpenAI Codex, GPT-5 series coding agent in this Paperclip session;
exact runtime context window was not exposed. Used shell, git, `gh`, and
local test/typecheck tooling.

## 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 why screenshots are intentionally omitted
- [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>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 12:55:49 -05:00
Dotta 3657854e5e Merge pull request #7554 from paperclipai/codex/pap-10343-comment-redaction
[codex] Redact deleted issue comments
2026-06-05 05:32:08 -10:00
Dotta 487361a5cc Merge pull request #7553 from paperclipai/codex/pap-10343-operator-qol-pr
[codex] Group operator QoL fixes
2026-06-05 05:29:56 -10:00
m.seomoon fb28cf38b4 fix(heartbeat): guard Hermes resume session state (#7516)
## Thinking Path

> - Paperclip is a control plane for AI-agent companies
> - Heartbeats reuse adapter session state so agents can continue work
across wakeups
> - Hermes can only resume from full canonical session IDs, not
truncated display IDs
> - #6347 exposed a case where Paperclip could save invalid Hermes
output like `from`, or a shortened display ID, as resumable state
> - This pull request hardens the host-side Hermes resume path so
Paperclip only stores and reuses session IDs that can actually resume
> - The benefit is that Hermes wakeups no longer get stuck retrying bad
saved resume state

## What Changed

- Added Hermes-only validation for canonical session IDs in
`server/src/services/heartbeat.ts`.
- Stopped building Hermes resume params from truncated display IDs such
as `20260601_141558_`.
- For explicit resume-from-run wakeups, pulls the full Hermes session ID
from the run result payload after validation.
- Preserves the previous valid Hermes session state when a run fails,
times out, or is cancelled instead of replacing it with invalid adapter
output like `from`.
- Clears existing Hermes resume state that fails validation.
- Leaves non-Hermes adapter session behavior unchanged.
- Added regression coverage in
`server/src/__tests__/heartbeat-workspace-session.test.ts`.

Addresses #6347.

Supersedes #6351 and covers the full-session resume metadata handoff
from #7280.

## Verification

- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/heartbeat-workspace-session.test.ts` — passed, 50 tests.
- `pnpm --filter @paperclipai/server typecheck` — passed.
- `pnpm -r typecheck` — passed.
- `pnpm build` — passed.
- `git diff --check` — clean.

Full suite did not finish green locally; the failures were outside this
server-only heartbeat path:

- `pnpm test:run`:
  - `@paperclipai/adapter-opencode-local` remote SSH tests timed out.
- `ui/src/pages/Inbox.test.tsx` failed once in `Inbox toolbar > syncs
hover with j/k selection on inbox rows`; the direct file rerun passed.
- `ui/src/components/IssueDocumentAnnotations.test.tsx` failed once in
`auto-opens the panel and focuses the thread when deep-linked`; the
direct file rerun passed.

## Risks

- Low risk: no schema, public API, shared contract, or UI changes.
- If Hermes changes its canonical session ID format, the validation
regex will need to be updated.
- Adapter-side parsing still needs its own fix; this PR prevents
non-resumable adapter output from becoming durable Paperclip resume
state.
- This does not add an immediate same-run retry after `Session not
found`; recovery happens by clearing or preserving durable resume state
for later wakeups.

> 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 GPT-5.5 (`openai/gpt-5.5`) via opencode, with repository
read/search tools and local shell/test execution. opencode did not
expose context-window or reasoning-mode details.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used, including exact model ID 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 — targeted checks passed; full `pnpm
test:run` had unrelated local failures disclosed above
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots — N/A, no UI changes
- [x] I have updated relevant documentation to reflect my changes — N/A,
no user-facing docs or commands changed
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-06-04 22:45:25 -07:00
DottaandPaperclip 9aa065a38c Make deleted-comment cleanup atomic
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 03:56:39 +00:00
DottaandPaperclip 1afa337841 Address Greptile deleted-comment feedback
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 03:43:12 +00:00
Dotta af0c43b205 Address operator QoL review feedback 2026-06-05 03:40:46 +00:00
DottaandPaperclip 5f481d50f1 Allow inline video attachment previews
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 03:28:07 +00:00
Dotta 39e0fba65f Filter issues by plan document 2026-06-05 03:28:07 +00:00
Dotta 4afe5ab7cb Add other answers to issue questions 2026-06-05 03:28:07 +00:00
DottaandPaperclip f360fcbbb3 Expire confirmations after user comments
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-05 03:28:07 +00:00
Dotta 17fa6fe0fe Add deleted comment regression coverage 2026-06-05 03:20:46 +00:00
Dotta 7f70759e61 Redact deleted issue comments 2026-06-05 03:20:46 +00:00
DottaandPaperclip 0cca059705 Address catalog review cleanup
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-04 21:10:29 +00:00
Dotta bee2b25f5d Add referenced last30days catalog entry 2026-06-04 20:01:25 +00:00
Aron PrinsandClaude Opus 4.7 1227bb8ead Improve OpenAPI spec coverage and auth metadata (#4579)
## Thinking Path

> - Paperclip orchestrates AI agents for zero-human companies
> - Its REST API is the control-plane contract for the board UI, agents,
plugins, and external integrations
> - This branch adds `/api/openapi.json`, which makes the generated
OpenAPI document part of that contract instead of an internal
implementation detail
> - Once the spec is published, it has to match the mounted Express
routes, auth model, and real HTTP behavior closely enough for client
generation and review
> - The existing spec drifted from the live server: it missed mounted
routes, documented a few nonexistent ones, omitted auth semantics, and
normalized response codes too aggressively
> - This pull request makes the generated spec track the real API
surface, exposes security requirements, and adds regression coverage so
drift is caught automatically
> - The benefit is that Paperclip's published API description becomes
trustworthy for integrators, SDK generation, and review without changing
runtime auth enforcement

## What Changed

- Added the OpenAPI endpoint wiring under `server/src/routes/openapi.ts`
so `/api/openapi.json` is generated from the current route-backed
OpenAPI builder.
- Replaced generic request/response bodies with typed schemas where
available so the generated document carries useful structure instead of
opaque blobs.
- Expanded the generated spec to cover the mounted route set, including
access/member flows, CLI auth challenge routes, invite acceptance, issue
thread interaction routes, adapter environment testing, budget policy
routes, resource memberships, secret provider routes, cloud upstream
routes, and `/api/openapi.json` itself.
- Corrected documented path mismatches such as `skills/scan` vs
`skills/scan-projects`, and other route-name/path drift.
- Added security schemes plus operation-level security metadata so
public, authenticated, board-only, and instance-admin endpoints are
distinguishable in the generated contract.
- Fixed reviewed response-code mismatches for create/accept flows and
authz failures, including `201`, `202`, and `403` cases that were
previously flattened away.
- Added `server/src/__tests__/openapi-routes.test.ts` to diff the
generated spec against mounted server routes and assert key
auth/response invariants.
- Hardened the route-drift test after review feedback: it now handles
single/double/template route literals, fails on unlisted route files
that declare router methods, and filters OpenAPI path-item keys to HTTP
methods only.

## Verification

- `pnpm exec vitest run server/src/__tests__/openapi-routes.test.ts`
- `pnpm --filter @paperclipai/ui exec vitest run
src/pages/Inbox.test.tsx`
- `pnpm -r typecheck`
- `pnpm test:run`
- `pnpm build`

Manual notes:
- Confirmed the generated spec now matches the mounted route set in the
focused regression test.
- Confirmed `/api/plugins/install` is marked privileged in the generated
security metadata.
- Confirmed `POST /api/invites/{token}/accept` documents `202`.
- Addressed the Greptile route coverage comments and reran the focused
OpenAPI test, typecheck, and build successfully.

## Risks

- Medium-low risk. The main risk is ongoing spec drift if new routes are
added without updating the OpenAPI builder, but the regression test now
fails on unknown route files that declare router methods.
- The auth metadata is descriptive only; it does not change runtime
enforcement. If reviewers assume this PR hardens server auth behavior,
that would be an incorrect expectation.
- This change increases the amount of hand-maintained OpenAPI mapping in
`server/src/routes/openapi.ts`, so future API additions still need
discipline.

> 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. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, GPT-5-based coding agent in Codex desktop. Exact
internal model variant/version and context-window size are not exposed
in this environment. Tool-enabled coding workflow with terminal
execution, git, and GitHub integration.

## 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 confirmed screenshots are not applicable
- [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.7 (1M context) <noreply@anthropic.com>
2026-06-04 09:59:22 -07:00
Doyeon BaekandClaude Opus 4.8 d60f50e4a4 feat(routines): suppress scheduled ticks while project is paused (TON-2139) (#7502)
Fixes #7501

## Thinking Path
Issue checkout already rejects paused projects (`issues.ts` → 409), but
that fires only *after* the routine execution issue exists. Per internal
TON-1102, the pause must be honored earlier — at the scheduler tick — so
no execution issue is ever created while a project is paused. The fix
gates dispatch in `tickScheduledTriggers` on the due routine's
`projects.pausedAt`, while preserving normal cron advancement so resume
does not backfill missed firings.

## What Changed
- `server/src/services/routines.ts`:
- `tickScheduledTriggers` LEFT JOINs `projects` and derives
`projectPaused` from `projects.pausedAt`. Routines with no project are
never suppressed.
- When paused: the tick is still claimed and `routineTriggers.nextRunAt`
advances by a single cron step (catch-up backfill bypassed while paused
— no replay on resume); `recordSuppressedScheduleRun` runs instead of
`dispatchRoutineRun`.
- New `recordSuppressedScheduleRun` inserts one `routine_runs` row
(`source: schedule`, `status: skipped`, `failureReason: paused`,
`linkedIssueId: null`, `completedAt` set), updates routine/trigger
touched state, and logs a `routine.run_skipped` activity entry.
- `nextResultText` gains a `skipped_paused` branch for pause-specific
audit text (does not overload the live-issue `skipped` text).
- `server/src/__tests__/routines-service.test.ts`: focused test proving
all four acceptance criteria (no issue created while paused; one
`skipped`/`paused`/null-link run; `nextRunAt` advanced; normal resume on
a later unpaused tick).

## Verification
```bash
pnpm --filter @paperclipai/server exec tsc --noEmit
npx vitest run server/src/__tests__/routines-service.test.ts
```
- The focused test in `routines-service.test.ts` proves all four
acceptance criteria: no execution issue is created while the project is
paused; exactly one `routine_runs` row is written with `source:
schedule` / `status: skipped` / `failureReason: paused` /
`linkedIssueId: null`; the trigger's `nextRunAt` advances by a single
cron step (missed firings are not backfilled); and a later tick after
the project is unpaused dispatches normally.

## Risks
- Catch-up backfill is intentionally bypassed while paused — missed
firings are **not** replayed on resume (specified no-backfill behavior).
- Scope is deliberately narrow: manual runs, webhook/API triggers,
routine-level paused status, workspace runtime start/stop,
`concurrencyPolicy`, and `catchUpPolicy` (beyond no-backfill) are
untouched.

## Model Used
claude-opus-4-8 (Paperclip CTO heartbeat)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 08:28:26 -07:00
244a5b8002 fix(plugins): allow agent JWTs to access plugin tool endpoints (supersedes #3272, with regression tests from #5549) (#7480)
## Thinking Path

> - Paperclip orchestrates AI agents for zero-human companies
> - Plugin tools are how agents call into plugin-contributed
capabilities (`GET /api/plugins/tools`, `POST
/api/plugins/tools/execute`)
> - Those two routes previously required board-level authentication, so
agent-issued JWTs were rejected — agents couldn't actually use the very
tools the plugin system was built to expose to them
> - Two community PRs (#3272 by @nullEFFORT and #5549 by @aperim-agent)
independently fixed this, but both went stale against master and neither
could be merged as-is
> - This pull request lands #3272's authz-helper approach
(`assertBoardOrAgent`) rebased on current master, and adds the
regression test suite from #5549 adapted to #3272's symbol names
> - The benefit is agents can finally call plugin tools while preserving
the existing board-scoped checks for the rest of the plugin admin
surface

## What Changed

- Adds `assertBoardOrAgent(req)` helper in `server/src/routes/authz.ts`
— accepts either a board user or an agent JWT
- Applies `assertBoardOrAgent` (in place of `assertBoard`) on `GET
/api/plugins/tools` and `POST /api/plugins/tools/execute` so
agent-issued tokens can list and execute plugin tools
- Updates the file-level doc comment on `server/src/routes/plugins.ts`
to note the agent-accessible routes
- Adds `server/src/__tests__/plugin-routes-authz.test.ts` (118 lines, 34
cases) covering: agent JWT can list tools, agent JWT can execute within
its company scope, agent JWT is rejected when `runContext.companyId` is
outside its authenticated scope, agent JWT is rejected when
`runContext.agentId` does not belong to `runContext.companyId`, plus the
existing board/admin paths

## Verification

- \`pnpm vitest run server/src/__tests__/plugin-routes-authz.test.ts\` →
**34/34 passing** locally
- Diff vs master is exactly 3 files: \`authz.ts\` (+6), \`plugins.ts\`
(+5/-3), \`plugin-routes-authz.test.ts\` (+118). No other surfaces
touched.

## Risks

Low risk.

- Authorization is being *widened* on two specific routes (board → board
or agent), not narrowed elsewhere. Every other plugin admin route still
uses \`assertBoard\` / \`assertInstanceAdmin\` /
\`assertBoardOrgAccess\`.
- Agent JWTs already encode \`companyId\` and \`agentId\`; the existing
\`validateToolRunContextScope\` queue still enforces that an agent
cannot execute a tool against a different company or impersonate another
agent. Regression coverage for both is included.
- No schema, migration, or wire-protocol changes.

## Model Used

- Claude (Anthropic), \`claude-opus-4-7\` via Claude Code, extended
thinking enabled, tool use enabled.

## 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 — N/A, server-only change
- [x] I have updated relevant documentation to reflect my changes
(file-level doc comment on \`plugins.ts\`)
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge

## Provenance / credit

This PR supersedes two community PRs that addressed the same agent-JWT
plugin-tools authz gap:

- **#3272 by @nullEFFORT** — original \`assertBoardOrAgent\` helper and
the two route changes. \`fix: allow agent JWTs to access plugin tool
endpoints\` (commit \`6991380\`) is cherry-picked here with author
attribution preserved.
- **#5549 by @aperim-agent** — regression test suite. Adapted to #3272's
symbol names (\`assertBoardOrAgent\`, three-row
\`validateToolRunContextScope\` queue) and included here.

Both originals went stale against master and could not be force-pushed
to the contributor forks from our OAuth-app-scoped tooling (workflow
files in our \`master\` introduce a \`workflow\` scope requirement on
pushes to those forks). This PR ships the same fix from our own branch
so we can land it without that blocker.

---------

Co-authored-by: Chad <chad@nulleffort.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-06-04 00:05:02 -07:00
dependabot[bot] 06ce7ec5b0 build(deps): bump dompurify from 3.3.2 to 3.4.8 (#7326)
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.3.2 to
3.4.8.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/cure53/DOMPurify/releases">dompurify's
releases</a>.</em></p>
<blockquote>
<h2>DOMPurify 3.4.8</h2>
<ul>
<li>Cleaned up the repository root, renamed some and removed unneeded
files</li>
<li>Fixed an issue with handling of Trusted Types policies, thanks <a
href="https://github.com/fulstadev"><code>@​fulstadev</code></a></li>
<li>Fixed the node iterator for better template scrubbing, thanks <a
href="https://github.com/IamLeandrooooo"><code>@​IamLeandrooooo</code></a></li>
<li>Included formerly missing LICENSE-MPL in published npm package,
thanks <a
href="https://github.com/asamuzaK"><code>@​asamuzaK</code></a></li>
<li>Bumped several dependencies where possible</li>
</ul>
<h2>DOMPurify 3.4.7</h2>
<ul>
<li>Hardened the handling of Shadow Roots when using
<code>IN_PLACE</code>, thanks <a
href="https://github.com/GameZoneHacker"><code>@​GameZoneHacker</code></a></li>
<li>Removed a problem leading to permanent hook pollution, thanks <a
href="https://github.com/offset"><code>@​offset</code></a></li>
<li>Refactored the test suite and expanded test coverage
significantly</li>
</ul>
<h2>DOMPurify 3.4.6</h2>
<ul>
<li>Fixed several issues with DOM Clobbering in <code>IN_PLACE</code>
mode, thanks <a
href="https://github.com/offset"><code>@​offset</code></a> &amp; <a
href="https://github.com/Bankde"><code>@​Bankde</code></a></li>
<li>Hardened the checks for cross-realm <code>IN_PLACE</code> and Shadow
DOM sanitization, thanks <a
href="https://github.com/offset"><code>@​offset</code></a> &amp; <a
href="https://github.com/Bankde"><code>@​Bankde</code></a></li>
<li>Added more test coverage for <code>IN_PLACE</code> and general DOM
Clobbering attacks</li>
<li>Bumped several dependencies where possible</li>
</ul>
<h2>DOMPurify 3.4.5</h2>
<ul>
<li>Fixed a bypass caused by the new HTML element
<code>selectedcontent</code> added in 3.4.4, thanks <a
href="https://github.com/KabirAcharya"><code>@​KabirAcharya</code></a></li>
</ul>
<p><strong>Note that this is a security release for an issue introduced
in 3.4.4 and should be upgraded to immediately.</strong></p>
<h2>DOMPurify 3.4.4</h2>
<ul>
<li>Added the <code>selectedcontent</code> element to default
allow-list, thanks <a
href="https://github.com/lukewarlow"><code>@​lukewarlow</code></a></li>
<li>Added the <code>command</code> and <code>commandfor</code>
attributes to default allowed-list, thanks <a
href="https://github.com/lukewarlow"><code>@​lukewarlow</code></a></li>
<li>Added better template scrubbing for <code>IN_PLACE</code>
operations, thanks <a
href="https://github.com/DEMON1A"><code>@​DEMON1A</code></a></li>
<li>Added stronger checks for cross-realm windows, thanks <a
href="https://github.com/DEMON1A"><code>@​DEMON1A</code></a> &amp; <a
href="https://github.com/fg0x0"><code>@​fg0x0</code></a></li>
<li>Updated demo website and made sure it uses the latest from main</li>
<li>Updated existing workflows, fuzzer, dependabot, etc., added more
tests</li>
<li>Bumped several dependencies where possible</li>
</ul>
<p>🚨 <strong>This release had been flagged as deprecated, please use
DOMPurify 3.4.5 instead</strong> 🚨</p>
<h2>DOMPurify 3.4.3</h2>
<ul>
<li>Fixed an issue with handling of nested Shadow DOM trees, thanks <a
href="https://github.com/fishjojo1"><code>@​fishjojo1</code></a></li>
<li>Fixed the template regexes to be more robust against ReDoS attacks,
thanks <a
href="https://github.com/aleung27"><code>@​aleung27</code></a></li>
<li>Updated the node iteration code to catch more Shadow DOM related
issues</li>
<li>Updated Playwright and added Node 26 to test matrix</li>
<li>Updated existing workflows, fuzzer, release signing, etc., added
more tests</li>
<li>Bumped several dependencies where possible</li>
</ul>
<h2>DOMPurify 3.4.2</h2>
<ul>
<li>Fixed an issue with URI validation on attributes allowed via
<code>ADD_ATTR</code> callback, thanks <a
href="https://github.com/nelstrom"><code>@​nelstrom</code></a></li>
<li>Fixed an issue with source maps referring to non-existing files,
thanks <a
href="https://github.com/cmdcolin"><code>@​cmdcolin</code></a></li>
<li>Updated existing workflows, fuzzer, release signing, etc., added
more tests</li>
<li>Bumped several dependencies where possible</li>
</ul>
<h2>DOMPurify 3.4.1</h2>
<ul>
<li>Fixed an issue with on-handler stripping for HTML-spec-reserved
custom element names (<code>font-face</code>,
<code>color-profile</code>, <code>missing-glyph</code>,
<code>font-face-src</code>, <code>font-face-uri</code>,
<code>font-face-format</code>, <code>font-face-name</code>) under
permissive <code>CUSTOM_ELEMENT_HANDLING</code></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/cure53/DOMPurify/commit/bcdd8285412dc9c4c149652aed2d712e790d6ccf"><code>bcdd828</code></a>
release: 3.4.8 (<a
href="https://redirect.github.com/cure53/DOMPurify/issues/1439">#1439</a>)</li>
<li><a
href="https://github.com/cure53/DOMPurify/commit/ca30f070c360df162a3e3848e80e6fd3c9e74bff"><code>ca30f07</code></a>
release: 3.4.7 (<a
href="https://redirect.github.com/cure53/DOMPurify/issues/1414">#1414</a>)</li>
<li><a
href="https://github.com/cure53/DOMPurify/commit/bb7739e5bccec7e1ab3dae3f3e42d02db3acaaae"><code>bb7739e</code></a>
release: 3.4.6 (<a
href="https://redirect.github.com/cure53/DOMPurify/issues/1394">#1394</a>)</li>
<li><a
href="https://github.com/cure53/DOMPurify/commit/011b0c78f2a0f57ee54f5fcccb697a46ca6e63ea"><code>011b0c7</code></a>
release: 3.4.5 (<a
href="https://redirect.github.com/cure53/DOMPurify/issues/1382">#1382</a>)</li>
<li><a
href="https://github.com/cure53/DOMPurify/commit/5817ad969c15e67dfcd6cb37248d6e9c1553e7c3"><code>5817ad9</code></a>
release: 3.4.4 (<a
href="https://redirect.github.com/cure53/DOMPurify/issues/1374">#1374</a>)</li>
<li><a
href="https://github.com/cure53/DOMPurify/commit/520edb0371a9638f9b51f1798051299a250c686b"><code>520edb0</code></a>
release: 3.4.3 (<a
href="https://redirect.github.com/cure53/DOMPurify/issues/1352">#1352</a>)</li>
<li><a
href="https://github.com/cure53/DOMPurify/commit/6f67fd396a7b8c64294343999fe607ca1f5299c0"><code>6f67fd3</code></a>
Sync/3.4.2 (<a
href="https://redirect.github.com/cure53/DOMPurify/issues/1322">#1322</a>)</li>
<li><a
href="https://github.com/cure53/DOMPurify/commit/5b0cdbbf52331e854c0a2de875b1a3790ecec2b8"><code>5b0cdbb</code></a>
chore: merge main into 3.x for 3.4.1 release (<a
href="https://redirect.github.com/cure53/DOMPurify/issues/1301">#1301</a>)</li>
<li><a
href="https://github.com/cure53/DOMPurify/commit/09f59115a311469de5b625225760593e551f080a"><code>09f5911</code></a>
test: added three more browsers to test setup (OSX, mobile)</li>
<li><a
href="https://github.com/cure53/DOMPurify/commit/5b16e0b892e82b1779d62b9928b43c4c4ff290b9"><code>5b16e0b</code></a>
Getting 3.x branch ready for 3.4.0 release (<a
href="https://redirect.github.com/cure53/DOMPurify/issues/1250">#1250</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/cure53/DOMPurify/compare/3.3.2...3.4.8">compare
view</a></li>
</ul>
</details>
<details>
<summary>Install script changes</summary>
<p>This version adds <code>prepare</code> script that runs during
installation. Review the package contents before updating.</p>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-03 23:20:50 -07:00
dependabot[bot] 07ec29bd84 build(deps): bump ajv from 8.18.0 to 8.20.0 (#7323)
Bumps [ajv](https://github.com/ajv-validator/ajv) from 8.18.0 to 8.20.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ajv-validator/ajv/releases">ajv's
releases</a>.</em></p>
<blockquote>
<h2>v8.20.0</h2>
<h2>What's Changed</h2>
<ul>
<li>fix: add support for node 22/24, drop node 16/21 by <a
href="https://github.com/jasoniangreen"><code>@​jasoniangreen</code></a>
in <a
href="https://redirect.github.com/ajv-validator/ajv/pull/2580">ajv-validator/ajv#2580</a></li>
<li>fix: add ES2022.RegExp for RegExpIndicesArray by <a
href="https://github.com/SignpostMarv"><code>@​SignpostMarv</code></a>
in <a
href="https://redirect.github.com/ajv-validator/ajv/pull/2604">ajv-validator/ajv#2604</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/ajv-validator/ajv/compare/v8.19.0...v8.20.0">https://github.com/ajv-validator/ajv/compare/v8.19.0...v8.20.0</a></p>
<h2>v8.19.0</h2>
<h2>What's Changed</h2>
<ul>
<li>fix prototype pollution via format keyword using $data ref by <a
href="https://github.com/epoberezkin"><code>@​epoberezkin</code></a> in
<a
href="https://redirect.github.com/ajv-validator/ajv/pull/2607">ajv-validator/ajv#2607</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/ajv-validator/ajv/compare/v8.18.0...v8.19.0">https://github.com/ajv-validator/ajv/compare/v8.18.0...v8.19.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/ajv-validator/ajv/commit/0fba0b8e649909613cfce0999b149cd08f4a4987"><code>0fba0b8</code></a>
8.20.0</li>
<li><a
href="https://github.com/ajv-validator/ajv/commit/9caf8d64409b05e2c670b3ff09cf7ca07937342e"><code>9caf8d6</code></a>
fix: add ES2022.RegExp for RegExpIndicesArray; fixes <a
href="https://redirect.github.com/ajv-validator/ajv/issues/2603">ajv-validator/ajv#2603</a>
(...</li>
<li><a
href="https://github.com/ajv-validator/ajv/commit/206535071f776f57737394c8896d4b2dc2bfb9a3"><code>2065350</code></a>
fix: add support for node 22/24, drop node 16/21 (<a
href="https://redirect.github.com/ajv-validator/ajv/issues/2580">#2580</a>)</li>
<li><a
href="https://github.com/ajv-validator/ajv/commit/154b58d690c6596e09ca676e12720ab8234ee3d2"><code>154b58d</code></a>
8.19.0</li>
<li><a
href="https://github.com/ajv-validator/ajv/commit/e8d2bdc501b3ba6f03922db5e595770d4763d9da"><code>e8d2bdc</code></a>
test/fix prototype pollution via $data ref with format keyword (<a
href="https://redirect.github.com/ajv-validator/ajv/issues/2607">#2607</a>)</li>
<li>See full diff in <a
href="https://github.com/ajv-validator/ajv/compare/v8.18.0...v8.20.0">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-03 23:18:48 -07:00
Devin Foley 93206f73fa fix: Stop archived companies from waking agents (#7478)
## Thinking Path

> - Paperclip orchestrates AI agents for zero-human companies
> - Each agent has a heartbeat scheduler that wakes it on timers and on
events; every wake spawns an adapter (Claude / Codex / …) run that bills
the operator's subscription
> - When an operator archives a company, the agents inside it remain in
invokable states — the heartbeat scheduler never consults company status
— so timers keep firing and event-driven wakes (comments, mentions,
blockers-resolved, etc.) keep cascading
> - On real deployments this silently drains the operator's
subscription: idle archived companies wake their CEOs hourly, plus any
cross-company event cascade
> - This pull request enforces "archived ⇒ never spawns a run" as a
structural invariant by guarding the wake path AND cascading agent state
on archive/reactivate
> - The benefit is that archived companies stop billing the operator,
and the UI/queue stays consistent with the invariant

## What Changed

- `server/src/services/heartbeat.ts`:
- `enqueueWakeup()` loads the company and short-circuits when status is
not `active`. Background sources (timer, automation, events) write a
`company.inactive` skipped wake and return `null`; explicit user invokes
throw a `conflict` so the UI surfaces the real reason.
- `tickTimers()` joins agents to active companies so the scheduler does
not iterate archived-company agents at all (no skip-row noise).
- `server/src/services/companies.ts`:
- `archive(id, actor?)` pauses runnable agents with `pauseReason =
"company_archived"` inside the transaction (preserving
`pending_approval`, `terminated`, and agents paused for unrelated
reasons), then cancels `queued`/`running` heartbeat runs after the
transaction commits.
- `update(id, data, actor?)` reverses the cascade only for agents whose
`pauseReason === "company_archived"` on the `archived → active`
transition; manually-paused agents stay paused.
- Both methods emit activity-log entries (`company.archived` with
`agentsPaused` + `runsCancelled`, `company.reactivated` with
`agentsRestored`) so the audit trail fires regardless of caller.
- `packages/shared/src/constants.ts` + `server/src/services/budgets.ts`:
add `company_archived` to the legal `PauseReason` union so the
restorable marker is a first-class value.
-
`packages/db/src/migrations/0094_backfill_archived_company_agent_pauses.sql`:
backfill so existing archived-company agents become `paused /
company_archived` (excludes `pending_approval`).
- `ui/src/lib/activity-format.ts`: add the `company.reactivated` label.

## Verification

- `npx vitest run src/__tests__/companies-service.test.ts` — archive
cascade, reactivate cascade, and activity-log entries (with counts) all
pass.
- `npx vitest run
src/__tests__/heartbeat-archived-company-guard.test.ts` — timer +
on-demand + event-wake paths all blocked for archived companies;
`company.inactive` skipped-wake row written; user-initiated wakes throw
`conflict`.
- `pnpm typecheck` — clean.
- Manual repro from the bug description: archive a company, wait an
interval / post a comment on one of its issues, observe zero new
heartbeat runs.

## Risks

- Migration `0094` is a single bulk UPDATE on `agents` joined to
archived `companies`. On large deployments it briefly holds row locks on
archived-company agent rows; should be quick because the predicate is
narrow (`status NOT IN (paused, terminated, pending_approval)` and
`companies.status = 'archived'`).
- New `pauseReason` value (`company_archived`) is opaque to older
clients that only know the previous union. Acceptable because the union
is read as plain text and the contract is sync'd in the same change.
- Behavior change for users: invoking an agent in an archived company
now fails with a conflict instead of silently spawning a run. Intended.

## Model Used

- Claude (Anthropic) — model `claude-opus-4-7` ("Opus 4.7"), Claude Code
CLI, with tool use (Read/Edit/Bash/Grep). No extended thinking mode.

## 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 — N/A, no UI changes beyond an activity-log label string
- [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

## Related Work

Fixes #1348 (`[Bug] Archived companies still running heartbeats and
consuming tokens`).

Prior attempts and parallel work in this area:

- #1365 and #1429 by @hungdqdesign (March 2026) — both closed without
merging. Same three-layer shape (`tickTimers` / `enqueueWakeup` /
`resumeQueuedRuns` + archive-route cancellation) targeting #1348. Credit
for first publicly proposing the wake-path-guard approach.
- #5865 by @stubbi (May 2026, open) — adds the same `companies.status !=
'archived'` joins to `tickTimers`, `enqueueWakeup`, `resumeQueuedRuns`,
**and** routines `tickScheduledTriggers`, bundled with plugin-table
tenant isolation (`plugin_entities` / `plugin_job_runs` / `plugin_logs`
/ `plugin_webhook_deliveries` get a `companyId` FK with `ON DELETE
CASCADE`). This PR is narrower — it does not touch routines or plugin
tables — but adds the **archive cascade** (pause agents with
`pauseReason = "company_archived"`), the **reactivate reverse**
(un-pause only that subset), the **`company_archived` pause-reason
marker**, and a **backfill migration** for pre-existing archived
companies, which #5865 does not include. Happy to coordinate sequencing
or rebase if #5865 lands first.
2026-06-03 21:07:14 -07:00
62863126a3 fix(plugin-tool-dispatcher): propagate pluginDbId so worker.isRunning resolves (#5671)
Fixes #2391
Fixes #3394
Fixes #4094
Fixes #5501
Fixes #5916
Fixes #6215
Fixes #6514

## Thinking Path

> - Paperclip orchestrates AI agents for zero-human companies
> - Plugins extend the platform by registering agent-callable tools
backed by long-running worker processes
> - `PluginToolDispatcher` is the boundary between the HTTP
`/api/plugins/tools/execute` route and `PluginWorkerManager`, which owns
those worker processes
> - `PluginWorkerManager` keys live workers by the plugin's **database
UUID**, but `plugin-loader` was registering tools using only `pluginKey`
— so every tool call did `workerManager.isRunning(pluginKey)` and always
got `false`
> - As a result, every `POST /api/plugins/tools/execute` against a
tool-exposing plugin returned 502 `worker for plugin X is not running`,
even though the worker process was alive (hit in production by
`vexion.council-chat`; `mem0-sync` would be next)
> - This pull request threads the DB UUID through the dispatcher →
registry hop and hardens the contract so omitting the UUID is a
compile-time error, not a silent fallback
> - The benefit is plugin tool execution actually works for any plugin
declaring `manifest.tools[]`, and the type system prevents the same bug
from recurring

## What Changed

- `server/src/services/plugin-loader.ts` — pass in-scope `pluginId` (DB
UUID) as the third argument to `toolDispatcher.registerPluginTools`.
Single-line root fix.
- `server/src/services/plugin-tool-dispatcher.ts` —
`registerPluginTools` now takes `pluginDbId: string` (required, was
optional). JSDoc updated to document the worker-routing contract and why
the optional signature masked the bug.
- `server/src/services/plugin-tool-registry.ts` — `registerPlugin`
throws on missing/empty `pluginDbId` so any new call site that forgets
the UUID fails immediately rather than silently falling back to
`pluginKey`.
- `server/src/__tests__/plugin-tool-dispatcher-pluginDbId.test.ts` — new
focused regression suite covering the activation path, disable→enable
lifecycle, worker re-spawn, and the empty-UUID guard.

## Verification

- `pnpm vitest run
server/src/__tests__/plugin-tool-dispatcher-pluginDbId.test.ts` — 6/6
passing.
- `pnpm vitest run server/src/__tests__/plugin-database.test.ts
server/src/__tests__/plugin-routes-authz.test.ts
server/src/__tests__/plugin-lifecycle-restart.test.ts` — 48/48 passing
on the merge commit.
- `pnpm --filter @paperclipai/server typecheck` — no new errors
introduced by these files.
- Manual repro path:
1. Install a plugin that declares `manifest.tools[]` and uses
`runWorker`.
2. Confirm status `ready` and a live worker (`paperclipai plugin
diagnostics <key>`).
3. `POST /api/plugins/tools/execute` with `{ tool:
"<pluginKey>:<toolName>", parameters, runContext }`.
4. Pre-fix: HTTP 502, `worker for plugin <key> is not running`.
Post-fix: tool dispatches normally.

## Risks

- Low risk. The signature tightening (`pluginDbId?` → `pluginDbId`) is a
back-compatible behavioral fix at the only production call site
(`plugin-loader`), which already had the UUID in scope.
- Test/recovery paths that previously omitted the UUID must now supply
it; the new error message identifies the missing arg explicitly.
- No database migration, no API/schema change, no plugin-author-facing
change.
- The merge commit pulls master into the PR branch additively (no
rebase); reviewers can read the fix commits independently of the merge.

## Model Used

- Provider/model: Anthropic Claude (Opus 4.7, `claude-opus-4-7`) for the
additive merge-conflict resolution, PR description rewrite, and Greptile
follow-up; original fix authored by
[@Ramon-nassa](https://github.com/Ramon-nassa).
- Capabilities used: tool use (file edit, shell, GitHub CLI), extended
thinking off, no code execution by the model.

## 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 (N/A — server-only change)
- [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

---

## Original Summary (preserved from contributor)

`plugin-loader` activates plugins and calls

```ts
toolDispatcher.registerPluginTools(pluginKey, manifest)
```

with only two args. `PluginToolDispatcher.registerPluginTools` forwards
them to `registry.registerPlugin(pluginKey, manifest)`. The registry
falls back `pluginDbId ?? pluginKey`, but `PluginWorkerManager` keys
live workers by the DB UUID — so the downstream

```ts
workerManager.isRunning(pluginKey)   // always false
```

causes every `POST /api/plugins/tools/execute` to fail with `worker for
plugin X is not running`, even when the worker process is alive and
healthy. **This hits every plugin that exposes tools** (we hit it in
`vexion.council-chat`; `mem0-sync` would too).

Reported-by: Vexion / Ramon Nassar (vexion.council-chat plugin, MO-068).

---------

Co-authored-by: ramon nassar <ramon@tabs.co>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Devin Foley <devin@devinfoley.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-06-03 19:13:21 -07:00
Aron PrinsandDevin Foley 70b1a9109d Improve CLI API parity coverage (#6626)
## Thinking Path

> - Paperclip is a control plane for AI-agent companies, with the CLI
acting as a scriptable operator and agent interface to that control
plane.
> - The REST API surface has grown across companies, agents, issues,
routines, plugins, auth, workspaces, secrets, and operational inspection
commands.
> - The CLI had drifted from that API surface: some commands were
missing, some command shapes differed from docs/reference material, and
several edge cases only failed during end-to-end local-source testing.
> - The local development runbook requires these tests to be disposable
and isolated from a real `~/.paperclip`, `~/.codex`, or `~/.claude`
installation.
> - This pull request adds broad CLI/API parity coverage, fixes the
actionable bugs found during that pass, and records the reproducible
test log under `doc/logs`.
> - The benefit is a more complete, scriptable CLI surface with
regression coverage for the command families exercised by the parity
run.

## What Changed

- Added or expanded CLI command coverage for access/auth, companies,
agents, projects, goals, issues and subresources, routines, plugins,
workspaces, activity/run/cost/dashboard inspection, assets, skills,
secrets, tokens, prompt/wake flows, and local setup helpers.
- Fixed CLI/API parity bugs found during the run, including context
profile patching, issue interaction optional payloads, malformed
tree-hold errors, environment duplicate handling, configure
invalid-section exit codes, worktree pnpm invocation, token agent ID
resolution, plugin tool worker lookup, and routine webhook secret
cleanup.
- Added missing CLI wrappers and route coverage for health/access,
invite resolution URL forwarding, join status normalization, secret
lifecycle commands, LLM docs routes, available-skill isolation, positive
board-claim coverage, and interactive `connect` prompt-flow tests.
- Added a schema-backed `/api/openapi.json` route sufficient for CLI
parity and `paperclipai openapi --json` smoke coverage.
- Added `doc/logs/2026-05-24-cli-api-parity-e2e-log.md` with the
detailed living test/bug log and renamed the log directory from
`doc/bugs` to `doc/logs`.
- Added `doc/plans/2026-05-23-cli-api-parity.md` and the OpenAPI parity
reference used during the pass.

OpenAPI note: this PR intentionally does not try to subsume
`feature/openapi-spec`. The OpenAPI implementation here is schema-backed
and better than the earlier route-inventory stub, but
`feature/openapi-spec` is the fuller/better OpenAPI branch because it
includes exact mounted-route coverage tests and additional current route
coverage. That branch should stay as its own PR and can supersede this
OpenAPI route implementation.

## Verification

Targeted automated checks run:

- `pnpm exec vitest run server/src/__tests__/openapi-routes.test.ts`
- `pnpm exec vitest run server/src/__tests__/board-claim.test.ts`
- `pnpm exec vitest run cli/src/__tests__/connect.test.ts`
- `pnpm exec vitest run cli/src/__tests__/agent-lifecycle.test.ts`
- `pnpm exec vitest run server/src/__tests__/plugin-database.test.ts`
- `pnpm exec vitest run server/src/__tests__/routines-service.test.ts`
- `pnpm --dir cli typecheck`
- `pnpm --dir server typecheck`

Manual/local E2E verification:

- Ran the full disposable local-source CLI/API parity pass with isolated
`PAPERCLIP_HOME`, `PAPERCLIP_CONFIG`, `PAPERCLIP_CONTEXT`,
`PAPERCLIP_AUTH_STORE`, `CODEX_HOME`, and `CLAUDE_HOME` under
`tmp/cli-api-parity`.
- Verified `DATABASE_URL` and `DATABASE_MIGRATION_URL` stayed unset for
the scratch server.
- Verified live health and schema-backed OpenAPI responses on
non-default port `3197`.
- Revoked created board/agent tokens and cleaned up temporary plugins,
secrets, non-default environments, and project workspaces.
- See `doc/logs/2026-05-24-cli-api-parity-e2e-log.md` for the full
command-by-command reproduction log.

Not run:

- Full `pnpm test`, `pnpm test:run`, or `pnpm build` were not run after
the entire branch because the branch is broad and the parity pass used
focused test/typecheck verification plus live isolated CLI reruns.

## Risks

- This is a broad PR and touches many CLI command modules, so review
surface is high. The changes are grouped around one theme, but a split
may be easier if maintainers prefer narrower PRs.
- The OpenAPI route in this PR is not the final/best OpenAPI
implementation. `feature/openapi-spec` has stronger exact-route coverage
and should remain the source for the dedicated OpenAPI PR.
- The living log is intentionally detailed and large. It is useful for
reproducibility but adds documentation weight.
- No UI changes are intended; screenshots are not applicable.

> 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 in Codex desktop. Exact served
model/context-window identifier was not exposed in the local app. Work
used shell/Git/GitHub CLI tooling, local source inspection, targeted
test execution, and live isolated Paperclip CLI/API smoke testing.

## 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: Devin Foley <devin@devinfoley.com>
2026-06-02 17:13:29 -07:00
d58a862549 fix(issues): coerce anchor.createdAt to Date before postgres binding (PRO-3144) (#5220)
## Thinking Path

> - Paperclip orchestrates AI agents in a control plane backed by
Postgres + drizzle-orm
> - `listComments` is the cursor-paginated comment listing on the issues
service; the cursor branch uses Drizzle's `gt`/`lt`/`eq` against
`issueComments.createdAt`
> - On postgres.js v3.4.8, passing a `Date` instance through the
comparison helpers triggers `TypeError [ERR_INVALID_ARG_TYPE]: The
"string" argument must be of type string or an instance of Buffer or
ArrayBuffer. Received an instance of Date`
> - The driver's binding path expects a Date constructed via the
standard runtime, but drizzle's `select` returns instances that don't
satisfy that check in this version
> - This PR coerces `anchor.createdAt` through `toISOString()` → `new
Date(...)` so the comparison helpers always receive a binding-safe Date,
then folds in a follow-up that hoists the Date into a single allocation
reused across all four `gt`/`lt`/`eq` call sites
> - The benefit is `listComments` cursor pagination stops 500-ing on Pg
v3.4.8 with one Date allocation per call instead of four, exercised by
both ascending and descending cursor tests

## What Changed

- `server/src/services/issues.ts` — coerce `anchor.createdAt` to a
binding-safe `Date` once and reuse the same instance across all four
cursor comparisons (`gt` / `lt` / `eq`)
- `server/src/__tests__/issues-service.test.ts` — add an
ascending-cursor sibling test so both `gt` and `lt` cursor paths are
exercised; the existing descending test continues to pass

## Verification

```bash
# Both cursor branches
pnpm --filter @paperclipai/server exec vitest run \
  src/__tests__/issues-service.test.ts -t "anchor comment"
# → 2 passed, 41 skipped

# Production smoke
curl -s "$PAPERCLIP_API_URL/api/issues/<issueId>/comments?after=<commentId>&order=asc" \
  -H "Authorization: Bearer $PAPERCLIP_API_KEY"
# Expect: JSON array, no 500 TypeError
```

## Risks

- Low risk. Pure cursor-pagination internals in `listComments`; no
schema, migration, or external contract changes
- Drizzle's `gt`/`lt`/`eq` continue to receive a `Date` for the
timestamp column, producing the same bound parameter as before
- Behavioural surface is exercised by ascending + descending cursor
tests against a real Postgres test database

## Model Used

- Claude Opus 4.7 (`claude-opus-4-7`), no extended-thinking mode, used
for the hoist+test follow-up commit

## Fixes

Closes #2612, Closes #3661, Closes #3830

## 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 — n/a, backend-only
- [x] I have updated relevant documentation to reflect my changes — n/a,
no docs touched
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Elena Voronova <elena@paperclip.ing>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Devin Foley <devin@devinfoley.com>
2026-06-02 15:26:59 -07:00
Dotta edeab22c28 Merge pull request #7362 from paperclipai/pap-10195-dev-runner-race
[codex] Fix dev runner snapshot race
2026-06-01 15:34:28 -10:00
Dotta dc58544832 Address dev runner snapshot review feedback 2026-06-01 22:03:51 +00:00
Dotta 8f25ba6381 Add dev runner snapshot race regression test 2026-06-01 21:55:30 +00:00