mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-07 16:11:46 +02:00
bf95a7eae255b390749fa5a4bda56de1127aa4e1
4176
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
bf95a7eae2 |
fix(ui): stabilize active-run steering queue (#12834)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The issue detail page shows a live agent run and accepts follow-up instructions. > - A follow-up must stay in a stable queue until the user sends, reorders, or removes it. > - Native runners can receive a steering event in the active run. > - Legacy runners must interrupt the active run and start a follow-up run. > - The current UI moved comments between the queue and the transcript and could show duplicate text or ambiguous chronology. > - This pull request makes the queue projection durable, keeps each message in one clear place, and labels when queued input was actually steered or delivered. > - The benefit is predictable steering with stable ordering, no duplicate messages, and visible causal timing. ## Linked Issues or Issue Description Refs #11374. Refs #12591. **What happened?** During an active run, a new follow-up could first appear as a transcript bubble and then move into the steering queue. After a steer or remove action, it could appear again. Progress text could also repeat the final response text. Once consumed, a queued bubble displayed only its original submission time even though it moved to its later causal slot, and a native run split by steering looked like two unrelated runs. **Expected behavior** An active-run follow-up must appear in the queue immediately. A native steer must move it once into the active run. A legacy interrupt must move it once into the follow-up run. A removed item must stay removed. Progress text that is identical to the final response must appear once. Consumed follow-ups must show both queue and steer/delivery times, and post-steer native segments must identify themselves as continuations of the same run. **Steps to reproduce** 1. Start a long-running task. 2. Send two or more follow-up messages while the agent is active. 3. Reorder the messages and remove one message. 4. Send the first queued message as steering. 5. Observe the queue and transcript during and after both runs. **Paperclip version or commit** The problem reproduced on commit `da1e40302`. **Deployment mode** Local development with the embedded database. ## What Changed - Project queued comments into the steering well for native and legacy live runners. - Send native steering to the active run and use interrupt-and-follow-up for legacy runners. - Keep optimistic queue order stable across refreshes and roll back failed actions. - Remove discarded comments from the transcript cache and keep them removed when the queue becomes empty. - Collapse only the final progress occurrence matching the durable response, including across steered transcript segments. - Show `Queued … · Steered …` for same-run input and `Queued … · Delivered …` for successor-run input at their causal positions. - Label settled and live post-steer segments `Continued after steering` and time them from the steer boundary. - Add regression tests for queue display, steering, fallback interrupt, reorder, remove, rollback, duplicate text, causal timestamps, and live/settled continuation headers. ## Verification - Ran the final focused steering/chronology UI suite with 233 passing tests. - Ran the activity-service regression suite with 5 passing tests. - Ran the broader queue-focused UI suite with 298 passing tests before the final chronology refinement. - Ran `pnpm -r typecheck` successfully. - Ran `pnpm build` successfully. - Ran `pnpm check:token-gates` successfully. - Tested native steering in a real browser with a 90-second baseline wait and a three-second steering correction. - Confirmed that the old final response did not appear before the steered response. - Tested three queued messages in a real browser. - Confirmed that reorder changed delivery order and that the removed message was never sent or shown again. - Tested a legacy runner in a real browser. - Confirmed that it used the interrupt fallback and showed the follow-up once. - Reloaded a saved mixed-steer/successor-run thread and confirmed the causal timestamps and continuation header render in the correct positions. - The complete macOS suite reaches five unrelated platform assertions in workspace-runtime tests. Two compare `/var` with `/private/var`. Three require Linux `/proc` listener data. GitHub Actions provides the authoritative Linux run. ## Risks - Low risk. The change is limited to issue-chat queue projection and transcript presentation. - The server run-history API adds only a read-only `contextIssueId` projection; the database schema does not change. - Optimistic actions restore the prior UI state when a request fails. ## Model Used - OpenAI Codex with GPT-5, extended reasoning, browser automation, shell tools, and code 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip <noreply@paperclip.ing>canary/v2026.904.0-canary.11 |
||
|
|
b84964e5a2 |
fix(runner): stabilize local paid E2E recovery (#12836)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Paid runner E2E tests verify the complete runner, control-plane, and UI path. > - A server restart could load a fresh task page while Playwright still waited on an unsettled Vite navigation lifecycle. > - The current server also ignored the isolated Vite cache path and skipped Vite's per-request HTML transform from the known-green runner snapshot. > - A one-cell paid run then exposed that download-artifact v8 removes the artifact-name directory for one pattern match. > - This pull request restores the Vite contract, proves a fresh document after restart, and accepts only the exact singleton artifact layout. > - The benefit is reliable local runner qualification without weaker UI, source, or artifact checks. ## Linked Issues or Issue Description Refs #12769 Refs #12828 Refs #12829 Refs #12833 **What happened?** The structured-question restart test could time out after the replacement server returned the task route and rendered the durable pending interaction. A focused one-cell rerun passed the paid test but failed aggregation because download-artifact v8 flattened its single artifact. **Expected behavior** The test must prove that a new document loaded after the server restart and that the same pending interaction survived. The aggregate must accept the exact documented singleton download layout while it continues to reject ambiguous or foreign artifacts. **Steps to reproduce** 1. Run the local ACPX-Codex structured-question restart-resume cell. 2. Restart the isolated server while the question waits for an answer. 3. Observe that the route and task UI can reload before Playwright settles the navigation promise. 4. Run a paid campaign with one selected cell. 5. Observe download-artifact v8 extract the sole campaign directory directly into the requested path. **Paperclip version or commit** The local campaign reproduced the navigation failure at `3586956a1b794b3cb4a9c5f57ffb7355e2b0c46d`. The one-cell aggregate reproduced the singleton layout at `f487660c0a06ba06ca140b57386f21ed39f13120`. This fix is `de4ccceff453a4b39436bf9a2eb8f03924151af7`. **Deployment mode** Local development and paid GitHub Actions. **Installation method** Built from source. **Agent adapter(s) involved** ACPX-Codex. The Vite and aggregate fixes are provider-neutral. ## What Changed - Prove a new post-restart browser document with an in-memory sentinel. - Tolerate only Playwright's navigation timeout before the exact UI and API checks run. - Honor `PAPERCLIP_VITE_CACHE_DIR` in the embedded Vite server. - Limit dependency optimization to the real UI entry. - Run `vite.transformIndexHtml` for each request while caching only the branded source template. - Accept download-artifact v8's flattened layout only for one expected cell with one unique recognized campaign. - Keep source SHA, source ref, workflow URL, execution ID, attempt, and unexpected-entry validation. - Add focused positive and negative regressions for Vite rendering and singleton artifact selection. ## Verification - Exact 45-cell local campaign https://github.com/paperclipai/paperclip/actions/runs/33888939013 passed 44/45. Its only failure was the post-restart navigation false negative fixed here. - Exact focused rerun https://github.com/paperclipai/paperclip/actions/runs/33891207957 passed the ACPX-Codex restart cell first attempt with the same session, two durable runs, the terminal marker once, and cleanup complete. - The focused Vite renderer suite passed 2/2 tests. - The focused rerun-artifact selector suite passed 12/12 tests. - Prettier and `git diff --check` passed. - An exact-head 45-cell confirmation is pending. ## Risks Low to medium risk. The Vite change restores known-green per-request transforms and isolated cache behavior. It can affect all development UI loads. The paid matrix and ordinary CI will verify that behavior. The singleton selector remains fail-closed for ambiguous layouts and validates every result source. ## Model Used OpenAI Codex, `gpt-5.6-sol`, extended reasoning, tool use, code execution, and parallel focused agents. ## 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting mergecanary/v2026.904.0-canary.10 |
||
|
|
184b014c25 |
feat(telemetry): add the agent.task_run event and emit it at every terminal run transition (#12809)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Paperclip records agent run outcomes through telemetry and run lifecycle services > - Terminal run transitions need one consistent event for outcome analysis > - The current paths do not report every terminal transition through one event > - This pull request adds the agent.task_run event and emits it at each terminal transition > - The benefit is complete run outcome data without exposing raw task identifiers ## Linked Issues or Issue Description **What existing behavior does this improve?** Paperclip telemetry reports agent activity, but it does not report every terminal task run through one event. **Subsystem affected** Cross-cutting (multiple of the above): packages/shared telemetry and server run lifecycle services. **Current behavior** Several run paths write a terminal status without a matching agent.task_run telemetry event. **Proposed behavior** Each terminal run transition emits one agent.task_run event. The event records the terminal state and uses the existing pseudonym helper for the optional task identifier. **Reason and benefit** Complete terminal-run data helps operators measure agent outcomes. The pseudonym helper prevents the raw task identifier from leaving the installation. **Breaking changes** None. The change adds an event and keeps existing event behavior compatible. ## What Changed - Add the agent.task_run telemetry contract and client helper. - Reuse the existing pseudonym helper for the task identifier. The helper hashes the identifier with a per-installation salt and returns 16 hexadecimal characters. The raw identifier never leaves the installation. Existing identifiers do not move. - Emit one event from each legacy, native, recovery, and issue terminal transition. - Keep emissions outside database transactions and make delivery best-effort. - Add regression tests for event shape, hashing, terminal transitions, and emission failures. - Document the event and its privacy rule in the telemetry data contract. ## Verification - `npx tsc --noEmit` in `server/` passes at the submitted commit. - The pull-request CI suite must pass. CI is the authority because local Vitest has a known dependency artifact. - The added regression tests cover event output shape, per-installation hash divergence, raw identifier handoff, omitted identifiers, and non-throwing emits. ## Risks - A missed terminal path could reduce event coverage. - Telemetry delivery remains best-effort and cannot change run finalization. - The pseudonym helper uses installation-specific state, so identifiers differ between installations. ## Model Used OpenAI Codex, GPT-5, tool use and code execution. Context window details were not provided. ## 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes: #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I have addressed all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>canary/v2026.904.0-canary.9 |
||
|
|
3586956a1b |
chore(lockfile): refresh pnpm-lock.yaml (#12828)
Co-Authored-By: lockfile-bot <lockfile-bot@users.noreply.github.com> |
||
|
|
da1e403022 |
test(runner): harden native OpenCode paid fixtures (#12833)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Paid runner E2E tests verify the full control-plane path for supported providers. > - Native OpenCode could write the reserved terminal marker through progress and final output. > - The restart fixture also waited for all development assets after the recovered UI was already usable. > - These behaviors made two valid local runner paths fail qualification. > - This pull request makes the OpenCode write contract explicit and uses the visible UI as the restart readiness gate. > - The benefit is reliable local OpenCode qualification without weaker duplicate detection. ## Linked Issues or Issue Description Refs #12769 Refs #12829 Refs #12828 **What happened?** The native OpenCode ask fixture allowed a progress tool call before the final response. OpenCode could write the reserved terminal marker in both places. The structured restart fixture could also time out while it waited for `DOMContentLoaded` after the recovered UI was visible and usable. **Expected behavior** The ask fixture must write the reserved marker once. The restart fixture must continue when the recovered UI and interaction API prove that the application is ready. **Steps to reproduce** 1. Run the local native OpenCode ask-question paid cell. 2. Observe a run that calls `report_progress`, calls `paperclip_finish`, and then emits the exact marker. 3. Run the local native OpenCode structured-question restart-resume cell with a fresh Vite graph. 4. Observe that the page is usable before the navigation lifecycle event completes. **Paperclip version or commit** The failures reproduced at `06cdf88bd9ac0fad82588025d23a68e810b20fd0`. The fixes are at `f7e044e71df11a0582eafe28d2fd52ea7cd07948`. **Deployment mode** Local dev. **Installation method** Built from source. **Agent adapter(s) involved** OpenCode through the native runner. ## What Changed - Require `paperclip_finish` to be the only tool call in the native ask fixture. - Forbid `report_progress` and other tool calls in that fixture. - Wait for navigation commit after a server restart. - Keep the explicit recovered UI and interaction API readiness checks. - Add prompt contract assertions. ## Verification - The exact two-cell paid run passed both affected cells on the AWS runner fleet: https://github.com/paperclipai/paperclip/actions/runs/33883334853 - Native OpenCode ask-question passed in job https://github.com/paperclipai/paperclip/actions/runs/33883334853/job/101058952662 - Native OpenCode structured restart-resume passed in job https://github.com/paperclipai/paperclip/actions/runs/33883334853/job/101058952823 - Prettier passed for all three changed files. - `git diff --check` passed. - The run-level aggregate failed only because the workflow source still used the pre-repair lockfile on `master`. PR #12828 repairs that lockfile. ## Risks Low risk. The prompt change affects native ask fixtures across provider profiles. The navigation change remains guarded by explicit UI and API assertions. ## Model Used OpenAI Codex, `gpt-5.6-sol`, extended reasoning, tool use, and code 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [ ] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
7dfc769f3b |
fix(server): honor proxy trust for forwarded host (#12832)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
4ef6155aae |
ci: harden paid runner browser and lock repair (#12829)
## Thinking Path Paid cells now reuse the AWS image's system Chrome, but Playwright video recording still resolves its revision-pinned FFmpeg helper from the Playwright cache. Run 33875618534 proved Chrome qualification succeeds and then failed before provider startup because that helper was absent. The same run also exposed that generic lock repair can churn unrelated package platform metadata, so the automated repair paths need resolution-only regeneration rather than lockfile-only metadata refresh. ## What Changed - install Playwright FFmpeg only on the AWS/system-Chrome path - retry the small helper installation up to three times before provider secrets are exposed - keep the GitHub-hosted Chromium fallback unchanged - bind static coverage to the exact FFmpeg step block and its pre-secret ordering - add pnpm `--resolution-only` to all four automated lock-repair paths while retaining full transitive resolution - require resolution-only repair in the shared workflow regression The actual generated lockfile correction remains bot-owned by PR #12828 and is intentionally not committed here. ## Verification - `node --test .github/scripts/tests/lockfile-refresh-workflows.test.mjs` - `actionlint -ignore SC2012` on all modified workflows - focused Prettier checks - `git diff --check` - prior run 33875618534: system Chrome 151 qualified; missing Playwright FFmpeg was the sole cell startup failure ## Risks Low. The new network operation is limited to Playwright's pinned FFmpeg payload, happens before paid credentials are exposed, and leaves the hosted-runner path unchanged. Resolution-only is still a full dependency-resolution pass, unlike lockfile-only, while avoiding unrelated current-platform metadata churn. ## Model Used GPT-5 |
||
|
|
af3023f1e3 |
fix(runner): repair paid provider startup paths (#12769)
## Thinking Path > - Paperclip manages AI agents that perform work. > - Paperclip Runner connects durable task runs to local provider processes. > - The full-stack paid matrix exposed failures after the runner integrity repair. > - Verified JavaScript entrypoints lost their relative module graph when Linux executed them through descriptor paths. > - Returned provider startup errors also remained pending and became indeterminate after recovery. > - Sparse Codex tool lifecycle events lost the `write_document` identity before task transcript projection. > - This pull request repairs those three boundaries and makes the structured-question fixture deterministic. > - The benefit is repeatable provider startup, exact failure replay, and correct inline Plan placement. ## Linked Issues or Issue Description Refs #12721 and #12700. **What happened?** The paid runner matrix failed ACPX and OpenCode startup before provider session creation. The runner journal then replaced the original startup error with an indeterminate recovery result. Native Codex saved a Plan but rendered it only as a fallback card. A legacy Claude waiting reply could also echo the reserved terminal marker before the answer arrived. **Expected behavior** Verified JavaScript providers must start from immutable descriptor-backed artifacts. Returned startup failures must persist as terminal failed command results. Native tool lifecycle updates must preserve the `write_document` boundary. Pre-answer fixture output must not contain the reserved terminal marker. **Steps to reproduce** 1. Run the local provider cells in the Runner Full-Stack E2E workflow. 2. Observe ACPX and OpenCode fail during `session.open` before provider execution. 3. Observe recovery report `execution_indeterminate` instead of the original startup error. 4. Run the native Codex Plan cell and observe the fallback Plan card after the tool activity row. 5. Run the legacy Claude structured-question resume cell and observe an early marker echo in waiting prose. **Paperclip version or commit** `0f9452101740835ce0b1488a204bf48acd5bafc3` **Deployment mode** Local development with the paid GitHub Actions acceptance workflow. ## What Changed - Bundle the ACPX sidecar and OpenCode proxy as self-contained Node ESM entrypoints before hashing and verified descriptor launch. - Anchor ACPX dynamic provider package resolution at a controller-derived provider-pack root and keep that root out of the provider child environment. - Persist executor-returned startup errors as redacted durable failed command results while retaining indeterminate recovery for true process death. - Coalesce sparse native tool items by stable ID so a late `write_document` name, input, and result reach the transcript boundary once. - Forbid the structured-question fixture from spelling or announcing its reserved terminal marker before the user answers. ## Verification - Rust and TypeScript regression tests cover durable failed replay, true crash ambiguity, bundle closure, package-root derivation, environment filtering, exact Codex tool lifecycle coalescing, and prompt determinism. - Local execution is intentionally limited to formatters and static diff checks. GitHub Actions will run tests, type checks, builds, and security checks. - After ordinary CI is green, scoped paid cells will validate one ACPX launch, one OpenCode launch, native Codex Plan projection, and legacy Claude structured resume before a complete matrix rerun. - Prior failing matrix: https://github.com/paperclipai/paperclip/actions/runs/33682434315 ## Risks - Bundling changes the bytes covered by provider launch hashes. Provider-pack generation already hashes the final built files. - ACPX still loads qualified provider packages dynamically. The controller supplies a normalized package root, while existing version, digest, path, and descriptor checks remain active. - Durable `failed` is terminal. Replays return the same redacted result and do not execute the provider effect twice. > 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 based on GPT-5 with agentic reasoning, repository inspection, code editing, Git, parallel subagents, and GitHub Actions coordination. The exact deployed snapshot and context-window size are not exposed to this task. ## 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either linked related public work or described the bug in this PR - [x] I have not referenced internal or instance-local Paperclip issues or links - [x] My branch name describes the change and contains no internal ticket id - [ ] I have run tests locally and they pass (intentionally deferred to GitHub Actions) - [x] I have added or updated tests where applicable - [x] No documentation change is required for this runtime repair - [x] I have considered and documented the risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
27622c156a |
fix(ui): recover expired Cloud tenant sessions (#12826)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Paperclip Cloud serves each tenant through a browser session and an HttpOnly cookie. > - A parked tenant tab can outlive that tenant session. > - The active SPA then receives a tenant-session 401 from its API calls and shows the internal error code. > - A page reload already enters the secure Cloud document and OIDC handoff and keeps the requested tenant route. > - This pull request detects only the two Cloud tenant-session 401 codes and starts that existing handoff once. > - The benefit is that an expired tenant session recovers without exposing tokens or showing temporary API errors. ## Linked Issues or Issue Description **What happened?** A Paperclip Cloud tenant tab can stay open after its HttpOnly tenant session expires. The next API request returns `401 tenant_session_required` or `401 tenant_session_invalid`. The SPA shows the internal error code in the full page or in sidebar data consumers. A manual page refresh clears the error. **Expected behavior** The tenant tab must enter the existing Cloud session handoff when an API request reports an expired tenant session. The handoff must keep the current route and query. The UI must not show the internal tenant-session error code. **Steps to reproduce** 1. Open a Paperclip Cloud tenant route. 2. Keep the SPA open until the tenant session expires. 3. Let the page make an API request. 4. Observe the tenant-session 401 in the page or sidebar. 5. Refresh the page and observe that the existing Cloud handoff restores the session. **Paperclip version or commit** The problem reproduces on `master` at commit `b5f862376`. **Deployment mode** Paperclip Cloud tenant deployment. ## What Changed - Added one tenant-session recovery coordinator for exact top-level Cloud error codes. - Reloaded the top-level document once and shared one pending promise across concurrent failures. - Applied recovery before normal error handling in the shared API client, auth API, and health API. - Applied the same recovery to direct audit CSV exports and provider trace downloads. - Preserved ordinary self-hosted 401 behavior and avoided automatic mutation replay. - Added tests for exact detection, concurrent failures, auth-session behavior, health bootstrap, and direct-fetch behavior. ## Verification - `pnpm exec vitest run --config vitest.config.ts src/lib/tenant-session-recovery.test.ts src/api/client.test.ts src/api/auth.test.ts src/api/health.test.ts src/api/heartbeats.test.ts src/api/audit.test.ts` from `ui/` — 30 tests passed. - `pnpm --filter @paperclipai/ui typecheck` — passed. - `pnpm check:token-gates` — passed. - `pnpm -r typecheck` — passed. - `pnpm build` — passed. - `pnpm test:run` — the changed UI tests passed, but the full local macOS run also hit existing failures in untouched server worktree and temporary-path tests. - GitHub verification — 30 checks passed, no checks failed, and the Storybook job was intentionally skipped because this PR has no visual changes. - Greptile — 5/5 on `fbba29a2f`, with no open findings. ## Risks - Low risk. Detection requires HTTP 401 and one exact top-level Cloud error code. - The recovery promise intentionally stays pending because document navigation replaces the active SPA. - If the Paperclip ID session has also expired, the existing Cloud sign-in flow remains authoritative. - This change does not modify APIs, cookies, token lifetimes, database state, or Cloud server code. > 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 Codex. The agent runtime identifies the model as GPT-5. The context-window size is not exposed. Reasoning, repository editing, shell execution, test execution, and GitHub CLI tool use were 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>canary/v2026.904.0-canary.8 |
||
|
|
b5f8623761 |
feat(onboarding): the API key field is the same card as the sign-in (#12820)
Flipping "Use API key instead" changed the shape of the connect step rather than its content: #12801 redrew the sign-in as a borderless 12px-radius card with 44px rows, and the key field stayed a bordered `rounded-md` box with a 28px control tucked to the right. Two visual languages in one canvas, one toggle apart. The field's own note already argued against exactly that — the two are alternatives to one question and have to read as two answers, not two kinds of thing. The reasoning held; only its target moved, and matching by restating measurements is what let it drift. It composes `OnboardingLoginCard` and the shared row input now, so there is nothing left to keep in sync. The environment variable takes the slot the sign-in cards use for their sentence, in mono, still answering what a paster cannot answer for themselves: where this step will put the key. Supporting changes: `instruction` widens to `ReactNode`, and the row input's classes move to an exported `onboardingCardInputClass`. The tests pin the sharing rather than the appearance — the two inputs carry the byte-identical class string, and the key field's shell is the same element the sign-in renders. Both fail against the old bordered box.canary/v2026.904.0-canary.7 |
||
|
|
2a5aa5e213 |
feat(ui): viewer=full document deep link opens the maximized side pane (#12812)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Agents ask humans for decisions through approval cards, and a chat gateway plugin can forward those cards to Slack with an "Open task" button > - The button opens the bare task page; to read the document under approval, the reviewer must click four more times (open the side pane, open the Artifacts tab, open the artifact, maximize the pane) > - Approvals are the highest-frequency human touchpoint, so each removed click matters > - This pull request adds a `viewer=full` option to the existing `#document-<key>` deep link; the link now opens the target document and maximizes the side pane > - The benefit is one-click access from an external notification to a full-size reading surface for the document under approval ## Linked Issues or Issue Description **What existing behavior does this improve?** The issue page already supports `#document-<key>` deep links. They open the document in the side pane, but at the pane's default width. **Current behavior** An external link cannot request the maximized (full-size) document view. A reviewer who follows an approval notification must maximize the pane by hand each time. **Proposed behavior** `#document-<key>&viewer=full` opens the document and maximizes the side pane. Plan documents open in the Plan tab, maximized. Mobile keeps the full-screen sheet. Unknown `viewer` values are ignored, so old links and new links stay compatible in both directions. **Reason and benefit** Chat notifications about approvals can now land the reviewer directly on a full-size view of the document they must read. This removes four clicks from every approval review. **Breaking changes** None. The parameter is optional and additive. Links without it keep today's behavior. ## What Changed - `ui/src/lib/document-annotation-hash.ts`: parse and build an optional `viewer=full` parameter in document hashes. - `ui/src/lib/issue-document-deep-link.ts`: thread a `maximize` flag on properties-pane routes; the continuation-summary route is unchanged. - `ui/src/context/PanelContext.tsx`: add a one-shot panel maximize request (`requestPanelMaximize` / `clearPanelMaximizeRequest`). - `ui/src/components/PropertiesPanel.tsx`: the resizable panel host consumes a pending request once it is visible and laid out, then clears it. - `ui/src/pages/IssueDetail.tsx`: request the maximize on the desktop deep-link path only; mobile keeps the sheet. - Tests for all of the above. ## Verification - `cd ui && pnpm typecheck` — clean. - `cd ui && pnpm vitest run src/lib/document-annotation-hash.test.ts src/lib/issue-document-deep-link.test.ts src/components/PropertiesPanel.test.tsx` — 31/31 green. - New cases cover: `viewer` parse/build round trip, unknown values ignored, maximize routing for document and plan tabs, a pending request consumed on mount, and a request held while the panel is hidden. - Manual check: open an issue with `#document-<key>&viewer=full` in the URL; the pane opens on that document, maximized. Remove the parameter; the pane opens at its normal width. ## Risks - Low risk. The parameter is optional; no data, schema, or API changes. - The maximize request lives in React context as a one-shot flag. It is cleared on first consumption, so a stale request cannot re-maximize the pane on later navigations. - If a link carries `viewer=full` on a web build older than this change, the parameter is ignored and the document still opens. ## Model Used - Claude Fable 5 (`claude-fable-5`), Anthropic. Agentic coding session with extended thinking and tool use (file edits, shell, test runs). ## 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [ ] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>canary/v2026.904.0-canary.6 |
||
|
|
54dd0f4868 |
feat(agents): grant new agents hire permission by default (#12814)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Agent permissions control which agents can create or hire other agents (`canCreateAgents`) > - Today only CEO-role agents get this permission by default; every other agent starts without it > - Teams that want agents to delegate and build out their own teams must flip the toggle on each hire, and most operators want delegation to work out of the box > - This pull request makes `canCreateAgents` default to enabled for new standard-trust agents, while low-trust agents keep a disabled default > - The benefit is that agent teams can grow without per-agent permission toggling, while low-trust containment and checkout protection stay intact ## Linked Issues or Issue Description Related (not fixed by this PR): #8064 also decouples an authority from `agents:create`. **Subsystem affected** Server agent permissions (`server/src/services/agent-permissions.ts`), authorization (`server/src/services/authorization.ts`), the shared `agentPermissionsSchema` validator, and the UI trust-preset helper. **Problem or motivation** New agents cannot hire other agents unless an operator enables `canCreateAgents` on each one. Only CEO-role agents get the permission by default. This blocks delegation-by-default workflows. Operators must toggle the permission for every hire. **Proposed solution** Default `canCreateAgents` to `true` for newly created agents. Apply and persist the default at creation only. Stored rows without an explicit value stay fail-closed at read and enforcement time. Keep the default at `false` when the agent's permissions record marks it low-trust (the `low_trust_review` preset or a trust boundary). Explicit values always win. Decouple `tasks:manage_active_checkouts` from `canCreateAgents` so the default-on flag does not let a peer agent write over another agent's checked-out issue. **Alternatives considered** Granting the default only at the route layer would leave stored rows and enforcement out of sync. Keeping the checkout authority coupled to `canCreateAgents` would void the active-checkout write protection once the flag is default-on. A per-company setting adds configuration surface without a clear need; explicit per-agent overrides already exist. **Roadmap alignment** Governance and trust-preset work already separates standard-trust from low-trust agents. This change follows that line: capability by default for standard trust, containment by default for low trust. ## What Changed - `normalizeAgentPermissions` now takes a `create`/`stored` context. Creation writes get the new default: enabled unless `permissionsImplyLowTrust()` detects the low-trust review preset or a trust boundary. Stored rows without an explicit value normalize to disabled (fail-closed). The role parameter is gone. - `agentPermissionsSchema` no longer injects `canCreateAgents: false` when the field is omitted. The server-side default applies instead. - `authorization.ts` normalizes raw agent rows for `agents:create`, so enforcement matches what the API reports for legacy rows. - `tasks:manage_active_checkouts` no longer rides on `canCreateAgents`. CEO role, explicit grants, and the manager chain remain the paths. - `agents:create` is denied outright inside any resolved low-trust execution context (agent, project, issue, or run policy). The default-on flag can never reach the legacy creator allow there. - The UI trust-preset helper sets `canCreateAgents: false` when an agent is switched to the low-trust preset, instead of carrying the old value forward. - `doc/CLI.md` describes the new default for `teams install`. - Tests pin the default matrix (standard, low-trust, explicit overrides) on the server and in the UI helper. ## Verification - `cd server && npx vitest run src/__tests__/agent-permissions-service.test.ts src/__tests__/agent-permissions-routes.test.ts src/__tests__/low-trust-red-team-routes.test.ts src/__tests__/authorization-service.test.ts` — 143 tests pass. - Broader sweep: 18 suites that touch `canCreateAgents` (hire, pending-approval, teams catalog, portability, built-in agents, plugin-managed agents) pass locally. - `cd ui && npx vitest run src/lib/trust-policy-ui.test.ts src/components/TrustPresetSection.test.tsx src/pages/NewAgent.test.tsx src/pages/Agents.test.tsx` — passes. - Typecheck is clean for the changed files in `packages/shared`, `server`, and `ui`. ## Risks - Behavioral shift: agents created after this change persist `canCreateAgents: true` unless low-trust. Pre-existing agents keep their stored value. Legacy or malformed permission records without an explicit value stay fail-closed at read and enforcement time; they never gain the authority retroactively. - Low-trust runs can no longer create agents at all, even when the agent carries an explicit `canCreateAgents: true`. Before this change, that combination could hire. The red-team suite and a new authorization test pin the denial. - Narrowing: a non-CEO agent with `canCreateAgents: true` loses implicit `tasks:manage_active_checkouts`. The manager chain and explicit grants still provide it. This narrowing is deliberate; without it, the default-on flag would let any peer bypass active-checkout write protection. - No migrations. No API shape changes. Low-trust defaults are covered by the red-team regression suite. ## Model Used - Claude Fable 5 (`claude-fable-5`), Anthropic — via Claude Code CLI with extended thinking and tool use (code search, editing, local test 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
c38b59484c |
fix(ui): remove the Account badge and version line from the account menu (#12818)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The web UI has a sidebar account menu that opens from the user's name in the lower left > - The menu header shows an "Account"/"Local" badge and a "Paperclip <sha>" (or "Paperclip v<version>") build line next to the user's identity > - These labels add noise to the header and repeat information that is available elsewhere: the email line already shows the sign-in state, and the opt-in "Server" debug section in the same menu shows the running commit > - This pull request removes the badge and the build line so the header shows only the user's name and email > - The benefit is a cleaner account menu that shows only identity information ## Linked Issues or Issue Description No existing issue. Related: #9637 (closed) added the source-sha rendering that this PR removes from the menu header. Description follows the enhancement template: **What existing behavior does this improve?** The sidebar account menu popover. Its header shows the user's name, an "Account" or "Local" badge, the email, and a build identifier line ("Paperclip <short sha>" with branch/commit links for source builds, or "Paperclip v<version>" for release builds). **Current behavior** The popover header mixes identity information with deployment and build metadata. The badge and the version line take space and do not help daily use. **Proposed behavior** The popover header shows only the user's name and email. Build information stays available in the "Server" section at the bottom of the same menu when the server-info debug view is enabled in experimental instance settings. **Reason and benefit** Less visual noise in a menu that users open often. No information is lost: sign-in state is clear from the email line, and the running commit remains visible through the server-info debug view. **Breaking changes** None. The `SidebarAccountMenu` components no longer accept the `serverGit` and `version` props; both call sites in the two `Layout` variants are updated in this PR. ## What Changed - `ui/src/components/SidebarAccountMenu.tsx` and `SidebarAccountMenu.production.tsx`: remove the "Account"/"Local" badge and the full version block (source-build branch/commit links and the release-version fallback); drop the now-unused `serverGit`/`version` props, the sha-parsing helper, and the `Badge` import - `ui/src/components/Layout.tsx` and `Layout.production.tsx`: stop passing the removed props at all four call sites - `ui/src/components/SidebarAccountMenu.test.tsx`: delete the source-build sha test; the sign-out test now pins that the popover contains neither "Account" nor "Paperclip v" - `ui/storybook/stories/navigation-layout.stories.tsx`: stop passing the removed `version` prop in the account-menu story ## Verification - `pnpm vitest run ui/src/components/SidebarAccountMenu.test.tsx ui/src/components/Layout.test.tsx` — 36 tests pass - `tsc --noEmit` for the `ui` package passes - Manual: open the app, click your name in the lower left. The popover header shows only name and email. ## Risks - Low risk. UI-only removal with no data or API changes. - Users who relied on the header sha to identify a source build must enable the experimental server-info debug view to see the running commit in the same menu. > 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 - Claude (Anthropic), Claude Fable 5, model ID `claude-fable-5`, extended thinking enabled, via Claude Code CLI with tool use (file edit, shell, test runner) ## 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
1a74719309 |
feat(onboarding): the connect step signs in from its own button (#12801)
Connect starts the sign-in; the card that appears is the sign-in rather than an offer of one; success advances to Review rather than reporting itself. The two logins end in different places and the button says which: Claude submits a code back here, so it spins on "Connecting"; OpenAI finishes in another tab, so it stays a still, disabled Next until the poll lands. AdapterLoginPanel grows autoStart / onCancel / onConnected / chrome rather than a second implementation — the session start, both polls, the server deadline, the one-shot completion read and the unmount release are the parts onboarding needs unchanged. Every prop is off by default, so the agent form and the new-agent page render what they did before. Claude's code auto-submits on the paste, not on every change: isValidBrowserCode accepts any printable ASCII from one character up, so a value-driven submit fired on the first keystroke of anyone who typed. Also orders the OpenAI card and the settings displayed-code panel code-above-link, with the instruction worded to match, and releases the displayed-code session on unmount so an abandoned login stops holding the one-per-owner reservation.canary/v2026.904.0-canary.5 |
||
|
|
9ef3b087c1 |
feat(onboarding): round-4 corrections to the connect and agent steps (#12796)
Reads the connect and agent steps from the design's own values through the Figma MCP rather than measuring an export, which corrected the arc column inset (433px content, 64px inset — `--sz-68px` goes with the mismeasurement it was minted for) and restored the selected tile's border alongside its fill. Round-4 items: sources named for the provider you sign in with, OpenAI's mark inlined so it can take `currentColor` on a light tile, monochrome autofill via `box-shadow` (Chrome ignores `background-color`), and the agent step's placeholder. Also wires `MODEL_SOURCE_NAMES`, which was added for the rename and never read — the tiles kept passing the display registry's label, so the step still showed "Claude Code" and "Codex" under a heading asking which provider you are signing in to. Covered by a test that fails on the unwired version.canary/v2026.904.0-canary.4 |
||
|
|
82ee0a68d4 |
chore(docker): pass PAPERCLIP_ALLOWED_HOSTNAMES through to quickstart (#6846)
## Thinking Path > - Operators run Paperclip in many places: localhost dev, LAN servers, Tailscale meshes, cloud VMs > - The server already supports a `PAPERCLIP_ALLOWED_HOSTNAMES` env var for hostname allow-listing (`server/src/config.ts`) > - But `docker/docker-compose.quickstart.yml` did not forward that env var from the host to the container > - So an operator running quickstart on a LAN gets "Hostname '<lan-ip>' is not allowed for this Paperclip instance" with no env-only escape hatch — they're forced to run the CLI inside the container to write `config.json` > - This PR adds a one-line passthrough so the existing env var works end-to-end with the quickstart compose file > - The benefit is parity with the server's documented config surface: anything settable via env on a bare-metal run is now settable via env on a quickstart docker run ## Linked Issues or Issue Description **What happened?** Running the quickstart compose file on a LAN host and opening the UI by the machine's LAN address fails with "Hostname '<lan-ip>' is not allowed for this Paperclip instance". The server supports `PAPERCLIP_ALLOWED_HOSTNAMES` for exactly this case and `doc/DOCKER.md` tells operators to set it, but `docker/docker-compose.quickstart.yml` never forwards the variable into the container, so setting it on the host has no effect. **Expected behavior** Setting `PAPERCLIP_ALLOWED_HOSTNAMES` on the host before `docker compose up` reaches the server, the same way `PAPERCLIP_PUBLIC_URL` and the provider keys do. **Steps to reproduce** 1. `export PAPERCLIP_ALLOWED_HOSTNAMES=my-lan-host` alongside the other quickstart variables. 2. `docker compose -f docker-compose.quickstart.yml up --build`. 3. Open `http://my-lan-host:3100` and observe the hostname rejection. **Paperclip version or commit** `master` when this PR was opened (May 2026); the quickstart file on current `master` still has no passthrough. The branch is rebased onto current `master`. **Deployment mode** Docker quickstart (`docker-compose.quickstart.yml`), authenticated and private. ## What Changed - `docker/docker-compose.quickstart.yml`: forward `PAPERCLIP_ALLOWED_HOSTNAMES` from the host environment with an empty default, matching the existing pattern used for `PAPERCLIP_PUBLIC_URL`, `OPENAI_API_KEY`, etc. ## Verification ```sh # 1. Set the env var echo \"PAPERCLIP_ALLOWED_HOSTNAMES=localhost,my-lan-ip\" >> .env # 2. Bring up the quickstart docker compose --env-file .env -f docker/docker-compose.quickstart.yml up -d # 3. Confirm the value reached the container docker compose -f docker/docker-compose.quickstart.yml exec paperclip \\ sh -c 'echo \"\$PAPERCLIP_ALLOWED_HOSTNAMES\"' # → localhost,my-lan-ip # 4. Confirm boot-time trusted-origins log includes the LAN host docker compose -f docker/docker-compose.quickstart.yml logs paperclip | grep trustedOrigins # 5. Confirm a request from the LAN host returns 401 (auth required), not the hostname rejection curl -i -H \"Host: my-lan-ip:3100\" http://localhost:3100/api/auth/get-session # → HTTP/1.1 401 Unauthorized ``` Tested locally on Linux with an authenticated/private deployment, migrated DB from another paperclip instance, and a LAN host reaching the container. The image was rebuilt with \`--no-cache\` from a clean checkout of this branch's tip (no other unmerged work in the build context) to confirm the change is self-contained. ## Risks Low risk. - Default value is empty string — behavior identical to before for any operator who doesn't set the var. - Env var name and semantics already implemented and documented on the server side (\`server/src/config.ts\`); this PR only routes the value through compose. - One-line yaml change, no code touched, no tests affected. ## Model Used - Claude (Anthropic) — Opus 4.7 (1M context). Used for the bug isolation, the env-var-vs-config-file choice, and the PR write-up. Authored alongside Ross Sclafani who tested end-to-end against a migrated LAN deployment. ## Checklist - [x] Thinking path traces from project context to this change - [x] Model used specified (with version + capability details) - [x] Checked ROADMAP.md — not a feature, no overlap with planned work - [x] Ran tests locally (\`pnpm install --frozen-lockfile\`, \`pnpm build\` clean; container rebuilt \`--no-cache\` from this branch tip and verified end-to-end) - Added or updated tests — N/A (compose env passthrough; no executable code path) - UI change screenshots — N/A (no UI) - [x] No documentation updates needed (env var already documented server-side) - [x] Considered risks (above) - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] Will address all Greptile/reviewer comments before requesting merge |
||
|
|
b98badb246 |
fix(recovery): exclude hidden issues from stranded recovery and continuation wakes (#5648)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The recovery subsystem watches assigned issues and re-wakes an agent whose run ended without finishing the work > - Intake can hide a duplicate issue by setting `hiddenAt` while leaving its status and assignee in place > - The stranded-issue query and the terminal-run cleanup both ignore `hiddenAt`, so a hidden issue is re-woken on every cycle > - Nothing on the board shows the hidden issue, so the repeated wakes have no visible cause > - This pull request adds a hidden-issue guard to both predicates and a test for each > - The benefit is that hiding an issue stops recovery work on it, with no other change in behavior for visible issues ## Linked Issues or Issue Description **What happened?** When intake marks an issue as a duplicate it sets `hiddenAt` but leaves the status at `todo` or `in_progress` with the agent still assigned. The stranded-issue recovery timer selects that issue on every tick and queues an `issue_continuation_needed` wake for it. The agent's run on the hidden issue fails or is cancelled, the terminal-run cleanup queues immediate recovery for the same issue, and the cycle repeats indefinitely. Hidden issues are invisible on the board, so nothing a person can see explains the wakes. **Expected behavior** A hidden issue is never a recovery candidate. Stranded-issue reconciliation skips it, and a failed, timed-out or cancelled run on it releases the issue without queuing a continuation. **Steps to reproduce** 1. Assign an issue to an agent and leave it `in_progress`. 2. Hide the issue (set `hiddenAt`, for example by marking it a duplicate through intake) without changing its status or assignee. 3. Let a run on that issue fail, or wait for the stranded-issue recovery timer. 4. Observe a new `issue_continuation_needed` heartbeat run queued for the hidden issue on every cycle. **Paperclip version or commit** Reproduced on `master` when this PR was opened (May 2026). The two predicates are unchanged on current `master`; this branch is rebased onto it. **Deployment mode** Not deployment-specific: both guards are in the server's recovery and heartbeat services and apply in every mode. ## What Changed - `server/src/services/recovery/service.ts`: `isNull(issues.hiddenAt)` added to the `reconcileStrandedAssignedIssues` candidate query, so hidden issues never enter the stranded set. - `server/src/services/heartbeat.ts`: `!issue.hiddenAt` added to `issueNeedsImmediateRecovery`, so terminal-run cleanup releases a hidden issue instead of queuing a continuation. - `server/src/__tests__/heartbeat-process-recovery.test.ts`: one test per guard. A failed run on a hidden issue queues no recovery run, and a hidden stranded issue is left out of reconciliation. ## Verification - `heartbeat-process-recovery.test.ts` covers both guards; CI runs it against embedded Postgres. ## Risks Low. Both changes narrow an existing predicate to exclude rows that already carry `hiddenAt`; visible issues take exactly the path they take today. A hidden issue that genuinely needs recovery would have to be unhidden first, which matches how hidden issues behave everywhere else in the board. ## Model Used The original two-line fix was authored by @im0xMagnus. The rebase onto current `master`, the two regression tests, and this description were produced with Claude (claude-fable-5-1, extended thinking, tool use) driven by a Paperclip maintainer through Prospector's triage flow. ## 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [ ] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Andrew Aymeloglu <aaymeloglu@gmail.com>canary/v2026.904.0-canary.3 |
||
|
|
89bf6a33c2 |
ci: activate Node-first pnpm setup for PRs (#12810)
## Thinking Path > - Paperclip validates every change through an immutable reusable PR workflow. > - That caller still pinned a revision that ran pnpm setup before Node setup. > - The implementation fix in #12808 is therefore present on master but inactive for ordinary PR CI. > - Advancing the immutable caller pin activates the already tested Node-first workflow. > - A focused contract prevents the caller from silently returning to the old revision. > - The benefit is a faster PR feedback loop without changing product code or secret boundaries. ## Linked Issues or Issue Description Refs #12808 ## What Changed - Pin ordinary PR CI to trusted workflow revision `a0a78ee60946a5f79f85b2bd0584fc766fae43bb`. - Assert that the reusable workflow call is canonical, unique, and SHA-pinned to that audited revision. ## Verification - Focused workflow security test: 8/8. - Prettier passed. - Actionlint passed. - `git diff --check` passed. ## Risks Low risk. The change only advances an immutable reusable-workflow pin to a revision whose full ordinary CI and security checks passed. Product code and credentials are unchanged. ## Model Used OpenAI Codex GPT-5 with agentic reasoning and repository 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 - [x] I have linked the related public PR - [x] I have not referenced internal issue links - [x] My branch name describes the change - [x] I have run focused tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have considered and documented risks |
||
|
|
f449b05bc5 |
feat(apps): unify permissions and action testing (#12802)
## Thinking Path > - Paperclip is the control plane for companies that use AI agents. > - Apps give humans and agents controlled access to external services. > - The existing app detail flow split permissions, tests, setup, and activity across separate pages. > - The split made access rules harder to understand and made reconnect work hard to find. > - New write actions also defaulted to Ask first, which did not match the intended connection policy. > - This pull request combines permission control and action testing, removes the setup page, and moves connection activity into Audit. > - The benefit is one clear place to configure, test, reconnect, and review each app. ## Linked Issues or Issue Description **What existing behavior does this improve?** The installed app Permissions, Test, Setup, and Activity views. **Subsystem affected** Cross-cutting. This change updates the React UI, shared app defaults, server permission behavior, tests, smoke scripts, and connection documentation. **Current behavior** App access and action testing use separate pages. The app detail view also links to a setup page after installation. Connection activity uses a separate tab. New write actions default to Ask first. **Proposed behavior** Permissions uses the connection access language from the initial flow. It includes searchable Read and Write sections, a three-state permission control, and a Test dialog for each action. Reconnect appears below a Needs attention header on Permissions and Review. Old Setup and Test links redirect to Permissions. Old Activity links redirect to the filtered company Audit feed. New write actions default to Allowed. **Reason and benefit** A person can understand and test app access without moving between several pages. Reconnect work stays visible where the person reviews the connection. Audit events use one consistent feed and filter model. New connections have the intended default policy. **Breaking changes** The Setup, Test, and app Activity tabs are removed. Existing deep links redirect to their replacement pages. Existing saved action permissions do not change. Only defaults for new write actions change. **Additional context** This builds on the managed app connection work in #12728. A search found no duplicate open pull request or issue. ## What Changed - Combined action testing with Permissions. - Added searchable Read and Write action groups. - Added Off, Ask first, and Allowed controls with tooltips. - Added an action Test dialog with agent selection, arguments, and formatted results. - Removed the installed-app Setup and Activity tabs. - Added reconnect guidance to Permissions and Review when a connection needs attention. - Routed connection activity into the company Audit feed and preserved the Apps & tools filter in streamlined Audit. - Moved connection removal to the Connectors-page management menu. - Made new write actions default to Allowed across connection creation paths. - Updated regression tests, browser suites, smoke scripts, and connection documentation. ## Verification - `pnpm check:token-gates` - `pnpm exec vitest run packages/shared/src/app-definitions.test.ts server/src/__tests__/generic-mcp-connection.test.ts server/src/__tests__/tool-access-service.test.ts ui/src/components/AppConnectionSidebar.test.tsx ui/src/pages/apps/AppDetail.test.tsx ui/src/pages/apps/AppNotConnected.test.tsx ui/src/pages/apps/AppsConnect.test.tsx ui/src/pages/apps/Browse.test.tsx ui/src/pages/apps/Connections.test.tsx ui/src/pages/apps/composio-services.test.ts ui/src/pages/audit/AuditFeed.test.tsx ui/src/pages/tools/PasteConfigTab.test.tsx` (517 tests passed) - `pnpm exec vitest run ui/src/pages/apps/app-detail/TestPanel.test.tsx ui/src/pages/audit/AuditHub.test.tsx ui/src/pages/audit/AuditFeed.test.tsx ui/src/pages/apps/AppDetail.test.tsx ui/src/pages/apps/Browse.test.tsx` (96 tests passed) - Targeted Playwright verification for connection removal, rename on Permissions, inline action testing, and Smoke Lab Audit evidence (5 flows passed) - `pnpm -r typecheck` - `pnpm build` - `pnpm test:run` completed with 5,755 passing tests and 20 unrelated macOS harness failures. The failures use `/tmp` versus `/private/tmp`, invalid ports above 65535, and workspace fixtures outside this change. ## Risks - Low migration risk. This change has no database migration. - Old app-detail URLs depend on redirect compatibility. - New connections grant write actions by default. Finalization remains configure-authorized and audited, Ask first and Off remain available per action, and existing connections keep their saved policy. > 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, exact model ID `gpt-5`. The client does not expose the context-window size. The model used reasoning, repository tools, code execution, and browser 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
a0a78ee609 |
ci: bootstrap Node before pnpm setup (#12808)
## Thinking Path The trusted workflows currently invoke `pnpm/action-setup@v6` before installing the repository Node version. On hosts whose ambient Node is older than 22.13, the action downloads standalone `@pnpm/exe`, which has repeatedly taken several minutes. Supplying Node 24 first lets the same pinned pnpm action use its normal Node-backed path. ## What Changed - install Node 24 before every trusted `pnpm/action-setup` invocation - preserve the existing pnpm-store cache setup, pinned actions, telemetry suppression, conditions, and secret boundaries - enforce ordering, modern Node, condition parity, and cache counts in the workflow security contract ## Verification - workflow security: 7/7 - Prettier - actionlint (excluding one pre-existing SC2129 in an untouched Daytona shell block) - `git diff --check` ## Risks Low. Product code, providers, paid-runner selection, credentials, and pnpm version are unchanged. Jobs that restore pnpm cache run `setup-node` a second time after pnpm becomes available; the first setup is deliberately cache-free. ## Model Used Codex (GPT-5) |
||
|
|
18ea965442 |
ci(runner): stamp paid target provenance (#12805)
## Thinking Path Trusted workflow-dispatch runs execute an authorized target SHA, but GitHub context still describes the default-branch workflow revision. Retained paid results and artifact names were therefore labeling target-branch executions as master. The workflow must explicitly pass its authorized target coordinates to target code and trusted reporting. ## What Changed - emit the canonical authorized target ref alongside the immutable target SHA - pass those coordinates to paid cells and the trusted report - name shared build/provider artifacts with the target SHA rather than workflow SHA - add workflow-security coverage for all trusted provenance wiring ## Verification - focused workflow-security tests: 6/6 passed - Prettier and git diff checks passed - run 33823252706 independently proved the pre-fix defect: functionally green target cells were retained as master SHA |
||
|
|
505e7b40fc |
fix: guard listComments against non-UUID afterCommentId to prevent 500 errors (#8695)
## Thinking Path > - Paperclip is an open-source app for managing AI agents > - The issue history subsystem stores comments per issue, with cursor-based pagination via the `after` query parameter > - `GET /issues/:id/comments?after=<commentId>` looks up the anchor comment by UUID to get its created_at timestamp > - When agents store an incorrect or truncated comment ID (e.g. `670427ab` instead of `670427ab-e0ae-4a54-959e-2b13a2e33d14`), Postgres throws `invalid input syntax for type uuid` before the anchor-not-found guard can execute > - This surfaces as an unhandled 500 and causes agents to fail when doing incremental comment reads on any issue > - This pull request adds a UUID validation guard in `listComments` using the already-imported `isUuidLike` helper > - The benefit is that invalid cursors get a clean empty-array response instead of a 500, matching what already happens when a valid UUID simply isn't found ## Linked Issues or Issue Description Refs #2612 (a different 500 on the same `after=` cursor path, fixed earlier; this PR covers the malformed-cursor case that remains). **What happened?** `GET /issues/:id/comments?after=<value>` returns a 500 when `after` is not a UUID. The route trims the query value and passes it straight to the anchor lookup, so Postgres raises `invalid input syntax for type uuid: "670427ab"` before the anchor-not-found guard can run. Any agent that stored a truncated or malformed comment ID as its pagination cursor gets stuck in a 500 loop on that issue. **Expected behavior** A cursor that cannot name a comment behaves like a cursor that names a missing comment: the endpoint returns `[]`. **Steps to reproduce** 1. Pick any issue id on a running instance. 2. Call `GET /api/issues/<issue-id>/comments?after=670427ab` (8 hex characters instead of a full UUID). 3. Observe a 500 with `PostgresError: invalid input syntax for type uuid: "670427ab"`, where a full-but-unknown UUID such as `00000000-0000-0000-0000-000000000000` returns `[]`. **Paperclip version or commit** `master` at the time this PR was opened (June 2026). The `listComments` anchor lookup in `server/src/services/issues.ts` is unchanged on current `master`, so the failure still reproduces there. **Deployment mode** Local dev (`pnpm dev`). Not deployment-specific: the failure is in the server's comment-listing service, so it reproduces in every mode. ## What Changed - `server/src/services/issues.ts` — added `if (!isUuidLike(afterCommentId)) return [];` guard in `listComments` before the DB anchor lookup, using the already-imported `isUuidLike` helper ## Verification ```bash # Start the dev server pnpm dev # Pass a truncated UUID — should return [] instead of 500 curl -s "http://localhost:3100/api/issues/<any-valid-issue-id>/comments?after=670427ab" # Expected: [] # Pass a valid full UUID that doesn't exist — should also return [] curl -s "http://localhost:3100/api/issues/<any-valid-issue-id>/comments?after=00000000-0000-0000-0000-000000000000" # Expected: [] # Pass a valid full UUID that exists — should return comments after that cursor curl -s "http://localhost:3100/api/issues/<any-valid-issue-id>/comments?after=<real-comment-uuid>" # Expected: array of comments ``` ## Risks Low risk. The change only adds an early-return guard for values that are provably invalid UUIDs. The code path for valid UUIDs is unchanged. The existing behavior for anchor-not-found (returning `[]`) is preserved for invalid UUIDs, which is the correct semantic (cursor not found → no comments after it). ## Model Used Claude Sonnet 4.6 (`claude-sonnet-4-6`) via Paperclip CTO agent, tool use + code execution mode, 200K context window. ## 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [ ] I have run tests locally and they pass - [ ] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [ ] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip CTO <cto@paperclip.ai> Co-authored-by: Paperclip <noreply@paperclip.ing> Co-authored-by: Andrew Aymeloglu <aaymeloglu@gmail.com> |
||
|
|
333abdd2c2 |
test(plugin-worker): remove the wall-clock race from the duplex buffered-replay tests (#12799)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - The plugin worker manager runs agent plugin workers through duplex
channels.
> - The duplex buffered-replay tests check data that arrives before a
listener attaches.
> - The tests used a fixed 60 ms sleep as the barrier for worker output.
> - Worker startup and output latency can exceed that delay under load.
> - This pull request uses a worker exit frame as a deterministic
barrier.
> - The benefit is stable test results without a product code change.
## Linked Issues or Issue Description
**What happened?**
The duplex buffered-replay tests used a fixed 60 ms sleep before they
attached a data listener. Under load, worker output could arrive after
the sleep. The tests then saw a partial buffer and failed.
**Expected behavior**
The tests must wait until the worker sends all three data frames before
they inspect the pre-bind buffer.
**Steps to reproduce**
1. Run npx vitest run src/__tests__/plugin-worker-manager-duplex.test.ts
in the server package.
2. Add a 200 ms or 800 ms delay to the worker fixture emit path.
3. Repeat the test run and observe the old fixed-sleep barrier fail
intermittently.
**Paperclip version or commit**
canary/v2026.904.0-canary.1
|
||
|
|
0ad180b85f |
ci(runner): skip bootstrap registry telemetry (#12797)
## Thinking Path Every trusted PR and paid-workflow job invokes the pinned pnpm setup action. Its internal npm install is currently waiting four to seven minutes on npm audit telemetry before any Paperclip or provider code runs. Audit, funding, and update notifications are not integrity controls for this action; its committed lockfile still verifies installed package bytes. ## What Changed - disable npm audit, funding, and update-notifier telemetry narrowly on all seven pinned setup steps in each of the trusted PR and full-stack workflows - add a workflow security contract proving every setup invocation remains covered and the overrides do not leak elsewhere ## Verification - focused workflow security tests: 6/6 passed - Prettier and git diff checks passed - observed unhealthy setup: 4-7+ minutes; historical healthy setup: about four seconds ## Risks This skips npm vulnerability-report telemetry for the setup action bootstrap only. Repository dependency checks, lockfile integrity, provider-secret authorization, and target-lock verification remain unchanged. ## Model Used Codex (GPT-5) |
||
|
|
446577d174 |
fix(ui): honor PAPERCLIP_HIDDEN_SETTINGS in the production switcher menu (#12788)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Operators control which settings surfaces appear via the `PAPERCLIP_HIDDEN_SETTINGS` env var (keys like `company.invites`, `company.members`) > - The sidebar organization switcher has an "Invite people" shortcut that points at the company Invites surface > - The streamlined switcher menu already hides that shortcut when the Invites/Members surface is hidden, but the production-shell menu (rendered when the streamlined UI is disabled) renders the invite row unconditionally > - So an operator that hides the Invites surface still sees the shortcut in the production shell — the hide is not fully honored > - This pull request gates the production menu's invite shortcut on the same hide keys, so `PAPERCLIP_HIDDEN_SETTINGS` controls it in both shells > - The benefit is one consistent, per-deployment knob: a hoster that wants the shortcut gone (e.g. Paperclip Cloud, whose managed stacks set `company.invites`) drops it by setting the env var, and every other hoster keeps it by leaving the key unset ## Linked Issues or Issue Description No existing issue. Description follows the enhancement template: **What existing behavior does this improve?** `PAPERCLIP_HIDDEN_SETTINGS` coverage for the organization switcher's "Invite people" shortcut in the production shell. **Subsystem affected** UI — `ui/src/components/SidebarCompanyMenu.production.tsx`. **Current behavior** The streamlined switcher menu hides the "Invite people" shortcut when `company.invites` or `company.members` is hidden. The production-shell menu renders the invite row unconditionally, so the hide keys have no effect there. **Proposed behavior** The production menu computes `showInvitePeople` from the same hide keys and gates the invite row on it. With no hidden settings (the default) the shortcut still shows; hiding either surface removes it in both shells. **Reason and benefit** This is the per-deployment knob operators already use for the Invites surface. Making the production shell honor it gives one consistent mechanism: Paperclip Cloud drops the shortcut on its managed stacks (which set `company.invites`, because the managed invite accept flow is being overhauled), while other hosters keep it by leaving the key unset — no cloud-specific branching in the app. **Breaking changes** None. Default behavior (no hidden settings) is unchanged; this only makes an existing env var take effect where it previously did not. ## What Changed - `SidebarCompanyMenu.production.tsx` imports `useHiddenSettings` + `hidesCompanyPage`, computes `showInvitePeople` exactly as the streamlined menu does, and renders the invite row only when it is true. - Tests: the production shell shows the shortcut by default and hides it when `company.invites` is hidden. - The streamlined menu is unchanged (it already honored the keys). ## Verification - `cd ui && npx vitest run src/components/SidebarCompanyMenu.test.tsx` — 20 tests pass. - `cd ui && npx tsc -p tsconfig.json --noEmit` — clean. - Manual: with `PAPERCLIP_HIDDEN_SETTINGS=company.invites`, the switcher's "Invite people" row is absent in both the streamlined and production shells; with the key unset it is present in both. ## Risks Low risk. UI-only visibility change; default (no hidden settings) is unchanged, and it only extends an existing, documented env var to a shell that was missing it. ## Model Used Claude Fable 5 (`claude-fable-5`, Anthropic), extended thinking, agentic tool use via Claude Code. ## 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
a661caf74e |
chore(deps): bump motion from 12.43.0 to 13.1.1 (#12255)
Bumps [motion](https://github.com/motiondivision/motion) from 12.43.0 to 13.1.1. <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/motiondivision/motion/blob/main/CHANGELOG.md">motion's changelog</a>.</em></p> <blockquote> <h2>[13.1.1] 2026-08-18</h2> <h3>Fixed</h3> <ul> <li>Guard animation <code>window</code> access in non-browser runtimes.</li> <li><code>AnimatePresence</code>: Improved compat with React 19 strict mode.</li> </ul> <h2>[13.1.0] 2026-08-10</h2> <h3>Added</h3> <ul> <li><code>Reorder</code>: Multidimensional reorder.</li> <li><code>Reorder</code>: Automatic axis detection.</li> <li><code>Reorder</code>: RTL support.</li> </ul> <h2>[13.0.0] 2026-08-05</h2> <h3>Changed</h3> <ul> <li>Removed optional <code>@emotion/is-prop-valid</code> dependency in favour of explicit <code><MotionConfig isValidProp={isPropValid}></code>.</li> </ul> <h3>Fixed</h3> <ul> <li>Hardware-accelerated SVG elements correctly apply final style on animation complete.</li> <li><code>AnimatePresence</code>: Ensure nodes are marked as safe to remove when rendering <code>propagate</code> with no <code>motion</code> children.</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/motiondivision/motion/commit/1b037b0032578b52af94b06ff3920bfa0aaa5e36"><code>1b037b0</code></a> v13.1.1</li> <li><a href="https://github.com/motiondivision/motion/commit/d734481aca2a7c45a244155f9ce3a2e56a2c69a6"><code>d734481</code></a> Updating changelog</li> <li><a href="https://github.com/motiondivision/motion/commit/9b9190da212b0f633735c5a7ea7c8d73f4624436"><code>9b9190d</code></a> Latest</li> <li><a href="https://github.com/motiondivision/motion/commit/c07d12e2bfb581482c7e6c82a2b3b4c2394f8d08"><code>c07d12e</code></a> Merge pull request <a href="https://redirect.github.com/motiondivision/motion/issues/3752">#3752</a> from motiondivision/fix-3746-animatepresence-strictm...</li> <li><a href="https://github.com/motiondivision/motion/commit/b497f1d2ac2ffc8139f988101d732e8cd7d4733a"><code>b497f1d</code></a> Merge branch 'main' into fix-3746-animatepresence-strictmode-remount</li> <li><a href="https://github.com/motiondivision/motion/commit/bbabb0066427bc4d91850504e01e3949f03f8857"><code>bbabb00</code></a> Merge pull request <a href="https://redirect.github.com/motiondivision/motion/issues/3751">#3751</a> from motiondivision/worktree-fix-issue-3735</li> <li><a href="https://github.com/motiondivision/motion/commit/06540faa2cb80ddd1d9103cd736a56ed524cd0e2"><code>06540fa</code></a> Merge branch 'main' into worktree-fix-issue-3735</li> <li><a href="https://github.com/motiondivision/motion/commit/adaf7a4e5368d704ea350669f6ac674fb26ff270"><code>adaf7a4</code></a> v13.1.0</li> <li><a href="https://github.com/motiondivision/motion/commit/e713759e5095298069b37701395083107eb4fc97"><code>e713759</code></a> Updating changelog</li> <li><a href="https://github.com/motiondivision/motion/commit/bc81c031212416f8aeee75d125a1431016a4e6bf"><code>bc81c03</code></a> Updating publish</li> <li>Additional commits viewable in <a href="https://github.com/motiondivision/motion/compare/v12.43.0...v13.1.1">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>canary/v2026.904.0-canary.0 |
||
|
|
1f92011f99 |
chore(deps): bump dompurify from 3.4.13 to 3.4.14 (#12266)
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.4.13 to 3.4.14. <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.14</h2> <ul> <li>Fixed an issue with possible bypasses when risky tags are allow-listed, thanks <a href="https://github.com/AlirezaRouhbakhsh"><code>@AlirezaRouhbakhsh</code></a></li> <li>Fixed a couple of edge cases with mixed document contexts, thanks <a href="https://github.com/fishjojo1"><code>@fishjojo1</code></a></li> <li>Added the SVG <code>pointer-events</code> and <code>vector-effect</code> presentation attributes to the allow-list, thanks <a href="https://github.com/Jaybhade"><code>@Jaybhade</code></a></li> <li>Conducted another refactoring run, removed dead branches and duplicated logic, flattened attribute validation</li> <li>Updated the documentation in several spots, README, wiki, etc., thanks <a href="https://github.com/Akokonunes"><code>@Akokonunes</code></a></li> <li>Updated several development dependencies and CI workflow actions</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/cure53/DOMPurify/commit/4e6fe24173f1a85eafacd95e3c82966e29d34d49"><code>4e6fe24</code></a> release: 3.4.14 (<a href="https://redirect.github.com/cure53/DOMPurify/issues/1587">#1587</a>)</li> <li>See full diff in <a href="https://github.com/cure53/DOMPurify/compare/3.4.13...3.4.14">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> |
||
|
|
d95c71027d |
chore(deps-dev): bump @types/react-dom from 19.2.4 to 19.2.5 (#12253)
Bumps [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) from 19.2.4 to 19.2.5. <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom">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> |
||
|
|
03faa644fb |
ci(runner): inspect Daytona image metadata remotely (#12795)
## Thinking Path The reused Daytona image path already verifies the signed immutable digest. It then downloads every filesystem layer only to read OCI config fields. Buildx can retrieve the same config from that immutable digest without pulling the layers. The assertions can therefore stay intact while removing the expensive transfer. ## What Changed - inspect the signed immutable Daytona image config through Buildx after GHCR logout - preserve digest, source revision, content ID, platform, user, and provider-pack assertions - extend the workflow contract test for the metadata-only path ## Verification - Daytona image and workflow security tests: 10 passed - Prettier and git diff checks passed - observed full pull/prune cost: about 4m55s; metadata inspection: about one second ## Risks The current image has one runnable linux/amd64 platform plus its attestation. A future genuinely multi-platform image would need explicit linux/amd64 selection. ## Model Used Codex (GPT-5) |
||
|
|
871f7d1124 |
fix(ui): polish core navigation and task layout (#12793)
<!-- Write all pull request text in Simplified Technical English (ASD-STE100): short sentences, one instruction per sentence, simple approved vocabulary, and the active voice. --> ## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Operators use the main navigation, contextual navigation, and task chat throughout the product. > - The recent core UI refactor left uneven spacing and inconsistent navigation styles. > - The Apps label also did not match the Connectors product language. > - The account area did not provide a clear direct path for feedback. > - This pull request aligns these related core UI surfaces and preserves their existing behavior. > - The benefit is a more consistent interface with clearer navigation and balanced task-chat layout. ## Linked Issues or Issue Description **What existing behavior does this improve?** This improves the core sidebar, Settings navigation, Connectors catalog, task-chat layout, and account controls. **Subsystem affected** `ui/` — React and Vite board UI. **Current behavior** The task chat had uneven edge treatment. Settings used a separate contextual-navigation style. Apps used inconsistent product labels. The account footer did not expose a direct feedback control. **Proposed behavior** The task chat keeps balanced content padding while its scrollbar sits at the properties boundary. Settings replaces the primary sidebar with a matching navigation surface and a Back to app link. Apps uses Connectors and Browse labels. The account footer provides a dedicated feedback icon with a tooltip. **Reason and benefit** These changes make related navigation and layout patterns predictable. They reduce duplicate labels and improve access to feedback. **Breaking changes** None. Routes, APIs, and stored data do not change. ## What Changed - Balanced the task-chat content gutter and moved its scrollbar to the properties-panel boundary. - Reworked Settings navigation to replace the main sidebar and use the shared primary-sidebar style. - Added a Back to app navigation item to Settings. - Renamed Apps to Connectors in the main navigation and added the `Unplug` icon. - Renamed the Connectors contextual item to Browse. - Added the Connectors top-level header and aligned the search field with the connector cards. - Added account-footer hover states and a direct feedback flag with a Share feedback tooltip. - Removed the duplicate Feedback item from the account popover. - Added regression coverage for each changed UI surface. ## Verification - `pnpm --filter @paperclipai/ui exec vitest run src/components/AppsSidebar.test.tsx src/components/CompanySettingsSidebar.test.tsx src/components/Layout.test.tsx src/components/Sidebar.test.tsx src/components/SidebarAccountMenu.test.tsx src/components/task-chat/TaskMessageScroller.test.tsx src/pages/apps/Browse.test.tsx` — 90 tests passed. - `pnpm --filter @paperclipai/ui typecheck` — passed. - `pnpm --filter @paperclipai/ui build` — passed. - `pnpm check:token-gates` — passed. - `git diff --check origin/master...HEAD` — passed. - `env PAPERCLIP_PLAYWRIGHT_CHANNEL=chrome PAPERCLIP_E2E_PORT=3201 pnpm exec playwright test --config tests/e2e/playwright.config.ts tests/e2e/apps-dark-mode-shots.spec.ts tests/e2e/sidebar-takeover.spec.ts` — 10 tests passed. - The full workspace typecheck and build reached the Rust runner and stopped because `cargo` is not installed on this machine. - The full test suite exposed unrelated server and workspace-runtime failures and was stopped after the affected suites completed. No changed UI test failed. - Manually verified the changed Settings, Connectors, task-chat, and account-menu surfaces in the running app. ## Risks - Low risk. The change affects layout and navigation presentation only. - The Settings sidebar now replaces the main sidebar by design. Users must use Back to app to return to the application navigation. - The task scrollbar offset depends on the existing responsive page gutters. Regression tests cover both narrow and desktop spacing. > 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.6-sol`, extended reasoning with tool use and code execution. The host does not expose the context-window size. ## 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [ ] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Scott Tong <scott@scottsmbpm5max.lan> Co-authored-by: Paperclip <noreply@paperclip.ing>canary/v2026.903.0-canary.9 |
||
|
|
fa86407ad8 |
chore(deps): bump yjs from 13.6.29 to 13.6.32 (#12256)
Bumps [yjs](https://github.com/yjs/yjs) from 13.6.29 to 13.6.32. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/yjs/yjs/releases">yjs's releases</a>.</em></p> <blockquote> <h2>v13.6.32</h2> <ul> <li>fix <a href="https://redirect.github.com/yjs/yjs/issues/797">#797</a> - undomanager clears destroy handler 95e890d9</li> </ul> <hr /> <p><a href="https://github.com/yjs/yjs/compare/v13.6.31...v13.6.32">https://github.com/yjs/yjs/compare/v13.6.31...v13.6.32</a></p> <h2>v13.6.31</h2> <ul> <li>Merge branch &<a href="https://redirect.github.com/yjs/yjs/issues/39">#39</a>;ppiotrowicz-fix/757-undo-attr-redo&<a href="https://redirect.github.com/yjs/yjs/issues/39">#39</a>; into v13 1ddba7e4</li> <li>fix <a href="https://redirect.github.com/yjs/yjs/issues/757">#757</a> in v13 d9aaff72</li> <li>fix undoing setAttribute combined with delete corrupts remote state - closes <a href="https://redirect.github.com/yjs/yjs/issues/757">#757</a> 67c809ee</li> </ul> <hr /> <p><a href="https://github.com/yjs/yjs/compare/v13.6.30...v13.6.31">https://github.com/yjs/yjs/compare/v13.6.30...v13.6.31</a></p> <h2>v13.6.30</h2> <ul> <li>lint 0504939a</li> <li>fix mutation of DeleteItem in sortAndMergeDeleteSet - closes <a href="https://redirect.github.com/yjs/yjs/issues/767">#767</a> 5d5f1ad6</li> </ul> <hr /> <p><a href="https://github.com/yjs/yjs/compare/v13.6.29...v13.6.30">https://github.com/yjs/yjs/compare/v13.6.29...v13.6.30</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/yjs/yjs/commit/1ce38f75f786e4bc0b2cc9703afbc6eea8fe7859"><code>1ce38f7</code></a> 13.6.32</li> <li><a href="https://github.com/yjs/yjs/commit/95e890d99ac6b8462fc02722e60b1dbd17c9c29d"><code>95e890d</code></a> fix <a href="https://redirect.github.com/yjs/yjs/issues/797">#797</a> - undomanager clears destroy handler</li> <li><a href="https://github.com/yjs/yjs/commit/271330889b13eae102873bb417d6747a0ddd8b4a"><code>2713308</code></a> 13.6.31</li> <li><a href="https://github.com/yjs/yjs/commit/1ddba7e48cfa9cdf4c0c51b2a1bd22986a0e8704"><code>1ddba7e</code></a> Merge branch 'ppiotrowicz-fix/757-undo-attr-redo' into v13</li> <li><a href="https://github.com/yjs/yjs/commit/d9aaff72b246c0f2a5c07eaa4f685079fe9e6e5a"><code>d9aaff7</code></a> fix <a href="https://redirect.github.com/yjs/yjs/issues/757">#757</a> in v13</li> <li><a href="https://github.com/yjs/yjs/commit/67c809ee6b787984d7bf709df9900b93cccffb7e"><code>67c809e</code></a> fix undoing setAttribute combined with delete corrupts remote state - closes ...</li> <li><a href="https://github.com/yjs/yjs/commit/676cc334edb39867b74bd1f50a05eb85c8275d9b"><code>676cc33</code></a> 13.6.30</li> <li><a href="https://github.com/yjs/yjs/commit/0504939a753165d32b8d968d38639f959c834eae"><code>0504939</code></a> lint</li> <li><a href="https://github.com/yjs/yjs/commit/5d5f1ad6fa0a91603cbbb783184b2fdfa80eef7d"><code>5d5f1ad</code></a> fix mutation of DeleteItem in sortAndMergeDeleteSet - closes <a href="https://redirect.github.com/yjs/yjs/issues/767">#767</a></li> <li>See full diff in <a href="https://github.com/yjs/yjs/compare/v13.6.29...v13.6.32">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> |
||
|
|
daa2391021 |
chore(deps): bump @aws-sdk/client-s3 from 3.1120.0 to 3.1122.0 (#12261)
Bumps [@aws-sdk/client-s3](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-s3) from 3.1120.0 to 3.1122.0. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/aws/aws-sdk-js-v3/releases">@aws-sdk/client-s3's releases</a>.</em></p> <blockquote> <h2>v3.1122.0</h2> <h4>3.1122.0(2026-08-31)</h4> <h5>Documentation Changes</h5> <ul> <li><strong>client-controltower:</strong> Updated the descriptions for the AWS Control Tower ListEnabledControls API parameters to make them more accurate and intuitive. (<a href="https://github.com/aws/aws-sdk-js-v3/commit/c54ac4e6019f585fcf54a956b8d30e38c6cb1a86">c54ac4e6</a>)</li> </ul> <h5>New Features</h5> <ul> <li><strong>client-pinpoint-sms-voice-v2:</strong> AWS End User Messaging SMS now returns ConditionalBehavior on DescribeRegistrationFieldDefinitions, allowing you to programmatically discover which registration fields are required, optional, or disallowed based on the values of other fields in the same form. (<a href="https://github.com/aws/aws-sdk-js-v3/commit/9cbace13989c31d55c45812ee801a29cf90f00ed">9cbace13</a>)</li> <li><strong>client-customer-profiles:</strong> This release introduces new APIs for segment membership events allowing segment definition membership events to be exported to a kinesis stream for downstream processing. Additionally, includes new calculated attribute statistic and 2 new segment dimension types. (<a href="https://github.com/aws/aws-sdk-js-v3/commit/be1a9dab4280a118cd0e47c7aaacee919e01c02b">be1a9dab</a>)</li> <li><strong>client-sagemaker:</strong> Amazon SageMaker Batch Transform now supports G6e instances, powered by NVIDIA L40S Tensor Core GPUs. G6e instances are the most cost-efficient GPU instances for deploying generative AI models and the highest-performance GPU instances for spatial computing workloads. (<a href="https://github.com/aws/aws-sdk-js-v3/commit/b063cf77a91073f3b32a33a1386f20978b646059">b063cf77</a>)</li> <li><strong>client-quicksight:</strong> This release adds support for managing apps in Amazon QuickSight with ListApps, SearchApps, DescribeApp, DescribeAppPermissions, UpdateAppPermissions, and DeleteApp (<a href="https://github.com/aws/aws-sdk-js-v3/commit/98a49570d50f800f74fce9014ec4ab0985fc0775">98a49570</a>)</li> <li><strong>client-connect:</strong> Added support for global routing on Amazon Connect Global Resiliency instances. New APIs GetCrossRegionRouting and UpdateCrossRegionRouting allow you to view and control cross-region contact routing between linked instances, so both Regions are active at all times. (<a href="https://github.com/aws/aws-sdk-js-v3/commit/ce41026342e42c9454be6c68ef24fe721f8149f2">ce410263</a>)</li> <li><strong>client-agent-registry-control:</strong> AWS Agent Registry becomes Generally Available (<a href="https://github.com/aws/aws-sdk-js-v3/commit/e41244e9301730ac7632a4e5f67bb2933156769c">e41244e9</a>)</li> <li><strong>client-kinesis:</strong> Adds support for data delivery to Amazon S3 Tables (Apache Iceberg) and general purpose Amazon S3 buckets with new CreateChannel, UpdateChannel, DeleteChannel, DescribeChannel, and ListChannels APIs for Amazon Kinesis Data Streams. (<a href="https://github.com/aws/aws-sdk-js-v3/commit/64ebb058e0b7ae64bd240c7ae325099fc64ab43a">64ebb058</a>)</li> <li><strong>client-agent-registry:</strong> AWS Agent Registry becomes Generally Available (<a href="https://github.com/aws/aws-sdk-js-v3/commit/e60306f198e7ad374089161aa448602dab590287">e60306f1</a>)</li> <li><strong>client-devops-agent:</strong> Adds support for Slack bidirectional communication configuration in AWS DevOps Agent agent spaces. (<a href="https://github.com/aws/aws-sdk-js-v3/commit/75bc6d6da3f88c398be5a737ad01d8d631773fcf">75bc6d6d</a>)</li> <li><strong>client-kafkaconnect:</strong> Amazon MSK Connect now supports restarting newly created connectors via the asynchronous RestartConnector API. Restart all tasks or only failed tasks, while preserving configuration and committed offsets. This returns a connector operation ARN that you can track with DescribeConnectorOperation. (<a href="https://github.com/aws/aws-sdk-js-v3/commit/8771afafd4c1723c29c1745ff8683145a837bda2">8771afaf</a>)</li> <li><strong>client-support:</strong> AWS Support now allows up to 10 attachments (150 MB each) per case correspondence, up from 3 at 5 MB. Customers can share large diagnostic logs, heap dumps, and packet captures directly in cases to reduce back-and-forth and speed up resolution. Available in US East, US West, and Europe (Ireland). (<a href="https://github.com/aws/aws-sdk-js-v3/commit/4ddd79c10633ffa37d957d96313bdffddcba4867">4ddd79c1</a>)</li> <li><strong>client-workspaces-instances:</strong> Amazon WorkSpaces Core managed instances now support nested virtualization. Customers can enable nested virtualization with supported instance types at launch via CpuOptions.NestedVirtualization in CreateWorkspaceInstance to run hypervisors and virtual machines inside their WorkSpaces Instance. (<a href="https://github.com/aws/aws-sdk-js-v3/commit/29587d1236c8805f7f72305e06a011bfc48ae55c">29587d12</a>)</li> </ul> <hr /> <p>For list of updated packages, view <strong>updated-packages.md</strong> in <strong>assets-3.1122.0.zip</strong></p> <h2>v3.1121.0</h2> <h4>3.1121.0(2026-08-28)</h4> <h5>New Features</h5> <ul> <li><strong>client-ecs:</strong> Amazon Elastic Container Service - This release adds support for early success criteria on ECS rolling deployments, letting deployment complete once a configurable percentage of tasks are healthy, with configurable BLOCKING (required) or DEFERRED (asynchronous) cleanup of previous service revisions. (<a href="https://github.com/aws/aws-sdk-js-v3/commit/ef22d750f27bd01ff6b88b8e1cc0f34efea8d171">ef22d750</a>)</li> <li><strong>client-healthlake:</strong> New HealthLake API, RestoreFHIRDatastore, providing the capability to restore active datastores to a point in time within the last 30 days or recover a deleted datastore from the delete snapshot. (<a href="https://github.com/aws/aws-sdk-js-v3/commit/6249174262656b83d0bba16cf59ba892b849a707">62491742</a>)</li> <li><strong>client-bedrock-agentcore:</strong> AgentCore Memory now supports direct ingestion into long-term memory via IngestData API (<a href="https://github.com/aws/aws-sdk-js-v3/commit/20d652de566b291145576f6e4c24a7c8da4ea2be">20d652de</a>)</li> <li><strong>client-partnercentral-selling:</strong> Releasing PARC, new APN Program that lets sellers add solftware revenue details to aws opportunity summary (<a href="https://github.com/aws/aws-sdk-js-v3/commit/2b6350f01269baa5e6d079a93ff9f6b0804d982f">2b6350f0</a>)</li> <li><strong>client-cognito-identity-provider:</strong> Adds two new operations - GetClientToken which allows M2M auth through the SDK, and DescribeTermsByClient to find which Terms are associated with a user-pool client without knowing the Terms resource id. (<a href="https://github.com/aws/aws-sdk-js-v3/commit/86dffd282f1ac269d1268f9a75f1550df61c5cc6">86dffd28</a>)</li> <li><strong>client-bedrock-agent:</strong> Adds an optional syncSchedule field to CreateDataSource and UpdateDataSource for Managed Knowledge Bases data source connectors, so a data source can sync automatically on a daily, weekly, or monthly schedule. (<a href="https://github.com/aws/aws-sdk-js-v3/commit/a8d3714a751f972452553ba631a98176e6ea584c">a8d3714a</a>)</li> </ul> <hr /> <p>For list of updated packages, view <strong>updated-packages.md</strong> in <strong>assets-3.1121.0.zip</strong></p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-s3/CHANGELOG.md">@aws-sdk/client-s3's changelog</a>.</em></p> <blockquote> <h1><a href="https://github.com/aws/aws-sdk-js-v3/compare/v3.1121.0...v3.1122.0">3.1122.0</a> (2026-08-31)</h1> <p><strong>Note:</strong> Version bump only for package <code>@aws-sdk/client-s3</code></p> <h1><a href="https://github.com/aws/aws-sdk-js-v3/compare/v3.1120.0...v3.1121.0">3.1121.0</a> (2026-08-28)</h1> <p><strong>Note:</strong> Version bump only for package <code>@aws-sdk/client-s3</code></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/aws/aws-sdk-js-v3/commit/e1cf460a1e4707e137931804e3e7b71a8392f227"><code>e1cf460</code></a> Publish v3.1122.0</li> <li><a href="https://github.com/aws/aws-sdk-js-v3/commit/e53a25aafbdd772c90d26471dc271e383f1daf71"><code>e53a25a</code></a> Publish v3.1121.0</li> <li>See full diff in <a href="https://github.com/aws/aws-sdk-js-v3/commits/v3.1122.0/clients/client-s3">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> |
||
|
|
a0028d7e1b |
chore(deps-dev): bump vitest from 4.1.10 to 4.1.11 (#12262)
Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 4.1.10 to 4.1.11. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/vitest-dev/vitest/releases">vitest's releases</a>.</em></p> <blockquote> <h2>v4.1.11</h2> <h3> 🐞 Bug Fixes</h3> <ul> <li>Revive global concurrency limit for test lifecycle [backport to v4] - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> and <a href="https://github.com/hi-ogawa"><code>@hi-ogawa</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10992">vitest-dev/vitest#10992</a> <a href="https://github.com/vitest-dev/vitest/commit/5146df80b"><!-- raw HTML omitted -->(5146d)<!-- raw HTML omitted --></a></li> <li><strong>browser</strong>: <ul> <li>Encode iframeId in tester iframe URL [backport to v4] - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a>, <strong>Pduhard</strong> and <strong>Claude Opus 4.8</strong> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10955">vitest-dev/vitest#10955</a> <a href="https://github.com/vitest-dev/vitest/commit/10b2cd201"><!-- raw HTML omitted -->(10b2c)<!-- raw HTML omitted --></a></li> <li>Trigger playwright/chromium gc on lower disk availability [backport to v4] - by <a href="https://github.com/hi-ogawa"><code>@hi-ogawa</code></a>, <strong>Hiroshi Ogawa</strong> and <strong>OpenCode</strong> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10951">vitest-dev/vitest#10951</a> <a href="https://github.com/vitest-dev/vitest/commit/9851dbc41"><!-- raw HTML omitted -->(9851d)<!-- raw HTML omitted --></a></li> </ul> </li> <li><strong>mocker</strong>: <ul> <li>Restrict redirect mocks to the fs allowlist [backport to v4] - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10974">vitest-dev/vitest#10974</a> <a href="https://github.com/vitest-dev/vitest/commit/fe5a11d3c"><!-- raw HTML omitted -->(fe5a1)<!-- raw HTML omitted --></a></li> </ul> </li> </ul> <h5> <a href="https://github.com/vitest-dev/vitest/compare/v4.1.10...v4.1.11">View changes on GitHub</a></h5> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/vitest-dev/vitest/commit/9bd8d464e6328c567c2dbcd8fdd977d57a9425c2"><code>9bd8d46</code></a> chore: release v4.1.11 (<a href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10995">#10995</a>)</li> <li><a href="https://github.com/vitest-dev/vitest/commit/9851dbc41c286a30abfb6b29cce65f3e5b7b40a1"><code>9851dbc</code></a> fix(browser): trigger playwright/chromium gc on lower disk availability [back...</li> <li>See full diff in <a href="https://github.com/vitest-dev/vitest/commits/v4.1.11/packages/vitest">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> |
||
|
|
3e28ec5f4c |
chore(deps): bump react-i18next from 17.0.11 to 17.0.12 (#12263)
Bumps [react-i18next](https://github.com/i18next/react-i18next) from 17.0.11 to 17.0.12. <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md">react-i18next's changelog</a>.</em></p> <blockquote> <h2>17.0.12</h2> <ul> <li>fix(IcuTrans): key-less <code>icu.macro</code> nodes (<code><Trans>Welcome, {name}!</Trans></code>, <code><Select></code>, <code><Plural></code> without <code>i18nKey</code>) rendered an empty string since 17.0.0. The macro now emits <code><IcuTrans defaultTranslation="…"></code> without a key and <code>IcuTrans</code> passed <code>undefined</code> to <code>t()</code>, which returns <code>''</code>. Like <code>Trans</code>, <code>IcuTrans</code> now uses <code>defaultTranslation</code> as the key when <code>i18nKey</code> is not provided.</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/i18next/react-i18next/commit/ea721fb58dccf1c569015969e5689c374ae20e4b"><code>ea721fb</code></a> 17.0.12</li> <li><a href="https://github.com/i18next/react-i18next/commit/6c2a71e1c0a67b4265a89d177dfc5ebf87e62b8d"><code>6c2a71e</code></a> fix(IcuTrans): use defaultTranslation as key when no i18nKey is given</li> <li><a href="https://github.com/i18next/react-i18next/commit/258c96daab2c332da0904469d2d7b53ae6da202b"><code>258c96d</code></a> chore(examples): upgrade all example apps off unmaintained toolchains</li> <li><a href="https://github.com/i18next/react-i18next/commit/b8677c805cd6634902bae49b99143a8fa60a02fe"><code>b8677c8</code></a> chore: update dependencies to close dependabot alerts</li> <li><a href="https://github.com/i18next/react-i18next/commit/aa9c92bd7fdbe638d970ef34c35eb1712fa0912d"><code>aa9c92b</code></a> docs: point Trans component links at the current docs (<a href="https://redirect.github.com/i18next/react-i18next/issues/1929">#1929</a>)</li> <li>See full diff in <a href="https://github.com/i18next/react-i18next/compare/v17.0.11...v17.0.12">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> |
||
|
|
2392a9895e |
fix(ui): drop the "Open invite" action from the invites section (#12787)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The Members page has an Invites tab where an admin mints single-use invite links for people > - After a link is created, the section offers two actions: "Copy link" and "Open invite" > - "Open invite" opens the inviter's own single-use link in a new tab, which is never what the inviter means — the link is for the invitee > - This pull request removes the "Open invite" button and keeps "Copy link" as the only action > - The benefit is that the section no longer invites a mistake, and the one remaining action matches the section's purpose ## Linked Issues or Issue Description No existing issue. Description follows the enhancement template: **What existing behavior does this improve?** The latest-invite panel on the Members page Invites tab. **Subsystem affected** UI — `ui/src/components/access/InvitesSection.tsx`. **Current behavior** After an invite is created, the panel shows a "Copy link" button and an "Open invite" button. "Open invite" opens the invite URL in a new tab as the inviter. **Proposed behavior** The panel shows only "Copy link". The invite URL field itself stays visible and selectable. **Reason and benefit** Invite links are single-use and addressed to the invitee. The inviter opening their own link at best shows them their own landing page and at worst walks the link toward consumption. Removing the button removes the trap. **Breaking changes** None. No API or data change. ## What Changed - Removed the "Open invite" anchor button from `InvitesSection`. - Removed the now-unused `ExternalLink` icon import. - The component test now asserts the action is absent. ## Verification - `cd ui && npx vitest run src/components/access/InvitesSection.test.tsx` — 3 tests pass. - `cd ui && npx tsc -p tsconfig.json --noEmit` — clean. - Manual: create an invite on the Members page Invites tab; the latest-invite panel shows the URL field and "Copy link" only. ## Risks Low risk. UI-only removal of one button; the invite URL remains fully visible and copyable. ## Model Used Claude Fable 5 (`claude-fable-5`, Anthropic), extended thinking, agentic tool use via Claude Code. ## 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
112ef5beec |
chore(deps): bump i18next from 26.3.6 to 26.4.0 (#12267)
Bumps [i18next](https://github.com/i18next/i18next) from 26.3.6 to 26.4.0. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/i18next/i18next/releases">i18next's releases</a>.</em></p> <blockquote> <h2>v26.4.0</h2> <ul> <li>perf: cache <code>toResolveHierarchy</code> results per <code>(code, fallbackCode)</code> pair. The hierarchy resolver runs on every <code>t()</code> call and calls <code>Intl.getCanonicalLocales</code> multiple times, which showed up prominently when profiling render-heavy UIs (e.g. virtualized data grids); with the cache the per-call cost drops from ~886 ns to ~41 ns. The cache is invalidated automatically when <code>options.fallbackLng</code> changes (reassignment or in-place array mutation); if you mutate other resolution-relevant options at runtime (<code>load</code>, <code>lowerCaseLng</code>, <code>cleanCode</code>, <code>nonExplicitSupportedLngs</code>), call <code>i18next.services.languageUtils.clearCache()</code> afterwards. Function-valued <code>fallbackLng</code> and per-call array/object <code>fallbackLng</code> options are never cached, so dynamic fallbacks keep working as before. Thanks <a href="https://github.com/equaterina"><code>@equaterina</code></a> (<a href="https://redirect.github.com/i18next/i18next/pull/2444">#2444</a>).</li> <li>chore: update all devDependencies (Babel stays on 7.x until <code>@rollup/plugin-babel</code> supports 8, eslint on 9.x for neostandard). Removed the unused <code>coveralls</code> package (CI uses the Coveralls GitHub Action) and replaced <code>sinon</code> with <code>nise</code> + <code>vitest.spyOn</code> in the v1 compatibility tests, which resolves all open <code>npm audit</code> findings (0 vulnerabilities) and should close the dependabot alerts on the lockfile.</li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/i18next/i18next/blob/master/CHANGELOG.md">i18next's changelog</a>.</em></p> <blockquote> <h2>26.4.0</h2> <ul> <li>perf: cache <code>toResolveHierarchy</code> results per <code>(code, fallbackCode)</code> pair. The hierarchy resolver runs on every <code>t()</code> call and calls <code>Intl.getCanonicalLocales</code> multiple times, which showed up prominently when profiling render-heavy UIs (e.g. virtualized data grids); with the cache the per-call cost drops from ~886 ns to ~41 ns. The cache is invalidated automatically when <code>options.fallbackLng</code> changes (reassignment or in-place array mutation); if you mutate other resolution-relevant options at runtime (<code>load</code>, <code>lowerCaseLng</code>, <code>cleanCode</code>, <code>nonExplicitSupportedLngs</code>), call <code>i18next.services.languageUtils.clearCache()</code> afterwards. Function-valued <code>fallbackLng</code> and per-call array/object <code>fallbackLng</code> options are never cached, so dynamic fallbacks keep working as before. Thanks <a href="https://github.com/equaterina"><code>@equaterina</code></a> (<a href="https://redirect.github.com/i18next/i18next/pull/2444">#2444</a>).</li> <li>chore: update all devDependencies (Babel stays on 7.x until <code>@rollup/plugin-babel</code> supports 8, eslint on 9.x for neostandard). Removed the unused <code>coveralls</code> package (CI uses the Coveralls GitHub Action) and replaced <code>sinon</code> with <code>nise</code> + <code>vitest.spyOn</code> in the v1 compatibility tests, which resolves all open <code>npm audit</code> findings (0 vulnerabilities) and should close the dependabot alerts on the lockfile.</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/i18next/i18next/commit/652847e70fd68344d00456f20ef0584da51e59f7"><code>652847e</code></a> 26.4.0</li> <li><a href="https://github.com/i18next/i18next/commit/6c6025f87e89f0b5e8ef3f0bf23fd61158bd64d3"><code>6c6025f</code></a> prettier fix</li> <li><a href="https://github.com/i18next/i18next/commit/742b9a95dd240891368bd296b6dbb09844bd365a"><code>742b9a9</code></a> chore: update dependencies and clean up dev tooling</li> <li><a href="https://github.com/i18next/i18next/commit/06924d961c64bd01a1f3d707b425b6c392a72a9a"><code>06924d9</code></a> fix: invalidate toResolveHierarchy cache on in-place fallbackLng mutation</li> <li><a href="https://github.com/i18next/i18next/commit/bb80369e1453cb9621011d51feaf7e0b8ba002f3"><code>bb80369</code></a> perf: cache toResolveHierarchy (<a href="https://redirect.github.com/i18next/i18next/issues/2444">#2444</a>)</li> <li>See full diff in <a href="https://github.com/i18next/i18next/compare/v26.3.6...v26.4.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>canary/v2026.903.0-canary.8 |
||
|
|
5f87090894 |
Make managed Cloud OAuth handoffs invisible (#12790)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Apps let people give agents governed access to external providers > - Paperclip Cloud brokers shared provider authorization for managed stacks > - The managed flow sent the browser through a confirmation page after the tenant had already prepared sign-in > - A lost confirmation response could also show an expired-session error before the provider page opened > - This pull request adds an opaque handoff contract and one shared tenant coordinator > - The benefit is a direct and recoverable transition from Paperclip to every Cloud-brokered provider ## Linked Issues or Issue Description **What happened?** A managed Paperclip Cloud connection opened the Cloud confirmation route. A response-loss race could show an expired-session error while the authorization still continued. **Expected behavior** The current Paperclip loading state must stay visible while the tenant exchanges an opaque session. The browser must then open the provider directly. Self-hosted and direct OAuth must keep their existing behavior. **Steps to reproduce** 1. Open Apps on a Paperclip Cloud stack. 2. Start a managed provider connection. 3. Select Continue to sign in. 4. Observe that the browser visits the Cloud confirmation route before it reaches the provider. **Paperclip version or commit** `b872cd3d1b404bdaff70af493a2973ceb7e5d6ec` **Deployment mode** Paperclip Cloud hosted stack. No related open issue or pull request was found in the repository search. ## What Changed - Add a backward-compatible opaque Cloud handoff to the shared OAuth start contract. - Validate the Cloud descriptor on the server and expose no browser-selected endpoint. - Exchange managed handoffs through one fixed same-origin route in every Apps OAuth launcher. - Keep dialog popups reserved before asynchronous work and retain the tenant loading state. - Add recent-login resume storage, bounded retry behavior, terminal tenant errors, tests, and Storybook states. ## Verification - `pnpm check:token-gates` - `pnpm -r typecheck` - Focused connector and UI suites: 184 passed and 202 skipped. - `pnpm build` - `pnpm build-storybook` - The full local suite reached one unrelated macOS path-alias failure. The untouched test expected `/var/...` and received the equivalent `/private/var/...`. The same test reproduces in isolation. ## Risks - A malformed managed descriptor now fails closed in Paperclip instead of opening a URL. - A legacy Cloud deployment can omit the descriptor. Paperclip then uses the existing validated confirmation URL. - Direct provider OAuth and self-hosted flows do not receive a handoff and remain unchanged. - Rollback is a normal revert of this commit because the contract is optional and backward compatible. > 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 with GPT-5.6, reasoning mode, tool use, code execution, and browser 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [ ] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
a36020da6a |
chore(deps): bump @radix-ui/react-slot from 1.3.0 to 1.3.3 (#12268)
Bumps [@radix-ui/react-slot](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/slot) from 1.3.0 to 1.3.3. <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/radix-ui/primitives/blob/main/packages/react/slot/CHANGELOG.md">@radix-ui/react-slot's changelog</a>.</em></p> <blockquote> <h2>1.3.2, 1.3.3</h2> <ul> <li>Reverted breaking changes that caused compatibility issues with React Server Components.</li> </ul> <h2>1.3.1</h2> <ul> <li>Republish through CI to attach provenance attestations. The previous versions of these packages were published manually outside of CI and therefore shipped without provenance; this patch re-releases the same code through the CI pipeline so every package includes an attestation.</li> <li>Updated dependencies: <code>@radix-ui/primitive@1.1.7</code>, <code>@radix-ui/react-compose-refs@1.1.4</code></li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/radix-ui/primitives/commits/HEAD/packages/react/slot">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> |
||
|
|
d3c04d8932 |
fix(runner-e2e): prepare frozen Daytona plugin dependencies (#12791)
## Thinking Path
> - Paperclip manages AI agents and their provider runtimes.
> - The paid runner workflow installs target dependencies with lifecycle
scripts disabled.
> - The bundled Daytona plugin depends on an audited repo-local plugin
SDK link.
> - The lifecycle-safe install path did not create that link.
> - This pull request restores only the trusted Daytona preparation step
before provider secrets are exposed.
> - The benefit is a working Daytona canary without enabling dependency
lifecycle scripts.
## Linked Issues or Issue Description
**What happened?**
The Daytona paid canary stopped before lease or provider startup. The
trusted paid job disabled root lifecycle scripts, so the repo-local
plugin SDK link was absent. The plugin install returned a missing
runtime dependency error for @paperclipai/plugin-sdk.
**Expected behavior**
The trusted workflow must prepare the bundled Daytona plugin without
running untrusted dependency lifecycle scripts. The paid cell must start
only after its runtime dependencies and entrypoints pass validation.
**Steps to reproduce**
1. Dispatch the runner full-stack paid workflow for
core-compatibility.runner-acpx-claude.daytona.message-marker.
2. Let the trusted job install root dependencies with lifecycle scripts
disabled.
3. Observe the Daytona plugin installation fail before a lease or
provider process starts.
**Paperclip version or commit**
Feature head
|
||
|
|
e0d5f02b8e |
chore(deps): bump @pierre/diffs from 1.3.5 to 1.3.6 (#12311)
Bumps @pierre/diffs from 1.3.5 to 1.3.6. <details> <summary>Maintainer changes</summary> <p>This version was pushed to npm by <a href="https://www.npmjs.com/~ije">ije</a>, a new releaser for <code>@pierre/diffs</code> since your current version.</p> </details> <br /> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
66ea41812d |
test(server): make the instance settings route suite deterministic under CPU contention (#12789)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Paperclip tests its server routes with mocked services and database calls > - The instance settings route suite reset and reloaded its module graph before each test > - Two concurrent module imports could bind a route to the real service module under CPU contention > - The task-drain overlap test also relied on a fixed delay and operating system request order > - This pull request loads the mocked graph once and waits for real events that prove request order > - The benefit is a deterministic 48-test suite with no production code change ## Linked Issues or Issue Description **What happened?** The instance settings route suite failed intermittently under CPU contention. A request that expected a 200 or 403 response sometimes received 500. The failing test changed between runs. **Expected behavior** The suite must use the configured service mocks for every test and must produce the expected response on every run. **Steps to reproduce** 1. Run `npx vitest run server/src/__tests__/instance-settings-routes.test.ts` many times in parallel on a busy host. 2. Compare the result with the same command on the base branch. 3. Observe intermittent 500 responses on the base branch and stable results on this branch. **Paperclip version or commit** Commit `02ae87010e621cf46bfbdf0d48b6f73887448a83`. **Deployment mode** Local dev (`pnpm dev`). The change affects tests only. **Installation method** Built from source. **Agent adapter(s) involved** Not adapter-specific (core bug). **Database mode** Not database-related. The test uses a mocked database layer. **Access context** Not applicable. **Node.js version** The CI environment runs the repository-supported Node.js version. **Operating system** Linux in continuous integration. **Relevant logs or output** The base branch reproduced `expected 500 to be 200` and `expected 500 to be 403` under parallel contention. **Relevant config (if applicable)** Not applicable. **Additional context** The branch loads the mocked module graph once per suite, restores mock behavior before each test, waits for the real transaction events, and sends the DELETE request after the POST holds the transition queue. ## What Changed - Load the mocked instance settings module graph once for the suite. - Restore each mock implementation before every test. - Wait for two real transaction events instead of a fixed 30 millisecond delay. - Send the overlapping DELETE request after the POST proves that it holds the transition queue. - Keep the test count at 48 with no skipped tests. ## Verification - Run `npx vitest run server/src/__tests__/instance-settings-routes.test.ts`. - Confirm that all 48 tests pass. - Run the 20-way parallel contention differential. - Confirm that the base arm passed 18 of 20 runs and reproduced two failures. - Confirm that the branch arm passed 20 of 20 runs, with 48 tests in each run. - Confirm that `git status --porcelain` is clean at the submitted commit. ## Risks Low risk. The change affects one test file and does not change production code, route behavior, database schema, or public API behavior. ## Model Used OpenAI Codex, GPT-5, current deployment, tool use and code execution 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes: #` / `Refs: #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
b872cd3d1b |
test(server): select exposure reservation host ports at run time (#12783)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The server manages runtime exposure and host port leases for workspace services > - This test suite used fixed host port pairs inside the Linux ephemeral port range > - An unrelated short-lived socket could take one pair and cause a false test failure > - This pull request selects free host port pairs at run time and starts above the low lease lane > - The benefit is a more stable test suite with the same deterministic allocator checks ## Linked Issues or Issue Description **What happened?** The runtime exposure reservation test suite used two fixed app and HMR port pairs. These ports sit inside the Linux ephemeral port range. An unrelated socket could use a pair during the test, and the guest bind could fail with `EADDRINUSE`. **Expected behavior** The suite must select two free app and HMR port pairs before each test. It must avoid the low lease lane that a live instance can own without a listener. **Steps to reproduce** 1. Run `npx vitest run server/src/__tests__/workspace-runtime-exposure-reservation.test.ts`. 2. Start another process that briefly uses one fixed test port. 3. Observe that the guest bind can fail even when the allocator works correctly. **Paperclip version or commit** `c982003e00f4e8a325bafec3af4ddb113c0c1f8a` **Deployment mode** Local dev test run. **Installation method** Built from source with pnpm. **Agent adapter(s) involved** Not adapter-specific. This change tests the runtime exposure allocator. **Database mode** Not database-related. ## What Changed - Select two free app and HMR port pairs in `beforeEach`. - Start the scan 500 ports above the runtime exposure range minimum. - Keep the synthetic host stub limited to the selected pairs. - Keep all seven test cases and the existing lifecycle coverage. ## Verification - Run `npx vitest run server/src/__tests__/workspace-runtime-exposure-reservation.test.ts`. - Run `npx vitest run server/src/services/workspace-runtime-exposure.test.ts`. - Run `pnpm --filter @paperclipai/server exec tsc --noEmit`. - Confirm the full CI suite reaches a terminal green state. ## Risks Low risk. This change updates one test file and does not change production code. A port can still become busy after discovery and before the guest bind; the test documents this remaining race. ## Model Used OpenAI GPT-5 (`gpt-5`), tool use and code 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
236588c753 |
fix(ui): stamp the service worker with a per-build id so deploys reach parked tabs (#12725)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The web UI ships a service worker (`ui/public/sw.js`) plus update logic (`ui/src/lib/service-worker-updates.ts`) whose job is to keep long-lived, parked SPA tabs on the freshly deployed bundle. > - That reload-on-update path fires only on `controllerchange` — i.e., only when the browser installs a new `sw.js`. > - But `sw.js` was a static public asset (`CACHE_NAME = "paperclip-v2"`), copied verbatim and never varying per deploy, so a normal deploy (new app bundle, unchanged `sw.js`) installed no new worker and triggered no reload. > - So a parked tab kept running the old bundle after a deploy until a manual reload — the exact failure the update logic was written to prevent. > - This pull request makes `sw.js` change whenever the app bundle changes, by stamping it with a per-build id at build time. > - The benefit is that shipped UI fixes actually reach open tabs, instead of waiting for each user to reload by hand. ## Linked Issues or Issue Description No separate issue. Describing the bug in-PR using the bug-report fields: **What happened?** After a deploy that changes the app bundle but not `sw.js`, tabs left open across the upgrade keep running the old bundle indefinitely. The network-first service worker means a manual reload always recovers, but nothing triggers that reload automatically. Concretely, the `2026.831.1` onboarding fix did not reach tabs that were open on `2026.831.0`. **Expected behavior** When a new bundle is deployed, the existing update machinery (`registration.update()` on visibility/interval, reload on `controllerchange`) should bring parked tabs onto the new bundle without a manual reload. **Steps to reproduce** 1. Open the app and leave the tab open. 2. Deploy a build that changes the app bundle but not `sw.js` (the common case — `sw.js` was static). 3. Observe the open tab keeps running the previous bundle; no new worker installs, so no `controllerchange` and no reload. **Paperclip version or commit** Reproduced against `2026.831.1` and `master` before this change. **Deployment mode** Any web deployment that serves the built UI (local trusted quickstart, managed, or self-hosted). Related PRs (searched open + closed before opening this one): - Refs #12198 (merged) — added the parked-tab `update()`/`controllerchange` reload logic this PR completes by making `sw.js` actually change per deploy. - Refs #9951 (open) — an alternative "prompt to reload on new build" approach to the same problem; this PR instead reuses the existing silent auto-reload path. Reviewers may want to pick one. - Refs #8112 (open) — serves `sw.js` with `no-cache`; complementary (that keeps the worker script itself fresh; this makes the script vary per build). ## What Changed - `ui/public/sw.js`: derive `CACHE_NAME` from a `__PAPERCLIP_BUILD_ID__` placeholder so the worker source varies per build. - `ui/src/lib/vite-sw-build-id.ts`: new Vite build plugin that rewrites the placeholder in the emitted `sw.js` with the entry chunk's content hash (stable when the app is unchanged, new when it changes). Throws if the placeholder is missing, so the worker can never silently stop rotating. - `ui/vite.config.ts`: register the plugin. - `ui/src/lib/vite-sw-build-id.test.ts`: unit tests for the stamping helper, the build-id derivation, and a contract test that `public/sw.js` still carries the placeholder. ## Verification - `vitest run ui/src/lib/vite-sw-build-id.test.ts` — 7 tests pass. - `vite build` — the emitted `dist/sw.js` contains `BUILD_ID = "index-<hash>"` matching the entry chunk `dist/assets/index-<hash>.js`, and the `__PAPERCLIP_BUILD_ID__` placeholder is gone. A subsequent build with unchanged app code produces the same id (no needless worker churn); a build with changed code produces a new id. - Dev (`vite serve`) leaves the literal placeholder in `sw.js`, where HMR (not the worker) drives refreshes. ## Risks - Low risk, build-time only. No runtime service-worker logic changes beyond the cache name being build-specific; the activate handler already deletes all caches, so a rotating name is inert there. - If a future edit removes the placeholder, the build fails loudly rather than silently shipping a non-rotating worker. ## Model Used - Claude (Anthropic), model id `claude-fable-5` (Claude Fable 5), used with tool use, shell commands, file editing, and test 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
0cf06c8fa1 |
test(server): make secret write-serialization tests deterministic (#12781)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Paperclip stores and controls secrets through server services > - The secret service tests check that concurrent writes use one lock at a time > - Fixed sleep times do not prove that a provider write started or stayed queued > - This pull request uses provider-write signals and measured waits to test lock behavior > - The benefit is stable test results and stronger detection of lock failures ## Linked Issues or Issue Description **What happened?** The secret write-serialization tests used fixed 20 ms sleeps. The sleeps sometimes ran before a provider write or after a queued write entered. The tests then failed or missed a broken lock. **Expected behavior** The tests must wait for real provider-write events and must detect a queued write that enters before the first write finishes. **Steps to reproduce** 1. Run `npx vitest run server/src/__tests__/secrets-service.test.ts`. 2. Repeat the test file under sustained load. 3. Remove the write lock and run the concurrency tests. 4. Observe intermittent timing failures or missed lock failures. **Paperclip version or commit** `13bff0adee0216ee9ec67c843e9ead94aa788c68` **Deployment mode** Local dev (`pnpm dev`) **Installation method** Built from source (`pnpm dev` / `pnpm build`) **Agent adapter(s) involved** Not adapter-specific (core test) **Database mode** Not database-related **Additional context** This pull request changes tests only. It does not change production code. ## What Changed - Wait for a deferred signal when the first operation reaches its provider write. - Measure an uncontended provider-write duration and use a safety multiple for the queued-write check. - Release the test gate in a `finally` block so failed assertions do not leave a write active. - Throw when the measurement helper does not observe the provider write. ## Verification - `npx tsc --noEmit -p server/tsconfig.json` reports no errors in the changed file. - `npx vitest run server/src/__tests__/secrets-service.test.ts` passes 90 of 90 tests. - The engineer ran the test file five times under sustained load, and all runs passed. - Full CI must pass after this pull request starts. ## Risks Low risk. The change affects test code only. The measured wait can expose a real lock regression, but it does not change runtime behavior. ## Model Used OpenAI Codex, GPT-5, tool use and code execution. The exact context window and reasoning mode are not exposed by the 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes: #` / `Refs: #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
1c9580e89b |
test(acpx): bind ACPX credential waits to the real retry envelope (#12780)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The ACPX runtime host tests manage credentials and sandbox operations. > - These tests poll operations that can join quarantine recovery. > - Recovery uses real backoff and directory synchronization, so the default poll deadline can expire while the operation makes progress. > - Three tests also stage a contender before the kernel lease release completes. > - This pull request binds every relevant poll and staging call to the documented retry envelope. > - The benefit is more stable tests and error output that names the last observed cause. ## Linked Issues or Issue Description **What happened?** Under concurrent test load, ACPX runtime host tests failed while credential recovery still made progress. Three tests also saw an active lease after they removed `auth.json`. **Expected behavior** The tests must wait for the documented retry envelope before they report a failure. They must stage a contender only after the credential lease becomes available. **Steps to reproduce** 1. Run `npx vitest run src/drivers/acpx/` from `packages/paperclip-runner`. 2. Run the suite under high concurrent load. 3. Observe intermittent timeout or active-lease failures in `runtime-host.test.ts`. **Paperclip version or commit** `865b4854fb44d3689f1c0ff17e3e715d52aaea73` base commit. **Deployment mode** Built from source. **Installation method** Built from source. **Agent adapter(s) involved** ACPX Codex runtime host tests. **Database mode** Not database-related. **Access context** Unclear / not applicable. **Node.js version** Not recorded in the handoff. **Operating system** Not recorded in the handoff. **Relevant logs or output** Under concurrent load, the failure included `Timed out in waitFor!` after 1157 ms and `Managed Codex credential home already has an active lease`. **Relevant config (if applicable)** Not applicable. **Additional context** The change touches test code only. It adds no test, removes no test, and weakens no assertion. The file keeps 28 tests and 146 assertions. ## What Changed - Add a test-local wait helper with an explicit 10-second deadline. - Apply the helper to every credential and sandbox poll in `runtime-host.test.ts`. - Report the last observed error when a poll reaches its deadline. - Guard the three credential staging calls that could race with lease release. - Set a 20-second timeout on tests that use the long wait. ## Verification - `npx vitest run src/drivers/acpx/runtime-host.test.ts` passes all 28 tests on the change branch. - A 40-run concurrent comparison produced zero `runtime-host.test.ts` failures on the change branch. - The base comparison produced 13 `runtime-host.test.ts` failures across 40 runs. - The broader ACPX suite still has a separate `codex-credentials.test.ts` flake on both arms. - CI and Greptile results will provide the remaining merge checks. ## Risks Low risk. The change affects test synchronization only. It increases selected test wait limits and does not change product behavior. ## Model Used OpenAI Codex, GPT-5. The model used tool calls and code execution. The runtime did not provide a context window value. ## 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes: #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and recorded the separate ACPX suite flake above - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
db4eeb1688 |
fix(server): validate project goal ids exist and belong to the company (#12779)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Projects can link to goals, through the `goalIds` list or the legacy
`goalId` field. The project service writes those links on create and
update.
> - The service never checked the goal ids. A nonexistent id died at the
`projects.goal_id` foreign key as an opaque 500, and the caller got no
actionable feedback — observed live on 2026-09-03, where one caller
retried the same bad id four times.
> - The foreign key also only proves a goal exists, not who owns it. A
goal id from another company linked silently on a multi-company
instance.
> - This pull request asserts every resolved goal id exists under the
caller's company before any write, and rejects with a 422 that names the
unknown ids.
> - The benefit is a clear, actionable client error instead of a 500,
and no cross-company goal links.
## Linked Issues or Issue Description
**What happened?**
`POST /companies/:companyId/projects` with a `goalIds` entry that does
not exist fails with an internal error: `insert or update on table
"projects" violates foreign key constraint
"projects_goal_id_goals_id_fk"`. The caller sees a 500 and retries. A
goal id that exists but belongs to a different company is accepted and
linked.
**Expected behavior**
The request fails fast with a 422 that names the unknown goal id(s).
Goals from other companies are rejected the same way. Valid links behave
exactly as before.
**Steps to reproduce**
1. Create a company and no goals.
2. `POST /companies/:companyId/projects` with `{ "name": "Rocket",
"goalIds": ["<any-uuid>"] }`.
3. Before this change: 500 from the foreign key. After: 422 naming the
id.
**Deployment mode**
Any; observed on an authenticated public deployment.
## What Changed
- `assertGoalsBelongToCompany` in the project service: one query for the
resolved ids scoped to the company; unknown ids produce `unprocessable`
(422) with the ids in the message and details
- called on create (before the project row insert, so no partial writes)
and on update (scoped to the existing project's company); both `goalIds`
and the legacy `goalId` field flow through the same resolution
- new embedded-Postgres test file: valid link, nonexistent id on create
with no partial insert, legacy field, another company's goal on create,
and a foreign-goal update that leaves existing links unchanged
## Verification
- `pnpm vitest run src/__tests__/project-goal-validation.test.ts` — 5
passed
- adjacent suites (`project-icon-persistence`,
`project-shortname-resolution`, `issue-goal-fallback`,
`project-goal-telemetry-routes`, `heartbeat-referenced-projects`,
`projects-list-archived-routes`) — 35 passed
## Risks
- Low risk. One extra indexed select per create/update that carries goal
ids. Requests that previously 500ed now 422; requests that silently
linked a foreign goal now fail — both are corrections, not regressions.
- Existing rows with foreign links (written before this check) are
untouched; only new writes validate.
## Model Used
Claude Fable 5 (claude-fable-5) via Claude Code, extended thinking with
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 searched GitHub for duplicate or related PRs and linked
them above (none found for goal-id validation)
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes (doc
comments; no user-facing docs affected)
- [x] I have considered and documented any risks above
canary/v2026.903.0-canary.6
|
||
|
|
2177b85eb5 |
fix(server): retry cloud-tenant auth sync once on a dropped DB connection (#12773)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Managed-cloud deployments authenticate tenant requests through trusted headers. The middleware syncs the tenant's user, company, and membership rows on the way through. > - Pooled Postgres endpoints sometimes close an established connection under an in-flight query (pooler recycle, compute suspend). The driver reconnects on the next query, but the statement on the wire fails. > - In this path a single dropped statement fails the whole request with a 500. This happened live on 2026-09-03: the idempotent company bootstrap insert died with `write CONNECTION_CLOSED`. > - This pull request retries the actor resolution exactly once when the error chain carries a postgres.js closed-connection code. The sync is idempotent end to end, so the replay is safe. > - The benefit is that a routine pooler blip no longer fails an authenticated request on the entry path. ## Linked Issues or Issue Description **What happened?** A cloud tenant request hit the trusted-header authentication middleware while the pooled Postgres endpoint closed the connection mid-query. The insert failed with `write CONNECTION_CLOSED <host>:5432` wrapped in a `Failed query: insert into "companies" …` error, and the request failed. **Expected behavior** The driver reconnects on the next query, and every statement in the tenant sync is idempotent (upserts, on-conflict inserts, deletes; the write debounce records only after the full sync succeeds). One in-request retry should absorb the blip and serve the request. Non-transient failures must keep failing fast. **Steps to reproduce** 1. Run an authenticated public deployment against a pooled Postgres endpoint. 2. Have the pooler close the connection while the middleware's tenant sync insert is on the wire. 3. Before this change the request fails with a 500; after it the retry serves the request. **Deployment mode** Authenticated public (managed cloud), external pooled PostgreSQL. ## What Changed - `resolveCloudTenantActor` now delegates to the (unchanged) resolution body through `retryOnTransientDbConnectionError`, which retries exactly once on a transient closed-connection failure - `isTransientDbConnectionError` walks the error `cause` chain (drizzle wraps the driver error) for the postgres.js codes `CONNECTION_CLOSED`, `CONNECTION_ENDED`, `CONNECTION_DESTROYED`; both helpers are exported for tests - New unit test file `cloud-tenant-transient-db-retry.test.ts`: detection matrix (including a `23505` staying non-transient), retry-once-then-succeed, no-retry on non-transient, propagate-on-second-failure ## Verification - `pnpm vitest run src/__tests__/cloud-tenant-transient-db-retry.test.ts` — 5 passed - `pnpm vitest run src/__tests__/cloud-tenant-company-provisioning.test.ts` — 7 passed against embedded Postgres, driving the real resolution path through the new wrapper ## Risks - Low risk. The retry is bounded to one attempt, gated on three explicit driver codes, and wraps an operation that is already idempotent by design. Every other failure propagates unchanged. - A genuinely down database now fails after two attempts instead of one — a few milliseconds of added latency on an already-failing request. ## Model Used Claude Fable 5 (claude-fable-5) via Claude Code, extended thinking with 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 searched GitHub for duplicate or related PRs and linked them above (none found for connection-retry work in this path) - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes (doc comments; no user-facing docs affected) - [x] I have considered and documented any risks above |
||
|
|
9dd6526b47 |
fix(security): harden privileged server boundaries (#12776)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The server controls secrets, host files, outbound requests, and workspace commands > - A red-team review found cases where restricted callers could cross these trust boundaries > - These cases could expose credentials or let untrusted input reach privileged resources > - This pull request applies least-privilege checks at each affected server boundary > - The benefit is safer agent execution without changing the private-instance bootstrap contract ## Linked Issues or Issue Description **What happened?** Several server paths used authorization, redaction, or content-delivery rules that were too broad. Restricted agent keys could obtain company-level operational data. Some adapter and instruction paths could reach server-owned network or file resources without the required owner approval. **Expected behavior** Paperclip must redact credential values, enforce restricted-key scopes, guard outbound network access, prevent same-origin script execution, and reserve host-level file and command controls for authorized operators. **Steps to reproduce** 1. Configure an authenticated development instance at the parent commit. 2. Exercise the affected APIs with a restricted agent key or a non-instance-admin company user. 3. Observe that the parent commit returns privileged data or accepts a privileged operation. 4. Repeat on this branch and observe a redacted response, a safe download, or an HTTP 403 response. **Paperclip version or commit** The findings reproduce from commit `39898ab22` and are fixed by this pull request. **Deployment mode** Authenticated self-hosted server and local development modes. **Installation method** Built from source with pnpm. ## What Changed - Redact generic secret `value` and `token` fields recursively in structured logs. - Classify exact and separator-suffixed `KEY` environment names as secrets in company exports. - Limit restricted self-identity responses and protect company run, log, and secret catalog APIs. - Route HTTP adapter requests through DNS-pinned SSRF protection with exact private-origin allowlisting. - Download HTML, SVG, and other script-capable assets with `nosniff` and a sandbox CSP. - Require instance-admin access for external instruction roots and exports that read them. - Block agent-authenticated host command persistence across supported workspace runtime shapes. - Apply the central runtime-management decision before workspace command controls. - Keep the documented first-user instance-admin claim contract unchanged. - Add regression tests and server-owner configuration documentation. ## Verification - `pnpm -r typecheck` passes. - The Node 24 remediation suite passes with 365 tests. It skips 25 environment-gated tests. - `pnpm build` passes under Node 24. - `git diff --check` passes. - The full local runner reaches known macOS-only general-server harness failures before the serialized route lane. The Linux PR matrix is the authoritative full-suite gate. ## Risks - Restricted agent keys now receive HTTP 403 responses from company-wide run, log, and secret catalog endpoints. - Script-capable assets now download instead of rendering inline. - External instruction roots now require instance-admin access. - Private HTTP adapter endpoints now require an exact origin in `PAPERCLIP_HTTP_ADAPTER_PRIVATE_ENDPOINT_ALLOWLIST`. - Public HTTP adapter endpoints remain enabled. Redirects and metadata or link-local targets remain blocked. - No database migration is required. > 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. The exact serving snapshot and context-window size are not exposed. The model used tool-enabled reasoning, repository access, code execution, and test 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
31a63638ac |
fix(agents): redact plaintext env values in agent read and mutation responses (#9860)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents are configured through `adapterConfig`, whose `env` block
holds the credentials an agent needs to talk to its provider (API keys,
tokens, and similar)
> - Those bindings come in several shapes: a legacy bare string, `{
type: "plain", value }`, and the indirection forms `{ type: "secret_ref"
}` / `{ type: "user_secret_ref" }`
> - Every endpoint that serializes an agent returned `adapterConfig` as
stored, so every `plain` binding was returned verbatim in the API
response
> - That means any caller able to read an agent — including the agent
itself via `GET /api/agents/me` — received live credentials in
plaintext, and those values then propagate into client state, logs, and
network traces
> - The exposure spans three response families that share no common
serializer: the single-agent detail reads, the company agent-list read,
and the create/update/lifecycle routes that echo the stored row straight
back
> - This pull request routes all three through one presenter that
redacts `plain` env bindings, so the leak is closed server-side and
cannot be bypassed by the caller
> - The benefit is that agent credentials stop appearing in API
responses while `secret_ref` indirection continues to work unchanged
## Linked Issues or Issue Description
No public upstream issue exists for this, so the underlying bug is
described inline below following
`.github/ISSUE_TEMPLATE/bug_report.yml`.
**What happened?**
Every endpoint that serializes an agent returned the full plaintext
value of each `adapterConfig.env` entry whose `type` was `"plain"` (and
each legacy bare-string binding). Any actor authorized to read an agent
received that agent's live credentials in the response body. Three
distinct response families were affected:
- **Single-agent reads** — `GET /api/agents/{id}` and `GET
/api/agents/me`, via `buildAgentDetail`.
- **Company agent list** — `GET /api/companies/{companyId}/agents`,
which serializes rows directly and therefore does not inherit any fix
applied to `buildAgentDetail`. Callers that pass the configuration-read
check received unredacted rows for every agent in the company in a
single request, making this the broadest of the three.
- **Mutation responses** — agent create, `PATCH /api/agents/{id}`, and
the `pause` / `resume` / `clear-error` / `approve` / `terminate` routes,
each of which echoes the stored row back to the caller.
**Expected behavior**
Read endpoints should never emit stored plaintext credentials. `plain`
bindings should be replaced with a redaction sentinel before
serialization, while `secret_ref` and `user_secret_ref` bindings — which
contain no secret material — pass through untouched.
**Steps to reproduce**
1. Configure an agent with an `adapterConfig.env` entry such as `{
"OPENAI_API_KEY": { "type": "plain", "value": "sk-example" } }`.
2. Call `GET /api/agents/{id}` (or authenticate as that agent and call
`GET /api/agents/me`).
3. Observe `sk-example` returned verbatim in the response body.
4. Call `GET /api/companies/{companyId}/agents` as a
configuration-reading caller and observe `sk-example` returned verbatim
for that agent alongside every other agent's credentials.
5. Call `PATCH /api/agents/{id}` with any unrelated field (for example
`{ "title": "Renamed" }`) and observe `sk-example` returned verbatim in
the mutation response.
**Paperclip version or commit**
Reproduced on `master` at `f12bb27b`.
**Deployment mode**
Self-hosted / local development server.
## What Changed
- `server/src/redaction.ts`: adds `redactAgentAdapterConfig`, which
rewrites every bare-string or `{ type: "plain", value }` env binding to
`{ type: "plain", value: "***REDACTED***" }` and passes `secret_ref` /
`user_secret_ref` bindings through unchanged. Reuses the existing
`REDACTED_EVENT_VALUE` and `isSecretRefBinding` /
`isUserSecretRefBinding` / `isPlainBinding` helpers — no new
dependencies.
- `server/src/redaction.ts`: `env` is destructured out and sanitized
only by `redactAgentEnvBinding`, while the remaining adapter keys go
through `redactEventPayload`. Previously the already-redacted `env` was
passed back through `sanitizeRecord`, so each binding was processed
twice — safe only because the sentinel is a fixed point of that second
pass. The two paths are now disjoint, making the invariant structural
rather than coincidental.
- `server/src/routes/agents.ts`: `buildAgentDetail` applies
`redactAgentAdapterConfig` before serialization, so `GET
/api/agents/{id}` and `GET /api/agents/me` both redact at the response
layer. Restricted views inherit the same protection.
- `server/src/routes/agents.ts`: adds `redactAgentRowForResponse`, the
single presenter for every response that emits a raw agent row, and
applies it to the company agent-list route and to the create / update /
pause / resume / clear-error / approve / terminate routes. It composes
with `redactForRestrictedAgentView` rather than replacing it: that
helper is an authorization filter (blank the whole config for low-trust
actors), this one is secret hygiene (mask values for every actor scope),
and the two invariants stay independent. `buildAgentDetail` now
delegates to the same presenter instead of inlining the call.
- `server/src/routes/agents.ts`: adds `restoreRedactedAgentEnv` on the
PATCH path so a client that round-trips a redacted detail response back
through `PATCH /api/agents/{id}` does not zero out stored values —
redacted-sentinel entries matching an existing key are restored from
storage.
## Verification
- `pnpm --filter @paperclipai/server exec tsc --noEmit` — clean.
- `pnpm --filter @paperclipai/server exec vitest run
agent-permissions-routes.test.ts` — 57 tests pass.
- Adjacent suites (`redaction`, `agent-adapter-validation-routes`,
`agent-cross-tenant-authz-routes`, `agents-pending-approval-config`,
`agents-service-secret-bindings`, `built-in-agent-routes`,
`plugin-managed-agents`, `agent-skills-routes`) — 8 files, 72 tests
pass, no regressions.
- Both new route tests were confirmed to **fail** with the route changes
reverted and pass with them applied, so they genuinely pin the behaviour
rather than passing incidentally.
Tests added:
- `server/src/__tests__/redaction.test.ts`: covers legacy-string, `{
type: "plain" }`, `secret_ref`, and `user_secret_ref` bindings,
asserting the plaintext value never appears in the serialized result;
plus coverage that non-env adapter keys are still sanitized, that env
binding shapes survive intact, and that configs with no `env` block are
handled.
- `server/src/__tests__/agent-permissions-routes.test.ts`: `GET
/api/agents/{id}` asserts redaction rather than plaintext passthrough;
new `GET /api/agents/me` redaction test across the same binding shapes;
new test asserting the `PATCH` round-trip preserves stored values; new
test asserting the board `GET /api/companies/{companyId}/agents`
response redacts every binding shape; new test asserting a mutation
response redacts rather than echoing the stored plaintext.
No real secret values appear in any test, fixture, or commit message.
## Risks
- **Behavioral change for API consumers.** Any client that read a
plaintext credential out of an agent detail, agent-list, or mutation
response will now receive `***REDACTED***`. This is the intended
security fix, but it is a breaking change for such consumers, which must
move to `secret_ref` indirection.
- **Mutation responses are redacted too.** Callers that previously
relied on a create or update response to echo back the credential they
had just written must now read it from their own request. This is
consistent with the `restoreRedactedAgentEnv` round-trip path, which
already assumes the client holds a redacted copy.
- **Round-trip data loss, mitigated.** A client that GETs an agent and
PATCHes the object straight back would otherwise persist the sentinel
over the real value. `restoreRedactedAgentEnv` restores redacted entries
from storage; the round-trip is covered by a regression test. A PATCH
that *intentionally* sets a value literally equal to the sentinel is not
distinguishable and would be treated as "unchanged" — an acceptable
trade-off given the sentinel is not a plausible credential.
- **No migration.** Stored data is untouched; redaction happens purely
at serialization time, so the change is fully reversible by revert.
- **Overlap with existing PRs** — see the duplicate-search note below.
Maintainers may prefer to consolidate rather than merge this in
isolation.
## Model Used
Claude Opus 4.8 (`claude-opus-4-8`), extended thinking enabled, with
tool use and local test execution.
## Duplicate search
Searching open and closed PRs for prior art surfaced several overlapping
efforts against the same defect. Linking them for maintainer triage — I
am not claiming this PR supersedes them, and consolidation may well be
preferable:
- #9823 — `fix(security): redact adapterConfig secrets on all agent read
endpoints` (closest overlap)
- #8779 — `fix(server): redact agent config secrets in read and mutation
responses`
- #8330 — `fix(server): redact adapterConfig.env for cross-actor agent
reads`
- #4856 — `fix(server): redact adapter env secrets in agent API
responses`
- #4763 — `fix(server): redact adapter_config secrets in agent detail
responses`
- #1839 — `fix: redact secret env vars from agent API responses`
- #4967 — `fix(routines): redact adapterConfig.env in GET
/api/routines/{id}` (same class, routines surface)
## 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 searched the GitHub PR list (open and closed) for similar or
duplicate PRs and linked them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [ ] My branch name describes the change and contains no internal
Paperclip ticket id — **not met**: the branch and title carry an
internal ticket id. Renaming the branch would invalidate this PR; happy
to reopen from a clean branch if maintainers prefer.
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes (no
user-facing docs affected)
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups —
the one P2 (env entries processed twice) is addressed above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Matthew Glover <5413384+glovario@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Andrew Aymeloglu <aaymeloglu@gmail.com>
|
||
|
|
313d6ca115 |
fix(runner): materialize pinned OpenCode binary (#12782)
## Thinking Path > - Paperclip manages AI agents and their provider runtimes. > - Paid runner validation installs target dependencies with lifecycle scripts disabled. > - OpenCode leaves a sentinel executable until its package lifecycle script runs. > - Running arbitrary lifecycle code would weaken the paid-secret boundary. > - This pull request materializes one exact pinned binary before secrets are exposed. > - The benefit is working OpenCode validation without trusting dependency install scripts. ## Linked Issues or Issue Description **What happened?** Every local OpenCode paid cell stopped before provider startup because `pnpm install --ignore-scripts` correctly retained `opencode-ai/bin/opencode.exe` as a sentinel. **Expected behavior** The trusted workflow must make the exact lockfile-pinned OpenCode executable available without running package lifecycle scripts. **Steps to reproduce** Run a local legacy or native OpenCode paid cell from the trusted workflow after the target dependency install. The provider health check reports that the OpenCode postinstall script was not run. **Paperclip version or commit** Default branch commit `865b4854fb44d3689f1c0ff17e3e715d52aaea73`. ## What Changed - Materialize only `opencode-linux-x64-baseline@1.18.17` into the matching `opencode-ai@1.18.17` package. - Verify package identity, version, regular-file type, SHA-256 equality, executable permissions, and runtime `--version`. - Invoke the helper for local OpenCode and breadth cells and for remote provider-pack assembly. - Retain `pnpm install --ignore-scripts`. - Add helper and trusted-workflow security regressions. ## Verification - Helper syntax checks passed. - Helper unit tests passed: 2/2. - Workflow-security tests passed: 5/5. - Prettier, actionlint, and diff whitespace checks passed. ## Risks Risk is low and contained to paid runner setup. The helper supports only Linux x64, fails closed on package or version drift, and runs before provider credentials enter the job. ## Model Used OpenAI GPT-5 Codex with repository tools and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change. - [x] I have specified the model used. - [x] I have checked ROADMAP.md and confirmed this does not duplicate planned core work. - [x] I have searched GitHub for duplicate or related PRs and found none. - [x] I have described the issue in this PR with the bug template labels. - [x] I have not referenced internal or instance-local issues. - [x] My branch name describes the change. - [x] Focused local tests pass. - [x] I added tests for the change. - [x] I updated the runner E2E security documentation. - [x] I documented the risks above. |