Commit Graph

3322 Commits

Author SHA1 Message Date
Dotta 24aa2f516d
feat(ui): add animated paperclip page loaders (#10456)
## Thinking Path

> - Paperclip is the open source control plane people use to manage AI
agents for work
> - Operators regularly pass through full-page loading states while
authentication and company context resolve
> - Those states currently render as small bare text, which is easy to
miss and does not reinforce Paperclip's visual identity
> - A shared loading component gives these transitions one accessible,
consistent representation
> - This pull request introduces an animated paperclip loader and uses
it at the existing full-page loading boundaries
> - The benefit is a clearer, calmer loading experience with
reduced-motion and screen-reader support

## Linked Issues or Issue Description

### Subsystem affected

`ui/` — React + Vite board UI

### Problem or motivation

Full-page authentication, access-gate, and company-context waits use
small bare `Loading…` text that is visually weak and inconsistent.

### Proposed solution

Use one large centered paperclip loader at those boundaries, drawing the
SVG with `currentColor` so it follows the active theme.

### Alternatives considered

Keeping text-only states or adding a generic spinner would preserve less
of Paperclip's product identity and would continue duplicating loading
markup.

### Roadmap alignment

This is tightly scoped UI polish and does not duplicate a planned
roadmap capability.

### Additional context

Internal coordination task PAP-15760 requested this focused change.

## What Changed

- Added `AnimatedPaperclipIcon`, a theme-aware SVG whose stroke draws in
a loop.
- Added `PaperclipLoading`, a large full-viewport centered loader with
`role="status"` and an `sr-only` `Loading…` label.
- Added a static fully drawn fallback under `prefers-reduced-motion:
reduce`.
- Replaced bare loading text in `CloudAccessGate`, the Auth session
check, and three company-context redirects.
- Used token-safe Tailwind utilities throughout the component.
- Added focused coverage for the status semantics and the Auth layout
height override.

## Verification

- `pnpm check:token-gates`
- `pnpm -C ui exec tsc -b`
- `pnpm -C ui exec vitest run
src/components/AnimatedPaperclipIcon.test.tsx`
- `pnpm -C ui exec vitest run src/App.test.tsx
src/App.cases-routing.test.tsx` — 8/8 tests passed
- Visually checked light and dark loading states; the screenshot below
shows both themes.

![Large centered paperclip loading state in light and dark
themes](https://pages.paperclip.ing/pap-15760-loading-state/pap15760-loading.png)

## Risks

- Low risk: this changes presentation only at existing loading branches.
- Motion-sensitive users receive a static, fully drawn paperclip through
the reduced-motion media query.
- Screen readers retain a concise loading announcement through the
status role and visually hidden label.

> 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 (exact service build ID and context-window size
are not exposed in this environment), with reasoning, repository
inspection, shell tool use, code execution, and image inspection.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used with all deployment details
available to this environment
- [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 found none
- [x] I have described the issue in-PR following the feature-request
fields
- [x] I included the task-mandated internal parent reference and no
private instance URL
- [x] I preserved the task-mandated existing branch name without
renaming it
- [x] I have run scoped tests locally and they pass
- [x] I added focused component coverage for the new loading state
- [x] No documentation update is required for this presentation-only
change
- [x] I have considered and documented the 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>
2026-07-29 17:58:50 -07:00
Nicky Leach a93a74f91a
feat(server): surface referenced-project sync warnings and enable multi-project sync by default (#10473)
## Thinking Path

> - Paperclip helps people manage AI agent work for a company
> - Workspace sync must keep one primary path and any referenced project
paths in step
> - A partial sync must not fail in silence
> - Operators also need a clear signal when the feature uses the new
default path
> - This pull request surfaces referenced-project warnings on the run
and turns the feature flag default on
> - The benefit is better visibility and a live multi-project sync path
by default

## Linked Issues or Issue Description

This pull request completes the multi-project workspace sync go-live
work.

Related pull requests:

- Refs: #10380
- Refs: #10448
- Refs: #10469

## What Changed

- Surface referenced-project warnings on the run when a project drops
during authorization or resolution.
- Record a structured failure reason for each dropped referenced
project.
- Emit one structured log line at run preparation with the requested
count, the synced count, and the failure reasons.
- Flip the workspace sync kill-switch default to on when the env value
is unset.
- Keep the primary workspace path unchanged.

## Verification

- `tsc --noEmit` passed in the server package.
- `heartbeat-referenced-projects.test.ts` and
`heartbeat-project-env.test.ts` passed.
- `workspace-runtime.test.ts` passed.
- `adapter-utils` runtime tests passed for sandbox, command, remote, and
file sync paths.

## Risks

- The new default can expose the feature to more runs if an operator
does not set the env override.
- The new surfaced warnings can change operator visible run output.
- The structured log line can add noise if a run has many referenced
project failures.

## Model Used

- OpenAI Codex, GPT-5, tool use, large 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 linked existing issues with `Fixes: #` / `Closes #`
/ `Refs #` or described the issue in-PR following the relevant issue
template
- [x] I have not referenced internal or instance-local Paperclip issues
or links
- [x] My branch name describes the change 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>
2026-07-29 17:12:22 -07:00
Nicky Leach 6a267e0328
feat(sandbox): stage referenced projects into the run sandbox (#10469)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Runs can reference more than one project
> - Each referenced project must land in its own sandbox tree so one run
does not mix files across projects
> - The anchor workspace must keep its own git history and overlay rules
> - Fail closed on sync and confinement errors, and keep the other
projects alive
> - This pull request stages referenced projects into isolated project
directories under the run sandbox root
> - The benefit is safer multi-project runs with clear failure isolation

## Linked Issues or Issue Description

No public issue exists.

Related PR: #10448.

## What Changed

- Thread additional referenced-project sources through the run prepare
path and the runtime layers.
- Stage each referenced project into its own `project-<projectId>`
directory under the runtime root.
- Keep the anchor workspace history and overlay semantics unchanged.
- Fail closed on confinement or sync errors for one project, and keep
the other projects running.
- Keep the path inert by default behind the multi-project workspace-sync
kill-switch.
- No documentation update was needed for this code-only runtime change.

## Verification

- `pnpm --filter @paperclipai/adapter-utils exec vitest run
src/sandbox-file-sync.test.ts src/command-managed-runtime.test.ts
src/sandbox-managed-runtime.test.ts src/remote-managed-runtime.test.ts`
- `pnpm --filter @paperclipai/adapter-utils exec tsc --noEmit`
- The branch points at `871378e4064a95adc8e4647e442ec1359768de61` on
`origin/feat/stage-referenced-projects-into-sandbox`.
- GitHub CI is green on PR #10469.

## Risks

- A referenced project can skip if confinement or sync fails.
- A new runtime tree layout can affect tools that assume one project
root.
- The kill-switch keeps the path inert until operators enable it.

## Model Used

OpenAI Codex, GPT-5, tool use enabled.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have 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 or
confirmed no docs update was needed
- [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>
2026-07-29 16:09:57 -07:00
Devin Foley 5c5366d0c1
fix(server): honor explicit plugin RPC timeouts (#10460)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Plugin workers connect Paperclip to external runtimes and sandbox
providers.
> - Some adapter heartbeats run a full sandbox session inside one
`environmentExecute` RPC.
> - The worker manager limited every RPC timeout to 15 minutes, even
when the caller gave a longer timeout.
> - This pull request keeps the normal default timeout behavior but
honors explicit caller timeouts.
> - The benefit is that long sandboxed agent sessions can continue past
15 minutes while other safety guards still bound hung work.

## Linked Issues or Issue Description

No public GitHub issue exists for this bug.

### Bug Report

Pre-submission checklist:
- Searched existing open and closed issues and did not find a duplicate.
- Confirmed the bug is reproducible on `master` from the current source
tree.
- Confirmed the error starts in Paperclip timeout handling, not in an
adapter provider or local configuration.

What happened?
- A sandbox-backed adapter heartbeat can run a full agent session inside
one `environmentExecute` plugin RPC.
- The plugin worker manager capped every RPC timeout at 15 minutes.
- The cap also applied when the caller passed a longer explicit timeout
for an execute-style call.
- A long sandbox command could fail before the adapter budget expired.

Expected behavior:
- Ordinary plugin RPC calls should keep the normal 30-second default
timeout.
- The default timeout path should still have a 15-minute maximum.
- A caller-supplied positive finite timeout should be honored, including
values above 15 minutes.

Steps to reproduce:
1. Use a plugin environment driver that calls `environmentExecute` with
an explicit timeout above 15 minutes.
2. Run a command that stays active longer than 15 minutes and remains
inside the adapter budget.
3. Observe that the worker manager times out the RPC at 15 minutes
before this fix.
4. Run the same path after this fix and observe that the explicit
timeout is used.

Paperclip version or commit:
- Reproduced from the current `master` line before this change.

Deployment mode:
- Local dev or self-hosted server with sandbox-backed execution.

Installation method:
- Built from source.

Agent adapter(s) involved:
- Codex.
- Custom or external plugin adapter.
- Core plugin worker timeout handling.

Database mode:
- Not database-related.

Access context:
- Agent execution context.

Node.js version:
- Not version-specific.

Operating system:
- Not OS-specific.

Relevant logs or output:
```shell
RPC call "environmentExecute" timed out after 900000ms
```

Relevant config:
- Not config-related.

Additional context:
- Execute-style sandbox calls already have adapter inactivity monitors,
platform silent-run checks, and provider command timeouts. This PR
removes the unintended worker-manager clamp only for explicit positive
finite caller timeouts.

Privacy checklist:
- Reviewed all pasted output for PII, user paths, API keys, tokens,
company names, and internal instance links.

Duplicate search:
- Searched open PRs and open issues in `paperclipai/paperclip` for
`environmentExecute timeout`, `MAX_RPC_TIMEOUT_MS`, and
`plugin-worker-manager timeout`.
- Searched the same terms in `HenkDz/paperclip`.
- Found no matching open PRs or issues.
- Compared this patch-id against my open PRs in `paperclipai/paperclip`;
no match was found.

## What Changed

- Added `resolveRpcCallTimeoutMs()` to keep explicit positive finite
timeouts intact.
- Kept the 15-minute maximum only for the default timeout path.
- Updated `callInternal()` to use the new resolver.
- Added unit tests for explicit long timeouts, default timeout clamping,
fractional values, and invalid explicit values.
- Clarified why notification invocation scopes still use the 15-minute
TTL.

## Verification

- `corepack pnpm install --frozen-lockfile`
- `corepack pnpm --filter @paperclipai/plugin-sdk ensure-build-deps`
- `corepack pnpm --filter @paperclipai/server exec vitest run
src/__tests__/plugin-worker-manager.test.ts`
- `corepack pnpm --filter @paperclipai/server exec tsc --noEmit`
- `git diff --check 9574cad3e8 HEAD`
- GitHub PR checks on `bf7bfd0d`: all passing; Storybook visual
regression skipped by workflow.
- Greptile on `bf7bfd0d`: 5/5, no blocking failure remains; prior P2
thread resolved.

## Risks

Low risk. The change affects RPC timeout resolution in the plugin worker
manager. Ordinary plugin calls still use the 30-second default and the
default path is still capped at 15 minutes. Callers that pass explicit
long timeouts now own that budget. Adapter inactivity monitors and
platform silent-run safety checks still bound hung runs.

## Model Used

OpenAI Codex, GPT-5-based coding agent, with shell and GitHub CLI tool
use.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have 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>
2026-07-29 14:27:23 -07:00
Nicky Leach 15ce70dc18
feat(server): thread plural referenced-project workspaces through run prep (#10448)
## Thinking Path

> - Paperclip coordinates work for autonomous companies.
> - A run needs a workspace view before execution starts.
> - That view now needs to cover one anchor project and more referenced
projects.
> - Those extra workspaces must stay separate and must not change the
anchor path when the feature stays off.
> - This PR threads plural workspace data through run prep behind a
default-off kill switch.
> - It also keeps extra project workspaces isolated and makes the
realization contract round-trip the new shape.
> - The benefit is safer run prep for referenced projects without
changing the current default path.

## Linked Issues or Issue Description

This PR does not link a public GitHub issue.
It follows the internal run-prep task for plural referenced-project
workspaces.

Problem:
- Run prep resolves the anchor project today, but it does not yet carry
each referenced project into the run workspace view.
- That gap blocks runs that need a second repo or sibling project during
preparation.

Proposed solution:
- Thread a plural workspace result through run prep.
- Keep the anchor path unchanged when the kill switch is off.
- Resolve each referenced project into its own managed checkout
directory when the flag is on.

Alternatives considered:
- Keep one shared workspace and layer the extra repos into it. Rejected
because it would blur isolation and make failures harder to bound.
- Upload the extra workspaces immediately. Rejected because this PR only
prepares the data path.

Roadmap alignment:
- This change sits in the workspace and sandbox path.
- It matches the roadmap work on workspace strategy and cloud or sandbox
agents.

## What Changed

- Added `additionalWorkspaces[]` to the run workspace result.
- Split workspace resolution into an anchor path and an optional
referenced-project path behind `PAPERCLIP_MULTI_PROJECT_WORKSPACE_SYNC`.
- Kept per-project failure isolation so one bad clone does not stop the
run.
- Keyed managed workspace directories by `projectId` so sibling
workspaces stay separate.
- Added `additionalSources[]` to the workspace realization request and
kept read and write paths backward compatible.
- Added tests for the anchor-only path, the new workspace shape, and the
per-project directory rule.

## Verification

- `pnpm --filter @paperclipai/server run typecheck`
- `pnpm --filter @paperclipai/shared run typecheck`
- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/heartbeat-project-env.test.ts` 21/21
- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/workspace-runtime.test.ts` 98/98

## Risks

Low risk. The new path stays behind a default-off kill switch, so the
anchor flow does not change when the flag is off.
The main risk is a bad referenced project clone. That case now drops
only the affected project and keeps the run alive.
The shared type change also needs every consumer to use the new array
field where extra workspaces matter.

## Model Used

OpenAI Codex (GPT-5; exact internal model ID not exposed in this
environment; tool use enabled)

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have 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>
2026-07-29 14:27:05 -07:00
Nicky Leach d51f42ed64
test(server): drain heartbeat runs to quiescence in sibling suite teardown (#10464)
## Thinking Path

> - Paperclip uses heartbeats to run work.
> - Test suites share heartbeat run state during teardown.
> - Late heartbeat work can race shared table deletes.
> - That race can deadlock or fail foreign key checks.
> - The primary suite already uses a drain helper to wait for
quiescence.
> - This pull request reuses that helper in the sibling suites that
share the race.
> - The benefit is stable teardown and fewer flake failures.

## Linked Issues or Issue Description

No public GitHub issue exists for this change.
Refs: #10450
This pull request reuses the quiescence drain from the primary suite.

## What Changed

- Added `server/src/__tests__/helpers/drain-heartbeat-runs.ts`.
- Reused the shared helper in `low-trust-red-team-routes.test.ts`.
- Applied the drain to the eight sibling suites that share the race.
- Kept the existing test intent unchanged.

## Verification

- `git log --oneline
origin/master..origin/test/heartbeat-teardown-quiescence-drain-sweep`
- `git diff --stat
origin/master...origin/test/heartbeat-teardown-quiescence-drain-sweep`
- Existing local test evidence in the handoff shows the primary suite
and the guarded suites pass.
- The handoff also records a stress loop with no `40P01` or `23503`
errors.

## Risks

- Low risk. The change touches test teardown only.
- The helper waits for active runs to drain. A new real background
execution path may need the same guard.

## Model Used

OpenAI GPT-5, 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 linked existing issues with `Fixes: #` / `Closes #`
/ `Refs #` or described the issue in-PR following the relevant issue
template
- [x] I have not referenced internal or instance-local Paperclip issues
or links
- [x] My branch name describes the change 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, or no
docs update was required for this test-only change
- [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>
2026-07-29 14:23:12 -07:00
Nicky Leach 7083c275c8
refactor(sandbox): retire the dead noProfile flag from the exec path (#10461)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The sandbox exec path starts agent commands and passes runtime
options to the server and plugin layers
> - This path kept a noProfile flag after the exec wrappers stopped
sourcing a login profile
> - The flag no longer changed behavior, so it left dead API surface in
the protocol and runtime helpers
> - This pull request removes that dead flag from the plugin protocol,
the server drivers, and the managed-runtime helpers
> - It also updates the tests and points the agent runtime README at the
sandbox requirements file
> - The benefit is a smaller and clearer exec-path contract with no
behavior change

## Linked Issues or Issue Description

- No public GitHub issue exists.

### What happened?

The sandbox exec path kept a `noProfile` field after the exec wrappers
stopped sourcing a login profile.

### Expected behavior

The plugin protocol, server drivers, and managed-runtime helpers should
not expose or forward a dead field.

### Steps to reproduce

1. Run a managed-runtime command through the sandbox exec path.
2. Inspect the protocol payload and runtime helper inputs.
3. Observe that `noProfile` is present even though it no longer changes
behavior.

### Paperclip version or commit

`60c7da86fc7a6c1dbf37bbcd86e25ecaaff01607`

### Deployment mode

Built from source (pnpm dev / pnpm build)

### Additional context

This pull request removes the dead field, updates the affected tests,
and updates the README note for the sandbox profile path.

## What Changed

- Removed noProfile from the plugin protocol and the server exec-path
call sites.
- Updated the managed-runtime helpers to use the narrower exec-path
contract.
- Updated the affected tests and added the README pointer to
SANDBOX-REQUIREMENTS.md.

## Verification

- `git grep -n "noProfile" -- packages/ server/` returns zero matches.
- `tsc --noEmit` passed for `@paperclipai/adapter-utils`,
`@paperclipai/plugin-sdk`, and `@paperclipai/server`.
- `command-managed-runtime.test.ts` passed: 22/22.
- `environment-runtime.test.ts` passed: 24/24.

## Risks

- Low risk. The flag was already a no-op.
- A hidden external caller may still send the removed field.

## Model Used

- OpenAI GPT-5, tool-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>
2026-07-29 14:21:57 -07:00
Devin Foley 7a5a217d60
fix(server): gate sandbox/ssh execution targets by shared remote-managed adapter capability (#10459)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Paperclip can run an agent in a remote-managed environment, such as
a sandbox provider or an SSH host.
> - The server resolves an execution target for each run. The resolver
kept its own hardcoded list of allowed adapters.
> - The shared capability metadata in
`packages/shared/src/environment-support.ts` already defines which
adapters support remote-managed environments. The environment selector
and the capabilities API use it.
> - The two lists drifted. The UI offered sandbox environments to Grok
Build (`grok_local`) agents, but the resolver refused them at run time.
> - This pull request makes the resolver use the shared capability check
for both the sandbox gate and the SSH gate.
> - The benefit is one source of truth. The UI and the runtime now agree
on which adapters can use remote-managed environments.

## Linked Issues or Issue Description

No public GitHub issue exists for this bug. Inline description per the
bug report template:

**What happened?**

A Grok Build (`grok_local`) agent was assigned a sandbox environment (a
Daytona provider). The UI allowed the assignment. Every run and
primary-model test then failed with the warning: `Adapter "grok_local"
is not allowed in "<environment>" environments.`

**Expected behavior**

An adapter that the environment selector offers for a sandbox
environment must also pass the runtime gate. The Grok Build run must
start in the sandbox.

**Steps to reproduce**

1. Create a sandbox environment (for example, with a Daytona provider
plugin).
2. Create an agent that uses the `grok_local` adapter.
3. Set the agent's environment to the sandbox environment. The UI
accepts this.
4. Run the agent, or run the primary-model test. The run fails with the
adapter-not-allowed warning.

**Paperclip version or commit**

Reproduced on `master` at `0edb742f8d`.

**Deployment mode**

Local instance with a remote sandbox provider plugin. The same gate also
applies to SSH environments.

## What Changed

- `resolveEnvironmentExecutionTarget` in
`server/src/services/environment-execution-target.ts` now gates the
sandbox path with the shared
`adapterSupportsRemoteManagedEnvironments()` helper. Before, it used a
hardcoded six-adapter list that did not include `grok_local`.
- The SSH path in the same file now uses the same shared helper.
- New regression tests in
`server/src/__tests__/environment-execution-target.test.ts`: sandbox
target resolution for every remote-managed adapter (including
`grok_local`), SSH target resolution for `grok_local`, and the null path
for an adapter without remote-managed support.

## Verification

- Run `node_modules/.bin/vitest run
server/src/__tests__/environment-execution-target.test.ts`. All 10 tests
pass, including the 3 new ones.
- Confirm `grok_local` is in the `REMOTE_MANAGED_ADAPTERS` set in
`packages/shared/src/environment-support.ts`. The resolver now reads the
same set.
- On a live local instance with this fix, a `grok_local` agent assigned
to a Daytona sandbox environment no longer produces the
adapter-not-allowed warning.

## Risks

Low risk. The change routes two hardcoded checks through existing shared
capability metadata. Behavior changes only where the lists had drifted:
`grok_local`, and any future adapter added to the shared set, can now
resolve sandbox and SSH execution targets. Adapters outside the shared
set still return `null`.

## Model Used

Claude Fable 5 (`claude-fable-5`) by Anthropic, with extended thinking
and tool use, running in 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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-29 12:59:51 -07:00
Devin Foley 78f8c6c3d4
Recover managed bundled plugin workers on demand (#10429)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Managed deployments can auto-provision bundled sandbox-provider
plugins so cloud or remote execution environments appear in the board UI
> - In a multi-service deployment, several server processes can share
one database and boot concurrently
> - A sibling process can create a bundled plugin row while the web
process sees it before it reaches `ready`
> - The web process correctly avoids clobbering the existing row, but
its startup `loadAll()` can miss the plugin and never start that worker
locally
> - The environments capabilities route then filters out the sandbox
provider because the plugin is ready in the database but not running in
the web process
> - This pull request adds a narrow managed-bundle recovery path that
lazily starts the missing worker when the capabilities route sees a
ready managed bundled plugin
> - The benefit is that the sandbox provider becomes visible after the
install finishes, without requiring a web-process restart

## Linked Issues or Issue Description

- No public GitHub issue found for this exact deployment race.
- Related broad plugin runtime context: Refs #432.

Bug description:

- What happened: in a managed multi-service deployment with shared
database state and bundled plugin auto-install enabled, the API-serving
process can skip a plugin row while it is still `installed`, run startup
plugin loading before that row becomes `ready`, and then permanently
omit the sandbox provider from environment capabilities.
- Expected behavior: once the managed bundled plugin row reaches
`ready`, the API-serving process should be able to start the plugin
worker and include its sandbox provider without a restart.
- Steps to reproduce: boot a web process and a sibling worker process
concurrently; have the sibling create the bundled plugin row and
transition it to `ready` after the web process has already skipped
auto-install and run `loadAll()`.
- Deployment mode: managed multi-service deployment with shared database
state and `plugins.autoInstall` configured.

## What Changed

- Added a managed bundled plugin worker recovery helper that
single-flights lazy `loadSingle()` starts and only allows configured
managed bundled plugin keys.
- Passed the managed recovery hook into the environments capabilities
route.
- Updated `listReadyPluginEnvironmentDrivers()` to attempt bounded
recovery for ready managed bundled plugins whose worker is missing in
the current process, and only for plugins that actually declare a
`sandbox_provider` environment driver.
- Made request-time recovery use `loadSingle(id, { markErrorOnFailure:
false })` so a local activation failure in one process never transitions
the shared plugin row to `error` (a sibling process may be running the
plugin successfully).
- When error writes are suppressed and activation fails after the worker
was spawned, the loader now tears down the partially-registered local
runtime (scheduler registration, event subscriptions, agent tools,
worker process) instead of leaving a half-activated worker lingering;
the teardown steps are factored out of `unloadSingle()` into a shared
helper.
- A failed recovery attempt now discards the crashed/stopped handle it
left registered in the worker manager (a worker that dies during
initialize is killed without a scheduled restart), so later capability
requests can retry recovery instead of being blocked by the
handle-presence gate until a process restart. Handles in
starting/running/backoff states are left to the worker manager's own
lifecycle; recovery only ever starts when no handle existed, so no
pre-existing worker can be affected.
- Added a regression test suite covering the installed-to-ready race,
allowlist behavior, the driver-kind gate, existing worker handles,
concurrent single-flight recovery, bounded slow recovery attempts,
suppressed shared error-state writes, partial-runtime teardown on late
activation failure, and retry after a dead handle is discarded.

## Verification

- `pnpm vitest run
src/__tests__/plugin-environment-driver-ready-recovery.test.ts` (in
`server/`) passed: 10 tests.
- `pnpm --filter @paperclipai/server typecheck` passed.

## Risks

- Low risk for self-hosted single-process deployments because lazy
recovery is only wired when managed plugin auto-install config is
present; with no managed config the capabilities route takes the exact
pre-change code path.
- The capabilities route can wait briefly while attempting recovery; the
attempt is bounded and defaults to 2 seconds.
- Failed recovery keeps the prior behavior of omitting the provider
until a later successful worker start, and now also cleans up any
partially-started local worker so retries begin from a clean slate.

## Model Used

- Initial implementation: OpenAI GPT-5 via Codex local coding agent,
with repository tool use and command execution.
- Review-feedback follow-ups (driver-kind gate, partial-runtime
teardown, expanded regression tests): Claude Fable 5 (claude-fable-5)
via Claude Code, with repository tool use and command 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>
2026-07-29 12:50:16 -07:00
Nicky Leach d6e235cbcf
perf(sandbox-providers): drop nvm sourcing from exec wrappers (#10443)
## Thinking Path

> - Paperclip keeps agent work on a controlled execution plane.
> - Sandbox exec wrappers run on the hot path for agent commands.
> - The current change removes the explicit `nvm.sh` load step from
those wrappers.
> - The sandbox image already restores PATH through profile startup.
> - This pull request keeps profile sourcing where the wrapper still
needs it and drops only the `nvm.sh` load step.
> - The result is a smaller command path with the same node and agent
CLI resolution.

## Linked Issues or Issue Description

No public GitHub issue exists for this change.

Problem:
The sandbox exec wrappers spent extra time sourcing `nvm.sh` before each
command.
The sandbox image already restores PATH in
`/etc/profile.d/00-restore-env.sh`, so that explicit `nvm.sh` work was
redundant.

Proposed solution:
Remove the `nvm.sh` source step from all six wrappers.
Keep the profile sourcing that the provider still needs for PATH setup.

Alternatives considered:
Keep the existing shell setup and accept the launch cost.
That keeps the current behavior, but it leaves the hot path slower than
needed.

Roadmap alignment:
This change keeps the sandbox command path small and predictable.
It does not change the adapter contract or the node resolution rules.

## What Changed

- Removed `nvm.sh` sourcing from all six sandbox exec wrappers.
- Kept profile sourcing where the provider still needs it for PATH
setup.
- Switched Modal to a non-login shell because the script now sources
profiles itself.
- Updated wrapper tests to assert that built commands do not source
`nvm.sh`.

## Verification

- Local TypeScript typecheck passed in each changed package.
- Focused provider tests passed for Daytona, E2B, Modal, exe-dev,
Cloudflare bridge, and adapter-utils.
- One Daytona test failure is pre-existing and unrelated to this change.

## Risks

- This change alters shell startup for sandbox exec paths.
- A provider that depends on implicit shell setup may need a follow-up.
- The current tests cover command shape, but they do not cover every
runtime shell path.

## Model Used

OpenAI Codex, GPT-5, 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
- [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 or instance-local Paperclip issues
or links
- [x] My branch name describes the change 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>
2026-07-29 12:40:16 -07:00
Devin Foley 4c8d92f086
fix(ui): leave agent detail after termination (#10451)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The agent detail page lets operators inspect one agent and run
lifecycle actions from that context
> - Terminated agents are removed from the normal active-agent surface,
so the current detail route may no longer be fetchable after termination
> - Before this change, terminating an agent from its detail page
invalidated agent queries while leaving the browser on the now-stale
detail route
> - That refetch could surface an "Agent not found" error even though
the terminate action itself succeeded
> - The shared action button already owns the terminate mutation, so it
can notify detail-page callers when termination succeeds
> - This pull request redirects the detail page back to the agents list
after a successful terminate action
> - The benefit is that operators land on a valid route and the Back
button does not return them to the stale terminated-agent detail route

## Linked Issues or Issue Description

No direct public GitHub issue or PR was found for this detail-page
termination flow.

### What happened?

After terminating an agent from its detail page, the UI could remain on
that agent's detail route and show an "Agent not found" error after
query invalidation/refetch.

### Expected behavior

Once termination succeeds, the operator should leave the now-stale
detail page and land on a valid agents view.

### Steps to reproduce

1. Open a non-built-in agent detail page.
2. Use the overflow actions menu to terminate the agent.
3. Observe the post-termination route/error state.

### Paperclip version or commit

Current `master` before this PR.

### Deployment mode

Browser UI behavior, independent of a specific deployment mode.

Duplicate search: searched public GitHub issues and PRs for `agent not
found terminate`, `terminate agent detail`, and `Agent not found`; no
direct duplicate or viable in-flight PR was found.

## What Changed

- Added an optional `onTerminateSuccess` callback to
`AgentActionButtons`, fired only after the shared terminate mutation
succeeds.
- Wired `AgentDetail` to replace-navigate to `/agents/all` after
successful termination.
- Extended `AgentActionButtons` coverage for the terminate success path,
including API args, callback payload, and query invalidations.

## Verification

- `corepack pnpm exec vitest run
ui/src/components/AgentActionButtons.test.tsx`
- `corepack pnpm check:token-gates`
- `git diff --check origin/master..HEAD`
- Local diff scan for obvious tokens, credential filenames, and email
addresses found no matches.

## Risks

Low risk. The new callback is optional, only fires for successful
terminate actions, and preserves existing behavior for other
`AgentActionButtons` callers.

## Model Used

OpenAI Codex, GPT-5-based coding agent (`gpt-5`), tool use enabled for
repository inspection, editing, local verification, and GitHub CLI
operations. Context window details were 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>
2026-07-29 12:26:07 -07:00
Nicky Leach 9574cad3e8
test(server): drain heartbeat runs to quiescence before low-trust teardown (#10450)
## Thinking Path

> - Paperclip manages AI work through tasks, comments, and heartbeats
> - A heartbeat wake can register after a test body ends
> - The low-trust red-team route suite tears down data while that wake
can still run
> - Teardown can then lock `issues` and `heartbeat_runs` in opposite
order and deadlock
> - This pull request adds a drain that waits for heartbeat runs to
reach quiescence before teardown
> - The benefit is stable test teardown without removing coverage

## Linked Issues or Issue Description

The serialized low-trust red-team route suite can deadlock in
`afterEach` teardown.
A heartbeat wake can register after the test body ends.
Teardown can then delete `heartbeat_runs` while the wake still writes
issue tables.
This change waits until no run is queued or running before any delete.

## What Changed

- Added `drainHeartbeatRunsToQuiescence` for test teardown.
- Called the drain first in the low-trust red-team route suite
`afterEach` path.
- Kept the change test-teardown only.

## Verification

- The author handoff reports `tsc -p server/tsconfig.json --noEmit` as
clean.
- The author handoff reports 60 of 60 stress-loop runs with zero
deadlocks.
- `pnpm --filter @paperclipai/server typecheck` could not run here
because this workspace lacks `node_modules/typescript/bin/tsc`.

## Risks

- Low risk.
- The change only affects test teardown.
- If a wake never reaches registration, the drain can wait longer than
expected.
- The loop re-checks the run table until no run is queued or running.

## Model Used

OpenAI GPT-5, tool-use, 256k context.

## Checklist

- [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 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>
2026-07-29 12:05:13 -07:00
Dotta 2dca2df71f
docs: require Simplified Technical English for PR text (#10447)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Many contributors are AI agents, and they write the pull request
text.
> - PR descriptions vary in clarity, and long or ambiguous prose slows
down review.
> - Simplified Technical English (ASD-STE100) is a controlled language
that makes technical text short, clear, and unambiguous.
> - This pull request adds one line to `CONTRIBUTING.md` and one line to
the pull request template. Both lines instruct the author to write PR
text in Simplified Technical English (ASD-STE100).
> - The benefit is clearer, faster-to-review pull request descriptions.

## Linked Issues or Issue Description

No related GitHub issue exists. This is a small documentation change. It
sets a writing-style rule for pull request text: authors must use
Simplified Technical English (ASD-STE100).

## What Changed

- Add one line to `CONTRIBUTING.md` (in "Writing a Good PR message")
that requires Simplified Technical English (ASD-STE100).
- Add one comment line to `.github/PULL_REQUEST_TEMPLATE.md` that gives
the same instruction to PR authors.

## Verification

- Read the two changed files. Confirm each new line is present and
correct.
- `git diff --stat origin/master` shows only the two files, with 4
inserted lines.

## Risks

Low risk. The change is documentation only. It adds guidance text and
does not change code or behavior.

## Model Used

Claude Opus 4.8 (claude-opus-4-8), 1M context window, extended thinking,
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
- [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
- [ ] 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

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 13:50:15 -05:00
Dotta 1452d5f413
perf(ui): warm issue detail navigation (#10416)
## Thinking Path

> - Paperclip is the open source control plane people use to coordinate
AI-agent companies
> - The board UI opens issue details from lists, quicklooks, and the
inbox
> - Those navigation paths already have enough issue data to paint the
header immediately, but the comment feed still waits for its first
request
> - That delay makes repeat navigation feel cold and can briefly show an
empty thread before comments arrive
> - This pull request centralizes the comment page shape, prefetches
issue detail plus the first comment page, and renders a reserved
skeleton while an uncached page is loading
> - The benefit is faster, stable warm navigation without coupling this
change to the separate aggregate issue-detail API work

## Linked Issues or Issue Description

- **Subsystem affected:** `ui/` — React + Vite board UI
- **Problem or motivation:** Opening an issue from an already-loaded
list still waits for the first comments request and may flash the
empty-thread state, making warm navigation feel slower than necessary.
- **Proposed solution:** Prefetch the issue-detail snapshot and first
comments page from every issue navigation entry point, reuse one
page-size constant for prefetch and render queries, and show the
existing chat skeleton until the uncached initial page resolves.
- **Alternatives considered:** Relying only on detail-query prefetch
leaves comments cold; bundling this with the aggregate issue-detail
endpoint would make the UI improvement harder to review and land
independently.
- **Roadmap alignment:** `ROADMAP.md` has no overlapping
issue-navigation initiative. This is a focused board responsiveness
improvement.
- **Related pull requests:** #10409 establishes the issue-detail
performance baseline; #10414 reduces server-side issue-detail request
overhead.

## What Changed

- Added one shared issue-comment page-size constant used by rendering
and prefetching.
- Added first-page comment prefetching and a combined navigation
prefetch helper.
- Wired quicklook, issue-list keyboard navigation, and inbox navigation
to warm both caches.
- Kept the existing chat skeleton visible while the first uncached
comment page loads.
- Added focused cache behavior tests for comment and combined navigation
prefetching.

## Verification

- `vitest run ui/src/lib/prefetchIssueComments.test.ts` — 3 tests
passed.
- `tsc -b ui` — passed.
- `pnpm check:token-gates` — passed.

## Risks

- Low risk: this adds background prefetch requests on intentional issue
navigation/hover paths. React Query stale-time deduplication prevents
repeat requests while the cache is fresh.
- The change intentionally remains independent of the separate aggregate
`getView` work and composes with it through the same query keys.

> 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 coding agent, exact model `gpt-5.6-sol`; context-window
size was not exposed; reasoning mode with repository 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>
2026-07-29 13:37:22 -05:00
Dotta 170c1e5adb
fix(claude-local): trust Paperclip URLs in allowlist sandbox (#10438)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Local adapters can confine agent processes with filesystem and
network sandbox policies
> - Allowlist confinement must still let an agent reach Paperclip's own
control plane and managed MCP servers
> - The Codex local adapter already marks those runtime-owned endpoints
as trusted, but the Claude local adapter did not
> - As a result, allowlisted Claude runs could not call their own
Paperclip API unless operators duplicated runtime URLs manually
> - This pull request mirrors the trusted-URL wiring in the Claude local
adapter and adds a regression test at the process-execution boundary
> - The benefit is that confined Claude agents retain their required
control-plane access without broadening the operator-managed network
allowlist

## Linked Issues or Issue Description

Refs #447

No exact public issue was found. The underlying bug is:

- **Observed:** with `claude_local` configured for local-process
`networkScope: "allowlist"`, the sandbox options omitted the
runtime-owned Paperclip API and MCP server URLs. Requests to those
endpoints could therefore be denied by confinement.
- **Expected:** Paperclip's own API URL and managed MCP server URLs are
passed as trusted sandbox targets, matching `codex_local` behavior.
- **Steps to reproduce:** configure a local Claude agent with allowlist
network confinement, omit the runtime Paperclip API URL from the
operator allowlist, and have the agent call its injected
`PAPERCLIP_API_URL`.
- **Version:** `ca92f727c5` (`origin/master` at branch creation).
- **Deployment mode:** local-process sandbox confinement in a local
deployment.

## What Changed

- Added the injected Paperclip API URL and runtime MCP server URLs to
`claude_local` sandbox `networkTrustedUrls`, filtering empty values.
- Added a unit test proving allowlist sandbox construction trusts
`PAPERCLIP_API_URL`.

## Verification

- `pnpm exec vitest run
packages/adapters/claude-local/src/server/execute.acp-fallback.test.ts`
- `pnpm --filter @paperclipai/adapter-claude-local typecheck`

## Risks

- Low risk. The change only affects confined local Claude processes and
trusts runtime-owned endpoints already injected by Paperclip.
- Operator-configured `networkAllowlist` behavior is unchanged; the
added URLs use the sandbox's separate trusted-target path.

> 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 (exact serving snapshot and context-window
size are not exposed), with reasoning, repository inspection, shell tool
use, code 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 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 (not
applicable: behavior parity fix with no user-facing configuration
change)
- [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>
2026-07-29 13:23:09 -05:00
Nicky Leach 0edb742f8d
test(server): relocate referenced-project run-prep tests to a dedicated file (#10446)
## Thinking Path

> - Paperclip keeps server tests that protect run-prep and issue service
behavior
> - The issue service test file now mixes issue service tests with
heartbeat run-prep tests
> - That mix makes the file harder to scan and harder to keep focused
> - The run-prep suites belong with the other heartbeat tests
> - This pull request moves those suites into
`heartbeat-referenced-projects.test.ts`
> - The benefit is a smaller issue service test file and a clearer home
for heartbeat tests

## Linked Issues or Issue Description

This PR has no public GitHub issue. It moves the referenced-project
run-prep suites into a dedicated heartbeat test file. The issue service
test file keeps only issue service tests.

## What Changed

- Moved the `resolveRunReferencedProjects` suite into
`server/src/__tests__/heartbeat-referenced-projects.test.ts`
- Moved the multi-project workspace sync kill-switch test into the same
file
- Left `server/src/__tests__/issues-service.test.ts` with issue service
coverage only

## Verification

- `pnpm exec tsc --noEmit`
- `pnpm exec vitest run
src/__tests__/heartbeat-referenced-projects.test.ts`
- `pnpm exec vitest run src/__tests__/issues-service.test.ts`
- `git log --oneline origin/master..HEAD` shows one commit
- `git diff --stat origin/master...HEAD` shows only the two test files

## Risks

- Low risk. This change moves tests only and does not change product
code.

## Model Used

OpenAI Codex, GPT-5, tool use enabled, local shell 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
- [ ] 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>
2026-07-29 10:22:01 -07:00
Nicky Leach 11273c18d6
feat(server): resolve per-project-authorized referenced-project set for run prep (#10380)
## Thinking Path

> - Paperclip is the control plane for autonomous AI companies
> - Run prep needs to know which referenced projects belong in a run
without breaking company boundaries
> - The anchor project must keep its existing authorization path, while
additional mentioned projects must be checked independently and fail
closed if access is denied or unknown
> - This pull request adds a helper that computes the deduped,
company-scoped referenced-project set for run prep and warns when a
project is rejected
> - It also introduces an off-by-default kill-switch so downstream
consumers can adopt the set safely
> - The benefit is safer multi-project run preparation without widening
access beyond what the run actor is already allowed to read

## Linked Issues or Issue Description

This PR does not rely on a public GitHub issue. The change is
self-contained and follows the feature-request style description below
so reviewers can evaluate it without leaving the PR.

**Problem / motivation**
- Run prep needs to assemble a referenced-project set that includes the
anchor project plus additional @-mentioned projects.
- Additional projects must be authorized independently and rejected
projects must not widen access.
- The result should be safe to merge inertly behind a default-off
kill-switch until downstream consumers opt in.

**Proposed solution**
- Add `resolveRunReferencedProjects(issueId, anchorProjectId, opts)` in
`server/src/services/heartbeat.ts`.
- Compute a deduped company-scoped set with the anchor project first and
additional mentions admitted only after a fail-closed `project:read`
authorization check.
- Drop missing, foreign-company, denied, or errored projects and append
run warnings when they are rejected.
- Keep the feature inert behind a default-off kill-switch until
downstream workspace resolution is wired to consume it.

**Alternatives considered**
- Reusing company membership alone was rejected because it would
over-admit projects and widen access.
- Including all mentioned projects without per-project authorization was
rejected because it would bypass the existing access model.

**Roadmap alignment**
- This is Phase 1 only: the helper is computed but not yet consumed
downstream, so the merge is inert until a later phase turns the flag on.

## What Changed

- Added `resolveRunReferencedProjects(issueId, anchorProjectId, opts)`
in `server/src/services/heartbeat.ts`.
- Enforced company scoping, deduplication, fail-closed authorization,
and warning emission for additional referenced projects.
- Added a configurable cap for the additional referenced-project set.
- Added tests covering allowed, denied, foreign-company, thrown-auth,
dedupe, and overflow cases.
- Added a default-off kill-switch for downstream consumption of the
computed set.

## Verification

- `tsc --noEmit`
- `server/src/__tests__/issues-service.test.ts` now passes 117/117
- `git log --oneline origin/master..HEAD` shows only the expected single
commit on this branch

## Risks

- The new helper is computed but not yet consumed by workspace
resolution, so behavior only changes once downstream code is wired to
it.
- The authorization path for additional referenced projects is stricter
than before, so any unexpected access gap will surface as a dropped
project plus warning.

## Model Used

OpenAI Codex, GPT-5, tool-use enabled, 128k context.

## 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>
2026-07-29 09:48:54 -07:00
dependabot[bot] 5b34d265a4
build(deps): bump @agentclientprotocol/claude-agent-acp from 0.59.0 to 0.63.0 (#10302)
Bumps
[@agentclientprotocol/claude-agent-acp](https://github.com/agentclientprotocol/claude-agent-acp)
from 0.59.0 to 0.63.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/agentclientprotocol/claude-agent-acp/releases">@​agentclientprotocol/claude-agent-acp's
releases</a>.</em></p>
<blockquote>
<h2>v0.63.0</h2>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.62.0...v0.63.0">0.63.0</a>
(2026-07-27)</h2>
<h3>Features</h3>
<ul>
<li>Update to claude agent sdk v0.3.220 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/921">#921</a>)
(<a
href="4c7b897183">4c7b897</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Only resolve a denied tool call the client was told about (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/923">#923</a>)
(<a
href="8f67b6a92b">8f67b6a</a>),
closes <a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/918">#918</a></li>
<li>Report tool_progress heartbeats against the tool call they describe
(<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/916">#916</a>)
(<a
href="5559ba890c">5559ba8</a>)</li>
<li><strong>tools:</strong> key Bash terminal metas off the announced
tool_use id (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/917">#917</a>)
(<a
href="d0604140f9">d060414</a>)</li>
</ul>
<h2>v0.62.0</h2>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.61.0...v0.62.0">0.62.0</a>
(2026-07-24)</h2>
<h3>Features</h3>
<ul>
<li><strong>deps:</strong> Bump <code>@​hono/node-server</code> from
1.19.14 to 1.19.15 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/908">#908</a>)
(<a
href="51936049e1">5193604</a>)</li>
<li><strong>deps:</strong> Bump media-typer from 1.1.0 to 1.1.1 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/909">#909</a>)
(<a
href="5d35001563">5d35001</a>)</li>
<li><strong>deps:</strong> Bump the minor group with 2 updates (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/900">#900</a>)
(<a
href="809d41c6b7">809d41c</a>)</li>
<li><strong>deps:</strong> Bump the minor group with 2 updates (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/907">#907</a>)
(<a
href="14d06273c0">14d0627</a>)</li>
<li>Update to claude-agent-sdk 0.3.218 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/904">#904</a>)
(<a
href="8cbaf97254">8cbaf97</a>)</li>
</ul>
<h2>v0.61.0</h2>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.60.0...v0.61.0">0.61.0</a>
(2026-07-22)</h2>
<h3>Features</h3>
<ul>
<li><strong>deps:</strong> Bump actions/setup-node from 6.4.0 to 7.0.0
(<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/897">#897</a>)
(<a
href="d9bd36d8b0">d9bd36d</a>)</li>
<li><strong>deps:</strong> Update to
<code>@​anthropic-ai/claude-agent-sdk</code> 0.3.217 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/899">#899</a>)
(<a
href="edf3af043b">edf3af0</a>)</li>
</ul>
<h2>v0.60.0</h2>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.59.0...v0.60.0">0.60.0</a>
(2026-07-20)</h2>
<h3>Features</h3>
<ul>
<li><strong>deps:</strong> Update to claude-agent-sdk 0.3.215 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/890">#890</a>)
(<a
href="92548f0435">92548f0</a>)</li>
<li>implement configurable LLM providers (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/853">#853</a>)
(<a
href="82cd692e50">82cd692</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>parse Agent/Task trailers without regex (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/879">#879</a>)
(<a
href="06c3d7bdbd">06c3d7b</a>)</li>
<li>remove ~15s stall on session/new and model switch by seeding the
context window synchronously (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/894">#894</a>)
(<a
href="ff9b96d462">ff9b96d</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/agentclientprotocol/claude-agent-acp/blob/main/CHANGELOG.md">@​agentclientprotocol/claude-agent-acp's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.62.0...v0.63.0">0.63.0</a>
(2026-07-27)</h2>
<h3>Features</h3>
<ul>
<li>Update to claude agent sdk v0.3.220 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/921">#921</a>)
(<a
href="4c7b897183">4c7b897</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Only resolve a denied tool call the client was told about (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/923">#923</a>)
(<a
href="8f67b6a92b">8f67b6a</a>),
closes <a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/918">#918</a></li>
<li>Report tool_progress heartbeats against the tool call they describe
(<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/916">#916</a>)
(<a
href="5559ba890c">5559ba8</a>)</li>
<li><strong>tools:</strong> key Bash terminal metas off the announced
tool_use id (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/917">#917</a>)
(<a
href="d0604140f9">d060414</a>)</li>
</ul>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.61.0...v0.62.0">0.62.0</a>
(2026-07-24)</h2>
<h3>Features</h3>
<ul>
<li><strong>deps:</strong> Bump <code>@​hono/node-server</code> from
1.19.14 to 1.19.15 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/908">#908</a>)
(<a
href="51936049e1">5193604</a>)</li>
<li><strong>deps:</strong> Bump media-typer from 1.1.0 to 1.1.1 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/909">#909</a>)
(<a
href="5d35001563">5d35001</a>)</li>
<li><strong>deps:</strong> Bump the minor group with 2 updates (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/900">#900</a>)
(<a
href="809d41c6b7">809d41c</a>)</li>
<li><strong>deps:</strong> Bump the minor group with 2 updates (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/907">#907</a>)
(<a
href="14d06273c0">14d0627</a>)</li>
<li>Update to claude-agent-sdk 0.3.218 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/904">#904</a>)
(<a
href="8cbaf97254">8cbaf97</a>)</li>
</ul>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.60.0...v0.61.0">0.61.0</a>
(2026-07-22)</h2>
<h3>Features</h3>
<ul>
<li><strong>deps:</strong> Bump actions/setup-node from 6.4.0 to 7.0.0
(<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/897">#897</a>)
(<a
href="d9bd36d8b0">d9bd36d</a>)</li>
<li><strong>deps:</strong> Update to
<code>@​anthropic-ai/claude-agent-sdk</code> 0.3.217 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/899">#899</a>)
(<a
href="edf3af043b">edf3af0</a>)</li>
</ul>
<h2><a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.59.0...v0.60.0">0.60.0</a>
(2026-07-20)</h2>
<h3>Features</h3>
<ul>
<li><strong>deps:</strong> Update to claude-agent-sdk 0.3.215 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/890">#890</a>)
(<a
href="92548f0435">92548f0</a>)</li>
<li>implement configurable LLM providers (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/853">#853</a>)
(<a
href="82cd692e50">82cd692</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>parse Agent/Task trailers without regex (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/879">#879</a>)
(<a
href="06c3d7bdbd">06c3d7b</a>)</li>
<li>remove ~15s stall on session/new and model switch by seeding the
context window synchronously (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/894">#894</a>)
(<a
href="ff9b96d462">ff9b96d</a>)</li>
<li>Silence missing PostToolUse callbacks (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/895">#895</a>)
(<a
href="1887ada215">1887ada</a>),
closes <a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/889">#889</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="15979bba79"><code>15979bb</code></a>
chore(main): release 0.63.0 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/922">#922</a>)</li>
<li><a
href="8f67b6a92b"><code>8f67b6a</code></a>
fix: Only resolve a denied tool call the client was told about (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/923">#923</a>)</li>
<li><a
href="5559ba890c"><code>5559ba8</code></a>
fix: Report tool_progress heartbeats against the tool call they describe
(<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/916">#916</a>)</li>
<li><a
href="d0604140f9"><code>d060414</code></a>
fix(tools): key Bash terminal metas off the announced tool_use id (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/917">#917</a>)</li>
<li><a
href="4c7b897183"><code>4c7b897</code></a>
feat: Update to claude agent sdk v0.3.220 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/921">#921</a>)</li>
<li><a
href="8663170f18"><code>8663170</code></a>
Add structured Bash titles and nested subagent transcripts (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/881">#881</a>)</li>
<li><a
href="53a0c36ce3"><code>53a0c36</code></a>
chore(main): release 0.62.0 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/901">#901</a>)</li>
<li><a
href="c91f943f86"><code>c91f943</code></a>
<code>@​anthropic-ai/claude-agent-sdk</code> 0.3.218 -&gt; 0.3.219 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/912">#912</a>)</li>
<li><a
href="5d35001563"><code>5d35001</code></a>
feat(deps): Bump media-typer from 1.1.0 to 1.1.1 (<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/909">#909</a>)</li>
<li><a
href="51936049e1"><code>5193604</code></a>
feat(deps): Bump <code>@​hono/node-server</code> from 1.19.14 to 1.19.15
(<a
href="https://redirect.github.com/agentclientprotocol/claude-agent-acp/issues/908">#908</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.59.0...v0.63.0">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-29 09:33:08 -07:00
Nicky Leach ca92f727c5
ci: publish the cloud image in its own parallel job (#10408)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The CI workflow is responsible for producing and publishing the
Docker images that power Paperclip deployments
> - The cloud image publish was previously coupled to the stock publish
job, so a failure or delay in one path could gate the other
> - That coupling makes the release pipeline less resilient than it
needs to be
> - This pull request gives the cloud publish its own top-level job so
both publishes can run in parallel without a `needs:` dependency
> - The benefit is better failure isolation and less wasted time when
one publish path is slow or broken

## Linked Issues or Issue Description

No public GitHub issue was found for this change.

Problem statement:
- The cloud image publish was implemented as trailing work inside the
stock publish job.
- That setup meant the cloud publish could be delayed or skipped if the
stock job failed early.
- The desired behavior is for the cloud publish to run independently so
a failure in one publish path does not gate the other.

Proposed solution:
- Split the cloud publish into its own top-level workflow job.
- Keep the same cloud-specific build settings and cache behavior.
- Preserve the existing top-level concurrency behavior.

Alternatives considered:
- Keeping both publishes in one job with conditionals or later steps.
Rejected because it still couples success and runtime between the two
publish paths.

## What Changed

- Split the cloud image publish into a separate top-level Docker
workflow job.
- Removed the dependency coupling so the cloud job does not need the
stock job.
- Expanded the drift-guard test to assert the two-job structure and the
absence of `needs:` on the cloud job.

## Verification

- The workflow YAML was parsed successfully and confirmed to contain two
jobs: `build-and-push` and `build-and-push-cloud`.
- The cloud job was confirmed to have no `needs:` entry.
- The drift-guard assertions were reproduced in a dependency-free
harness and passed.
- PR #10408 completed GitHub Actions with all required checks green,
including the e2e shards.
- Greptile review completed at 5/5 with no unresolved comments.
- No documentation files changed because this is a workflow/test-only
change.

## Risks

- The workflow now duplicates the prep steps across two runners, so any
shared setup change must be kept in sync between both jobs.
- The new job increases workflow surface area slightly, which can make
future maintenance more verbose.
- Overall risk is low because the change is limited to CI orchestration
and test coverage.

## Model Used

OpenAI Codex (GPT-5, tool-using code assistant)

## 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>
2026-07-28 15:38:01 -07:00
Nicky Leach db02ca7402
ci: keep in-flight docker builds from being cancelled (#10403)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The repository uses GitHub Actions workflows to build and publish
Docker images
> - A workflow-level concurrency policy controls whether newer pushes
cancel in-flight builds
> - The current job-level setting can cancel a running image build
before it finishes publishing
> - That leaves the Docker image pipeline brittle when a new push
arrives during an active publish
> - This pull request moves concurrency to the workflow level and
disables cancel-in-progress so running builds finish
> - The benefit is that only pending work is superseded, while a build
already publishing is allowed to complete

## Linked Issues or Issue Description

No public GitHub issue exists for this change. This PR addresses the
Docker workflow concurrency behavior directly: it ensures in-flight
image builds are not cancelled by newer pushes, while still serializing
builds per ref.

## What Changed

- Moved the Docker workflow concurrency block from the job level to the
workflow level.
- Set `cancel-in-progress: false` so an active build can finish
publishing.
- Added a drift-guard test that parses `.github/workflows/docker.yml`
and asserts the workflow-level concurrency policy remains `false`.

## Verification

- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/cloud-image-bundled-plugins.test.ts`
- `python3 -c "import yaml;
yaml.safe_load(open('.github/workflows/docker.yml'))"`
- Verified the fetched remote branch contains a single commit on top of
`origin/master`.
- Searched GitHub for duplicate or related PRs and issues; none found.
- Checked `ROADMAP.md` and did not find overlapping planned core work.

## Risks

- Low risk: the change is limited to workflow concurrency behavior and a
targeted test assertion.
- If the workflow concurrency key is changed later, the drift-guard test
will fail and require an update.

## Model Used

OpenAI Codex (GPT-5, tool use; context window not surfaced in this
environment)

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have 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] 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>
2026-07-28 15:08:17 -07:00
Michael Nguyen 4eace88f6b
feat(adapter-claude): add Claude Opus 5 to the static model fallback (#10327)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents pick their model from a dropdown in agent config, populated
per-adapter by `listAdapterModels()` → each adapter's live provider
catalog merged over a static fallback list
> - For `claude_local`, newer model ids only reach the dropdown via the
live Anthropic `/v1/models` fetch, which needs a server
`ANTHROPIC_API_KEY`, a <5s round-trip, non-Bedrock mode, and account
entitlement; on any miss it silently falls back to the static `models`
array
> - Claude Opus 5 (`claude-opus-5`) is generally available — Anthropic
lists it as the recommended model for complex agentic coding and
enterprise work — but it was absent from that static fallback, so it
appeared only when live discovery happened to succeed
> - This pull request adds `claude-opus-5` to the `claude_local` static
model list so it is selectable regardless of the live-discovery path
> - The benefit is a consistent, reliable dropdown that surfaces the
current GA Opus flagship without depending on a flaky live fetch

## Linked Issues or Issue Description

No public GitHub issue. The bug is described inline following the
bug-report template:

**What happened**
The `claude_local` agent-config model dropdown omitted Claude Opus 5.
`claude-opus-5` was missing from the adapter's static fallback `models`
array (`packages/adapters/claude-local/src/index.ts`), so it only
surfaced when the live Anthropic `/v1/models` discovery happened to
succeed.

**Expected behavior**
Claude Opus 5 is a shipped, generally-available flagship (Anthropic's
recommended model for agentic coding) and should always be selectable in
the dropdown, independent of whether live discovery succeeds.

**Steps to reproduce**
1. Run the server without a working live Anthropic `/v1/models` path (no
`ANTHROPIC_API_KEY`, Bedrock mode, a discovery timeout, or a cache
miss).
2. Open agent config for a `claude_local` agent and inspect the model
dropdown.
3. Observe that `claude-opus-5` is absent because the static fallback
list omitted it.

**Deployment mode**
Self-hosted / local adapter (`claude_local`); the server process reads
`ANTHROPIC_API_KEY` from its environment.

## What Changed

- Added `{ id: "claude-opus-5", label: "Claude Opus 5" }` to the
`claude_local` static `models` fallback. Placed after the current
5-family entries and above the legacy `claude-opus-4-7`, so
`claude-opus-4-8` stays the default (index 0) option.
- Added an explicit regression assertion in
`server/src/__tests__/adapter-models.test.ts` that `claude-opus-5` is
present in the `claude_local` fallback when live discovery is
unavailable.

## Verification

- `pnpm -C server exec vitest run src/__tests__/adapter-models.test.ts`
— **17/17 pass**, including the new `claude-opus-5` assertion and the
existing `models[0] === "claude-opus-4-8"` default invariant (unaffected
— Opus 5 is inserted lower in the list).
- Change is a single static-data addition plus a test assertion; no
control-flow change.

## Risks

- Low risk. Pure additive change to a fallback list; no control-flow
change. Worst case is an id a given account isn't entitled to, which the
existing "current"/manual-model UI paths already tolerate.
- Note for reviewers: a sibling PR adds `claude-sonnet-5` to the same
static array (near `claude-opus-4-8`). Both are complementary "refresh
the static list to current GA" changes; whichever merges second may need
a one-line merge resolution in
`packages/adapters/claude-local/src/index.ts` and the matching test
assertion block.

## Model Used

Claude (Anthropic), model id `claude-opus-4-8` (Opus 4.8), extended
thinking + tool use, run as the Paperclip CTO agent.

## 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 (branch is the assigned
execution-workspace branch and cannot be renamed this run)
- [x] I have run tests locally and they pass (server adapter-models
suite, 17/17)
- [x] I have added or updated tests where applicable (explicit
`claude-opus-5` fallback assertion)
- [x] I have updated relevant documentation to reflect my changes (n/a —
no docs reference this list)
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green (pending CI)
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
(pending review)
- [x] I will address all Greptile and reviewer comments before
requesting merge

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-28 16:25:25 -05:00
github-actions[bot] b8ceddbf11
chore(lockfile): refresh pnpm-lock.yaml (#10391)
Auto-generated lockfile refresh after dependencies changed on master.
This PR only updates pnpm-lock.yaml.

Co-authored-by: lockfile-bot <lockfile-bot@users.noreply.github.com>
2026-07-28 14:16:19 -07:00
Dotta 487e33b8b6
fix(codex-local): resolve GPT-5.6 model metadata at source (#9780)
## Thinking Path

> - Paperclip is the open source control plane people use to manage AI
agents for work
> - The `codex_local` adapter runs OpenAI's Codex CLI through direct CLI
and ACP execution lanes
> - The adapter defaulted to the bare `gpt-5.6` alias while the bundled
ACP Codex version lacked GPT-5.6-family metadata
> - Default and legacy-configured runs therefore emitted
fallback-metadata warnings and could use generic context limits
> - This pull request upgrades the bundled Codex ACP dependency, selects
the concrete `gpt-5.6-sol` model, and normalizes the legacy alias in
both execution lanes
> - The benefit is correct model metadata without hiding genuine stderr
or transcript warnings

## Linked Issues or Issue Description

Related public PRs: Refs #9342, Refs #9352, and Refs #9382. This PR is
narrower: it upgrades bundled Codex metadata and normalizes the legacy
bare alias in both execution lanes.

**Bug report**

### What happened

Default `codex_local` runs, and agents still configured with the bare
`gpt-5.6` model, print a model-metadata fallback warning and use generic
context-window limits.

Root cause: the ACP lane bundled a Codex release predating
GPT-5.6-family metadata, while Paperclip's default and advertised model
used the bare `gpt-5.6` alias for which Codex publishes no metadata.

### Expected behavior

A default Codex run resolves to a concrete model slug with published
metadata and does not emit a fallback-metadata warning.

### Deployment mode

Self-hosted/local `codex_local` adapter.

## What Changed

- Upgraded `@agentclientprotocol/codex-acp` from `^1.1.0` to `^1.1.4`
- Changed `DEFAULT_CODEX_LOCAL_MODEL` from `gpt-5.6` to `gpt-5.6-sol`
- Removed the bare alias from advertised models and listed concrete
GPT-5.6 Fast-mode variants
- Added `normalizeCodexModel()` and applied it in both CLI and ACP
execution lanes
- Updated adapter docs, Storybook fixtures, and regression tests
- Preserved warning visibility; no stderr, transcript, or log filtering
changed

## Verification

- `pnpm --filter @paperclipai/adapter-codex-local typecheck`
- `pnpm check:token-gates`
- `cd packages/adapters/codex-local && pnpm exec vitest run` — 205 tests
passed
- `cd server && pnpm exec vitest run
src/__tests__/adapter-models.test.ts` — 17 tests passed
- Confirmed the PR diff excludes `pnpm-lock.yaml` and
`.github/workflows/**` as required by repository policy
- Confirmed `.github/workflows/pr.yml` regenerates and uploads the PR
lockfile artifact before downstream `pnpm install --frozen-lockfile`
steps

## Risks

Low risk. The behavior change is scoped to `codex_local` model
selection. Existing concrete model IDs pass through unchanged; only the
legacy bare `gpt-5.6` alias is rewritten. Dependency resolution may
select a newer compatible `codex-acp` release within the declared range,
so CI remains the final compatibility gate.

> 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

- Original implementation: Anthropic Claude Opus 4.8 (`claude-opus-4-8`,
1M context, tool use and code execution)
- Conflict resolution and PR preparation: OpenAI GPT-5.5 (`gpt-5.5`,
Codex CLI coding agent, high-reasoning tool use and code execution;
host-managed 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)
- [ ] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
— branch name is fixed by the assigned execution workspace and cannot be
renamed in-place
- [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>
2026-07-28 16:15:08 -05:00
dependabot[bot] a90f816c89
build(deps): bump lexical from 0.46.0 to 0.48.0 (#10299)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The UI depends on `lexical` for rich text editing in user-facing
flows
> - Dependabot detected a newer `lexical` release with bug fixes and
security hardening
> - A dependency-only bump is the smallest safe way to pick up those
upstream fixes
> - This pull request updates `lexical` from 0.46.0 to 0.48.0
> - The benefit is lower maintenance risk and a smaller security/support
gap without changing app logic

## Linked Issues or Issue Description

- No public issue exists for this maintenance update.
- Related public PR: Refs #9885.

## What Changed

- Bumped `lexical` from 0.46.0 to 0.48.0.
- Refreshed the lockfile entries for the dependency update.

## Verification

- GitHub Actions checks on PR #10299 passed.
- No local code changes were needed for this dependency-only update.

## Risks

- Low risk overall because this is a dependency-only update.
- Upstream editor behavior could still shift subtly; CI and the
dependency bump itself are the primary safeguard.

## Model Used

- OpenAI GPT-5 (Codex), tool-using agent.

## 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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-28 11:58:22 -07:00
Nicky Leach 91c79d28cb
test(e2e): retry run-lock 409 in signoff-policy agentPatch (#10386)
## Thinking Path

> - Paperclip is the control plane people use to manage AI-agent work
across companies
> - This repository's e2e suite verifies the execution and approval
paths that keep the control plane reliable
> - The signoff-policy flow uses a helper that runs a heartbeat and then
PATCHes the issue with that run id
> - That PATCH can race the heartbeat's run-lock ownership and
intermittently receive a transient 409
> - When that happens, a single-positive transition fails the shard even
though the underlying behavior is only a lock contention race
> - This pull request makes the helper retry the 409 path by re-reading
the current lock and re-PATCHing under the winning run id
> - The benefit is a stable e2e shard without weakening the
negative-path assertions that protect the contract

## Linked Issues or Issue Description

No public GitHub issue exists for this change. This PR addresses a flaky
signoff-policy e2e transition where the helper can lose a run-lock race
and receive a transient 409 while the issue is still assigned to the
acting agent.

## What Changed

- Added bounded retry/backoff handling in the signoff-policy
`agentPatch` helper for transient run-lock 409 responses.
- Re-read the issue's current lock before retrying so the helper can
re-PATCH with the winning run id.
- Kept the retry guarded so non-participant rejection and
missing-comment 400s still surface unchanged.
- Preserved the existing positive-path behavior without adding
Playwright retries or weakening assertions.

## Verification

- Reviewed the diff shape for a single-file change in
`tests/e2e/signoff-policy.spec.ts`.
- Verified the pushed commit matches the authorized submit SHA from the
handoff.
- Confirmed the branch contains only the expected commit and no
unrelated history.
- The handoff notes record deterministic harness evidence showing the
pre-fix helper fails on the 409 race and the post-fix path passes.

## Risks

- Low functional risk: the retry is narrowly scoped to the transient 409
lock-contention path.
- If the lock semantics change server-side, the helper may need a
follow-up adjustment.
- The change only affects the e2e helper and does not alter production
API behavior.

## Model Used

OpenAI Codex (GPT-5, tool-using coding agent)

## 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>
2026-07-28 11:53:16 -07:00
Devin Foley dc12197cce
fix: prevent duplicate built-in agents and self-heal reconciliation (#10223)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Every company is auto-provisioned a set of built-in agents (e.g. the
Summarizer), and a startup reconciler keeps that set correct across
every company on boot.
> - Provisioning marks these agents with
`metadata.paperclipBuiltInAgent.key`, but nothing in the database
enforced one active agent per `(company, key)` —
`provision()`/`ensure()` did a check-then-insert with no guard.
> - Two concurrent server processes (e.g. a `tsx watch` double-boot)
could both read "no summarizer exists" and both insert, leaving a
company with duplicate built-in agents plus paired orphan pending
`hire_agent` approvals.
> - That data blemish then became a recurring outage: `findSingleAgent`
throws on >1 marked row, and because the throw escaped
`reconcileBuiltInAgentsOnStartup`'s sequential loop, **every company
after the affected one was silently skipped** on each boot — no
auto-provisioning, no default grants — until manual DB surgery.
> - This pull request closes the race at the database level and makes
reconciliation self-healing and fault-isolated.
> - The benefit is that concurrent provisioning can no longer create
duplicates, and even pre-existing duplicates are resolved automatically
instead of bricking startup reconciliation for unrelated companies.

## Linked Issues or Issue Description

- [x] I searched the GitHub PR list (open and recently closed) for
similar PRs and confirmed this is not a duplicate.

No public GitHub issue exists; describing the bug in-PR (bug-report
shape):

**What happened**

A dev instance booted with two concurrent server processes. Both ran
built-in agent provisioning for the same company at the same time, and
the check-then-insert in `provision()`/`ensure()`
(`server/src/services/built-in-agents.ts`) let both writers see "no
summarizer exists" and each create one — the company ended up with two
identical Summarizer agents (identical `paperclipBuiltInAgent` markers)
plus two paired pending `hire_agent` approvals.

From then on, **every** server boot logged:

```
ERROR: startup reconciliation of built-in agents failed
       Multiple built-in agents found for summarizer (built_in_agent_duplicate_instance)
```

because `findSingleAgent` throws on >1 marked row rather than resolving
the duplicate. Worse, `reconcileBuiltInAgentsOnStartup` loops companies
sequentially and the throw escaped the loop, so every company *after*
the affected one was silently skipped on every boot.

**Expected behavior**

1. Concurrent provisioning must not create duplicate built-in agents
(there was no DB uniqueness constraint on the marker key per company).
2. Reconciliation should be resilient: if duplicates exist anyway,
self-heal (keep the oldest row, terminate the newer dupe, cancel its
orphan pending `hire_agent` approval), and never let one bad company
abort reconciliation for the rest.

**Steps to reproduce**

- Race two `provision(companyId, "summarizer")` calls for a company with
board approval for new agents enabled (or simulate a double-boot); both
insert.
- Restart the server → startup reconciliation error fires, companies
later in the loop are never reconciled.

## What Changed

**Part 1 — stop creating duplicates**

- Migration `0192_built_in_agent_unique_marker` adds a **partial unique
index** on `(company_id, metadata->'paperclipBuiltInAgent'->>'key')`
where the marker exists and `status != 'terminated'`. It first resolves
any pre-existing duplicates (keep oldest by `created_at`, terminate
newer dupes, cancel their orphan pending `hire_agent` approvals, revoke
their API keys) so the index can be created on already-affected
instances.
- `provision()`/`ensure()` now catch the losing race's `23505` unique
violation (walking the driver's wrapped cause chain) and re-resolve to
the winning row instead of surfacing the error.

**Part 2 — resilient reconciliation**

- `findSingleAgent` self-heals: keeps the oldest marked row, terminates
the newer duplicates, and cancels each one's orphan pending `hire_agent`
approval (idempotent) instead of throwing.
- `reconcileBuiltInAgentsOnStartup` isolates per-company failures in
both loops so one bad company can't abort reconciliation for the rest;
it surfaces a `companyFailures` count in the startup log.
- Adds `approvalService.cancel()` for system-initiated cancellation of
an orphan approval.

## Verification

- `pnpm --filter @paperclipai/db run check:migrations` → numbering +
safety checks pass.
- `packages/db` migration test (real embedded Postgres) — seeds
pre-index duplicate state, runs the migration, asserts dupes resolved +
index enforced: **1 passed**.
- `server` `built-in-agents.test.ts` — self-heal, concurrent races
(plain and board-gated), and startup
self-heal-without-aborting-later-companies: **34 passed**.

```
pnpm --filter @paperclipai/db exec vitest run src/built-in-agent-unique-marker-migration.test.ts
pnpm --filter @paperclipai/server exec vitest run src/__tests__/built-in-agents.test.ts
```

## Risks

- **Migration safety**: the migration mutates data (terminates duplicate
rows, cancels their orphan pending approvals, revokes their API keys)
before creating the index. It keeps the oldest row per `(company, key)`
and only touches non-terminated marked rows; the destructive step is
covered by the migration test and the safety-check baseline. On a clean
instance it is a no-op cleanup followed by `CREATE UNIQUE INDEX IF NOT
EXISTS`.
- Otherwise low risk: the unique index is partial (excludes terminated
rows, so re-provisioning after a termination stays possible), and the
conflict handling degrades gracefully to re-resolving the existing
winner.

## Model Used

Claude Opus 4.8 (`claude-opus-4-8`), 1M context window, extended
thinking, with tool use.
2026-07-28 11:12:58 -07:00
Nicky Leach c8c2ae82a3
test(e2e): wait for connections fetch before asserting applications status pill (#10384)
## Thinking Path

> - Paperclip relies on end-to-end tests to catch regressions in the
operator UI
> - The applications list status pill is rendered from more than one
data fetch, so the visible label can lag behind the row itself
> - A default Playwright assertion timeout can expire before the
connections fetch finishes under CI load
> - That creates a flaky failure without changing the underlying product
behavior
> - This pull request extends the two status-pill assertions to use the
longer timeout already used elsewhere in the spec
> - The benefit is the same UI coverage with fewer false negatives

## Linked Issues or Issue Description

There is no public GitHub issue linked to this repo-local fix. This PR
addresses a flaky Playwright assertion in
`tests/e2e/applications-crud.spec.ts`, where the status pill can render
after the default assertion timeout because it depends on the
connections fetch as well as the applications fetch.

## What Changed

- Increased the wait window for the two status-pill visibility
assertions in `tests/e2e/applications-crud.spec.ts`.
- Kept the assertions anchored to the exact expected labels (`Healthy`
and `Not connected`) so the test still verifies the same behavior.

## Verification

- The spec is still discovered cleanly by Playwright.
- The diff stays limited to `tests/e2e/applications-crud.spec.ts`; there
are no product, dependency, or lockfile changes.
- The full browser-backed e2e signal remains CI for this change.

## Risks

- Low risk. This only changes assertion timing in a test file and does
not alter runtime product behavior.

## Model Used

OpenAI Codex, GPT-5, tool-using coding agent.

## 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>
2026-07-28 11:00:04 -07:00
Devin Foley 9f5af4ea5d
fix(server): accept secret_ref binding objects in sandbox provider environment config (#10355)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents execute in environments; sandbox provider plugins (Daytona,
Modal, e2b, …) declare their config via a JSON schema, with credentials
marked `format: "secret-ref"`
> - The environments UI renders those fields with a secret picker that
submits `{ type: "secret_ref", secretId, version }` binding objects,
while the server-side environment config paths only understood raw
string values and bare secret-id strings
> - The binding object reached the plugin worker's
`environmentValidateConfig` untouched; plugins parse non-string config
values as absent, so saving or testing an environment with a
picker-bound secret always failed validation (e.g. "Daytona sandbox
environments require an API key in config or DAYTONA_API_KEY.", "Modal
sandbox environments require tokenId and tokenSecret.")
> - Worse, an environment first saved with raw pasted values becomes
uneditable: the stored value is a secret reference, the edit form
re-submits it as a binding object, and every subsequent save fails the
same way
> - This pull request canonicalizes binding objects to the bare secret
id before plugin validation, and teaches the persistence/runtime/probe
secret-ref resolvers to accept the object shape defensively
> - The benefit is that picker-bound secrets work for every
schema-driven sandbox provider — create, edit, and Test — with no plugin
changes required

## Linked Issues or Issue Description

Fixes #10105

The same failure reproduces with the Daytona provider: Settings →
Instance settings → Environments → New, driver sandbox, provider
daytona, bind Api Key to an existing secret via the picker → Save fails
with "Daytona sandbox environments require an API key in config or
DAYTONA_API_KEY."

## What Changed

- `server/src/services/json-schema-secret-refs.ts`: new
`parseSecretRefBindingObject()` that recognizes the `{ type:
"secret_ref", secretId, version? }` shape the secret picker submits
(version defaults to `"latest"`; malformed objects return null).
- `server/src/services/plugin-environment-driver.ts`:
`validatePluginSandboxProviderConfig()` now canonicalizes binding
objects at the driver schema's `format: "secret-ref"` paths to the bare
secret id (the persisted shape) before invoking the plugin worker's
`environmentValidateConfig`. Pinned numeric versions are rejected with a
clear 422, since sandbox provider references always resolve the latest
version — silently resolving a different version would be worse.
- `server/src/services/environment-config.ts`: the persistence, runtime,
and probe secret-ref resolvers plus `collectEnvironmentSecretRefs()`
accept the binding-object shape defensively, so any previously persisted
object-shaped refs (from providers whose validation tolerated them)
resolve instead of being silently skipped; the missing-companyId runtime
guard also now fails closed for object-shaped refs.

## Verification

- `npx vitest run server/src/__tests__/json-schema-secret-refs.test.ts
server/src/__tests__/plugin-sandbox-provider-config-validation.test.ts
server/src/__tests__/environment-routes.test.ts
server/src/__tests__/environment-config.test.ts` — 82 tests pass,
including new coverage: binding-object canonicalization before plugin
validation, pinned-version rejection, raw-string pass-through, and a
route-level create with a picker-submitted binding object persisting the
bare secret id without minting a duplicate secret.
- `npx vitest run server/src/__tests__/environment-runtime.test.ts` — 24
tests pass against embedded Postgres, including a new test that persists
an object-shaped ref and verifies runtime resolution produces the
plaintext credential for the plugin worker.
- `pnpm typecheck` in `server/` — clean.

## Risks

- Low. The canonical persisted shape (bare secret-id string) is
unchanged, so existing saved environments and lease-resume fingerprints
are unaffected; raw pasted values and bare-id strings take exactly the
same code path as before.
- New behavior only triggers where a save/probe previously failed 422
(binding objects at secret-ref paths) or where an object-shaped ref was
previously skipped silently at runtime (now resolved, or failed closed
without a companyId).
- Pinned binding versions at sandbox-provider paths are now an explicit
422 instead of an accidental validation failure; no UI submits pinned
versions today (`allowVersionSelector={false}`).

## Model Used

Claude Fable 5 (`claude-fable-5`, Anthropic) with extended thinking and
agentic tool use (Claude Code harness): source diagnosis, fix, and
tests.

## 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 (no
doc surface changed)
- [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
2026-07-28 10:50:13 -07:00
dependabot[bot] f9034ab3ca
build(deps-dev): bump @types/node from 22.19.21 to 22.20.1 (#10304)
Bumps
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)
from 22.19.21 to 22.20.1.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-28 10:48:45 -07:00
dependabot[bot] dac7e66724
build(deps-dev): bump storybook from 10.4.6 to 10.5.5 (#10303)
Bumps
[storybook](https://github.com/storybookjs/storybook/tree/HEAD/code/core)
from 10.4.6 to 10.5.5.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/storybookjs/storybook/releases">storybook's
releases</a>.</em></p>
<blockquote>
<h2>v10.5.5</h2>
<h2>10.5.5</h2>
<ul>
<li>CLI: Update AI setup instructions to msw-storybook-addon v3 - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35512">#35512</a>,
thanks <a
href="https://github.com/yannbf"><code>@​yannbf</code></a>!</li>
<li>Core: Upgrade `ws` to fix security advisories - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35584">#35584</a>,
thanks <a
href="https://github.com/ndelangen"><code>@​ndelangen</code></a>!</li>
<li>ReactNative: Telemetry framework detection fix - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35560">#35560</a>,
thanks <a
href="https://github.com/ndelangen"><code>@​ndelangen</code></a>!</li>
<li>SyntaxHighlighter: Fix PrismJS dark mode mismatch - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35541">#35541</a>,
thanks <a
href="https://github.com/hxy-asdw"><code>@​hxy-asdw</code></a>!</li>
<li>TanStack: Preserve explicit route ids on pathful clones - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35499">#35499</a>,
thanks <a
href="https://github.com/unpunnyfuns"><code>@​unpunnyfuns</code></a>!</li>
<li>TanStack: Resolve mock redirects through Vite's resolver - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35501">#35501</a>,
thanks <a
href="https://github.com/unpunnyfuns"><code>@​unpunnyfuns</code></a>!</li>
<li>TanStack: Respect routeOverrides component overrides in stories - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35497">#35497</a>,
thanks <a
href="https://github.com/unpunnyfuns"><code>@​unpunnyfuns</code></a>!</li>
</ul>
<h2>v10.5.4</h2>
<h2>10.5.4</h2>
<ul>
<li>ReactNative: Telemetry framework detection fix - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35560">#35560</a>,
thanks <a
href="https://github.com/ndelangen"><code>@​ndelangen</code></a>!</li>
<li>SyntaxHighlighter: Fix PrismJS dark mode mismatch - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35541">#35541</a>,
thanks <a
href="https://github.com/hxy-asdw"><code>@​hxy-asdw</code></a>!</li>
</ul>
<h2>v10.5.3</h2>
<h2>10.5.3</h2>
<ul>
<li>Dependencies: Upgrade TypeScript to 6.0.3 - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34971">#34971</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
</ul>
<h2>v10.5.2</h2>
<h2>10.5.2</h2>
<ul>
<li>Angular-Vite: Drop <code>@​angular/platform-browser-dynamic</code>
peer dependency - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35457">#35457</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Angular-Vite: Widen TypeScript peer dependency range to support
TypeScript 6 - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35455">#35455</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Core: Include chromatic packages in ecosystem identifier - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35170">#35170</a>,
thanks <a
href="https://github.com/yannbf"><code>@​yannbf</code></a>!</li>
<li>TanStack: Fix createServerFn validator mock - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35185">#35185</a>,
thanks <a
href="https://github.com/sjh9714"><code>@​sjh9714</code></a>!</li>
<li>TanStack: Support pathless layout routes (id-only) in story routing
- <a
href="https://redirect.github.com/storybookjs/storybook/pull/35465">#35465</a>,
thanks <a
href="https://github.com/unpunnyfuns"><code>@​unpunnyfuns</code></a>!</li>
<li>Tanstack-react: Add missing Hydrate export - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35111">#35111</a>,
thanks <a
href="https://github.com/arun-357"><code>@​arun-357</code></a>!</li>
<li>Tanstack-react: Keep JSX-only component references during dead-code
elimination - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35206">#35206</a>,
thanks <a
href="https://github.com/yatishgoel"><code>@​yatishgoel</code></a>!</li>
<li>Vitest: Fix coverage toggle crash on Vite 6 by clearing closed
Vitest instance on restart - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35461">#35461</a>,
thanks <a
href="https://github.com/yannbf"><code>@​yannbf</code></a>!</li>
</ul>
<h2>v10.5.1</h2>
<h2>10.5.1</h2>
<ul>
<li>Angular-Vite: Drop <code>@​angular/platform-browser-dynamic</code>
peer dependency - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35457">#35457</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Angular-Vite: Widen TypeScript peer dependency range to support
TypeScript 6 - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35455">#35455</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Core: Include chromatic packages in ecosystem identifier - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35170">#35170</a>,
thanks <a
href="https://github.com/yannbf"><code>@​yannbf</code></a>!</li>
</ul>
<h2>v10.5.0</h2>
<h2>10.5.0</h2>
<blockquote>
<p><em>Foundational changes for new AI workflows</em></p>
</blockquote>
<p>Storybook 10.5 contains hundreds of fixes and improvements:</p>
<ul>
<li>️ Angular-vite framework: Modern, fast dev, docs, and test
(preview)</li>
<li>🌈 Vitest initialGlobals: Test across themes, viewports, locales</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md">storybook's
changelog</a>.</em></p>
<blockquote>
<h2>10.5.5</h2>
<ul>
<li>CLI: Update AI setup instructions to msw-storybook-addon v3 - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35512">#35512</a>,
thanks <a
href="https://github.com/yannbf"><code>@​yannbf</code></a>!</li>
<li>Core: Upgrade <code>ws</code> to fix security advisories - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35584">#35584</a>,
thanks <a
href="https://github.com/ndelangen"><code>@​ndelangen</code></a>!</li>
<li>ReactNative: Telemetry framework detection fix - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35560">#35560</a>,
thanks <a
href="https://github.com/ndelangen"><code>@​ndelangen</code></a>!</li>
<li>SyntaxHighlighter: Fix PrismJS dark mode mismatch - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35541">#35541</a>,
thanks <a
href="https://github.com/hxy-asdw"><code>@​hxy-asdw</code></a>!</li>
<li>TanStack: Preserve explicit route ids on pathful clones - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35499">#35499</a>,
thanks <a
href="https://github.com/unpunnyfuns"><code>@​unpunnyfuns</code></a>!</li>
<li>TanStack: Resolve mock redirects through Vite's resolver - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35501">#35501</a>,
thanks <a
href="https://github.com/unpunnyfuns"><code>@​unpunnyfuns</code></a>!</li>
<li>TanStack: Respect routeOverrides component overrides in stories - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35497">#35497</a>,
thanks <a
href="https://github.com/unpunnyfuns"><code>@​unpunnyfuns</code></a>!</li>
</ul>
<h2>10.5.4</h2>
<ul>
<li>ReactNative: Telemetry framework detection fix - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35560">#35560</a>,
thanks <a
href="https://github.com/ndelangen"><code>@​ndelangen</code></a>!</li>
<li>SyntaxHighlighter: Fix PrismJS dark mode mismatch - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35541">#35541</a>,
thanks <a
href="https://github.com/hxy-asdw"><code>@​hxy-asdw</code></a>!</li>
</ul>
<h2>10.5.3</h2>
<ul>
<li>Dependencies: Upgrade TypeScript to 6.0.3 - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34971">#34971</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
</ul>
<h2>10.5.2</h2>
<ul>
<li>TanStack: Fix createServerFn validator mock - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35185">#35185</a>,
thanks <a
href="https://github.com/sjh9714"><code>@​sjh9714</code></a>!</li>
<li>TanStack: Support pathless layout routes (id-only) in story routing
- <a
href="https://redirect.github.com/storybookjs/storybook/pull/35465">#35465</a>,
thanks <a
href="https://github.com/unpunnyfuns"><code>@​unpunnyfuns</code></a>!</li>
<li>Tanstack-react: Add missing Hydrate export - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35111">#35111</a>,
thanks <a
href="https://github.com/arun-357"><code>@​arun-357</code></a>!</li>
<li>Tanstack-react: Keep JSX-only component references during dead-code
elimination - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35206">#35206</a>,
thanks <a
href="https://github.com/yatishgoel"><code>@​yatishgoel</code></a>!</li>
<li>Vitest: Fix coverage toggle crash on Vite 6 by clearing closed
Vitest instance on restart - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35461">#35461</a>,
thanks <a
href="https://github.com/yannbf"><code>@​yannbf</code></a>!</li>
</ul>
<h2>10.5.1</h2>
<ul>
<li>Angular-Vite: Drop <code>@​angular/platform-browser-dynamic</code>
peer dependency - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35457">#35457</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Angular-Vite: Widen TypeScript peer dependency range to support
TypeScript 6 - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35455">#35455</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Core: Include chromatic packages in ecosystem identifier - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35170">#35170</a>,
thanks <a
href="https://github.com/yannbf"><code>@​yannbf</code></a>!</li>
</ul>
<h2>10.5.0</h2>
<blockquote>
<p><em>Foundational changes for new AI workflows</em></p>
</blockquote>
<p>Storybook 10.5 contains hundreds of fixes and improvements:</p>
<ul>
<li>️ Angular-vite framework: Modern, fast dev, docs, and test
(preview)</li>
<li>🌈 Vitest initialGlobals: Test across themes, viewports, locales</li>
<li>🤖 Agentic review: AI-curated visual changesets and search results
(experimental)</li>
<li>⚛️ React docgen service: Unified metadata across MCP, Docs, and
Controls (experimental)</li>
<li>🧑‍💻 Claude / Codex plugins: One-click ADE integration
(experimental)</li>
</ul>
<!-- raw HTML omitted -->
<ul>
<li>A11y: Fix MDX heading anchors not keyboard accessible - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34368">#34368</a>,
thanks <a
href="https://github.com/TheSeydiCharyyev"><code>@​TheSeydiCharyyev</code></a>!</li>
<li>A11y: Handle lang attribute throughout preview - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35321">#35321</a>,
thanks <a
href="https://github.com/Sidnioulz"><code>@​Sidnioulz</code></a>!</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="05a52b7a88"><code>05a52b7</code></a>
Bump version from &quot;10.5.4&quot; to &quot;10.5.5&quot; [skip
ci]</li>
<li><a
href="201e77a25c"><code>201e77a</code></a>
Merge pull request <a
href="https://github.com/storybookjs/storybook/tree/HEAD/code/core/issues/35512">#35512</a>
from storybookjs/yann/ai-setup-msw-v3</li>
<li><a
href="cac1e6d595"><code>cac1e6d</code></a>
Merge pull request <a
href="https://github.com/storybookjs/storybook/tree/HEAD/code/core/issues/35584">#35584</a>
from storybookjs/norbert/upgrade-ws-8.21</li>
<li><a
href="9166a91fc2"><code>9166a91</code></a>
Merge pull request <a
href="https://github.com/storybookjs/storybook/tree/HEAD/code/core/issues/35567">#35567</a>
from ia319/bug/35566-npm-12-registry-flags</li>
<li><a
href="3327dc4469"><code>3327dc4</code></a>
Bump version from &quot;10.5.3&quot; to &quot;10.5.4&quot; [skip
ci]</li>
<li><a
href="3f07eb74ae"><code>3f07eb7</code></a>
Merge pull request <a
href="https://github.com/storybookjs/storybook/tree/HEAD/code/core/issues/35560">#35560</a>
from storybookjs/norbert/fix-rn-telemetry-metadata</li>
<li><a
href="22e36662a2"><code>22e3666</code></a>
Merge pull request <a
href="https://github.com/storybookjs/storybook/tree/HEAD/code/core/issues/35541">#35541</a>
from hxy-asdw/fix/prismjs-dark-mode-contrast-35540</li>
<li><a
href="9ac273930a"><code>9ac2739</code></a>
Bump version from &quot;10.5.2&quot; to &quot;10.5.3&quot; [skip
ci]</li>
<li><a
href="b4b00f2766"><code>b4b00f2</code></a>
Merge pull request <a
href="https://github.com/storybookjs/storybook/tree/HEAD/code/core/issues/34971">#34971</a>
from storybookjs/valentin/upgrade-typescript-6</li>
<li><a
href="518f711cb3"><code>518f711</code></a>
Bump version from &quot;10.5.1&quot; to &quot;10.5.2&quot; [skip
ci]</li>
<li>Additional commits viewable in <a
href="https://github.com/storybookjs/storybook/commits/v10.5.5/code/core">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-28 10:16:56 -07:00
dependabot[bot] 91e1eb43af
build(deps): bump i18next from 26.3.1 to 26.3.6 (#10300)
Bumps [i18next](https://github.com/i18next/i18next) from 26.3.1 to
26.3.6.
<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.3.6</h2>
<ul>
<li>fix: allow TypeScript 7 in the optional <code>typescript</code> peer
dependency range (<code>^5 || ^6 || ^7</code>). With
<code>typescript@7.0.2</code> in a project, <code>npm install</code>
failed with an <code>ERESOLVE</code> peer conflict. The published types
are TS7-compatible as-is: every <code>test/typescript</code> suite
produces identical results under 6.0 and 7.0.2. Reported in <a
href="https://redirect.github.com/i18next/react-i18next/issues/1927">react-i18next#1927</a>,
thanks <a
href="https://github.com/andikapradanaarif"><code>@​andikapradanaarif</code></a>.</li>
</ul>
<h2>v26.3.5</h2>
<ul>
<li>fix: <code>$t()</code> nesting options blocks that span multiple
lines are now parsed. <code>nest()</code> decided where the nested key
ends by testing <code>match[1]</code> with <code>/{.*}/</code>, whose
dot does not cross line breaks — so a <code>$t(key, { ... })</code>
options object containing a newline was treated as having no options,
mis-split as formatters, and the nested lookup ran without its options
(placeholders stayed unresolved). The nesting regexp itself already
matches newlines inside <code>$t(...)</code>; adding the <code>s</code>
(dotAll) flag makes multiline options behave like the single-line form.
Thanks <a href="https://github.com/spokodev"><code>@​spokodev</code></a>
(<a
href="https://redirect.github.com/i18next/i18next/pull/2440">#2440</a>).</li>
<li>fix: <code>getUsedParamsDetails</code> (the <code>returnDetails:
true</code> path) no longer mutates the passed <code>replace</code>
object. It wrote <code>count</code> straight onto
<code>options.replace</code> so the returned <code>usedParams</code>
would include it — a caller reusing one <code>replace</code> object
across <code>t()</code> calls then carried a stale <code>count</code>
into later interpolations (e.g. a previous call's <code>count: 5</code>
rendered instead of the current call's value). The details are now built
from a copy; <code>usedParams</code> still includes <code>count</code>.
Thanks <a href="https://github.com/spokodev"><code>@​spokodev</code></a>
(<a
href="https://redirect.github.com/i18next/i18next/pull/2441">#2441</a>).</li>
<li>fix: with the default <code>skipOnVariables: true</code> +
<code>escapeValue: true</code>, a <code>{{placeholder}}</code> carried
inside an interpolated value now stays literal even when the value
contains escapable characters. The skip logic advanced the regex
<code>lastIndex</code> by the raw value length, but the escaped text
written into the string is longer, so <code>lastIndex</code> landed
inside the inserted value and a trailing <code>{{placeholder}}</code> in
it got interpolated — leaking another in-scope variable that should have
stayed literal (values without escapable characters were already skipped
correctly). The advance now uses the escaped length that is actually
written, and the regex-safe <code>$</code>-doubling is applied only at
the <code>String.replace</code> call so it can't distort the length
arithmetic. Thanks <a
href="https://github.com/spokodev"><code>@​spokodev</code></a> (<a
href="https://redirect.github.com/i18next/i18next/pull/2442">#2442</a>).</li>
</ul>
<h2>v26.3.4</h2>
<ul>
<li>fix(security): <code>deepExtend</code> (used by
<code>addResourceBundle(..., deep, overwrite)</code>) no longer recurses
into inherited properties. It checked key existence with the
<code>in</code> operator, which walks the prototype chain, so a source
key matching an inherited built-in (e.g. <code>hasOwnProperty</code>,
<code>toString</code>) caused recursion into the shared
<code>Object.prototype</code> function and, with <code>overwrite:
true</code>, could overwrite e.g.
<code>Object.prototype.hasOwnProperty.call</code> with a non-callable
value — corrupting a shared built-in process-wide (DoS). Existence is
now checked with <code>Object.prototype.hasOwnProperty.call</code>, so
such keys are copied as plain own data instead. This complements the
existing <code>__proto__</code>/<code>constructor</code> guard and is
also strictly more correct for an own-property merge. Only affects
applications that pass attacker-controlled data with <code>deep:
true</code> and <code>overwrite: true</code>; no standard
backend/integration does this. Distinct from CVE-2026-48713 /
CVE-2026-48714 (different packages, <code>setPath</code> mechanism).
Thanks to zx (Jace) for the responsible disclosure.</li>
</ul>
<h2>v26.3.3</h2>
<ul>
<li>fix(types): selector <code>t($ =&gt; $.arr, { returnObjects: true,
context })</code> on a JSON array of <strong>heterogeneous</strong>
objects now preserves each element's full shape (e.g. <code>{ transKey1:
string; transKey2: string }[]</code>) instead of collapsing to a union
of partial element types. Two type-level causes: (1)
<code>FilterKeys</code> evaluated the whole array element type at once,
so <code>keyof (A | B)</code> only saw the keys common to every element
— it now distributes over the object union and filters each element
independently; (2) when TypeScript merges mismatched array element types
it injects phantom optional <code>undefined</code> keys (e.g.
<code>transKey1_withContext?: undefined</code> on elements that don't
define it), which the context-detection helpers mistook for real context
variants — they now skip keys typed as <code>undefined</code>. Also adds
a dedicated <code>context</code> + <code>returnObjects: true</code>
selector overload using <code>const Fn</code> +
<code>ReturnType&lt;Fn&gt;</code>, so <code>Target</code> is no longer
collapsed to <code>unknown</code> via <code>ApplyTarget</code>. Resolves
Problem 1 of <a
href="https://redirect.github.com/i18next/i18next/issues/2398">#2398</a>
(Problem 2 was already fixed on master). Thanks <a
href="https://github.com/sauravgupta-dotcom"><code>@​sauravgupta-dotcom</code></a>
(<a
href="https://redirect.github.com/i18next/i18next/pull/2438">#2438</a>).
Fixes <a
href="https://redirect.github.com/i18next/i18next/issues/2398">#2398</a>.</li>
</ul>
<h2>v26.3.2</h2>
<ul>
<li>fix: chained formatters with a parenthesised option that contains
the format separator (e.g. <code>join(separator: ', ')</code>) now work
at <strong>any</strong> position in the chain, not just first.
Previously the comma-in-parens reassembly only repaired
<code>formats[0]</code>, so <code>{{v, uppercase, join(separator: ',
')}}</code> split the <code>join(...)</code> option on the inner comma
and never rejoined it, producing corrupt output. Replaced the
first-position-only repair with a position-independent pass that
re-joins fragments until each open paren closes. Thanks <a
href="https://github.com/spokodev"><code>@​spokodev</code></a> (<a
href="https://redirect.github.com/i18next/i18next/pull/2437">#2437</a>).</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.3.6</h2>
<ul>
<li>fix: allow TypeScript 7 in the optional <code>typescript</code> peer
dependency range (<code>^5 || ^6 || ^7</code>). With
<code>typescript@7.0.2</code> in a project, <code>npm install</code>
failed with an <code>ERESOLVE</code> peer conflict. The published types
are TS7-compatible as-is: every <code>test/typescript</code> suite
produces identical results under 6.0 and 7.0.2. Reported in <a
href="https://redirect.github.com/i18next/react-i18next/issues/1927">react-i18next#1927</a>,
thanks <a
href="https://github.com/andikapradanaarif"><code>@​andikapradanaarif</code></a>.</li>
</ul>
<h2>26.3.5</h2>
<ul>
<li>fix: <code>$t()</code> nesting options blocks that span multiple
lines are now parsed. <code>nest()</code> decided where the nested key
ends by testing <code>match[1]</code> with <code>/{.*}/</code>, whose
dot does not cross line breaks — so a <code>$t(key, { ... })</code>
options object containing a newline was treated as having no options,
mis-split as formatters, and the nested lookup ran without its options
(placeholders stayed unresolved). The nesting regexp itself already
matches newlines inside <code>$t(...)</code>; adding the <code>s</code>
(dotAll) flag makes multiline options behave like the single-line form.
Thanks <a href="https://github.com/spokodev"><code>@​spokodev</code></a>
(<a
href="https://redirect.github.com/i18next/i18next/pull/2440">#2440</a>).</li>
<li>fix: <code>getUsedParamsDetails</code> (the <code>returnDetails:
true</code> path) no longer mutates the passed <code>replace</code>
object. It wrote <code>count</code> straight onto
<code>options.replace</code> so the returned <code>usedParams</code>
would include it — a caller reusing one <code>replace</code> object
across <code>t()</code> calls then carried a stale <code>count</code>
into later interpolations (e.g. a previous call's <code>count: 5</code>
rendered instead of the current call's value). The details are now built
from a copy; <code>usedParams</code> still includes <code>count</code>.
Thanks <a href="https://github.com/spokodev"><code>@​spokodev</code></a>
(<a
href="https://redirect.github.com/i18next/i18next/pull/2441">#2441</a>).</li>
<li>fix: with the default <code>skipOnVariables: true</code> +
<code>escapeValue: true</code>, a <code>{{placeholder}}</code> carried
inside an interpolated value now stays literal even when the value
contains escapable characters. The skip logic advanced the regex
<code>lastIndex</code> by the raw value length, but the escaped text
written into the string is longer, so <code>lastIndex</code> landed
inside the inserted value and a trailing <code>{{placeholder}}</code> in
it got interpolated — leaking another in-scope variable that should have
stayed literal (values without escapable characters were already skipped
correctly). The advance now uses the escaped length that is actually
written, and the regex-safe <code>$</code>-doubling is applied only at
the <code>String.replace</code> call so it can't distort the length
arithmetic. Thanks <a
href="https://github.com/spokodev"><code>@​spokodev</code></a> (<a
href="https://redirect.github.com/i18next/i18next/pull/2442">#2442</a>).</li>
</ul>
<h2>26.3.4</h2>
<ul>
<li>fix(security): <code>deepExtend</code> (used by
<code>addResourceBundle(..., deep, overwrite)</code>) no longer recurses
into inherited properties. It checked key existence with the
<code>in</code> operator, which walks the prototype chain, so a source
key matching an inherited built-in (e.g. <code>hasOwnProperty</code>,
<code>toString</code>) caused recursion into the shared
<code>Object.prototype</code> function and, with <code>overwrite:
true</code>, could overwrite e.g.
<code>Object.prototype.hasOwnProperty.call</code> with a non-callable
value — corrupting a shared built-in process-wide (DoS). Existence is
now checked with <code>Object.prototype.hasOwnProperty.call</code>, so
such keys are copied as plain own data instead. This complements the
existing <code>__proto__</code>/<code>constructor</code> guard and is
also strictly more correct for an own-property merge. Only affects
applications that pass attacker-controlled data with <code>deep:
true</code> and <code>overwrite: true</code>; no standard
backend/integration does this. Distinct from CVE-2026-48713 /
CVE-2026-48714 (different packages, <code>setPath</code> mechanism). See
advisory <a
href="https://github.com/i18next/i18next/security/advisories/GHSA-6jcc-5g8w-32mx">GHSA-6jcc-5g8w-32mx</a>,
CVSS 5.9 (<code>CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:H</code>).
Thanks to zx (Jace) <a
href="https://github.com/manus-use"><code>@​manus-use</code></a> for the
responsible disclosure.</li>
</ul>
<h2>26.3.3</h2>
<ul>
<li>fix(types): selector <code>t($ =&gt; $.arr, { returnObjects: true,
context })</code> on a JSON array of <strong>heterogeneous</strong>
objects now preserves each element's full shape (e.g. <code>{ transKey1:
string; transKey2: string }[]</code>) instead of collapsing to a union
of partial element types. Two type-level causes: (1)
<code>FilterKeys</code> evaluated the whole array element type at once,
so <code>keyof (A | B)</code> only saw the keys common to every element
— it now distributes over the object union and filters each element
independently; (2) when TypeScript merges mismatched array element types
it injects phantom optional <code>undefined</code> keys (e.g.
<code>transKey1_withContext?: undefined</code> on elements that don't
define it), which the context-detection helpers mistook for real context
variants — they now skip keys typed as <code>undefined</code>. Also adds
a dedicated <code>context</code> + <code>returnObjects: true</code>
selector overload using <code>const Fn</code> +
<code>ReturnType&lt;Fn&gt;</code>, so <code>Target</code> is no longer
collapsed to <code>unknown</code> via <code>ApplyTarget</code>. Resolves
Problem 1 of <a
href="https://redirect.github.com/i18next/i18next/issues/2398">#2398</a>
(Problem 2 was already fixed on master). Thanks <a
href="https://github.com/sauravgupta-dotcom"><code>@​sauravgupta-dotcom</code></a>
(<a
href="https://redirect.github.com/i18next/i18next/pull/2438">#2438</a>).
Fixes <a
href="https://redirect.github.com/i18next/i18next/issues/2398">#2398</a>.</li>
</ul>
<h2>26.3.2</h2>
<ul>
<li>fix: chained formatters with a parenthesised option that contains
the format separator (e.g. <code>join(separator: ', ')</code>) now work
at <strong>any</strong> position in the chain, not just first.
Previously the comma-in-parens reassembly only repaired
<code>formats[0]</code>, so <code>{{v, uppercase, join(separator: ',
')}}</code> split the <code>join(...)</code> option on the inner comma
and never rejoined it, producing corrupt output. Replaced the
first-position-only repair with a position-independent pass that
re-joins fragments until each open paren closes. Thanks <a
href="https://github.com/spokodev"><code>@​spokodev</code></a> (<a
href="https://redirect.github.com/i18next/i18next/pull/2437">#2437</a>).</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="e1c60d4dd2"><code>e1c60d4</code></a>
26.3.6</li>
<li><a
href="04da43e08c"><code>04da43e</code></a>
fix: allow typescript 7 in optional peerDependencies range
(react-i18next#1927)</li>
<li><a
href="8eed4accc6"><code>8eed4ac</code></a>
build</li>
<li><a
href="573ae73568"><code>573ae73</code></a>
26.3.5</li>
<li><a
href="cc54b05b5c"><code>cc54b05</code></a>
docs(changelog): 26.3.5 — multiline $t() options, replace mutation,
escaped-l...</li>
<li><a
href="3180d67291"><code>3180d67</code></a>
fix: skip interpolation of placeholders inside escaped values (<a
href="https://redirect.github.com/i18next/i18next/issues/2442">#2442</a>)</li>
<li><a
href="d16f5a2da7"><code>d16f5a2</code></a>
fix: stop mutating the passed replace object when returning details (<a
href="https://redirect.github.com/i18next/i18next/issues/2441">#2441</a>)</li>
<li><a
href="bed56c1159"><code>bed56c1</code></a>
fix: parse $t() nesting options block that spans multiple lines (<a
href="https://redirect.github.com/i18next/i18next/issues/2440">#2440</a>)</li>
<li><a
href="c19e45864f"><code>c19e458</code></a>
docs(changelog): link GHSA advisory for deepExtend fix</li>
<li><a
href="7bb87d09f9"><code>7bb87d0</code></a>
docs(changelog): reference security advisory for deepExtend fix</li>
<li>Additional commits viewable in <a
href="https://github.com/i18next/i18next/compare/v26.3.1...v26.3.6">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=i18next&package-manager=npm_and_yarn&previous-version=26.3.1&new-version=26.3.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-28 10:04:55 -07:00
dependabot[bot] fb680df728
build(deps-dev): bump @storybook/addon-a11y from 10.4.2 to 10.5.4 (#10305)
Bumps
[@storybook/addon-a11y](https://github.com/storybookjs/storybook/tree/HEAD/code/addons/a11y)
from 10.4.2 to 10.5.4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/storybookjs/storybook/releases">@​storybook/addon-a11y's
releases</a>.</em></p>
<blockquote>
<h2>v10.5.4</h2>
<h2>10.5.4</h2>
<ul>
<li>ReactNative: Telemetry framework detection fix - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35560">#35560</a>,
thanks <a
href="https://github.com/ndelangen"><code>@​ndelangen</code></a>!</li>
<li>SyntaxHighlighter: Fix PrismJS dark mode mismatch - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35541">#35541</a>,
thanks <a
href="https://github.com/hxy-asdw"><code>@​hxy-asdw</code></a>!</li>
</ul>
<h2>v10.5.3</h2>
<h2>10.5.3</h2>
<ul>
<li>Dependencies: Upgrade TypeScript to 6.0.3 - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34971">#34971</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
</ul>
<h2>v10.5.2</h2>
<h2>10.5.2</h2>
<ul>
<li>Angular-Vite: Drop <code>@​angular/platform-browser-dynamic</code>
peer dependency - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35457">#35457</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Angular-Vite: Widen TypeScript peer dependency range to support
TypeScript 6 - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35455">#35455</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Core: Include chromatic packages in ecosystem identifier - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35170">#35170</a>,
thanks <a
href="https://github.com/yannbf"><code>@​yannbf</code></a>!</li>
<li>TanStack: Fix createServerFn validator mock - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35185">#35185</a>,
thanks <a
href="https://github.com/sjh9714"><code>@​sjh9714</code></a>!</li>
<li>TanStack: Support pathless layout routes (id-only) in story routing
- <a
href="https://redirect.github.com/storybookjs/storybook/pull/35465">#35465</a>,
thanks <a
href="https://github.com/unpunnyfuns"><code>@​unpunnyfuns</code></a>!</li>
<li>Tanstack-react: Add missing Hydrate export - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35111">#35111</a>,
thanks <a
href="https://github.com/arun-357"><code>@​arun-357</code></a>!</li>
<li>Tanstack-react: Keep JSX-only component references during dead-code
elimination - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35206">#35206</a>,
thanks <a
href="https://github.com/yatishgoel"><code>@​yatishgoel</code></a>!</li>
<li>Vitest: Fix coverage toggle crash on Vite 6 by clearing closed
Vitest instance on restart - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35461">#35461</a>,
thanks <a
href="https://github.com/yannbf"><code>@​yannbf</code></a>!</li>
</ul>
<h2>v10.5.1</h2>
<h2>10.5.1</h2>
<ul>
<li>Angular-Vite: Drop <code>@​angular/platform-browser-dynamic</code>
peer dependency - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35457">#35457</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Angular-Vite: Widen TypeScript peer dependency range to support
TypeScript 6 - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35455">#35455</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Core: Include chromatic packages in ecosystem identifier - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35170">#35170</a>,
thanks <a
href="https://github.com/yannbf"><code>@​yannbf</code></a>!</li>
</ul>
<h2>v10.5.0</h2>
<h2>10.5.0</h2>
<blockquote>
<p><em>Foundational changes for new AI workflows</em></p>
</blockquote>
<p>Storybook 10.5 contains hundreds of fixes and improvements:</p>
<ul>
<li>️ Angular-vite framework: Modern, fast dev, docs, and test
(preview)</li>
<li>🌈 Vitest initialGlobals: Test across themes, viewports, locales</li>
<li>🤖 Agentic review: AI-curated visual changesets and search results
(experimental)</li>
<li>⚛️ React docgen service: Unified metadata across MCP, Docs, and
Controls (experimental)</li>
<li>🧑‍💻 Claude / Codex plugins: One-click ADE integration
(experimental)</li>
</ul>
<!-- raw HTML omitted -->
<ul>
<li>A11y: Fix MDX heading anchors not keyboard accessible - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34368">#34368</a>,
thanks <a
href="https://github.com/TheSeydiCharyyev"><code>@​TheSeydiCharyyev</code></a>!</li>
<li>A11y: Handle lang attribute throughout preview - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35321">#35321</a>,
thanks <a
href="https://github.com/Sidnioulz"><code>@​Sidnioulz</code></a>!</li>
<li>A11y: Surface required args and keyboard-reachable Setup controls in
ArgsTable - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35306">#35306</a>,
thanks <a
href="https://github.com/Sidnioulz"><code>@​Sidnioulz</code></a>!</li>
<li>Addon A11y: Preserve disabled a11y rules with runOnly - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34649">#34649</a>,
thanks <a
href="https://github.com/cyphercodes"><code>@​cyphercodes</code></a>!</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md">@​storybook/addon-a11y's
changelog</a>.</em></p>
<blockquote>
<h2>10.5.4</h2>
<ul>
<li>ReactNative: Telemetry framework detection fix - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35560">#35560</a>,
thanks <a
href="https://github.com/ndelangen"><code>@​ndelangen</code></a>!</li>
<li>SyntaxHighlighter: Fix PrismJS dark mode mismatch - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35541">#35541</a>,
thanks <a
href="https://github.com/hxy-asdw"><code>@​hxy-asdw</code></a>!</li>
</ul>
<h2>10.5.3</h2>
<ul>
<li>Dependencies: Upgrade TypeScript to 6.0.3 - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34971">#34971</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
</ul>
<h2>10.5.2</h2>
<ul>
<li>TanStack: Fix createServerFn validator mock - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35185">#35185</a>,
thanks <a
href="https://github.com/sjh9714"><code>@​sjh9714</code></a>!</li>
<li>TanStack: Support pathless layout routes (id-only) in story routing
- <a
href="https://redirect.github.com/storybookjs/storybook/pull/35465">#35465</a>,
thanks <a
href="https://github.com/unpunnyfuns"><code>@​unpunnyfuns</code></a>!</li>
<li>Tanstack-react: Add missing Hydrate export - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35111">#35111</a>,
thanks <a
href="https://github.com/arun-357"><code>@​arun-357</code></a>!</li>
<li>Tanstack-react: Keep JSX-only component references during dead-code
elimination - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35206">#35206</a>,
thanks <a
href="https://github.com/yatishgoel"><code>@​yatishgoel</code></a>!</li>
<li>Vitest: Fix coverage toggle crash on Vite 6 by clearing closed
Vitest instance on restart - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35461">#35461</a>,
thanks <a
href="https://github.com/yannbf"><code>@​yannbf</code></a>!</li>
</ul>
<h2>10.5.1</h2>
<ul>
<li>Angular-Vite: Drop <code>@​angular/platform-browser-dynamic</code>
peer dependency - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35457">#35457</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Angular-Vite: Widen TypeScript peer dependency range to support
TypeScript 6 - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35455">#35455</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Core: Include chromatic packages in ecosystem identifier - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35170">#35170</a>,
thanks <a
href="https://github.com/yannbf"><code>@​yannbf</code></a>!</li>
</ul>
<h2>10.5.0</h2>
<blockquote>
<p><em>Foundational changes for new AI workflows</em></p>
</blockquote>
<p>Storybook 10.5 contains hundreds of fixes and improvements:</p>
<ul>
<li>️ Angular-vite framework: Modern, fast dev, docs, and test
(preview)</li>
<li>🌈 Vitest initialGlobals: Test across themes, viewports, locales</li>
<li>🤖 Agentic review: AI-curated visual changesets and search results
(experimental)</li>
<li>⚛️ React docgen service: Unified metadata across MCP, Docs, and
Controls (experimental)</li>
<li>🧑‍💻 Claude / Codex plugins: One-click ADE integration
(experimental)</li>
</ul>
<!-- raw HTML omitted -->
<ul>
<li>A11y: Fix MDX heading anchors not keyboard accessible - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34368">#34368</a>,
thanks <a
href="https://github.com/TheSeydiCharyyev"><code>@​TheSeydiCharyyev</code></a>!</li>
<li>A11y: Handle lang attribute throughout preview - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35321">#35321</a>,
thanks <a
href="https://github.com/Sidnioulz"><code>@​Sidnioulz</code></a>!</li>
<li>A11y: Surface required args and keyboard-reachable Setup controls in
ArgsTable - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35306">#35306</a>,
thanks <a
href="https://github.com/Sidnioulz"><code>@​Sidnioulz</code></a>!</li>
<li>Addon A11y: Preserve disabled a11y rules with runOnly - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34649">#34649</a>,
thanks <a
href="https://github.com/cyphercodes"><code>@​cyphercodes</code></a>!</li>
<li>Addon Docs: DocsContent not filling available width when TOC is
enabled - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35043">#35043</a>,
thanks <a
href="https://github.com/k-utsumi"><code>@​k-utsumi</code></a>!</li>
<li>Addon Docs: Resolve CSF4 module exports without a default export -
<a
href="https://redirect.github.com/storybookjs/storybook/pull/34834">#34834</a>,
thanks <a
href="https://github.com/TheSeydiCharyyev"><code>@​TheSeydiCharyyev</code></a>!</li>
<li>Addon Docs: Resolve providerImportSource to a path instead of a
file:// URL - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34841">#34841</a>,
thanks <a
href="https://github.com/TheSeydiCharyyev"><code>@​TheSeydiCharyyev</code></a>!</li>
<li>Addon Vitest: Add an initialGlobals option to pin a project's
globals - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35226">#35226</a>,
thanks <a
href="https://github.com/lifeiscontent"><code>@​lifeiscontent</code></a>!</li>
<li>Addon Vitest: Avoid erroring out on benign Win process exits - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35287">#35287</a>,
thanks <a
href="https://github.com/Sidnioulz"><code>@​Sidnioulz</code></a>!</li>
<li>Addon Vitest: Fix dynamic import failure with Vitest 3 - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34927">#34927</a>,
thanks <a
href="https://github.com/Sidnioulz"><code>@​Sidnioulz</code></a>!</li>
<li>Addon Vitest: Subscribe for run completion before triggering it - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35291">#35291</a>,
thanks <a
href="https://github.com/tsushanth"><code>@​tsushanth</code></a>!</li>
<li>Angular: Add versioned <code>@types/node</code> to packages
installed during <code>storybook init</code> - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34192">#34192</a>,
thanks <a
href="https://github.com/copilot-swe-agent"><code>@​copilot-swe-agent</code></a>!</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3327dc4469"><code>3327dc4</code></a>
Bump version from &quot;10.5.3&quot; to &quot;10.5.4&quot; [skip
ci]</li>
<li><a
href="9ac273930a"><code>9ac2739</code></a>
Bump version from &quot;10.5.2&quot; to &quot;10.5.3&quot; [skip
ci]</li>
<li><a
href="b4b00f2766"><code>b4b00f2</code></a>
Merge pull request <a
href="https://github.com/storybookjs/storybook/tree/HEAD/code/addons/a11y/issues/34971">#34971</a>
from storybookjs/valentin/upgrade-typescript-6</li>
<li><a
href="518f711cb3"><code>518f711</code></a>
Bump version from &quot;10.5.1&quot; to &quot;10.5.2&quot; [skip
ci]</li>
<li><a
href="c253a0667d"><code>c253a06</code></a>
Bump version from &quot;10.5.0&quot; to &quot;10.5.1&quot; [skip
ci]</li>
<li><a
href="9dafcd22ed"><code>9dafcd2</code></a>
Bump version from &quot;10.5.0-beta.2&quot; to &quot;10.5.0&quot; [skip
ci]</li>
<li><a
href="ad709148eb"><code>ad70914</code></a>
Addon A11y: Keep nested command output while closing stdin</li>
<li><a
href="c557fc0fb6"><code>c557fc0</code></a>
CLI: Fix silent hang in deferred addon configuration during upgrade</li>
<li><a
href="448db85e65"><code>448db85</code></a>
Bump version from &quot;10.5.0-beta.1&quot; to &quot;10.5.0-beta.2&quot;
[skip ci]</li>
<li><a
href="a4ce9790a7"><code>a4ce979</code></a>
Bump version from &quot;10.5.0-beta.0&quot; to &quot;10.5.0-beta.1&quot;
[skip ci]</li>
<li>Additional commits viewable in <a
href="https://github.com/storybookjs/storybook/commits/v10.5.4/code/addons/a11y">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@storybook/addon-a11y&package-manager=npm_and_yarn&previous-version=10.4.2&new-version=10.5.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-28 10:04:08 -07:00
dependabot[bot] 00b43a7446
build(deps): bump @tanstack/react-query from 5.101.2 to 5.101.4 (#10307)
Bumps
[@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query)
from 5.101.2 to 5.101.4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/TanStack/query/releases">@​tanstack/react-query's
releases</a>.</em></p>
<blockquote>
<h2><code>@​tanstack/react-query-devtools</code><a
href="https://github.com/5"><code>@​5</code></a>.101.4</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies []:
<ul>
<li><code>@​tanstack/query-devtools</code><a
href="https://github.com/5"><code>@​5</code></a>.101.4</li>
<li><code>@​tanstack/react-query</code><a
href="https://github.com/5"><code>@​5</code></a>.101.4</li>
</ul>
</li>
</ul>
<h2><code>@​tanstack/react-query-next-experimental</code><a
href="https://github.com/5"><code>@​5</code></a>.101.4</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies []:
<ul>
<li><code>@​tanstack/react-query</code><a
href="https://github.com/5"><code>@​5</code></a>.101.4</li>
</ul>
</li>
</ul>
<h2><code>@​tanstack/react-query-persist-client</code><a
href="https://github.com/5"><code>@​5</code></a>.101.4</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies []:
<ul>
<li><code>@​tanstack/query-persist-client-core</code><a
href="https://github.com/5"><code>@​5</code></a>.101.4</li>
<li><code>@​tanstack/react-query</code><a
href="https://github.com/5"><code>@​5</code></a>.101.4</li>
</ul>
</li>
</ul>
<h2><code>@​tanstack/react-query</code><a
href="https://github.com/5"><code>@​5</code></a>.101.4</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies []:
<ul>
<li><code>@​tanstack/query-core</code><a
href="https://github.com/5"><code>@​5</code></a>.101.4</li>
</ul>
</li>
</ul>
<h2><code>@​tanstack/react-query-devtools</code><a
href="https://github.com/5"><code>@​5</code></a>.101.3</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies []:
<ul>
<li><code>@​tanstack/query-devtools</code><a
href="https://github.com/5"><code>@​5</code></a>.101.3</li>
<li><code>@​tanstack/react-query</code><a
href="https://github.com/5"><code>@​5</code></a>.101.3</li>
</ul>
</li>
</ul>
<h2><code>@​tanstack/react-query-next-experimental</code><a
href="https://github.com/5"><code>@​5</code></a>.101.3</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies []:
<ul>
<li><code>@​tanstack/react-query</code><a
href="https://github.com/5"><code>@​5</code></a>.101.3</li>
</ul>
</li>
</ul>
<h2><code>@​tanstack/react-query-persist-client</code><a
href="https://github.com/5"><code>@​5</code></a>.101.3</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies []:
<ul>
<li><code>@​tanstack/query-persist-client-core</code><a
href="https://github.com/5"><code>@​5</code></a>.101.3</li>
<li><code>@​tanstack/react-query</code><a
href="https://github.com/5"><code>@​5</code></a>.101.3</li>
</ul>
</li>
</ul>
<h2><code>@​tanstack/react-query</code><a
href="https://github.com/5"><code>@​5</code></a>.101.3</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies [<a
href="7e3c822a10"><code>7e3c822</code></a>]:</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md">@​tanstack/react-query's
changelog</a>.</em></p>
<blockquote>
<h2>5.101.4</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies []:
<ul>
<li><code>@​tanstack/query-core</code><a
href="https://github.com/5"><code>@​5</code></a>.101.4</li>
</ul>
</li>
</ul>
<h2>5.101.3</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies [<a
href="7e3c822a10"><code>7e3c822</code></a>]:
<ul>
<li><code>@​tanstack/query-core</code><a
href="https://github.com/5"><code>@​5</code></a>.101.3</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="86bb8a6fb2"><code>86bb8a6</code></a>
ci: Version Packages (<a
href="https://github.com/TanStack/query/tree/HEAD/packages/react-query/issues/11094">#11094</a>)</li>
<li><a
href="181ea826cb"><code>181ea82</code></a>
ci: Version Packages (<a
href="https://github.com/TanStack/query/tree/HEAD/packages/react-query/issues/11089">#11089</a>)</li>
<li><a
href="6d55b0759b"><code>6d55b07</code></a>
test({react,preact}-query): use the '.then()' convention consistently
(<a
href="https://github.com/TanStack/query/tree/HEAD/packages/react-query/issues/11085">#11085</a>)</li>
<li><a
href="44f38df5de"><code>44f38df</code></a>
test({react,preact,solid}-query/useInfiniteQuery): inline the shared
'fetchIt...</li>
<li><a
href="d1558c1491"><code>d1558c1</code></a>
test({react,preact}-query/usePrefetchQuery): inline the
'generateQueryFn' fac...</li>
<li><a
href="99690d18b7"><code>99690d1</code></a>
test({react,preact}-query/usePrefetchInfiniteQuery): inline single-use
helper...</li>
<li><a
href="10770f0720"><code>10770f0</code></a>
test({react,preact}-query/usePrefetchInfiniteQuery): inline the shared
'Suspe...</li>
<li><a
href="dbd5a86e95"><code>dbd5a86</code></a>
test({react,preact}-query/usePrefetchQuery): inline the shared
'Suspended' co...</li>
<li><a
href="b955f60d79"><code>b955f60</code></a>
test({react,preact}-query/useSuspenseQuery): assert the 'loading'
fallback is...</li>
<li><a
href="b9c657e20b"><code>b9c657e</code></a>
test({react,preact}-query/usePrefetchQuery): assert the 'Loading...'
fallback...</li>
<li>Additional commits viewable in <a
href="https://github.com/TanStack/query/commits/@tanstack/react-query@5.101.4/packages/react-query">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@tanstack/react-query&package-manager=npm_and_yarn&previous-version=5.101.2&new-version=5.101.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-28 10:03:59 -07:00
dependabot[bot] e95045905b
build(deps): bump better-auth from 1.6.23 to 1.6.25 (#10306)
Bumps
[better-auth](https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth)
from 1.6.23 to 1.6.25.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/better-auth/better-auth/releases">better-auth's
releases</a>.</em></p>
<blockquote>
<h2>v1.6.25</h2>
<h2><code>better-auth</code></h2>
<h3>Bug Fixes</h3>
<ul>
<li>Fixed Apple OAuth not sending the PKCE code challenge during
authorization, causing token exchange failures (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10294">#10294</a>)</li>
<li>Fixed Google One Tap creating new users when sign-up was disabled on
the Google provider (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10479">#10479</a>)</li>
<li>Fixed <code>$fetch</code> and <code>$store</code> not being exposed
on the Solid client (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10444">#10444</a>)</li>
<li>Fixed internal adapter queries being routed to the wrong table when
a built-in table's <code>modelName</code> was set to another table's
schema key (e.g. <code>user.modelName =
&quot;account&quot;</code>).</li>
</ul>
<p>For detailed changes, see <a
href="07a646ea19/packages/better-auth/CHANGELOG.md"><code>CHANGELOG</code></a></p>
<h2>Contributors</h2>
<p>Thanks to everyone who contributed to this release:</p>
<p><a href="https://github.com/birkskyum"><code>@​birkskyum</code></a>,
<a href="https://github.com/jsj"><code>@​jsj</code></a>, <a
href="https://github.com/krish-vachhani"><code>@​krish-vachhani</code></a></p>
<p><strong>Full changelog:</strong> <a
href="https://github.com/better-auth/better-auth/compare/v1.6.24...v1.6.25"><code>v1.6.24...v1.6.25</code></a></p>
<h2>v1.6.24</h2>
<h2><code>better-auth</code></h2>
<h3>Features</h3>
<ul>
<li>Added request context (<code>ctx</code>) as a third argument to
<code>verifyIdToken</code>, enabling custom ID token verifiers to read
request headers (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10376">#10376</a>)</li>
<li>Added <code>beforeStoreCookie</code> option to the last-login-method
plugin for GDPR compliance (<a
href="https://redirect.github.com/better-auth/better-auth/pull/5753">#5753</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Replaced flaky MongoDB where-coercion integration test with a direct
unit test for more reliable test runs (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10369">#10369</a>)</li>
<li>Fixed the <code>get-session</code> endpoint to include
<code>no-store</code> cache control headers, preventing stale session
data from being served (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10222">#10222</a>)</li>
<li>Fixed SQLite migration diffs to recognize <code>BIGINT</code> as a
valid number type, preventing spurious pending changes on rate limiter
columns (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10316">#10316</a>)</li>
<li>Fixed auth requests failing when request cloning throws an error
inside verification callbacks (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10336">#10336</a>)</li>
<li>Fixed <code>useSession({ throw: true })</code> incorrectly excluding
<code>null</code> from its <code>data</code> type (<a
href="https://redirect.github.com/better-auth/better-auth/pull/9787">#9787</a>)</li>
<li>Fixed auth query revalidation and signal listeners not being
restored after a client component remounts (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10379">#10379</a>)</li>
<li>Fixed the <code>CookieAttributes</code> index signature type to be
more precise (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10442">#10442</a>)</li>
<li>Fixed silent misrouting of adapter queries when
<code>user.modelName</code> was set to a value that collides with
another schema key (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10235">#10235</a>)</li>
<li>Fixed Kysely migration generation producing duplicate indexes for
fields marked both <code>unique</code> and <code>index</code> (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10357">#10357</a>)</li>
<li>Fixed magic-link and email-OTP send endpoints to validate the
<code>Origin</code> header on cookieless requests, preventing
cross-origin abuse (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10368">#10368</a>)</li>
<li>Fixed remote MCP auth 401 challenge headers being hidden from
browser clients due to missing CORS exposure (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10290">#10290</a>)</li>
<li>Fixed OpenAPI schema to include plugin user fields (such as
<code>username</code> and <code>displayUsername</code>) in
<code>/sign-up/email</code> and <code>/update-user</code> request bodies
(<a
href="https://redirect.github.com/better-auth/better-auth/pull/10453">#10453</a>)</li>
<li>Fixed <code>organization.listMembers</code> failing with &quot;User
not found for member&quot; for organizations with more than ~100 members
(<a
href="https://redirect.github.com/better-auth/better-auth/pull/10342">#10342</a>)</li>
<li>Fixed organization invitations to use database-generated IDs when
<code>advanced.database.generateId</code> is configured, matching the
behavior of other models (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10040">#10040</a>)</li>
<li>Fixed <code>getDefaultModelName</code> to prefer exact schema key
matches over <code>modelName</code> aliases, preventing adapter queries
from being misrouted when a built-in table's name collides with another
schema key</li>
</ul>
<p>For detailed changes, see <a
href="9a661c7b7a/packages/better-auth/CHANGELOG.md"><code>CHANGELOG</code></a></p>
<h2><code>auth</code></h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/better-auth/better-auth/blob/main/packages/better-auth/CHANGELOG.md">better-auth's
changelog</a>.</em></p>
<blockquote>
<h2>1.6.25</h2>
<h3>Patch Changes</h3>
<ul>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10479">#10479</a>
<a
href="5124c34879"><code>5124c34</code></a>
Thanks <a
href="https://github.com/krish-vachhani"><code>@​krish-vachhani</code></a>!
- Prevent Google One Tap from creating new users when sign-up is
disabled for the Google provider.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10444">#10444</a>
<a
href="743935991f"><code>7439359</code></a>
Thanks <a
href="https://github.com/birkskyum"><code>@​birkskyum</code></a>! -
Expose the real <code>$fetch</code> instance and <code>$store</code>
atoms from the Solid client instead of resolving them as dynamic API
routes.</p>
</li>
<li>
<p>Updated dependencies [<a
href="0ffd1fb28d"><code>0ffd1fb</code></a>]:</p>
<ul>
<li><code>@​better-auth/core</code><a
href="https://github.com/1"><code>@​1</code></a>.6.25</li>
<li><code>@​better-auth/drizzle-adapter</code><a
href="https://github.com/1"><code>@​1</code></a>.6.25</li>
<li><code>@​better-auth/kysely-adapter</code><a
href="https://github.com/1"><code>@​1</code></a>.6.25</li>
<li><code>@​better-auth/memory-adapter</code><a
href="https://github.com/1"><code>@​1</code></a>.6.25</li>
<li><code>@​better-auth/mongo-adapter</code><a
href="https://github.com/1"><code>@​1</code></a>.6.25</li>
<li><code>@​better-auth/prisma-adapter</code><a
href="https://github.com/1"><code>@​1</code></a>.6.25</li>
<li><code>@​better-auth/telemetry</code><a
href="https://github.com/1"><code>@​1</code></a>.6.25</li>
</ul>
</li>
</ul>
<h2>1.6.24</h2>
<h3>Patch Changes</h3>
<ul>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10235">#10235</a>
<a
href="03dc5a046f"><code>03dc5a0</code></a>
Thanks <a
href="https://github.com/ping-maxwell"><code>@​ping-maxwell</code></a>!
- Fixes silent foreign-key and adapter-join misrouting when a user
remaps a built-in model name to a string that collides with another
schema key</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10357">#10357</a>
<a
href="7508940376"><code>7508940</code></a>
Thanks <a href="https://github.com/c-nicol"><code>@​c-nicol</code></a>!
- Fixes Kysely migration generation for new-table fields that are both
unique: true and index: true.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10342">#10342</a>
<a
href="bae71988ab"><code>bae7198</code></a>
Thanks <a
href="https://github.com/ping-maxwell"><code>@​ping-maxwell</code></a>!
- Fix <code>organization.listMembers</code> failing with &quot;User not
found for member&quot; for orgs with more than ~100 members by applying
the same membership limit to the users query.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10336">#10336</a>
<a
href="ef4d27360c"><code>ef4d273</code></a>
Thanks <a
href="https://github.com/Tushar-Khandelwal-2004"><code>@​Tushar-Khandelwal-2004</code></a>!
- Prevent verification callbacks from failing auth requests when cloning
the request throws.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10333">#10333</a>
<a
href="99dbdd7ea9"><code>99dbdd7</code></a>
Thanks <a href="https://github.com/c-nicol"><code>@​c-nicol</code></a>!
- Fixes Drizzle schema generation for fields that are both unique: true
and index: true.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10368">#10368</a>
<a
href="086ca91f51"><code>086ca91</code></a>
Thanks <a
href="https://github.com/gaurav0107"><code>@​gaurav0107</code></a>! -
Force-validate the request <code>Origin</code> on the magic-link
(<code>/sign-in/magic-link</code>) and email-otp
(<code>/email-otp/send-verification-otp</code>) send endpoints,
including cookieless requests, to match the built-in
<code>/sign-in/email</code> and <code>/sign-up/email</code> routes. A
cookieless cross-origin POST can no longer trigger a magic-link or
verification-OTP email to an arbitrary address. Cookieless requests that
carry no <code>Origin</code> (server-to-server) are unaffected.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10290">#10290</a>
<a
href="8f2dedd893"><code>8f2dedd</code></a>
Thanks <a
href="https://github.com/GautamBytes"><code>@​GautamBytes</code></a>! -
Expose the remote MCP auth client's 401 challenge headers to browser
clients using CORS.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10453">#10453</a>
<a
href="4e685eef42"><code>4e685ee</code></a>
Thanks <a
href="https://github.com/ping-maxwell"><code>@​ping-maxwell</code></a>!
- OpenAPI now includes <code>user.additionalFields</code> and plugin
user schema fields (e.g. username plugin <code>username</code> /
<code>displayUsername</code>) on <code>/sign-up/email</code> and
<code>/update-user</code> request bodies.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10190">#10190</a>
<a
href="3bf0e4981e"><code>3bf0e49</code></a>
Thanks <a
href="https://github.com/gaurav-init"><code>@​gaurav-init</code></a>! -
Pass the endpoint context as the second argument to
<code>beforeDeleteOrganization</code> and
<code>afterDeleteOrganization</code> hooks in the organization plugin,
matching the signature shown in the docs and the existing
<code>databaseHooks</code> pattern. The Stripe plugin's
<code>beforeDeleteOrganization</code> wrapper now forwards the context
to user-supplied hooks instead of dropping it.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10040">#10040</a>
<a
href="f59a0ee789"><code>f59a0ee</code></a>
Thanks <a
href="https://github.com/shiminshen"><code>@​shiminshen</code></a>! -
Organization invitations now let the database generate their
<code>id</code> when ID generation is delegated to the database (e.g.
<code>advanced.database.generateId: &quot;uuid&quot;</code> with a
UUID-capable adapter such as Postgres), matching every other model.
Previously <code>createInvitation</code> always generated the invitation
<code>id</code> in application code, so invitation rows received an
app-generated value instead of a database-generated one while
organizations, members and teams correctly deferred to the database (<a
href="https://redirect.github.com/better-auth/better-auth/issues/10024">better-auth/better-auth#10024</a>).
A caller-provided id (e.g. via <code>beforeCreateInvitation</code>) is
still honored.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10302">#10302</a>
<a
href="0f2cc1b33b"><code>0f2cc1b</code></a>
Thanks <a
href="https://github.com/momomuchu"><code>@​momomuchu</code></a>! -
Prefer exact schema-key matches over <code>modelName</code> aliases in
<code>getDefaultModelName</code>, so remapping a built-in table onto
another table's schema key (e.g. <code>user.modelName =
&quot;account&quot;</code>) does not reroute internal adapter queries to
the wrong table.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/9787">#9787</a>
<a
href="ae78109118"><code>ae78109</code></a>
Thanks <a
href="https://github.com/ping-maxwell"><code>@​ping-maxwell</code></a>!
- Fixes an issue where <code>useSession({ throw: true })</code>
incorrectly excluded <code>null</code> from its <code>data</code>
type.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10222">#10222</a>
<a
href="46d2bf02c9"><code>46d2bf0</code></a>
Thanks <a
href="https://github.com/ping-maxwell"><code>@​ping-maxwell</code></a>!
- fix: add no-store cache-control headers to get-session route</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10316">#10316</a>
<a
href="29a373eaf1"><code>29a373e</code></a>
Thanks <a
href="https://github.com/vinay-oppuri"><code>@​vinay-oppuri</code></a>!
- Recognize SQLite <code>BIGINT</code> as a valid number type in
migration diffs so database-backed rate limiter columns like
<code>lastRequest</code> no longer report spurious pending changes on
every run.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10379">#10379</a>
<a
href="f6d18fa8f7"><code>f6d18fa</code></a>
Thanks <a
href="https://github.com/ping-maxwell"><code>@​ping-maxwell</code></a>!
- fix(client): restore auth query revalidation and signal listeners
after remount</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="07a646ea19"><code>07a646e</code></a>
chore: release v1.6.25 (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/10491">#10491</a>)</li>
<li><a
href="743935991f"><code>7439359</code></a>
fix(solid): expose $fetch and $store on the solid client (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/10444">#10444</a>)</li>
<li><a
href="dac701c94b"><code>dac701c</code></a>
chore(deps): bump next from 16.2.6 to 16.2.11 (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/10493">#10493</a>)</li>
<li><a
href="5124c34879"><code>5124c34</code></a>
fix(one-tap): enforce google provider signup restrictions (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/10479">#10479</a>)</li>
<li><a
href="9a661c7b7a"><code>9a661c7</code></a>
chore: release v1.6.24 (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/10323">#10323</a>)</li>
<li><a
href="4e685eef42"><code>4e685ee</code></a>
fix(open-api): include plugin user fields on sign-up/update bodies (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/10453">#10453</a>)</li>
<li><a
href="d3ce782332"><code>d3ce782</code></a>
fix(cookies): tighten CookieAttributes index signature type (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/10441">#10441</a>)
(<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/10442">#10442</a>)</li>
<li><a
href="ae78109118"><code>ae78109</code></a>
fix(client): preserve null in useSession().data type with throw:true (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/9787">#9787</a>)</li>
<li><a
href="f6d18fa8f7"><code>f6d18fa</code></a>
fix(client): restore auth query lifecycle after remount (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/10379">#10379</a>)</li>
<li><a
href="086ca91f51"><code>086ca91</code></a>
fix(magic-link, email-otp): force-validate Origin on cookieless send
endpoint...</li>
<li>Additional commits viewable in <a
href="https://github.com/better-auth/better-auth/commits/v1.6.25/packages/better-auth">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=better-auth&package-manager=npm_and_yarn&previous-version=1.6.23&new-version=1.6.25)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-28 10:03:52 -07:00
dependabot[bot] 0a6532175c
build(deps): bump react-resizable-panels from 4.12.1 to 4.12.2 (#10301)
Bumps
[react-resizable-panels](https://github.com/bvaughn/react-resizable-panels)
from 4.12.1 to 4.12.2.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/bvaughn/react-resizable-panels/blob/main/CHANGELOG.md">react-resizable-panels's
changelog</a>.</em></p>
<blockquote>
<h2>4.12.2</h2>
<ul>
<li><a
href="https://redirect.github.com/bvaughn/react-resizable-panels/issues/726">726</a>:
Updated inline documentation to clarify size units.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="a1eeb7aefd"><code>a1eeb7a</code></a>
4.12.1 -&gt; 4.12.2</li>
<li>See full diff in <a
href="https://github.com/bvaughn/react-resizable-panels/compare/4.12.1...4.12.2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=react-resizable-panels&package-manager=npm_and_yarn&previous-version=4.12.1&new-version=4.12.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-28 10:03:49 -07:00
dependabot[bot] 4881f548be
build(deps): bump @cursor/sdk from 1.0.19 to 1.0.24 (#10298)
Bumps [@cursor/sdk](https://github.com/cursor/cursor) from 1.0.19 to
1.0.24.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/cursor/cursor/commits">compare view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~luist18">luist18</a>, a new releaser for
<code>@​cursor/sdk</code> since your current version.</p>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@cursor/sdk&package-manager=npm_and_yarn&previous-version=1.0.19&new-version=1.0.24)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-28 10:03:36 -07:00
Nicky Leach 9ff7e1caf3
perf(adapter-utils): content-hash-skip process-session remote script write + lock inbound round-trip count (#10377)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The sandbox runtime depends on efficiently staging files into remote
environments
> - The process-session bridge was rewriting a static remote script on
every start, even when the remote copy already matched
> - That caused unnecessary round trips and made the startup path
noisier than it needed to be
> - This pull request adds a hash-skip path for the process-session
script write and keeps the existing bridge-entrypoint hash gate on the
same helper
> - It also locks in the reduced inbound round-trip count so the
collapse from the prior PR cannot silently regress
> - The benefit is fewer remote execs on warm starts and a stronger
guard against performance regressions

## Linked Issues or Issue Description

- Refs: https://github.com/paperclipai/paperclip/pull/10354

### Feature request-style description

**Subsystem affected**
- Cross-cutting (packages/adapter-utils and sandbox staging helpers)

**Problem or motivation**
- The process-session bootstrap path was rewriting a static remote
script on every start even when the remote file already matched the host
content.
- That added avoidable remote execs and latency to warm starts.
- The inbound staging collapse from the previous PR also needed a
regression lock so it could not silently drift back to extra round
trips.

**Proposed solution**
- Route the process-session remote script upload through the existing
hash-skip helper used by the sandbox callback bridge entrypoint.
- Keep the bridge-entrypoint behavior unchanged by delegating it to the
same helper.
- Add a regression test that asserts the inbound staging path still
collapses to the expected round-trip count.

**Alternatives considered**
- Keep the existing unconditional write path and accept the extra execs
on warm starts. Rejected because it preserves avoidable overhead.
- Add a second specialized helper just for process-session scripts.
Rejected because the bridge-entrypoint logic already solved the same
problem and should stay aligned.

**Roadmap alignment**
- This fits the roadmap items around cloud/sandbox agents and enforced
outcomes by reducing bootstrap waste and preventing performance
regressions.
- It does not introduce new product surface area, telemetry, or
user-facing workflow changes.

**Additional context**
- The implementation preserves the existing upload/verify/rename
behavior when the remote content differs and only skips the write when
the hash already matches.
- PR #10354 collapsed the inbound staging path; this PR preserves that
win.

## What Changed

- Added a shared hash-skip helper for remote text-file synchronization
so unchanged content skips the write path after a single remote hash
check.
- Switched the process-session remote script upload to use that helper,
preserving the existing write/verify/rename behavior when the remote
content differs.
- Refactored the sandbox callback bridge entrypoint sync to use the same
helper without changing its observable behavior.
- Added a mocked-native-runner regression test that locks the inbound
staging path to one `client.syncIn` round-trip per step and zero direct
write/run execs.

## Verification

- `tsc --noEmit`
- `pnpm --filter @paperclipai/adapter-utils exec vitest run`
- Full adapter-utils vitest sweep: 338 passed / 4 skipped

## Risks

- Low risk: the helper changes when a write occurs, not the script
contents or the remote execution surface.
- A hash-check failure now fails loudly instead of silently rewriting,
which is safer but could surface provider-side issues earlier than
before.
- The regression test is intentionally specific to the current collapsed
staging path, so future architectural changes will need test updates.

## Model Used

OpenAI Codex (GPT-5, tool-using coding agent)

## 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: Harold Kim <harold@paperclip.ing>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-28 08:33:12 -07:00
Nicky Leach 341993ebae
feat(sandbox-runtime): route all inbound staging through client.syncIn (Codex home -> native uploadFiles; delete usesCustomProvision gate) (#10354) 2026-07-28 07:22:18 -07:00
Nicky Leach 7797995038
perf(plugin-daytona): opt-in no-profile fast path for default-PATH execs (#10352)
## Thinking Path

> - Paperclip is the control plane for autonomous AI companies
> - The Daytona adapter turns tasks into shell commands and manages
execution overhead
> - Many short-lived exec calls still pay for login-shell profile
sourcing even when the binary already resolves on the sandbox default
PATH
> - That extra startup work adds latency on the hot path for repeated
command execution
> - This pull request adds an opt-in fast path that skips profile
sourcing only when the caller explicitly requests it and the command
does not need shell initialization
> - The benefit is lower per-call latency for eligible commands without
changing the conservative default behavior for commands that need the
profile

## Linked Issues or Issue Description

This change does not reference a public GitHub issue. It follows the
same Daytona startup-speed work as merged PR #10335 and narrows the
execution path for eligible commands while keeping the default
login-shell behavior intact.

## What Changed

- Added an optional `noProfile` flag to
`PluginEnvironmentExecuteParams`.
- Refactored Daytona login-shell script assembly so the profile and nvm
sourcing block is omitted only on the explicit fast path.
- Preserved environment prefixing, `cd`, shell quoting,
`NONINTERACTIVE_GIT_ENV`, stdin handling, and `durationMs` behavior on
both paths.
- Added regression tests for the fast path omission, the preserved
execution parameters, and the default profile-sourcing path.

## Verification

- `pnpm --filter @paperclipai/sandbox-provider-daytona exec vitest run
src/plugin.test.ts`
- `pnpm --filter @paperclipai/plugin-sdk tsc --noEmit`
- Reverted the guard locally to confirm the two behavior tests fail
again, then restored the change.

## Risks

- If a caller opts into `noProfile` for a command that depends on shell
initialization, the command can fail to resolve its binary.
- The API comment and opt-in design keep that risk narrow; the default
path remains unchanged.

## Model Used

OpenAI GPT-5 (Codex tool-using coding agent)

## 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>
2026-07-27 21:47:05 -07:00
Nicky Leach 0ccba45e4d
feat(sandbox-providers): native providers honor postUploadCommands (Daytona executes; Kubernetes executes) (#10347)
## Thinking Path

> - Paperclip is the control plane for autonomous AI companies, so
runtime handoffs have to preserve the exact behavior an agent asked for.
> - The sandbox-provider layer is where uploaded files and follow-up
commands become a real in-sandbox operation.
> - The provider-delegable sync-in seam already exists from the prior
PR; without this follow-up, native providers can still accept
command-bearing uploads and silently drop the commands.
> - That is a fail-open gap for native sandbox providers, because the
file transfer succeeds while the intended post-upload work never runs.
> - This pull request teaches Daytona and Kubernetes to execute
`postUploadCommands` in order, inside the sandbox, after the files land.
> - The benefit is consistent and safer sync semantics: native providers
either run the commands as requested or fail fast instead of pretending
the operation completed fully.

## Linked Issues or Issue Description

This PR builds on the previously merged provider-delegable sync-in seam
and closes the remaining gap for native providers that still dropped
`postUploadCommands`.

Problem:
- A sync operation could include ordered `postUploadCommands`, but a
native provider could finish the file upload and skip the commands
entirely.
- That creates fail-open behavior for command-bearing uploads,
especially when the caller relies on the provider to execute the
follow-up action in the sandbox.

Proposed fix:
- Execute `postUploadCommands` inside the sandbox after file placement.
- Preserve the provided command order.
- Fail fast on the first non-zero exit or timeout.
- Keep command execution verbatim and confine any provided `cwd` under
the workspace root.

Related public PR:
- Refs: #10340

## What Changed

- Daytona `performSyncIn` now executes ordered `postUploadCommands`
through the existing `executeCommand` seam.
- Kubernetes `performSyncIn` now executes ordered `postUploadCommands`
through its streaming pod exec path.
- Added workspace confinement for provided `cwd` values and defaulted
missing `cwd` to the remote root.
- Added tests covering the new post-upload command execution behavior in
both provider packages.

## Verification

- Latest validation recorded on the handoff branch:
`@paperclipai/plugin-sdk` and `@paperclipai/plugin-kubernetes`
typechecks passed.
- Daytona Vitest: `63/63` passing in `plugin.test.ts`.
- Kubernetes Vitest: `195/195` passing, including `file-sync.test.ts`.
- `git log --oneline origin/master..HEAD` showed a single expected
commit on the branch.

## Risks

- Command execution semantics are stricter now, so malformed commands or
a bad `cwd` will fail the sync instead of being ignored.
- The change makes provider behavior more explicit, which can surface
previously hidden failures in callers that assumed commands were
optional.
- Timeout behavior may differ slightly between providers, so the failure
mode is intentionally fail-fast.

## Model Used

OpenAI Codex, GPT-5-based coding agent with tool use enabled.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have 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>
2026-07-27 21:17:16 -07:00
Dotta 1cd09ed555
perf(heartbeat): reuse task sessions for issue-scoped timer wakes and bound control-plane write retries (#10350)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents make progress in heartbeats: the server wakes an agent
session, it does a slice of work on an issue, records a disposition, and
exits
> - Benchmarking identical coding tasks run as Paperclip-orchestrated
agent pairs vs invoking the same agent harness directly measured a
1.8–2.2× wall-clock slowdown for the Paperclip pairs, dominated by
per-heartbeat orchestration overhead rather than model time
> - Two contributors stood out: (1) since PF-4 (#4838) every
`heartbeat_timer` wake starts a brand-new task session, so continuation
work on a specific issue repays the full session-start and
re-orientation cost on every heartbeat; (2) in degraded environments
agents burn many tool calls retrying the same failing control-plane
write before giving up
> - This pull request reuses the task session for issue-scoped timer
wakes (keeping the PF-4 fresh-session rule only for unscoped exploratory
wakes, which were the original context-bloat case) and adds a
bounded-retry rule to the wake prompt and core skill: after 2
consecutive failures of the same control-plane write, stop retrying it
for the rest of the heartbeat and rely on the adapter/runtime status
channel
> - The benefit is materially less wall-clock and token overhead per
heartbeat while preserving the context-bloat protection PF-4 was added
for

## Linked Issues or Issue Description

Refs #4838 (merged PF-4 change whose reset rule this refines), Refs
#5287, Refs #1907 (related timer-heartbeat session work).

No public GitHub issue exists for the slowdown itself; bug-report
fields:

- **What happened:** Agent pairs orchestrated through Paperclip
heartbeats complete identical task sets 1.8–2.2× slower (wall-clock)
than the same harness invoked directly. Profiling attributed the gap to
per-heartbeat orchestration overhead: every timer wake discards the task
session (full session start + re-orientation), and in degraded
environments agents repeatedly retry the same failing control-plane
write.
- **Expected behavior:** Heartbeat orchestration should add minimal
wall-clock overhead on top of the underlying harness; issue-scoped
continuation work should not pay a fresh-session tax each interval.
- **Steps to reproduce:** Run a fixed benchmark task set once through
Paperclip issue heartbeats and once via direct harness invocation with
the same model/config; compare wall-clock totals.
- **Version/commit:** master @ 3d23c3b2c3, self-hosted deployment.

## What Changed

- `server/src/services/heartbeat.ts`: `shouldResetTaskSessionForWake`
now resets only for `heartbeat_timer` wakes with no derivable task key
(unscoped exploratory wakes). Issue-scoped timer wakes reuse the issue's
task session. `describeSessionResetReason` updated to stay in exact
agreement.
- `server/src/__tests__/heartbeat-timer-wake-session-reset-pf4.test.ts`:
new cases for scoped vs unscoped timer wakes, plus the scoped case added
to the reset/reason agreement invariant.
- `packages/adapter-utils/src/server-utils.ts`: wake prompt template and
execution contract gain a bounded-retry rule — after 2 consecutive
failures of the same control-plane write, stop retrying it for the rest
of the heartbeat, continue useful work, report the failure in the final
response, and use the adapter/runtime status channel as the sanctioned
fallback.
- `packages/adapter-utils/src/server-utils.test.ts`: asserts the new
prompt lines are present in both the template and the rendered wake
prompt.
- `skills/paperclip/SKILL.md`: documents the same bounded write-retry
rule in the core Paperclip skill.

## Verification

- `node_modules/.bin/vitest run
packages/adapter-utils/src/server-utils.test.ts` — 1 file, 83 tests
passed
- `cd server && node_modules/.bin/vitest run
src/__tests__/heartbeat-timer-wake-session-reset-pf4.test.ts` — 1 file,
14 tests passed
- Both run on this branch rebased onto current master (3d23c3b2c3)

## Risks

- Behavioral shift: issue-scoped timer wakes now reuse sessions, so a
long-lived issue session can grow across heartbeats. Mitigated by
keeping the PF-4 reset for unscoped wakes (the originally observed bloat
case) and by existing session compaction.
- Prompt/skill text changes alter agent guidance; the new rule is scoped
narrowly to repeated failures of the same control-plane write.
- No migrations, no API or schema changes, no dependency changes.

## Model Used

- Claude (Anthropic) — `claude-fable-5` (Fable 5), extended reasoning
with tool use, driven via Claude Code / Claude Agent SDK.

## 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>
2026-07-27 22:01:29 -05:00
Nicky Leach 3d23c3b2c3
perf(plugin-daytona): cache the started sandbox handle per lease (#10335)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The Daytona sandbox adapter spends time on repeated per-exec sandbox
lookups during a lease
> - That repeated lookup is pure overhead once the started sandbox
handle is already known and trusted for the lease
> - The adapter still needs strict isolation and fail-closed behavior
because the handle is an authenticated compute object, not an inert
value
> - This pull request memoizes the started sandbox handle per lease in a
process-scoped cache, and now advances freshness only after successful
reuse so failed commands cannot suppress stale-handle refreshes
> - The benefit is lower provider-get latency on the hot path while
keeping resume safety, teardown safety, and observability intact

## Linked Issues or Issue Description

This is a Daytona performance fix, not a standalone public GitHub issue.

### Problem / Motivation

- Repeated `client.get(sandboxId)` calls on the sandbox hot path
re-fetch a handle that is already started and trusted for the current
lease.
- The extra provider round-trip is pure overhead on repeated exec, sync,
resume, and interactive-cancel flows.
- Cache freshness also has to be tied to successful reuse, or a failed
command can make a stale sandbox look freshly used.

### Proposed Solution

- Cache the started `Sandbox` handle in process memory, keyed by a
non-secret composite lease scope.
- Enforce strict identity checks and eviction on release, destroy,
interactive cancel, and resume-sentinel mismatch.
- Block teardown cleanup until active lease operations finish so
delete/stop cannot race in-flight execute or sync work.
- Advance freshness only after successful execute, sync, or resume
reuse, so failed operations do not mask an auto-stopped sandbox.
- Preserve `getDurationMs` in exec metadata so provider-get latency
remains observable.

### Alternatives Considered

- Keep fetching the sandbox on every exec path.
- Cache only by bare lease id.

### Roadmap Alignment

- This change is part of the Daytona performance work and narrows
per-call overhead without changing the public adapter contract.

## What Changed

- Memoized the started Daytona `Sandbox` handle in a process-scoped
cache keyed by a composite lease scope.
- Added fail-closed identity checks so cache hits and single-flight
populate paths reject mismatched sandbox ids.
- Evicted cached handles on release, destroy, interactive cancel, and
resume sentinel mismatch.
- Blocked release, destroy, and interactive cancel teardown cleanup
until active lease operations drain.
- Advanced cache freshness only after successful execute, sync, and
resume reuse.
- Kept `getDurationMs` in exec metadata so provider-get latency remains
observable.
- Expanded the Daytona plugin tests to cover same-lease reuse,
cross-scope isolation, eviction paths, rejected populate handling,
concurrent single-flight behavior, cached-resume sentinel revalidation,
teardown cancellation safety, and failed-execute freshness handling.

## Verification

- `pnpm exec vitest run --config vitest.config.ts` in
`packages/plugins/sandbox-providers/daytona` — 81/81 passing, including
the teardown-cancel, snapshot-capture, syncIn-cancel, and failed-execute
freshness regressions.
- `git rev-parse origin/perf/daytona-sandbox-handle-cache` matched the
authorized submit SHA `528158f998fa88bb0748300f156b38d86d6589cd` before
the fixup commits.
- `git log --oneline
origin/master..origin/perf/daytona-sandbox-handle-cache` shows the
expected focused Daytona changes.
- GitHub duplicate/related PR search and ROADMAP review were completed
before opening the PR.
- Remote CI and Greptile completed successfully after this description
was updated; the PR is now ready for board handoff.

## Risks

- The cache is process-scoped, so correctness depends on the eviction
paths staying complete.
- A bug in the scope key or identity checks could leak reuse across the
wrong lease boundaries, but the implementation fails closed on id
mismatches.
- Teardown now waits for active operations to drain, so any missed
activity bookkeeping could delay cleanup instead of racing it.
- Freshness updates now happen after success, which is safer, but it
means any missed success-path call would trigger an extra refresh rather
than silently masking staleness.

## Model Used

OpenAI GPT-5 via Codex, tool-using coding agent; exact context window
not surfaced in the workspace.

## 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>
2026-07-27 19:14:53 -07:00
Devin Foley c274f10abc
feat(server): computed owner instance-admin elevation for cloud-managed instances, behind platform floors (#10343)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Cloud-managed instances authenticate tenant users through a
trusted-header path (`resolveCloudTenantActor`) that deliberately never
grants `instance_admin`, so every tenant user is company-scoped
> - On a dedicated (single-owner) managed instance that leaves the
paying owner unable to administer their own instance: instance settings,
the environments admin surface, and the custom sandbox image flow are
all instance-admin gated (the environments UI can't even show the
provider/image of the platform sandbox because the restricted read view
blanks `config` entirely)
> - Re-granting the old blanket `instance_user_roles` row would repeat
the mistake the shared-pool hardening fixed: DB rows go stale, resurrect
via restores, and elevate through every auth path
> - This pull request elevates only the stack `owner`, computed per
request at the trusted-header boundary behind a new managed-tier feature
flag, and ships that elevation together with code floors on the
platform-owned surfaces an instance admin must not control on a managed
instance
> - The benefit is that dedicated-stack owners can administer their own
instance while platform credentials, execution policy, backups, and
runtime code-install stay platform-owned, and self-hosted behavior is
unchanged

## Linked Issues or Issue Description

No public GitHub issue exists for this change; the underlying issue is
described here following the feature-request template.

### Problem or motivation

- On cloud-managed instances, tenant users resolved from trusted headers
are always company-scoped. For dedicated instances with a single paying
owner, the owner cannot reach any instance-admin surface of their own
instance (instance settings, environments administration, custom image
setup), and the restricted environment read view hides even structural
fields like the sandbox provider and image.
- The previous hardening intentionally removed blanket elevation (and
purges stale `instance_user_roles` rows on every trusted-header
authentication). That protection must not regress for shared
multi-tenant pools.

### Proposed solution

- Owner-only, computed, flag-gated elevation plus code floors on
platform-owned surfaces, in one PR so the elevation can never ship
without the floors.

### Alternatives considered

- Re-inserting an `instance_user_roles` row for owners (the
pre-hardening model): rejected — DB rows go stale, survive restores, and
elevate through every auth path; #7525 removed exactly this.
- Widening only the environments read view without any elevation:
rejected — it fixes one screen but still leaves a dedicated-instance
owner unable to administer instance settings or custom images.
- Elevating additional stack roles (`member`/`admin`/`support`):
rejected — only the owner has an ownership claim over the whole
instance; other roles stay company-scoped.

### Roadmap alignment

- Extends the shipped "Cloud deployments" roadmap work (multi-tenant
isolation, company-scoped cloud tenants, managed-instance bootstrap)
without overlapping planned core items, and leaves self-hosted behavior
unchanged.

## What Changed

- **New feature key** `enableOwnerInstanceAdmin` (`packages/shared`):
boolean flag in `instanceExperimentalSettingsSchema`, catalog tier
`managed`, `cloudDefault: true`, `selfHostedDefault: false`. Inert on
self-hosted instances — the elevation path only exists behind the cloud
tenant trust token.
- **Computed elevation** (`server/src/middleware/auth.ts`):
`resolveCloudTenantActor` now returns `isInstanceAdmin: true` only when
the trusted-header stack role is `owner` **and** the flag is enabled.
The flag is resolved through the instance-settings service so the
managed-config overlay applies (the control plane can disable elevation
fleet-wide without touching tenant databases; a DB row edit or restore
cannot resurrect it). Resolution fails closed on settings read errors.
The `instance_user_roles` never-insert and the per-request stale-row
purge are byte-identical. `member`/`admin`/`support` stack roles stay
company-scoped.
- **Authorization guard split**
(`server/src/services/authorization.ts`): the blanket-allow now trusts
the actor's *computed* `isInstanceAdmin` flag (only the attested
resolver can set it for `cloud_tenant` actors) while keeping the
`instance_user_roles` DB lookup excluded for `cloud_tenant` — a stale or
hand-inserted role row still elevates nothing.
- **Floor F1 — platform environment credentials**
(`server/src/routes/environments.ts`): on cloud-managed instances,
platform-provisioned environment rows (`managedByPaperclip` marker, plus
the legacy managed-Kubernetes marker) use a single floored view for
every reader on all environment routes (list, get, create, update,
delete responses): `envVars` are never echoed and credential-shaped
`config` keys (reusing the managed-config
`SECRET_LIKE_CONFIG_KEY_PATTERN`) are dropped — for **all** actors
including instance admins — while structural config (provider, image,
template, region, …) and the managed markers stay visible. This also
fixes the environments UI for managed sandboxes, which previously lost
the provider/image entirely in the restricted view. The floor also
covers writes: `PATCH /environments/:id` and `DELETE /environments/:id`
on a platform-provisioned row are rejected (403,
`environment_platform_managed`) for every actor including instance
admins, and the guard binds to the persisted row's markers so a patch
cannot strip the managed marker to lift the floor. The one recovery path
is a metadata-only PATCH that solely clears the marker keys
(null/false), for rows stamped through the old unrestricted API before
the markers became reserved — and it never applies to a row whose slot
markers are live platform state: the single local row
(`environments_local_driver_idx`), which `ensureLocalEnvironment` adopts
and stamps on cloud-managed instances from every caller (company
creation, the heartbeat, run orchestration), and the single marked
sandbox row (`environments_managed_sandbox_idx`) while a managed-sandbox
bootstrap path is configured (managed-config `environments` section or
`PAPERCLIP_EXECUTION_MODE=kubernetes`) and the provisioner therefore
adopts and refreshes it on every boot. Clearing a live slot row's
markers would let the next write reclassify it as tenant-managed and
bypass the floor; conversely, when no sandbox provisioning path is
configured the platform holds no claim on any sandbox row, so a platform
marker there is stale by definition and the recovery patch applies.
Every marker outside a live slot is clearable, so no legacy row is ever
locked permanently. Custom-image setup and probes on the platform
sandbox stay available to instance admins — those are the owner-facing
flows this elevation exists for. The marker keys themselves are
reserved: client create/update payloads that set `managedByPaperclip` or
`managedKubernetesSandbox` are rejected (422,
`environment_platform_marker_reserved`) on cloud-managed instances, so a
tenant row can never be stamped platform-provisioned through the API and
self-locked behind the write floor (the provisioner writes markers at
the service layer, not through these routes). Tenant-created
environments are otherwise unaffected.
- **Floor F2 — executionMode**
(`server/src/routes/instance-settings.ts`): on cloud-managed instances,
`PATCH /instance/settings/general` rejects writes that would change
`executionMode` (403, `execution_mode_platform_managed`). Same-value
echoes pass so settings forms that submit the full general-settings
object keep working. The boot-time execution-policy bootstrap path is
untouched (it calls the service directly).
- **Floor F3 — manual database backups**
(`server/src/routes/instance-database-backups.ts`): floored off on
cloud-managed instances (403, `database_backups_platform_managed`);
backups are platform-owned there, and the result would also echo a
server-side filesystem path.
- **Floor F4 — adapter code install** (`server/src/routes/adapters.ts`):
`POST /adapters/install` and `POST /adapters/:type/reinstall` are
floored off on cloud-managed instances (403,
`adapter_install_platform_managed`). Adapter packages execute in the
server process, so a runtime install would let an instance admin read
the platform trust anchors out of the process environment. This mirrors
the existing bundled-only plugin install floor; adapter code on managed
instances comes bundled with the platform image.

## Instance-admin surface audit

Before widening who can hold `isInstanceAdmin`, every
instance-admin-gated surface in `server/src` was enumerated and reviewed
for whether its response or side effects could echo process environment
values or platform credentials (tenant trust token, JWT signing keys,
database connection strings, provider API keys): 29 distinct gate
definitions covering ~90+ call sites, in four groups — sole
instance-admin gates (12), instance-admin-or-company-permission gates
(10), response-shaping/scope-widening sites (6), and the central
`allow_instance_admin` short-circuit in the authorization service (58
`decide()` call sites).

Findings and dispositions:
- **Environment read/write responses** exposed platform sandbox
`envVars`/credential-shaped config to instance admins → closed by floor
F1.
- **Manual backup trigger** echoed a server filesystem path and triggers
a platform-owned operation → closed by floor F3.
- **Adapter install/reinstall** loads externally fetched code into the
server process (indirect, complete env exposure) → closed by floor F4.
The sibling plugin-install path already had a bundled-only floor on
managed instances and needed no change.
- **Token-minting surfaces** (gateway tokens, custom-image
terminal/connection tokens) mint credentials scoped to the instance's
own resources, not platform trust anchors → acceptable for an
owner-admin of a dedicated instance; unchanged.
- All remaining gated surfaces return ordinary instance-scoped business
data; none echo `process.env` or platform secrets directly. OAuth client
secrets are referenced by env-var *name* only; SSH private keys are
stored as secret refs before persistence and are not echoed.

Operational note for managed platforms: this model assumes the process
environment of a managed instance holds only that instance's own
credentials. Platform operators should keep provider credentials
per-instance (never fleet-shared) since an instance admin ultimately
controls in-process code on their own instance.

## Verification

- `pnpm vitest run server/src/middleware/cloud-tenant-actor.test.ts` —
resolver matrix: owner × flag on/off, flag via managed overlay
(on-over-DB-off and off-over-DB-on), member/admin/support × flag on,
no-token self-hosted, fail-closed settings read, purge still runs and no
role row is ever inserted (14 tests).
- `pnpm vitest run server/src/__tests__/authorization-service.test.ts` —
computed flag elevates a `cloud_tenant` actor; a stale
`instance_user_roles` row still never does; `session` actors unchanged
(full suite, embedded Postgres).
- `pnpm vitest run server/src/__tests__/environment-routes.test.ts` —
F1: no secret echo to admins on get/list, structural config visible to
restricted readers, platform-row PATCH/DELETE rejected for admins
(including a marker-stripping patch), marker-clear recovery allowed for
stale legacy rows and for a marked sandbox row when no provisioning path
is configured, but refused on the managed local row and on the sandbox
slot row under a managed-config `environments` entry or the forced
kubernetes execution mode, client marker-stamping creates/patches
rejected, tenant rows still readable and writable, self-hosted
read+write regression (60 tests).
- `pnpm vitest run server/src/__tests__/environment-service.test.ts` —
`ensureLocalEnvironment` adopts a pre-existing local row on
cloud-managed instances (marker stamped, other metadata preserved,
idempotent — no rewrite on re-ensure) and leaves self-hosted rows
untouched (22 tests, embedded Postgres).
- `pnpm vitest run server/src/__tests__/instance-settings-routes.test.ts
server/src/__tests__/instance-database-backups-routes.test.ts` — F2
change-vs-echo matrix incl. self-hosted regression; F3 floor for both
admin shapes (32 tests).
- `pnpm vitest run server/src/__tests__/adapter-routes-authz.test.ts` —
F4 floor; self-hosted install/reinstall behavior unchanged (existing
cases).
- `pnpm vitest run server/src/__tests__/first-admin-claim.test.ts
server/src/__tests__/bootstrap-claim-routes.test.ts
server/src/__tests__/managed-config.test.ts
server/src/__tests__/health.test.ts
server/src/__tests__/instance-settings-managed-overlay.test.ts
server/src/services/managed-environments.test.ts
server/src/services/execution-policy-bootstrap.test.ts` — first-admin
bootstrap gate and managed-config behavior unchanged (91 tests).
- `pnpm vitest run packages/shared/src/feature-catalog.test.ts` —
catalog/schema sync tests cover the new key (selfHostedDefault must
equal the schema default).
- `pnpm run typecheck` — all 31 workspace projects clean.

## Risks

- Self-hosted behavior is unchanged: every floor binds to
`isCloudManagedInstance()` (tenant trust token present), the new flag
defaults off with no elevation path, and regression tests pin the
self-hosted branches.
- The elevation is fail-closed and stateless: turning the flag off
(managed overlay or DB) de-elevates on the next request; there is no
role row to clean up and restores cannot resurrect elevation.
- On a cloud-managed instance a pre-existing unmarked local row is
adopted (stamped `managedByPaperclip`) by the next ensure and becomes
platform-owned — the intended managed-product semantic: the platform
owns the single local slot. Self-hosted instances are untouched.
- F1 widens restricted readers' view of platform-provisioned rows from
fully blanked `config`/`metadata` to structural-only `config` plus
markers. Platform-delivered config is guaranteed secret-free by the
managed-config contract (secret-shaped keys fail startup), and the floor
re-drops secret-shaped keys defensively.
- One extra instance-settings read per trusted-header request for
owner-role actors (the resolver already performs several queries per
request).

## Model Used

Claude Fable 5 (Anthropic) — model id `claude-fable-5`, extended
thinking enabled, agentic tool use via Claude Code; read-only explore
subagents on the same model were used for the surface audit sweep.

## 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
- [ ] 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>
2026-07-27 18:58:31 -07:00
Dotta c3bd0c5d50
feat(skills): add beta releases for the core Paperclip skill (#10228)
## Thinking Path

> - Paperclip is the open source control plane people use to organize
and operate AI-agent companies.
> - Agent behavior depends partly on the bundled Paperclip core skill
synchronized into each runtime.
> - The existing database and runtime plumbing already supports
immutable skill-version snapshots and per-agent version selections, but
no product workflow exposed that capability.
> - Replacing the live bundled skill globally would make champion
adoption risky and difficult to compare across agents.
> - This pull request adds an experimental, instance-level beta-skills
gate plus a repository release registry, immutable seeded releases,
enforcement, and a per-agent release picker.
> - The benefit is controlled per-agent evaluation of frozen core-skill
releases while the default-off path remains behaviorally unchanged.

## Linked Issues or Issue Description

### Subsystem affected

Cross-cutting: `server/`, `ui/`, `packages/db`, and `packages/shared`.

### Problem or motivation

Paperclip needs a safe way to evaluate improved versions of its core
operating skill without globally replacing the live default. Today the
version-snapshot and per-agent pin plumbing exists, but operators cannot
use it. A global replacement would make regressions difficult to contain
and would prevent controlled comparisons across agents.

### Proposed solution

Add a default-off instance experiment that exposes immutable, named
core-skill releases. When enabled, operators can pin each agent to a
seeded release; when disabled, every agent resolves the live default
while saved pins remain intact. Validate pinned writes at the API
boundary, gate reads at runtime, and expose the selection in the agent
Skills tab.

### Alternatives considered

- **Replace the bundled core skill globally:** rejected because it
changes every agent at once and provides no rollback/isolation boundary.
- **Ship releases as separate skills:** rejected because releases are
versions of one core capability, not independently enabled skills.
- **Store release snapshots only outside the repository:** rejected
because repository provenance and hashes make builds reproducible and
reviewable.

### Roadmap alignment

This extends the Skills Manager / Skill Studio direction in `ROADMAP.md`
by making core-skill versions operable per agent. It does not duplicate
another open implementation PR; GitHub searches found no related
`enableBetaSkills` change.

### Additional context

The feature remains experimental and default off. The V7 champion was
selected through a multi-model evaluation process, and the frozen
release contents are verified by SHA-256 below.

## What Changed

- Added the default-off instance-level `enableBetaSkills` experimental
flag.
- Added `skills-releases/paperclip/` with the ordered release registry
and frozen `v0` plus `v7-roster` snapshots.
- Added release metadata to `company_skill_versions` and idempotent
release seeding. The migration was planned as `0191`, then renumbered to
`0192` because current `master` claimed `0191` before final rebase.
- Added read-time gating and write-time validation so disabled instances
always resolve the live default and reject pinned-version writes.
- Added the per-agent Release picker in the agent Skills tab, including
responsive layout and beta-pin state.
- Kept `EDITS.md` out of the release registry and PR diff.

### V7 Adoption Evidence

- Paid roster: 6 models, 94-case suite.
- Result: 553/564 pass-within-2, mean 92.17/94, versus the P2 baseline
of 544/564.
- Reference model improved 84→91; maximin improved 84→90.
- Final report:
https://pages.paperclip.ing/skills/optimization/paperclip/pap-14624-p3-final-20260721/

### Provenance

- `v7-roster` is the Phase 1 champion plus additions-only edits
E107–E112. Per-edit rationale remains in the evals repository at
`source/v7-roster/EDITS.md` and is deliberately excluded from this PR.
- `v0` is the `skills/paperclip` tree from commit `ea66ea81`.
- Champion selection was accepted on July 21, 2026 via board card
`9c304fc2` (PAP-14624 G3).
- This delivery mechanism was accepted on July 24, 2026 via plan
revision `2367abd2` (PAP-14858).

### QA Evidence

- P4 QA matrix comment `b7f40522-4e9b-4a3a-9821-28e86fe1a987`: all 6
acceptance criteria passed.
- Automated QA matrix: 166 tests passed with 0 failures, including real
filesystem materialization and full SHA-256 assertions.
- UI QA exercised the real agent Skills tab at desktop and mobile widths
with the experimental flag both on and off.

## Verification

- `pnpm check:token-gates`
- Focused beta-release matrix: 169 tests passed across shared
validators, server services/routes/heartbeat behavior, instance settings
UI, and release picker UI.
- `pnpm -r typecheck`
- `pnpm build`
- `pnpm test:run`: server and UI partitions passed; one CLI doctor test
inherited temporary AWS credentials from the agent heartbeat and
expected no static credentials. The isolated rerun with
`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`
unset passed 8/8.
- V7 SHA-256:
- `SKILL.md`:
`53ab290489684cbf116fdd1406a95f6b6f53c9c36358b1bf8bfeae481e253575`
- `references/cases.md`:
`3b821f59064a7761091020a14819a8d787131f24029748563d6c0e1be7e6eaec`
- `references/workflows.md`:
`69747bd6e05f7e3673d1e67b07ff295df1869c05e1fd029804d5fa9177db92cd`
- Confirmed 49 changed files, no `pnpm-lock.yaml`, no workflow changes,
and no `EDITS.md`.

## Risks

- **Migration:** low-to-moderate risk. Three nullable columns and one
partial unique index are added idempotently; existing rows remain valid.
- **Behavior:** low risk while the flag is off because read-time
resolution forces the live default and saved pins are preserved but
inactive.
- **Frozen content:** release snapshots intentionally diverge from
future live skill edits; provenance and hashes make that divergence
explicit and reproducible.
- **UI:** low risk. The picker only renders for the bundled core skill
when the experimental flag is enabled and seeded releases exist.

> This extends the existing Skills Manager / Skill Studio direction
described in `ROADMAP.md`; it does not duplicate another open
implementation PR. The GitHub PR search found no related
`enableBetaSkills` change.

## Model Used

- OpenAI Codex using `gpt-5.5` with reasoning and
terminal/code-execution tools; context-window size is not exposed by
this runtime. Earlier implementation commits also record Claude Opus 4.8
assistance where applicable.

## 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
- [ ] I have not referenced internal/instance-local Paperclip issues or
links (required governance identifiers are included above; no internal
URL is included)
- [ ] My branch name describes the change and contains no internal
Paperclip ticket id (the approved delivery plan mandated this shared
branch name)
- [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>
2026-07-27 19:45:59 -05:00
Nicky Leach 030dd9d15c
feat(adapter-utils): provider-delegable syncIn seam with ordered post-upload commands (#10340)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The adapter/runtime layer has to move files into sandboxes safely
and efficiently
> - The current sync-in path needs a provider-delegable seam so
providers can use their native upload transport when available
> - The upload contract also needs ordered post-upload commands so
extracted content can be finalized fail-fast after transfer
> - The fallback path still has to preserve current behavior when the
provider does not expose native sync verbs
> - This pull request adds the contract and runtime seam for
provider-delegable sync-in, plus the single-stream collapse flag
> - The benefit is fewer round trips, a cleaner provider-owned upload
path, and a compatible fallback for existing runners

## Linked Issues or Issue Description

No public GitHub issue exists for this change. The underlying feature
request is described below in the repository's feature-request format.

### Problem or motivation

Paperclip needs a sync-in path that lets each provider choose the best
available upload transport instead of forcing the harness to orchestrate
uploads the same way every time. The runtime also needs a way to
describe ordered post-upload commands so providers can finalize
extracted content fail-fast after transfer.

### Proposed solution

Extend the sync contract with ordered post-upload commands, forward that
contract through the plugin and environment runtime layers, and make
client syncIn always available. When a provider advertises native sync
verbs, the client should delegate to that transport; otherwise it should
fall back to the existing tarball/write/extract behavior and then run
the post-upload commands in order.

### Alternatives considered

Keeping upload orchestration entirely host-side would avoid a contract
change, but it would block provider-specific transport optimizations and
keep the harness responsible for a path the provider can do more
efficiently. A separate post-upload API would add another surface
without improving the existing sync flow.

### Roadmap alignment

This work aligns with the broader runtime and adapter roadmap because it
improves provider integration without changing the external product
model. It is an additive contract change that preserves backward
compatibility for providers that do not expose native sync verbs.

### Additional context

The fallback path still needs to preserve existing observable behavior,
including command ordering, cwd confinement, and fail-fast execution.
The single-stream progress flag is part of the same transport
improvement so smaller writes can collapse to a single round trip when
the runner supports it.

## What Changed

- Added ordered `postUploadCommands` support to the sync operation
contract and SDK mirror.
- Plumbed the sync-in contract through the plugin and environment
runtime layers.
- Implemented a runtime client `syncIn` path that delegates to native
provider transport when available, otherwise uses the generic
tarball/write/extract fallback.
- Preserved fail-fast execution of ordered post-upload commands in the
fallback path.
- Flipped the sandbox runner's single-stream stdin progress flag to
collapse small `writeFile` operations to a single round trip.
- Added and updated tests for contract forwarding, fallback behavior,
cwd rejection, fail-fast behavior, and single-stream collapse.

## Verification

- `pnpm --filter @paperclipai/plugin-sdk exec vitest run
protocol.postupload.test.ts`
- `pnpm --filter @paperclipai/plugin-sdk exec vitest run
environment-sync-negotiation.test.ts`
- `pnpm --filter @paperclipai/adapter-utils exec vitest run
command-managed-runtime.test.ts`
- `pnpm --filter @paperclipai/server exec vitest run
environment-execution-target.test.ts`
- Local typecheck and targeted suite runs reported in the handoff passed
before PR creation.

## Risks

- The new fallback path could diverge from the previous inline upload
behavior if the tarball/extract contract changes.
- Provider-native sync handling may expose provider-specific edge cases
if a runner advertises sync verbs but does not fully honor the contract.
- The single-stream flag changes transport behavior for small uploads,
so regressions would likely show up as round-trip or upload failures.

## Model Used

OpenAI Codex (GPT-5, tool-using coding agent).

## 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 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>
2026-07-27 17:19:57 -07:00
Dotta c111ee4cb3
feat(server): add per-user document stars (#9952)
## Thinking Path

> - Paperclip is the open source control plane people use to manage
AI-agent companies and their work.
> - Artifacts and documents are first-class outputs, but users need a
personal way to keep important documents easy to find.
> - Existing resource memberships already model per-user starred
projects and agents with company scoping and activity logging.
> - Documents lacked the equivalent membership model, route, and
artifact filtering behavior.
> - The shared membership contract also needs to remain safe for
existing UI project/agent mutation helpers when documents become a
recognized resource type.
> - This pull request extends the existing resource-membership system
with per-user document stars and a starred artifacts view.
> - The benefit is a company-scoped, idempotent server foundation for a
dedicated starred-documents experience without weakening authorization
or artifact filtering semantics.

## Linked Issues or Issue Description

### Problem / Motivation

Board users cannot star individual documents, and the company artifacts
API cannot return only the current user's starred documents.

### Proposed Solution

Add company/user-scoped document memberships, a board-only document star
route, document membership data in the shared contract, and a
`starred=true` artifacts filter.

### Alternatives Considered

A document column was rejected because stars are per-user; a separate
star API was rejected because projects and agents already use resource
memberships.

### Roadmap Alignment

This extends the existing Artifacts & Work Products roadmap area and
does not duplicate another open pull request found in the repository
search.

## What Changed

- Added the `document_memberships` schema and migration with
company/user/document uniqueness and starred ordering.
- Extended shared resource-membership and artifact-query contracts for
documents and `starred=true`.
- Added company-scoped document star/unstar service and board-only route
behavior with activity logging.
- Added starred document artifact filtering, including user-authored
documents, document kinds, cursor ordering, and incompatible-kind
handling.
- Preserved idempotency under concurrent star requests and synchronized
UI membership defaults/helpers with the expanded contract.
- Added focused shared, route, service, and UI regression coverage.

## Verification

- `pnpm exec vitest run packages/shared/src/resource-memberships.test.ts
server/src/__tests__/company-artifacts-service.test.ts
server/src/__tests__/resource-memberships-routes.test.ts`
- `pnpm exec vitest run ui/src/components/SidebarAgents.test.tsx
ui/src/components/SidebarProjects.test.tsx
ui/src/components/SidebarStarredProjects.test.tsx`
- `pnpm --filter @paperclipai/db check:migrations`
- `pnpm -r typecheck`
- `pnpm test:run`
- `pnpm build`

## Risks

- The migration adds a new membership table and non-concurrent indexes;
migration safety gates pass with the repository's established policy.
- The starred artifacts query intentionally returns only documents and
relaxes the normal agent-authored/system-kind predicates for documents
the current user explicitly starred.
- Document membership mutations remain board-user-only; agent callers
receive no document-star capability.

> 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 CLI; runtime model ID and context-window size were not
exposed to this session. Reasoning, repository tool use, code execution,
and test execution 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>
2026-07-27 19:13:35 -05:00
Dotta 3b0156238a
docs(connections): cross-reference the identity model (identity vs. connections) (#9953)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Integrations are governed through the Apps v2 "connections"
substrate documented in `doc/connections/`
> - Contributors adding connectors had no written boundary between
*signing a user in* (identity) and *connecting an external resource* (a
connection), so app-store work could drift into merging the two
> - Unwritten, that boundary risks a design where a sign-in provider's
token gets reused as a resource token, or the identity service grows a
connections hub — exactly the failure the separation exists to prevent
> - This pull request adds an "Identity vs. connections" section to the
public connections docs that names the three planes, states the standing
rule verbatim, and aligns naming across surfaces
> - The benefit is that connector implementers inherit the
identity/connection boundary from accessible repository documentation
instead of re-deriving it

## Linked Issues or Issue Description

Docs-only change. No public GitHub issue.

**Problem:** The `doc/connections/` docs describe how to add a connector
(the First-30 matrix and connector playbook) but never state where
identity ends and connections begin. Without an accessible statement of
that boundary, connector work can accidentally blur sign-in tokens and
resource tokens.

**Change:** Adds a public reference section fixing the boundary and
makes it self-contained for contributors without access to private
identity-service implementation documentation.

## What Changed

- `doc/connections/README.md`: adds an **Identity vs. connections**
section with the P1/P2/P3 model, D7 standing rule, rationale, naming
alignment, and canonical-doc cross-reference.
- `doc/connections/FIRST-30-MATRIX.md`: notes that every listed provider
is a plane-P2 connection and links the new section.
- `doc/connections/CONNECTOR-PLAYBOOK.md`: points connector authors to
the boundary and standing rule before implementation.
- Removes inaccessible private-repository documentation links so every
reference in the new public guidance is usable by contributors.

## Verification

- `git diff --check origin/master...HEAD`
- Verified Markdown table column consistency across the three changed
files.
- Verified no private `paperclip-id` URLs or new internal Paperclip
issue references remain in the diff.
- Current-head CI is fully green, including typecheck, build,
server/workspace tests, serialized suites, canary, and both e2e shards.
- Greptile reviewed commit `d964abab50b39a79fef394c0b1855dd1f2e4b92b` at
5/5 with no unresolved findings; its connections-doc validation returned
`RESULT: PASS`.

## Risks

Low risk — documentation only. No code, schema, migration, or runtime
behavior changes.

> 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

- Anthropic Claude Opus 4.8 (`claude-opus-4-8`), 1M context, extended
thinking with tool use, authored the initial documentation change.
- OpenAI Codex CLI (runtime model identifier not exposed to this
session), agentic reasoning with shell and GitHub tooling, performed PR
preparation, rebase, review-loop diagnosis, and the public-link
correction.

## 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>
2026-07-27 19:12:57 -05:00
Dotta 1426494ab8
fix(agents): disable cheap model profiles by default (#10019)
## Thinking Path

> - Paperclip is the control plane people use to create and govern
AI-agent companies
> - Agent creation persists runtime configuration that controls which
model profiles future runs may select
> - Adapters can expose a `cheap` profile, and existing creation paths
implicitly left that profile available when operators made no choice
> - That made a newly created agent eligible for a lower-cost model
without an explicit operator opt-in
> - The UI also dropped an explicit opt-in when the operator selected
the adapter's default cheap model rather than a custom model ID
> - Codex additionally hardcoded `gpt-5.3-codex-spark` into its cheap
profile and static fallback model list, making Paperclip choose an
auth-dependent model rather than requiring an operator choice
> - This pull request makes new-agent creation disable an available
cheap profile by default while preserving explicit opt-in from the UI or
API
> - The Codex cheap profile now remains available for explicit
configuration but supplies no model default, so an unconfigured cheap
request stays on the primary model
> - The benefit is predictable model quality for new agents and an
intentional, auditable choice before lower-cost routing is enabled

## Linked Issues or Issue Description

**Problem**

New agents created with an adapter that exposes a `cheap` model profile
can inherit that profile without the operator explicitly enabling it. In
the UI, enabling the adapter-default cheap model is also omitted because
runtime configuration is only written when a custom model ID is present.

**Expected behavior**

- New agents default an available `cheap` model profile to `{ enabled:
false }` when the caller does not specify it.
- Explicit API configuration remains authoritative.
- UI opt-in persists even when the adapter default model is used.
- Codex does not advertise or automatically select
`gpt-5.3-codex-spark`; operators must explicitly configure any
lower-cost Codex model.

**Related public work**

- Refs #4881, which introduced cheap model profiles for local adapters.
- Supersedes the default-selection portions of #8032 and #10004 by
removing the Codex model default instead of replacing it with another
hardcoded model.

## What Changed

- Detect whether the selected adapter exposes a `cheap` model profile
during agent creation and hiring.
- Persist `runtimeConfig.modelProfiles.cheap.enabled = false` only when
the caller did not explicitly configure the profile.
- Preserve UI cheap-profile opt-in when using the adapter's default
model by writing an empty adapter config.
- Remove `gpt-5.3-codex-spark` from the Codex static model list.
- Keep the Codex `cheap` profile explicitly configurable while giving it
an empty adapter config, so Paperclip never chooses a cheap Codex model
automatically.
- Verify that a Codex cheap request without an explicit model leaves the
primary model unchanged.
- Extend server route and UI runtime-config tests for default-disable
and explicit-opt-in behavior.

## Verification

- `env -u PAPERCLIP_IN_WORKTREE -u PAPERCLIP_WORKTREE_NAME -u
PAPERCLIP_CONFIG -u PAPERCLIP_HOME -u PAPERCLIP_INSTANCE_ID -u
PAPERCLIP_CONTEXT pnpm exec vitest run
packages/adapters/codex-local/src/index.test.ts
packages/adapters/codex-local/src/server/codex-args.test.ts
server/src/__tests__/adapter-models.test.ts
server/src/__tests__/adapter-registry.test.ts
server/src/__tests__/heartbeat-model-profile.test.ts
server/src/__tests__/agent-permissions-routes.test.ts
ui/src/lib/new-agent-runtime-config.test.ts`
- Result: 7 test files passed, 105 tests passed.
- GitHub `Typecheck + Release Registry` check passed on the final head.
- `git diff --check public-gh/master...HEAD`

## Risks

- Low behavioral risk: only newly created or hired agents are
normalized; existing agents are unchanged.
- Explicit `cheap` profile settings remain untouched, including explicit
opt-in.
- Codex users who explicitly opt into the cheap lane must choose a
model; requests without a configured override intentionally continue on
the primary model.
- Adapter profile discovery is now awaited during creation, adding a
small amount of adapter metadata lookup work.
- The source branch name is automation-provided and retained as required
by the task, so it does not satisfy the preferred public branch naming
convention.

> 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.4` via Codex CLI, with reasoning, repository editing,
terminal execution, and GitHub/Paperclip tool access. The runtime did
not expose a 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)
- [ ] 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>
2026-07-27 19:11:51 -05:00
Dotta 71a6535792
docs(execution-semantics): define routable blocking and watchdog restoration (#10094)
## Thinking Path

> - Paperclip is the open source control plane people use to manage
AI-agent companies.
> - Execution semantics define when work may stop, how child work
reports upward, and how watchdog recovery proves liveness was restored.
> - The existing docs did not require a routable waiting path before
entering `blocked`, leaving permission-denial and review workflows
vulnerable to dead ends.
> - Child-to-parent reporting and low-trust review delegation also
needed explicit channels and ownership boundaries.
> - Watchdog recovery needed bounded restoration verification rather
than treating a recovery write as proof of restored progress.
> - The security-sensitive defaults were reviewed and approved before
publication.
> - This pull request documents those contracts and synchronizes the
bundled Paperclip skills that operationalize them.
> - The benefit is clearer stop conditions, safer reporting defaults,
and bounded watchdog recovery without sacrificing liveness.

## Linked Issues or Issue Description

- No public GitHub issue exists for this execution-semantics
documentation phase, so the problem and solution are described here in
full.
- Problem: `blocked` could be entered without a routable owner/action
path, review findings could be reported on the wrong issue or treated as
blockers, and watchdog recovery lacked bounded verification of restored
liveness.

## What Changed

- Require a routable waiting path for `blocked` and clarify that
permission denial alone is not a blocker.
- Define canonical child-to-parent completion/report channels,
review-delegation ownership, and the sanctioned courier pattern.
- Specify atomic watchdog recovery batches, fingerprint validation,
bounded restoration attempts, and human escalation.
- Document the low-trust preset default for report comments and align
both bundled Paperclip skills.

## Scope and Sequencing

- This is the contract-first P1 documentation PR. Runtime enforcement is
intentionally excluded and follows in the separately owned
implementation phases; these docs define the acceptance contract those
phases must satisfy.
- The five-file patch is approved and frozen for this PR, so review
findings about absent runtime support are tracked as
implementation-phase requirements rather than edits to this docs-only
change.

## Verification

- `git diff --check origin/master...HEAD`
- Confirmed the PR diff is exactly 5 approved docs/skill files with 91
insertions and 1 deletion.
- Confirmed the patch preserves the approved execution-semantics
contract after replay on latest `origin/master`.

## Risks

- Low implementation risk: documentation and skill guidance only; no
runtime code, schema, migration, dependency, lockfile, or workflow
changes.
- Semantic risk is limited to readers or agents applying the clarified
contracts; the security-sensitive R1a default was approved before
publication.

> 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 coding agent (exact underlying model ID and
context-window size are not exposed by this runtime), with reasoning,
terminal tool use, Git/GitHub operations, 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 private URLs or internal issue identifiers
- [x] My branch name describes the change and contains no internal
Paperclip ticket id
- [x] I have run the applicable docs-only checks locally and they pass
- [x] Tests are not applicable because this is a
docs/skill-guidance-only change
- [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>
2026-07-27 19:10:28 -05:00
Dotta 8339bcc7e7
fix(ui): keep decision training under decisions (#10181)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Operators review decisions and turn useful outcomes into training
examples
> - The training library belongs to the Decisions surface, but its
routes and entry point appeared as a separate top-level destination
> - That mismatch made the training icon feel disconnected and left
internal links pointing at legacy `/training` URLs
> - This pull request nests the training library and inspector under
`/decisions/training`, keeps legacy URLs working through redirects, and
uses one route helper everywhere
> - The benefit is a clearer Decisions workflow without breaking
existing bookmarks or links

## Linked Issues or Issue Description

Refs: #9718
Refs: #9779

**Problem:** The Decisions page exposed training as a labeled header
action while the training library lived at the unrelated top-level
`/training` route. Links across the UI duplicated that legacy path.

**Expected behavior:** Training should be an icon action alongside the
other Decisions controls, and training library/record URLs should live
under `/decisions/training` while old URLs continue to redirect.

**Steps to reproduce:**
1. Open the Decisions page.
2. Observe the separate labeled Training button in the page heading.
3. Open a training record and note the top-level `/training/...` URL.

**Version/commit:** Current `master` before this PR.

**Deployment mode:** All UI deployment modes.

## What Changed

- Move the training library and inspector routes under
`/decisions/training`.
- Redirect legacy `/training` and `/training/:id` URLs to the new
locations.
- Add `decisionTrainingHref()` and use it for training links and
navigation.
- Place the Training icon action with the Decisions filter and sort
controls.
- Add focused tests for library and record URL generation.

## Verification

- `pnpm exec vitest run ui/src/lib/decisionTraining.test.ts`
- `pnpm --filter @paperclipai/ui typecheck`
- `pnpm --filter @paperclipai/ui build`
- `pnpm check:token-gates`

## Risks

- Low risk: the change is limited to client-side routes and navigation.
- Existing `/training` bookmarks remain supported through replacement
redirects.
- No API, database, migration, dependency, or workflow changes.

> 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 using GPT-5.4 with reasoning, repository tool use, shell
execution, and code/test 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>
2026-07-27 19:08:36 -05:00