Commit Graph
3097 Commits
Author SHA1 Message Date
Nicky Leach 3a727bf780 fix(codex): warn when sandbox auth is shadowed (#9259) canary/v2026.715.0-canary.3 2026-07-15 10:02:28 -07:00
89ce36d7af feat(skills): open-by-default company skill policy and core UX (#9564)
## Thinking Path

> - Paperclip uses company skills to make agent capabilities reusable
across an organization.
> - Skill operations currently mix capability availability with
permission checks, which creates avoidable setup friction and
inconsistent denial handling.
> - The policy contract needs to remain open by default while allowing
company-scoped restrictions for governed deployments.
> - Core owns the canonical policy actions, persistence, evaluation, API
behavior, safe import boundaries, and generic denial/read-only UI.
> - Enterprise policy-editor implementation belongs in the separate
`paperclip-ee` repository and is intentionally excluded from this PR.

### Problem or motivation

Company skill operations can encounter permission dead ends even when no
explicit restriction has been configured, and import-source
classification can drift between policy evaluation and execution.

### Proposed solution

Define eight canonical skill policy actions, default all actions to
allowed, persist company-scoped restrictions, expose policy evaluation
APIs, normalize import sources at the boundary, and update Skill Studio
to present actionable restriction states without embedding Enterprise
Edition implementation in the core repository.

### Alternatives considered

Keeping capability checks distributed across routes and UI surfaces was
rejected because it duplicates policy logic and makes denial behavior
inconsistent. Shipping the Enterprise policy editor in this repository
was rejected because `paperclip-ee` is a separate repository and must
receive its own PR.

### Roadmap alignment

Extends the completed **Skills Manager** roadmap area by adding coherent
governance and removing workflow dead ends.

### Additional context

The core API contract remains suitable for a separate Enterprise Edition
editor, but this PR contains no `paperclip-ee` package or EE-specific UI
integration code.

## What Changed

- Added the company skill policy contract to product and implementation
documentation, including the open-by-default rule, eight canonical
actions, decision shape, and core/EE ownership boundary.
- Added the company-scoped policy schema, migration `0170`, shared
validators, policy service, REST routes, OpenAPI coverage, and focused
server tests.
- Hardened import policy enforcement by normalizing import sources and
keeping source classification consistent between policy evaluation and
execution.
- Updated core Skill Studio behavior to remove generic permission dead
ends and show actionable policy/platform denial states only when an
operation is actually denied.
- Removed the `plugin-paperclip-ee` package, Docker wiring, EE
discovery/deep-link helpers, and EE-specific UI tests/stories from this
PR so that implementation can be submitted separately to the EE
repository.
- Preserved open-by-default behavior when no explicit company
restriction exists.

## Verification

- `pnpm --filter @paperclipai/ui exec vitest run
src/components/skill-studio/SkillPolicySurfaces.test.tsx
src/lib/skill-policy-denial.test.ts` — 20/20 passed.
- `pnpm --filter @paperclipai/ui exec tsc --noEmit` — passed.
- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/worktree-config.test.ts` — 12/12 passed.
- `pnpm check:token-gates` — passed with all gates clean.
- `git diff --check` — passed.
- `git diff --name-only origin/master | rg
'paperclip-ee|ee-skill-policy'` — no matches.

## Risks

- Migration `0170` introduces company policy persistence; rollout
depends on the migration applying before policy routes are exercised.
- Open-by-default is an intentional behavioral policy: deployments
expecting implicit denials must configure explicit restrictions.
- Import normalization is security-sensitive and should retain focused
review.
- The separate EE editor must stay contract-compatible with the core
policy API as policy actions evolve.

## Model Used

- OpenAI Codex CLI, runtime model identifier and context-window size not
exposed by this execution environment; reasoning, repository tool use,
shell execution, and code review capabilities 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 available to this runtime)
- [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 or
described the result 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 focused 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 on the latest head
- [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>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Evyatar Bluzer <bluzername@users.noreply.github.com>
canary/v2026.715.0-canary.2
2026-07-15 11:42:40 -05:00
24bd860280 Stop cancelled productivity review loops (#5210)
## Thinking Path

> - Paperclip orchestrates AI agents for zero-human companies.
> - Productivity review reconciliation creates manager-owned review
issues when assigned work shows no-comment, long-active, or high-churn
patterns.
> - SplatImmo hit a loop because productivity-review issues were
auto-cancelled while the source issue still matched the same trigger.
> - The service already snoozed recently completed reviews, but
cancelled reviews were ignored for that snooze check.
> - This pull request treats recently cancelled productivity reviews as
terminal snooze evidence.
> - The benefit is that cancelling a review now suppresses immediate
recreation without disabling useful future productivity reviews.

## What Changed

- Renamed the recent-review lookup to terminal-review semantics and
included `cancelled` alongside `done`.
- Added a regression test proving a recently cancelled productivity
review produces `snoozed` instead of creating another review.

## Verification

- `pnpm exec vitest run
server/src/__tests__/productivity-review-service.test.ts` passes: 1
file, 12 tests.
- Queried the SplatImmo Paperclip instance for existing `Review
productivity` issues: 500 `issue_productivity_review` issues found, all
already `cancelled`, 0 active.

## Risks

- Low risk: this only affects the reconciliation branch after a terminal
productivity-review issue exists.
- Operators who cancel a productivity review now get the same default
6-hour quiet window as completed reviews; after that window, persistent
evidence can still create a fresh review.

## Model Used

- OpenAI Codex coding agent, GPT-5 class model, tool-enabled code
editing and local 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 run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge

Co-authored-by: Yanis Ismail <yanis.ismail@emissive.fr>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-15 11:38:37 -05:00
DottaandPaperclip 0ecae2cd7e fix(adapters): forward resolved adapter env to local agents, keep runtime env authoritative (#9617)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Local coding adapters (Claude, Codex) run each agent heartbeat in a
spawned child process; Paperclip resolves adapter-configured env —
including `secret_ref` bindings — into the env for that process
> - The resolved adapter env was not being forwarded reliably: config
env could overwrite Paperclip's own runtime vars, and a warm/resumable
ACP session could keep serving stale env because its fingerprint ignored
the resolved env
> - This mattered because a configured API key or other secret could be
silently absent from the agent shell, and a resumed session would never
pick up an updated value — while a config binding could also override
runtime identity/wake vars
> - This pull request keeps Paperclip-managed `PAPERCLIP_*` runtime env
authoritative over config, and folds a stable hash of the applied
adapter env into the session fingerprint so an env change forces a fresh
launch
> - The benefit is that adapter-configured env (plain values and
resolved secrets) reliably reaches the agent process, updates are picked
up on the next launch, and runtime identity can never be clobbered by
config

## Linked Issues or Issue Description

No public GitHub issue exists, so the underlying bug is described inline
following the bug-report template.

**What happened**

Env keys configured on a local adapter (plain values and `secret_ref`
bindings, resolved server-side into plain strings) did not reliably
reach the spawned agent process. Two distinct gaps: (1) when merging
config env into the process env, a config key in the reserved
`PAPERCLIP_*` namespace could overwrite a Paperclip-managed runtime
variable (identity, wake, workspace, API access); (2) a warm-handle /
resumable ACP session computed its reuse fingerprint from
`secretManifestHash` only, which misses plain-value edits and
same-version secret rotations — so a resumed session kept serving stale
env and never re-launched with updated values.

**Expected behavior**

Non-`PAPERCLIP_*` adapter env (plain + resolved secret values) is
forwarded to the agent process; a change to any applied forwarded value
invalidates a warm/resumable session so the next launch sources the
latest env; configured `PAPERCLIP_*` entries can never override
Paperclip runtime env, while an explicitly configured
`PAPERCLIP_API_KEY` (stable per-run config) is still honored and its
rotation also busts the session.

**Steps to reproduce**

Configure an adapter with an env key (e.g. a `secret_ref` API key) and a
resumable ACP session. On resume, the updated env value is not sourced;
separately, a `PAPERCLIP_*` config key overrides the runtime value.

**Deployment mode**

Local adapters (Claude / Codex) via the shared adapter-utils execution
path.

## What Changed

- `packages/adapter-utils/src/server-utils.ts`: add
`isPaperclipRuntimeEnvKey` and, in
`refreshPaperclipWorkspaceEnvForExecution` (used by all local adapters),
skip a `PAPERCLIP_*` config key when Paperclip has already assigned it
this run; all other keys still forward.
- `packages/adapter-utils/src/acpx-engine/execute.ts`: apply the same
`PAPERCLIP_*` non-override rule (via the shared helper) when merging
config env, capture the applied config env in `resolvedAdapterEnv`, and
fold a stable `adapterEnvHash` of it into the session fingerprint so an
env change forces a fresh launch. Per-wake `PAPERCLIP_*` runtime vars
are assigned earlier and never enter that map, so they stay out of the
hash; stable configured `PAPERCLIP_*` values (e.g. an explicit
`PAPERCLIP_API_KEY`) are included so rotating one busts the session.
- Added unit/integration tests for plain + secret forwarding,
`PAPERCLIP_*` non-override, the explicit-API-key path, fingerprint
refresh-on-env-change vs. stable-across-wakes, and rotation of a
configured `PAPERCLIP_API_KEY`.

## Verification

- `npx vitest run packages/adapter-utils/src/acpx-engine/execute.test.ts
packages/adapter-utils/src/server-utils.test.ts` → 2 files, 111 tests
passing (includes the new cases).
- Tests assert: forwarded plain/secret values appear in the spawned
wrapper `.env`; a `PAPERCLIP_*` config key does not override the runtime
value; changing an applied forwarded env value (including a rotated
`PAPERCLIP_API_KEY`) changes `configFingerprint`, while a new wake with
the same config env keeps it stable.

## Risks

Low risk. Behavior change is limited to (a) config env no longer
overriding `PAPERCLIP_*` runtime vars — a security-positive tightening —
and (b) a resumable session re-launching when its applied config env
changes, which is the intended fix. Per-wake `PAPERCLIP_*` churn is
deliberately excluded from the fingerprint so normal sessions still
resume across heartbeats. Existing sessions get a new fingerprint once
on first deploy (the added `adapterEnvHash` field), which is expected.
No secret values are logged (key-name redaction in the adapter plus
manifest-driven redaction of `meta.env`).

## Model Used

Claude Opus 4.8 (Anthropic), model id `claude-opus-4-8`, extended
reasoning with tool use.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.715.0-canary.1
2026-07-15 11:26:47 -05:00
Evyatar Bluzer b287281940 docs: add inline comments to docker quickstart compose file (#2431)
## Problem

The quickstart docker-compose file was recently moved to
\`docker/docker-compose.quickstart.yml\` during the Docker
reorganization but still have zero inline comments. When new user copy
this file for self-hosting, they see variables like:
- \`BETTER_AUTH_SECRET\` - what is this? How to generate?
- \`PAPERCLIP_DEPLOYMENT_MODE: "authenticated"\` - what other modes
available?
- \`PAPERCLIP_DEPLOYMENT_EXPOSURE: "private"\` - what does private vs
public mean?
- \`OPENAI_API_KEY\` and \`ANTHROPIC_API_KEY\` - both required? Or just
one?

They have to go read DOCKER.md or other docs to understand each
variable.

## What I changed

Added inline YAML comments directly in the file:
- Header block with step-by-step quickstart commands (cd docker, export,
docker compose up)
- Section headers grouping LLM keys, deployment settings, and secrets
- Comment explaining each non-obvious variable with valid values
- Note about \`BETTER_AUTH_SECRET\` with openssl generation command
- Comment on the volume explaining what data it persist

No functional change - only YAML comments added.
canary/v2026.715.0-canary.0
2026-07-15 09:39:20 -05:00
DottaandPaperclip ea66ea81e6 fix(auth): honor responsible-user grants for company skills (#9571)
## Thinking Path

> - Paperclip is the open source control plane people use to manage
AI-agent companies
> - Company skills are governed resources, so board users and agents
acting for responsible users must be authorized consistently before
mutating skill configuration
> - The responsible-user authorization intersection handled several task
permissions but did not map company-skill mutation actions to the
corresponding `skills:create`, `skills:update`, and `skills:delete`
grants
> - That gap caused valid skill import and mutation requests to be
rejected even when the responsible user held the exact direct permission
required by the route
> - The branch also introduces the repo-sourced `prepare-paperclip-pr`
skill so the standard PR preparation process is versioned and reviewable
alongside the code
> - This pull request adds the missing authorization mappings, covers
board, agent, JWT-route, and denial behavior with regression tests, and
adds the renamed PR-preparation skill
> - The benefit is that governed company-skill workflows honor explicit
grants without weakening the responsible-user permission intersection

## Linked Issues or Issue Description

No public issue exists. Bug-report shape:

- **Affected area**: company skill authorization and skill import routes
- **Observed behavior**: agents acting under a responsible user could
receive `403` responses for company-skill mutations even when that user
had the matching direct `skills:create`, `skills:update`, or
`skills:delete` grant
- **Expected behavior**: the responsible-user authorization intersection
should accept exact company-skill grants while preserving denials for
missing or unrelated grants
- **Reproduction**: authenticate as an agent with a responsible user,
grant that user the relevant company-skill permission, then import or
mutate a company skill
- **Additional repository change**: adds the renamed
`prepare-paperclip-pr` skill as the versioned source of truth for PR
preparation

Supersedes #9324, which added the PR-preparation skill under the old
`prepare-pr` name.

## What Changed

- Added `.agents/skills/prepare-paperclip-pr/SKILL.md` with the standard
worktree, commit, rebase, guardrail, review-loop, and handoff procedure
- Mapped company `skill_config:create`, `skill_config:update`, and
`skill_config:delete` actions to direct `skills:create`,
`skills:update`, and `skills:delete` responsible-user grants
- Preserved restrictive behavior for unsupported resources, missing
grants, and unrelated permissions
- Added authorization-service regression coverage for board actors and
responsible-user agent intersections
- Added route-level JWT regression coverage for company skill imports,
including allowed and denied cases

## Verification

- `pnpm exec vitest run
server/src/__tests__/authorization-service.test.ts
server/src/__tests__/company-skills-import-authz-routes.test.ts` — 42
tests passed
- `pnpm -r typecheck` — passed
- `pnpm build` — passed
- `pnpm test:run` — server and UI groups passed; one unrelated CLI
doctor assertion failed because the execution environment injects static
`AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY`, which intentionally changes
the result from `pass` to `warn`
- `env -u AWS_ACCESS_KEY_ID -u AWS_SECRET_ACCESS_KEY
NODE_ENV=development pnpm exec vitest run
cli/src/__tests__/secrets.test.ts -t 'passes AWS doctor checks when
non-secret provider config is present'` — passed, confirming the
full-suite failure is environment-specific
- GitHub CI — all required checks passed on head `0758393c`; one
unrelated `packages/db/src/client.test.ts` 5-second timing timeout
passed on the single allowed failed-job rerun after three consecutive
local passes (42/42 tests)

## Risks

- Low-to-moderate authorization risk: the change expands accepted
responsible-user grants only for company-scoped skill configuration
actions and is protected by explicit allow/deny regression cases
- No database migrations, workflow changes, lockfile changes, or UI
changes
- The added skill is documentation consumed by agent tooling and does
not alter runtime application behavior

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex coding agent; exact runtime model ID and context-window
size were not exposed to the session. Used reasoning, terminal
execution, Git/GitHub tooling, and test/build execution.
- Earlier commits were assisted by Claude Fable 5 (`claude-fable-5`) and
an OpenAI Codex coding agent, as recorded in the branch history/task
workflow.

## 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 documented the one
environment-specific full-suite failure
- GitHub CI — all required checks passed on head `0758393c`; one
unrelated `packages/db/src/client.test.ts` 5-second timing timeout
passed on the single allowed failed-job rerun after three consecutive
local passes (42/42 tests)
- [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-15 07:52:54 -05:00
Nicky LeachandPaperclip 7947308276 fix(codex): classify refresh auth failures (#9598)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Paperclip supports the Codex local adapter, which runs OpenAI Codex
CLI sessions on behalf of agents
> - Codex uses OAuth refresh tokens to maintain long-running
authenticated sessions
> - When a refresh fails, the failure has distinct root causes: a
refresh token was already reused in a parallel request, the token
expired by TTL, or the token was invalidated/revoked by the provider
> - Without classifying these failure modes, all refresh auth errors
surface identically — operators cannot distinguish retryable transient
collisions from permanent invalidations, and run logs carry no
actionable diagnosis
> - This pull request adds structured classification
(`refresh_token_reused`, `refresh_token_expired`,
`refresh_token_invalidated`) of Codex refresh-token auth failures across
the CLI quota-probe, ACP auth path, and execute path
> - The benefit is that these distinct failure modes can be surfaced in
run logs and acted on appropriately — transient reuse can be retried;
true invalidations require re-auth

## Linked Issues or Issue Description

<!-- Path B: no public GitHub issue — describing inline as a bug fix -->

**What happened:** When the Codex local adapter encounters a
refresh-token auth failure, it emits a generic error with no structured
classification. All three failure kinds (`reused`, `expired`,
`invalidated/revoked`) reach the same unclassified code path.

**Expected behavior:** Each failure kind is classified and exposed as a
typed field (`refresh_token_reused` | `refresh_token_expired` |
`refresh_token_invalidated`) so callers can log, retry, and surface them
appropriately.

**Steps to reproduce:**
1. Run a Codex agent session with a reused or expired OAuth refresh
token.
2. Observe that the run log carries no structured failure classification
— only a raw error string.

**Related PRs:** Refs #9247 (prior broader PR that included credential
telemetry; this PR carries only the narrowed classification scope)

## What Changed

- Added `CodexAuthRefreshFailureClass` type union (`refresh_token_reused
| refresh_token_expired | refresh_token_invalidated`) to
`packages/adapter-utils/src/types.ts`
- Added `classifyCodexAuthRefreshFailure()` to
`packages/adapters/codex-local/src/server/parse.ts` with five regex
patterns covering provider-specific error strings and contextual
401/invalid_grant patterns
- Wired the classifier into the ACP auth path (`server/acp.ts`), execute
path (`server/execute.ts`), and CLI quota-probe (`cli/quota-probe.ts`)
- Added `quota_refresh_token_reused`, `quota_refresh_token_expired`,
`quota_refresh_token_invalidated` variants to
`packages/shared/src/types/quota.ts`
- Added classification unit tests (`parse.test.ts`,
`quota-spawn-error.test.ts`, `acp.test.ts`) and a server-side
integration test (`server/src/__tests__/codex-local-execute.test.ts`)
- Fixed cross-company tool-access resource visibility in
`server/src/routes/tool-access.ts`
- Stabilized `heartbeat-retry-scheduling.test.ts` (CASCADE cleanup),
`heartbeat-run-log.test.ts`, and `quota-windows.test.ts`

## Verification

- `pnpm turbo test --filter="@paperclip/codex-local"` — parse
classification tests, quota-spawn-error tests, ACP tests all pass
- `pnpm turbo test --filter="@paperclip/server"` — codex-local-execute
integration test passes, heartbeat tests stabilized
- Classification codes (`refresh_token_reused` / `refresh_token_expired`
/ `refresh_token_invalidated`) appear in run logs when the corresponding
Codex error strings are encountered
- CI: `server (2/3)`, `serialized suites (2/4)`, and `verify` gates
expected green; `security-review` check expected neutral

## Risks

Low risk. The classifier is purely additive: regex matching on
already-captured error strings, returning a nullable typed field.
Callers that do not inspect the classification field are unaffected. No
execution paths, retry logic, or existing error surfaces changed.

## Model Used

- **Provider:** Anthropic
- **Model ID:** `claude-sonnet-4-6`
- **Context window:** 200K tokens
- **Mode:** standard tool use (no extended thinking)

## 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-14 22:40:38 -07:00
Jannes StubbemannandClaude Opus 4.7 7f2ed0ad90 security(server): close cross-tenant existence oracle (404 instead of 403) (#3967)
## Thinking Path

> - Paperclip orchestrates AI agents for zero-human companies
> - In a multi-tenant deployment, route handlers that take a resource id
(`issue`, `goal`, `project`, `approval`, etc.) look the resource up by
id and then call `assertCompanyAccess` on its `companyId` — 404 if it
doesn't exist, 403 if it exists in another tenant
> - The split status codes are a classic *existence oracle*: any
authenticated user can enumerate ids across tenants by probing for the
403/404 boundary, mapping out which issues, labels, approvals, etc.
exist in other customers' tenants even when they cannot read the
contents
> - The right fix is a single uniform 404 for both "not found" and
"found but cross-tenant", which collapses the oracle but still preserves
write-path checks (active membership, viewer-readonly) for *authorized*
tenants
> - This pull request adds a non-throwing `hasCompanyAccess(req,
companyId)` helper plus a `getAccessibleResource` wrapper that ~130
handlers across 14 route files now use, folding the access check into
the existence check while still running `assertCompanyAccess` for
authorized tenants so viewer-readonly / inactive-membership rejections
fire unchanged on write paths
> - The benefit is closing a multi-tenant information leak without
breaking write-path security or single-tenant local-first behavior

## Linked Issues or Issue Description

Refs #709 — asks for company-scope regression coverage across
approval/activity/access routes, because a subtle route refactor could
leak cross-tenant data; this PR hardens exactly those surfaces (uniform
404 across 14 route files including `approvals`, `activity`, `secrets`)
and updates cross-tenant expectations in test files. It does not add the
full coverage matrix #709 asks for — hence Refs, not Closes.

No existing issue covers the oracle itself — described in-PR:

- Route handlers returned 404 for "not found" but 403 for "exists in
another tenant", a classic *existence oracle*: any authenticated user
could enumerate ids across tenants by probing the 403/404 boundary.
- That maps out which issues, labels, approvals, etc. exist in other
customers' tenants even when their contents are unreadable.
- Fix: a uniform 404 for both cases, while keeping write-path checks
(active membership, viewer-readonly) for authorized tenants.

## What Changed

- **`server/src/routes/authz.ts`** — new `hasCompanyAccess(req,
companyId): boolean` helper alongside the existing
`assertCompanyAccess`. Docstring spells out the two-step pattern (404
gate, then `assertCompanyAccess` for write-path checks). The helper
mirrors `assertCompanyAccess`'s company-scope semantics exactly — in
particular, signed-in instance admins do **not** get blanket access to
companies they are not a member of (the repo's `authz-company-access`
tests pin that behavior for `assertCompanyAccess`; an earlier draft of
the helper accidentally widened it for reads).
- **`getAccessibleResource(req, res, lookup, notFoundMessage)`** — the
safe thing is now the easy thing. One helper wraps the whole pattern
(uniform 404 for missing/cross-tenant, then `assertCompanyAccess` for
write-path membership checks) and ~130 handlers across 14 route files
use it:
  ```ts
const goal = await getAccessibleResource(req, res, svc.getById(id),
"Goal not found");
  if (!goal) return;
  ```
Files: `activity`, `agents`, `approvals`, `assets`, `costs`,
`environments`, `execution-workspaces`, `file-resources`, `goals`,
`issue-tree-control`, `issues`, `projects`, `routines`, `secrets`.
Handlers with bespoke not-found behavior (the legacy `200 []` contract,
audit-logged denials in `file-resources`, null-returning authz helpers)
compose `hasCompanyAccess` directly using the documented two-step
pattern:
  ```ts
// step 1: close the oracle (uniform 404 for both not-found and
cross-tenant)
  if (!existing || !hasCompanyAccess(req, existing.companyId)) {
    res.status(404).json({ error: "Goal not found" });
    return;
  }
// step 2: enforce write-path membership checks for authorised tenants
(no-op on GET)
  assertCompanyAccess(req, existing.companyId);
  ```
Routes where `companyId` comes from *request input*
(`req.params.companyId`, `req.body.companyId`, e.g. in `companies.ts`
and `plugins.ts`) deliberately retain plain `assertCompanyAccess` —
there's no existence oracle to close because the companyId is an input,
not a discovered value.
- **Full-sweep coverage** — a scripted audit of every
`assertCompanyAccess(req, <resource>.companyId)` call site in
`server/src/routes/` found ~55 lookup-then-assert pairs the first pass
missed; all are now gated. Notable ones: the
`/secret-provider-configs/:id` CRUD routes, the agents
instructions-bundle/config-revision/skills-sync routes (which check
access via the `assertCanUpdateAgent` / `assertCanReadAgent` /
`assertCanManageInstructionsPath` helpers), `POST
/heartbeat-runs/:runId/watchdog-decisions`, `GET
/issues/:id/cost-summary`, the environment + environment-lease GET
routes, all six issue-tree-control routes, ~24 issue sub-resource routes
(document annotations, interactions, approvals links, recovery actions,
plan decompositions, lock/unlock), and the three workspace file-resource
routes (these throw `notFound` instead of `forbidden` inside their
audit-logging wrappers, so denied attempts are still activity-logged
server-side while the client sees a uniform 404).
- **Helpers made self-defending** — `assertCanUpdateAgent` /
`assertCanReadAgent` / `assertCanManageInstructionsPath` (agents) and
`assertCanManage{Project,Execution}WorkspaceRuntimeServices` throw
`notFound` for cross-tenant resources before their `assertCompanyAccess`
step, so a future caller that forgets the route-level gate still can't
reopen the oracle.
- **Pattern enforcement** — new `authz-existence-oracle-guard.test.ts`
statically scans `server/src/routes/*.ts` and fails CI on any
`assertCompanyAccess(req, <resource>.companyId)` call that is not
preceded by a `hasCompanyAccess` gate, with an explicit allowlist (plus
staleness check) for the request-input cases. New routes that regress to
the 403/404 split fail the suite with a message pointing at the
documented pattern.
- **Tests** — cross-tenant expectations updated from 403→404 where
routes are now gated; new `hasCompanyAccess` unit tests in
`authz-company-access.test.ts` pin the
instance-admin/local-implicit/agent/none semantics in lockstep with
`assertCompanyAccess`; `write-path-membership.test.ts` (added in an
earlier round) confirms viewer/inactive users are still rejected on
writes.
- **One legacy-contract preserve** — `GET /heartbeat-runs/:runId/issues`
still returns `200 []` for both "doesn't exist" and "cross-tenant" so
the legacy contract is preserved while the oracle stays closed.

## Verification

- `pnpm run typecheck` — PASS.
- `pnpm -F @paperclipai/server exec vitest run` — full server suite
green locally apart from 4 pre-existing local-environment failures
(`paperclip-skill-utils` ×2 and `workspace-runtime` ×1 are
cwd/git-environment dependent — verified identical on a clean checkout
of the base; `heartbeat-process-recovery` is the known macOS flake).
- The new `authz-existence-oracle-guard` test sweeps
`server/src/routes/*.ts` and confirms no remaining
`assertCompanyAccess(resource.companyId)` site without a
`hasCompanyAccess` gate; the only allowlisted holdouts take `companyId`
from request input.

## Risks

- **API contract narrowing.** Any client that specifically checked for
`403` on cross-tenant access now sees `404`. This is a strict narrowing
(one status instead of two for the same negative outcome) and matches
what a client should expect for any id it can't access.
- **Write-path checks preserved.** `assertCompanyAccess` still runs
after the 404 gate on write routes, so viewer-readonly /
inactive-membership rejections fire unchanged for legitimate users.
- **Instance-admin scope unchanged.** `hasCompanyAccess` denies
signed-in instance admins without an explicit membership, exactly like
`assertCompanyAccess` (pinned by unit tests) — so the gate introduces no
new read access for admins.
- **Single-tenant local-first deploys** behave identically — the helper
short-circuits to `true` for `local_implicit` sessions.
- No new env vars, no deployment-mode switch.

## Model Used

Claude Opus 4.7 (1M context), extended thinking mode; completeness sweep
+ instance-admin parity fix by Claude Fable 5 (1M context).

## Checklist

- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] Thinking path traces from project context to this change
- [x] Model used specified
- [x] Checked ROADMAP.md — part of the multi-tenant hardening initiative
- [x] Tests run locally and pass
- [x] Added/updated cross-tenant 404 expectations across test files
- [x] No UI changes
- [x] Documented risks above
- [x] Will address all Greptile and reviewer comments before merge

Part of the multi-tenant hardening initiative — see also #5864
(per-company JWT keys) and #5865 (plugin tables `company_id`).

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-07-14 15:53:09 -07:00
b79f744a8d Fix Codex auth merge host-unusable fail closed (#9276)
## Thinking Path

> - Paperclip is the open source platform people use to manage AI agents
for work
> - The Codex adapter runs agent tasks in isolated sandbox environments
on the user's machine
> - When a Codex sandbox is reused across agent runs, its home directory
(including `~/.codex/auth.json`) is restored from a prior snapshot
> - Both the host machine and the sandbox independently maintain
`auth.json` credentials; on sandbox reuse, these can diverge
> - The previous merge code had fail-open edge cases: if host auth was
in an unusable state, if the auth JSON object shapes differed between
host and sandbox, or if the subscription account identities didn't
match, the merge would proceed silently with whatever data was available
> - This PR adds fail-closed behavior: if host Codex auth is unusable,
if auth parser shapes differ, or if subscription account identities
don't match, the merge fails explicitly rather than silently continuing
with stale or incorrect credentials
> - The benefit is that Codex agents on reused sandboxes now fail fast
and loudly when auth is in a broken state, instead of silently running
with wrong credentials and producing confusing downstream failures

## Linked Issues or Issue Description

No pre-existing public GitHub issue. This is a targeted security
hardening fix for the Codex reused-sandbox auth merge path.

**Problem:** When a Codex sandbox is reused, the merge logic that
reconciles host and sandbox `auth.json` credentials failed open in
several cases:
- Host `auth.json` present but in an unusable state (missing required
keys, empty token material, malformed JSON) → merge would proceed with
whatever the sandbox had
- Host and sandbox auth payloads had different shapes (e.g., one uses
`OPENAI_API_KEY`, the other uses a `tokens` object) →
parser-differential case not detected
- Subscription account identities (`tokens.account_id`) differed between
host and sandbox → stale sandbox identity would be used silently

**Fix:** All three cases now fail closed. The merge returns an explicit
error rather than proceeding with potentially stale or mismatched
credentials.

Related PRs:
- Refs #9262 — sandbox Codex auth shadow warning (adjacent auth area)
- Refs #9259 — auth precedence exports (adjacent auth area)

## What Changed

- `packages/adapters/codex-local/src/server/codex-home.ts` — New file
with `hasUsableAuthPayload()`, `codexHomeHasUsableAuth()`, and full
Codex home setup/teardown. Includes fail-closed auth merge guards:
rejects unusable host auth, detects parser shape differentials, and
checks subscription account identity match before merging
- `packages/adapter-utils/src/workspace-restore-merge.ts` — New file
with directory snapshot diffing and restore-merge logic; the merge
operation fails closed when auth validation fails
- `packages/adapters/codex-local/src/server/codex-home.test.ts` — Unit
tests covering auth usability checks, symlink management, and
fail-closed merge paths
- `packages/adapter-utils/src/workspace-restore-merge.test.ts` — Unit
tests for snapshot/restore-merge behavior including fail-closed cases
- `packages/adapter-utils/src/sandbox-managed-runtime.ts` — Updated to
invoke the fail-closed auth merge during sandbox restore

## Verification

Tests run and passing:

```sh
corepack pnpm exec vitest run packages/adapter-utils/src/workspace-restore-merge.test.ts packages/adapters/codex-local/src/server/codex-home.test.ts
corepack pnpm exec vitest run packages/adapter-utils/src/sandbox-managed-runtime.test.ts
corepack pnpm --filter @paperclipai/adapter-utils typecheck
corepack pnpm --filter @paperclipai/adapter-codex-local typecheck
git diff --check origin/master HEAD
```

All passed locally before push.

## Risks

- **Intentional behavioral change (breaking for previously-silent
failures):** Reused sandboxes that previously completed auth merge with
unusable host auth, parser-differential auth shapes, or mismatched
account identities will now fail with an explicit error. This is the
correct behavior — the prior silent-proceed path was the bug. Users
affected will see a clear error message rather than a confusing
downstream auth failure.
- **Auth.json symlink migration:** `ensureSymlink()` detects stale
copied `auth.json` files (written by older Paperclip versions) and
replaces them with symlinks on first run. This is safe: the target is
always under the Paperclip-managed company home, never the user's real
`~/.codex`. Directories at the symlink path are left untouched (EISDIR
is not silently swallowed).
- **Low risk for non-reuse paths:** The fail-closed logic only activates
during sandbox restore/reuse. Fresh sandbox allocations are unaffected.

## Model Used

- **Provider:** Anthropic
- **Model ID:** claude-sonnet-4-6 (Claude Sonnet 4.6)
- **Context window:** 200k tokens
- **Mode:** Agentic coding with tool use; extended thinking not used
- **Role:** Code author (Priya Raman, BackendEngineer) with Harold Kim
(Git Expert) handling push and PR operations

## 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: Priya Raman <priya.raman@paperclip.local>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Harold Kim <harold@paperclip.ing>
canary/v2026.714.0-canary.16
2026-07-14 15:49:36 -07:00
Jannes StubbemannandClaude Fable 5 1cfed0c0ff security(invites): widen invite-token entropy and rate-limit public invite endpoints (#8979)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Companies onboard human members through shareable invite links; the
`/api/invites/:token` endpoints are deliberately public so a recipient
can view the invite and accept it without being logged in
> - That publicness makes the invite token itself the only secret
guarding company membership — and it was guessable: the token suffix
carried only ~41 bits of entropy, and the endpoints had no rate limiting
> - An attacker could therefore enumerate the token space online and
accept an invite into someone else's company, gaining member access to
its onboarding data, skills, and workspace
> - This pull request widens invite tokens to 256 bits of entropy and
puts a per-IP rate limit in front of every public `/invites/:token`
sub-route
> - The benefit is that invite links stop being brute-forceable while
their shape, storage scheme, and UX stay exactly the same — existing
links keep working

## Linked Issues or Issue Description

No public issue exists; describing the problem in-PR (security/bug):

**What happens:** Company invite tokens are **public**: anyone with the
link can `GET /api/invites/:token`, fetch onboarding/logo/skills, and
`POST /api/invites/:token/accept`. Two weaknesses combined to make them
brute-forceable:

1. **Token entropy ~41 bits.** The token suffix was 8 chars over a
36-char alphabet (`8 * log2(36) ≈ 41.4` bits). That is
online-enumerable.
2. **No rate limit on `/invites/:token*`.** The public endpoints had no
throttling, so the ~41-bit space could be enumerated online.

**Impact:** an attacker who guesses a live token can accept the invite
and join the company as a member — unauthenticated, from any IP.

**Expected:** invite tokens should be computationally infeasible to
guess, and the public endpoints should throttle guessing attempts anyway
(defense in depth).

## What Changed

**Entropy**

- `createInviteToken` now uses `crypto.randomBytes(32)` (256 bits)
base64url-encoded, keeping the human-readable `pcp_invite_` prefix so
link shape and UX are unchanged. The duplicate generator in
`plugin-host-services.ts` is updated to match.
- Tokens are stored **hashed** (sha256) in `invites.tokenHash`; the raw
value is only returned once on creation. Storage scheme is unchanged.
- **Backward compatible**: only newly minted tokens are affected; lookup
is by hash of the presented value, so existing invite links keep
working.

**Rate limit**

- New generic in-memory per-IP sliding-window limiter
(`server/src/services/invite-rate-limit.ts`, 20 req/min/IP), applied as
a router-level middleware on `/invites/:token` so every current and
future sub-route is covered (summary, logo, onboarding, onboarding.txt,
skills/index, skills/:name, test-resolution, and POST accept).
- Returns `429` with `Retry-After` and `X-RateLimit-*` headers.
In-memory ⇒ per-process, which bounds enumeration per replica. Mirrors
the existing `company-search-rate-limit` pattern; no new dependency.
- Adds a `tooManyRequests(429)` error helper in `server/src/errors.ts`.

## Verification

- `invite-token-entropy.test.ts`: prefix preserved, suffix ≥ 128 bits /
22 chars, charset, 1000 unique tokens.
- `invite-rate-limit.test.ts`: allows up to limit then 429s with
retry-after; per-IP isolation; forgets hits after the window.
- `invite-rate-limit-route.test.ts`: `GET /invites/:token` and `POST
/invites/:token/accept` return 429 once the per-IP threshold is
exceeded.
- Manual: create an invite, open the link (works once per token as
before), then hammer `GET /api/invites/<token>` >20 times within a
minute from one IP → `429` with `Retry-After`.
- Server package typechecks clean for all touched files.

## Risks

- Low risk. Token change affects only newly minted tokens; existing
links resolve via the same sha256-hash lookup.
- The limiter is in-memory and per-process: in multi-replica deployments
each replica enforces its own 20 req/min/IP budget. That still bounds
enumeration (per-replica) and matches the existing
`company-search-rate-limit` approach; a shared store can be layered
later if needed.
- Legitimate users behind a single NAT/proxy IP share the 20 req/min
budget for invite endpoints; the invite flow makes only a handful of
requests, so headroom is ample.
- No DB migration, no API shape change.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- Claude (Anthropic) — Claude Fable 5 (`claude-fable-5`), extended
thinking enabled, agentic tool use (code search, editing, local
typecheck) via Claude Code.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

Supersedes #8147.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 15:47:58 -07:00
Jannes StubbemannandClaude Fable 5 b4e7ba5143 feat(run-logs): durable run-log store via object-storage mirror (#8984)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Every agent run streams its stdout/stderr/system output into the
run-log store (`server/src/services/run-log-store.ts`), and the run-log
API serves those logs back for review and debugging
> - The only store implementation is `local_file`: logs live on the
server pod's filesystem under `PAPERCLIP_HOME`
> - In hardened / ephemeral deployments, `PAPERCLIP_HOME` is an
`emptyDir` with no persistent volume, so every pod restart wipes the log
files while the DB row still references them — the run-log API then
returns "Run log not found" for every completed run after any redeploy
> - Run logs are the primary audit/debugging trail for agent work;
losing them on routine redeploys undermines trust in the platform
> - This pull request adds transparent durability: when
`RUN_LOG_S3_BUCKET` is set, the store mirrors each completed log to
object storage on `finalize` (same `logRef` key) and falls back to it on
`read` when the local file is gone; live append/tail stays on the fast
pod-local file
> - The benefit is that completed run logs survive pod restarts and
redeploys with zero changes for existing deployments (unset bucket =
today's behaviour) and zero downstream changes (store id stays
`local_file`)

## Linked Issues or Issue Description

No existing public issue — inline description following the bug report
template:

**What happened?** After any server pod restart/redeploy, the run-log
API returns "Run log not found" for all previously completed runs. The
DB still references the log file, but the file is gone because run logs
are written only to the pod-local filesystem.

**Expected behavior:** Completed run logs remain readable across pod
restarts and redeploys.

**Steps to reproduce:**
1. Deploy the server with `PAPERCLIP_HOME` on an `emptyDir` (no
persistent volume — common in hardened/ephemeral Kubernetes
deployments).
2. Complete an agent run and confirm its log is readable via the run-log
API.
3. Restart or redeploy the server pod.
4. Request the same run's log — the API throws "Run log not found".

**Paperclip version or commit:** reproducible on current `master`.
**Deployment mode:** Kubernetes (server pod without persistent volume).
**Agent adapter(s) involved:** Not adapter-specific (core bug).

Supersedes #8795.

## What Changed

- `server/src/services/run-log-store.ts`: the local-file store becomes a
durable store with an optional object-storage mirror
- `finalize` mirrors the completed NDJSON log to S3-compatible object
storage (keyed by the same `logRef`), best-effort so a failed upload can
never break run finalization; upload failures are logged via
`console.warn` so operators can detect a persistently broken mirror
before a pod roll makes logs unreadable
- `read` serves the pod-local file when present and falls back to a
ranged object-storage read (with correct `nextOffset`) when the local
file is gone
- Live `append`/tail stays on the pod-local file — fast path unchanged,
no per-chunk PUT
- Store id stays `local_file`, so nothing downstream changes (feedback
pipeline, read casts, fixtures untouched)
- New optional config, all read at store construction:
`RUN_LOG_S3_BUCKET`, `RUN_LOG_S3_ENDPOINT`, `RUN_LOG_S3_REGION` (default
`us-east-1`), `RUN_LOG_S3_PREFIX` (default `run-logs`),
`RUN_LOG_S3_FORCE_PATH_STYLE` (default `true`); credentials via the
standard AWS env chain; works with any S3-compatible endpoint
- Reuses the existing `createS3StorageProvider`; deliberately
independent from `PAPERCLIP_STORAGE_PROVIDER` so enabling durable logs
does not redirect workspace/file storage
- `server/src/services/run-log-store.test.ts` (new): 7 tests with an
in-memory `StorageProvider` mock

## Verification

- `npx vitest run src/services/run-log-store.test.ts` in `server/` — 7/7
pass locally:
  - store id stays `local_file`
  - live read served from the local file (no S3 round-trip)
  - `finalize` uploads the completed log to the mirror
- read falls back to S3 after a simulated pod roll (local file deleted)
  - ranged S3 read returns correct slice + `nextOffset`
  - not-found when neither local nor mirror has the log
  - local-only safe degrade when no bucket is configured
- `npx tsc --noEmit -p server` — clean for the touched files
- Manual: set `RUN_LOG_S3_*` against any S3-compatible endpoint (e.g.
MinIO), complete a run, delete the local `.ndjson` file, and re-request
the log via the run-log API — it is served from the mirror

## Risks

- Low risk: with `RUN_LOG_S3_BUCKET` unset (the default), behaviour is
byte-for-byte today's local-only store
- Mirror upload is best-effort by design — a misconfigured bucket loses
durability (not correctness) for affected runs; failures are now
surfaced via a `console.warn` per failed upload
- No DB migration, no API shape change, no change to the persisted
`store`/`logRef` handle format

## Model Used

- Claude (Anthropic), model ID `claude-fable-5` (Fable 5), via Claude
Code with extended thinking and tool use (code execution, file editing).
Original implementation TDD-authored with the same tooling.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have 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: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 15:45:39 -07:00
Jannes StubbemannandClaude Fable 5 543de323f6 fix(shared): tolerate empty-string user name in profile/session parse (#8986)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Humans sign in through the auth layer; every authenticated request
parses the session/user profile with `currentUserProfileSchema` in
`packages/shared`
> - The schema requires `name` to be `null` or a non-empty string, but
some identity providers hand back `name: ""` for users who never set a
display name
> - For those users the session payload fails validation on every
request, so the app treats them as unauthenticated and bounces them to
`/auth` in a loop — they can never get in
> - This pull request preprocesses empty/whitespace-only names to `null`
before validation, so the existing `min(1).max(120).nullable()` rule
still holds for real names
> - Review found the sibling `email` field has the same failure mode
(the DB `auth` schema declares `email` as `notNull`, so a provider that
supplies no email stores `""`, which `z.string().email()` rejects); the
same preprocess is applied there
> - The benefit is that users whose provider reports an empty name (or
email) can sign in normally instead of being locked out, with no change
in behavior for anyone else

## Linked Issues or Issue Description

No existing issue; described in-PR following the bug report template:

**What happened?**

Users whose auth provider returns `name: ""` (empty string) in the
profile payload fail `currentUserProfileSchema` / `authSessionSchema`
parsing (`name: z.string().min(1)...`). The parse failure makes the
session look invalid and the UI redirects to `/auth` on every attempt —
an endless sign-in loop. The `email` field has the same failure mode
(`z.string().email()` rejects `""`).

**Expected behavior:**

An empty display name (or email) should be treated the same as a missing
one (`null`); the user should be signed in normally.

**Steps to reproduce:**

Sign in with an account whose upstream identity record has an
empty-string name (or set a user's `name` column to `''` directly), then
load the app: session parse fails and you are bounced back to `/auth`.

**Adapter(s) involved:**

Not adapter-specific (core bug).

**Deployment mode / version:**

Any; reproduces on current `master`.

## What Changed

- `packages/shared/src/validators/access.ts`:
`currentUserProfileSchema.name` now runs through `z.preprocess` that
coerces empty or whitespace-only strings to `null` before the existing
`z.string().min(1).max(120).nullable()` validation.
- `packages/shared/src/validators/access.ts`: the same preprocess is
applied to `email` (review follow-up): `users.email` is `notNull` in the
DB schema, so a provider without an email stores `""`, which
`z.string().email()` rejects — the identical lockout loop.
Empty/whitespace-only emails now coerce to `null` (the field was already
nullable); malformed non-empty emails are still rejected.
- `packages/shared/src/validators/access.test.ts` (new): covers
empty-string → `null`, whitespace-only → `null`, real values preserved,
`null` preserved, and malformed non-empty email still rejected — for
both `name` and `email`, and the same cases through `authSessionSchema`.

## Verification

- `vitest run src/validators/access.test.ts` in `packages/shared` — 13
tests pass.
- `tsc --noEmit -p packages/shared` passes.
- Manual: parse `{ id, email: "", name: "", image: null }` with
`currentUserProfileSchema` — succeeds with `name: null` and `email:
null` instead of failing validation.

## Risks

- Low risk. The change only widens accepted input (empty/whitespace
string → `null` for `name` and `email`); every previously valid payload
parses identically. `updateCurrentUserProfileSchema` (user-initiated
rename) is untouched and still rejects empty names.

## Model Used

Claude Fable 5 (Anthropic, `claude-fable-5`, agentic coding harness via
Claude Code, extended reasoning enabled). Original fix drafted with
Claude Sonnet 4.6.

## 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: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 15:40:04 -07:00
Jannes StubbemannandClaude Fable 5 4f539625f7 build(agent-runtime): ship ripgrep in the base image (#8976)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents execute inside sandboxed runtime containers built from
`docker/agent-runtime/Dockerfile.base`
> - OpenCode's skill tooling shells out to ripgrep; when `rg` is not on
PATH it tries to download a pinned build from
`github.com/BurntSushi/ripgrep/releases` at run time
> - In a sandbox with locked-down egress that download hangs ~127s and
then fails, burning run budget on every agent run before the agent
reaches its actual work
> - The root repo `Dockerfile` already installs ripgrep; the
agent-runtime base image drifted without it
> - This pull request adds `ripgrep` to the base image's apt install so
OpenCode uses the system binary and never reaches for the network
> - The benefit is that every sandboxed agent run stops wasting ~2
minutes on a doomed download and spends its budget on real work

## Linked Issues or Issue Description

No existing issue — problem described here per the bug report template:

- **What happened:** Sandboxed agent runs using OpenCode stall for ~127
seconds at startup, then log `Transport error ...
BurntSushi/ripgrep/releases/download/...` before continuing degraded.
- **Expected behavior:** The agent starts working immediately; skill
tooling finds `rg` on PATH.
- **Root cause:** The agent-runtime base image
(`docker/agent-runtime/Dockerfile.base`) does not ship ripgrep, so
OpenCode falls back to downloading a pinned build at run time, which
egress-restricted sandboxes block.
- **Reproduction:** Run any OpenCode-backed agent in a sandbox with
locked-down egress using the current agent-runtime image; observe the
startup hang and transport error.

Supersedes #8859.

## What Changed

- Added `ripgrep` to the existing `apt-get install
--no-install-recommends` list in `docker/agent-runtime/Dockerfile.base`
- Added an explanatory comment documenting why ripgrep must be present
(run-time download fallback + egress-restricted sandboxes), restoring
parity with the root repo `Dockerfile`

## Verification

- `docker build -f docker/agent-runtime/Dockerfile.base .` then `docker
run --rm <image> rg --version` — prints the ripgrep version from the
system package
- Run an OpenCode-backed agent in an egress-restricted sandbox on the
new image: no `BurntSushi/ripgrep` download attempt, no ~127s startup
stall

## Risks

- Low risk: no behavior change beyond shipping one additional apt
package in the base image; slightly larger image size

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- Claude (Anthropic), model ID `claude-fable-5` (Fable 5), agentic
coding via Claude Code with tool use; original change authored with
Claude Opus 4.8 (1M context) and re-based/re-verified with Fable 5

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

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
canary/v2026.714.0-canary.15
2026-07-14 15:38:52 -07:00
df0e5bd021 fix(interactions): don't supersede decision cards on machine-authored comments (#9015)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents and humans coordinate on issue threads, where
`request_confirmation` cards capture pending decisions; a genuine human
comment on the thread is meant to supersede (cancel) a card.
> - Supersession is keyed on `!comment.authorUserId` — the guard assumes
only real human comments carry a user id.
> - But local-CLI agent heartbeats post comments under user auth, so a
machine comment's `authorUserId` is populated **nondeterministically per
run** (the same agent resolves as `agent` on one run and `user` on
another).
> - As a result an agent's own on-thread comment — or a teammate's, from
a different run — can carry `authorUserId` and silently expire a pending
decision card. A card was observed expiring 7ms after its own automated
comment landed, stranding the decision with no live approval path.
> - This PR switches the discriminator to a durable, deterministic
signal already persisted on every comment — `created_by_run_id` — so
only comments with **no run context** (genuine board-UI comments)
supersede.
> - The benefit: machine-authored comments can never again expire
decision cards, while real human supersession is preserved exactly.

## Linked Issues or Issue Description

No public GitHub issue — describing the bug in-PR.

- **What happened:** A pending `request_confirmation` decision card was
expired by an automated, machine-authored comment on the same thread.
Supersession is keyed on `!comment.authorUserId`, but local-CLI agent
heartbeats post under user auth, so a machine comment's `authorUserId`
is set nondeterministically per run. An agent's own comment (or a
teammate's, from a different run) can therefore carry a user id and
expire a pending card — one was observed expiring 7ms after its own
automated comment landed.
- **Expected behavior:** Only genuine interactive human (board-UI)
comments should supersede pending decision cards. Machine-authored
comments must never expire them, regardless of how the adapter's auth
resolves.
- **Steps to reproduce:** With a pending `request_confirmation` card
(`supersedeOnUserComment: true`), post a comment via a local-CLI agent
run whose actor resolves to `user`; the card expires with outcome
`superseded_by_comment`.
- **Deployment mode:** server (self-hosted), reproduced against
`master`.

Related PRs (same lifecycle area, not duplicates): #6094 (auto-resolve
stale `request_confirmation` interactions) and #8799 (expire ask-user
questions superseded by comments, merged).

## What Changed

- Supersession now fires **only on comments with no run context**
(`created_by_run_id` is null), in both paths:
- `expireRequestConfirmationsSupersededByComment` (live post path) —
early-return when `comment.createdByRunId` is set.
- `expireRequestConfirmationsSupersededByHistoricalComments` (repair
sweep) — query filters `isNull(created_by_run_id)`.
- Mirrors the existing `shouldImplicitlyMoveCommentedIssueToTodo` reopen
guard, which already uses run context to solve the same
nondeterministic-identity problem.
- Adds live + historical regression tests asserting a run-originated
comment under user auth does not supersede a pending card.

## Verification

- Interactions service suite: **27 tests pass (1 file)**, including the
two new regression tests.
- CI: all substantive gates green (Build, General tests, serialized
server suites, Typecheck, e2e, verify, security-review, policy).
- Manual: with a pending card, a comment carrying `created_by_run_id`
leaves it `pending`; a comment with null run context still supersedes
it.

## Risks

- Low risk, narrowly scoped to the supersession discriminator. Human
supersession is preserved (comments with no run context still cancel
cards); only the machine-authored case is closed.
- No schema migration — `created_by_run_id` is already persisted by
`addComment`.
- Alternatives considered: (a) ignore only the assignee's own run —
misses cross-run machine comments; (b) default `supersedeOnUserComment:
false` for agent-created cards — would drop the legitimate "human
comment redirects → cancel the card" behavior. The run-context guard
covers all machine comments while preserving human supersession.

## Model Used

Claude Opus 4.8 (Anthropic), model id `claude-opus-4-8`, extended
reasoning + tool use, via Claude Code.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [ ] My branch name describes the change and contains no internal
Paperclip ticket id — **not yet met**; renaming an open PR's branch
risks closing this PR, so it's flagged for a maintainer to rename safely
(or via the GitHub rename-branch API).
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] I have updated relevant documentation to reflect my changes — N/A
(internal behavior fix, no user-facing docs)
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green (the only red check is the
automated PR-review template gate this revision addresses)
- [ ] Greptile is 5/5 with no open P2s — re-review requested after this
revision
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Andrew Aymeloglu <aaymeloglu@gmail.com>
canary/v2026.714.0-canary.14
2026-07-14 15:56:26 -05:00
DottaandPaperclip 3db2e6bdd2 feat(mcp) [split 8/8]: add e2e coverage and operator docs (#9563)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Governed MCP access spans contracts, runtime enforcement, adapters,
UI surfaces, and operator verification
> - The parity reference PR #9534 is too large for effective automated
or human review
> - The feature therefore needs a linear stack whose individual diffs
stay below the 100-file review limit
> - This pull request is split 8/8 and focuses on end-to-end coverage,
operator docs, evals, and release notes
> - The benefit is a standalone, testable review boundary while
preserving byte-for-byte parity at the top of the stack

## Linked Issues or Issue Description

- Related parity reference: #9534
- Problem: The complete stack needs discoverable browser scenarios,
operator guidance, threat modeling, eval coverage, and a parity proof
before merge.
- Proposed solution: Adds MCP user-story and Smoke Lab e2e suites,
docs/evals/release notes, the skill update, and the root e2e driver
script registration.
- Alternatives considered: keeping #9534 as one 403-file review, or
rewriting the feature to manufacture seams; both were rejected in favor
of path extraction plus compile-driven boundary moves.
- Roadmap alignment: this advances the existing governed MCP/tool-access
work already represented by #9534; it does not introduce a separate
roadmap initiative.
- Stack position: base branch is `pap10341-split/07-ui-apps-activation`.
- Merge policy: merge bottom-up, in order, only after the complete
eight-PR stack has been reviewed and the top-of-stack parity gate
remains empty.
- Requested review: QA for flag audit and e2e/browser acceptance;
Greptile on every PR.

## What Changed

- Adds MCP user-story and Smoke Lab e2e suites, docs/evals/release
notes, the skill update, and the root e2e driver script registration.
- Keeps this PR below 100 changed files and independently typecheckable.
- Preserves the final tree from #9534 when combined with the other seven
stack levels.

## Verification

- `pnpm typecheck`
- `node --check scripts/e2e-mcp-user-stories.mjs`
- `pnpm exec playwright test --config tests/e2e/playwright.config.ts
--list` — 43 tests discovered
- `git diff pap10341-split/08-e2e-docs
6b40e3876d9297105d4ec306e47e46d351c86172` — empty (0 bytes)

## Risks

- Browser suites depend on runtime services and environment setup; this
PR validates discovery locally while QA owns full flag-on/flag-off
execution.
- Stack risk: merging out of order can expose incomplete layers;
mitigate by following the documented bottom-up merge policy.
- Parity risk: later edits to an intermediate branch can drift from
#9534; mitigate by re-running the empty top-of-stack diff before merge.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, exact model ID `gpt-5.4`; runtime-managed context
window; medium reasoning with repository, shell, Git, GitHub CLI, and
code-execution tools 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] Internal references are omitted except the execution-plan link
explicitly required for this coordinated split stack
- [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
- [ ] 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


## Stack Coordination

- Internal execution plan:
[PAP-13874](/PAP/issues/PAP-13874#document-plan)
- Parity reference: #9534
- Stack: #9556 → #9557 → #9558 → #9559 → #9560 → #9561 → #9562 → #9563
- Merge bottom-up only after full-stack review and an empty parity diff
at #9563.

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-14 15:48:57 -05:00
DottaandPaperclip f712cedbc2 feat(mcp) [split 7/8]: activate Apps and gateway UI (#9562)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Governed MCP access spans contracts, runtime enforcement, adapters,
UI surfaces, and operator verification
> - The parity reference PR #9534 is too large for effective automated
or human review
> - The feature therefore needs a linear stack whose individual diffs
stay below the 100-file review limit
> - This pull request is split 7/8 and focuses on Apps/Gateways UI and
feature-flagged activation
> - The benefit is a standalone, testable review boundary while
preserving byte-for-byte parity at the top of the stack

## Linked Issues or Issue Description

- Related parity reference: #9534
- Problem: The standalone UI foundation needs feature-flagged routes,
navigation, app detail flows, gateways, Storybook scenarios, and QA
configuration.
- Proposed solution: Adds Apps/Gateways pages and components,
navigation/route activation, remaining page integrations, Storybook
stories, and QA Vite configuration.
- Alternatives considered: keeping #9534 as one 403-file review, or
rewriting the feature to manufacture seams; both were rejected in favor
of path extraction plus compile-driven boundary moves.
- Roadmap alignment: this advances the existing governed MCP/tool-access
work already represented by #9534; it does not introduce a separate
roadmap initiative.
- Stack position: base branch is
`pap10341-split/06-ui-tools-foundation`.
- Merge policy: merge bottom-up, in order, only after the complete
eight-PR stack has been reviewed and the top-of-stack parity gate
remains empty.
- Requested review: UXDesigner sanity pass on Apps/Gateways flows and
flag-off behavior; Greptile on every PR.

## What Changed

- Adds Apps/Gateways pages and components, navigation/route activation,
remaining page integrations, Storybook stories, and QA Vite
configuration.
- Keeps this PR below 100 changed files and independently typecheckable.
- Preserves the final tree from #9534 when combined with the other seven
stack levels.

## Verification

- `pnpm typecheck`
- `pnpm check:token-gates` — all gates clean
- Focused UI Vitest run with `NODE_ENV=test` — 17 files, 147 tests
passed

## Risks

- Navigation or flag regressions could expose incomplete experiences;
activation remains controlled by existing experimental settings.
- Stack risk: merging out of order can expose incomplete layers;
mitigate by following the documented bottom-up merge policy.
- Parity risk: later edits to an intermediate branch can drift from
#9534; mitigate by re-running the empty top-of-stack diff before merge.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, exact model ID `gpt-5.4`; runtime-managed context
window; medium reasoning with repository, shell, Git, GitHub CLI, and
code-execution tools 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] Internal references are omitted except the execution-plan link
explicitly required for this coordinated split stack
- [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
- [ ] 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


## Stack Coordination

- Internal execution plan:
[PAP-13874](/PAP/issues/PAP-13874#document-plan)
- Parity reference: #9534
- Stack: #9556 → #9557 → #9558 → #9559 → #9560 → #9561 → #9562 → #9563
- Merge bottom-up only after full-stack review and an empty parity diff
at #9563.


## UI Evidence

QA captured these from the live Garden MCP split stack at 1440px and
verified clean rendering:

![Apps
connections](https://raw.githubusercontent.com/paperclipai/paperclip/42512d030c96f678c379fbd97d8b7c1737d654fc/doc/screenshots/garden-mcp-split-stack/apps-list.png)

![Gateway
detail](https://raw.githubusercontent.com/paperclipai/paperclip/42512d030c96f678c379fbd97d8b7c1737d654fc/doc/screenshots/garden-mcp-split-stack/gateway-detail.png)

![BYO connect
wizard](https://raw.githubusercontent.com/paperclipai/paperclip/42512d030c96f678c379fbd97d8b7c1737d654fc/doc/screenshots/garden-mcp-split-stack/byo-connect.png)

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.714.0-canary.13
2026-07-14 15:40:08 -05:00
DottaandPaperclip a116713b9a feat(mcp) [split 6/8]: add Tools and Profiles UI foundation (#9561)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Governed MCP access spans contracts, runtime enforcement, adapters,
UI surfaces, and operator verification
> - The parity reference PR #9534 is too large for effective automated
or human review
> - The feature therefore needs a linear stack whose individual diffs
stay below the 100-file review limit
> - This pull request is split 6/8 and focuses on UI API, shared
components, and Tools/Profile surfaces
> - The benefit is a standalone, testable review boundary while
preserving byte-for-byte parity at the top of the stack

## Linked Issues or Issue Description

- Related parity reference: #9534
- Problem: Operators need typed clients and administration surfaces that
compile independently before navigation exposes them.
- Proposed solution: Adds UI APIs, hooks, libraries, shared components,
Tools/Profiles pages, and the plugin settings consumer required by the
new company-scoped API.
- Alternatives considered: keeping #9534 as one 403-file review, or
rewriting the feature to manufacture seams; both were rejected in favor
of path extraction plus compile-driven boundary moves.
- Roadmap alignment: this advances the existing governed MCP/tool-access
work already represented by #9534; it does not introduce a separate
roadmap initiative.
- Stack position: base branch is
`pap10341-split/05-runtime-integration`.
- Merge policy: merge bottom-up, in order, only after the complete
eight-PR stack has been reviewed and the top-of-stack parity gate
remains empty.
- Requested review: UXDesigner sanity pass on Tools/Profile surfaces;
Greptile on every PR.

## What Changed

- Adds UI APIs, hooks, libraries, shared components, Tools/Profiles
pages, and the plugin settings consumer required by the new
company-scoped API.
- Keeps this PR below 100 changed files and independently typecheckable.
- Preserves the final tree from #9534 when combined with the other seven
stack levels.

## Verification

- `pnpm typecheck`
- `pnpm check:token-gates` — all gates clean
- Focused UI Vitest run with `NODE_ENV=test` — 28 files, 183 tests
passed

## Risks

- Large dead-code UI additions can drift from activation routes; PR 7
supplies the registration layer and top-level parity catches omissions.
- Stack risk: merging out of order can expose incomplete layers;
mitigate by following the documented bottom-up merge policy.
- Parity risk: later edits to an intermediate branch can drift from
#9534; mitigate by re-running the empty top-of-stack diff before merge.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, exact model ID `gpt-5.4`; runtime-managed context
window; medium reasoning with repository, shell, Git, GitHub CLI, and
code-execution tools 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] Internal references are omitted except the execution-plan link
explicitly required for this coordinated split stack
- [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
- [ ] 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


## Stack Coordination

- Internal execution plan:
[PAP-13874](/PAP/issues/PAP-13874#document-plan)
- Parity reference: #9534
- Stack: #9556 → #9557 → #9558 → #9559 → #9560 → #9561 → #9562 → #9563
- Merge bottom-up only after full-stack review and an empty parity diff
at #9563.


## UI Evidence

QA captured these from the live Garden MCP split stack at 1440px and
verified clean rendering:

![Profiles
index](https://raw.githubusercontent.com/paperclipai/paperclip/ac72de3ec85feb14c5ec1ed0a3d39b29baa0abff/doc/screenshots/garden-mcp-split-stack/profiles-index.png)

![Profile
wizard](https://raw.githubusercontent.com/paperclipai/paperclip/ac72de3ec85feb14c5ec1ed0a3d39b29baa0abff/doc/screenshots/garden-mcp-split-stack/profile-wizard.png)


![Policies](https://raw.githubusercontent.com/paperclipai/paperclip/ac72de3ec85feb14c5ec1ed0a3d39b29baa0abff/doc/screenshots/garden-mcp-split-stack/policies.png)

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.714.0-canary.12
2026-07-14 15:31:12 -05:00
DottaandPaperclip 9c8adee48b feat(mcp) [split 5/8]: integrate adapters and deployment runtime (#9560)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Governed MCP access spans contracts, runtime enforcement, adapters,
UI surfaces, and operator verification
> - The parity reference PR #9534 is too large for effective automated
or human review
> - The feature therefore needs a linear stack whose individual diffs
stay below the 100-file review limit
> - This pull request is split 5/8 and focuses on remaining adapters,
CLI, plugin examples, and deployment packaging
> - The benefit is a standalone, testable review boundary while
preserving byte-for-byte parity at the top of the stack

## Linked Issues or Issue Description

- Related parity reference: #9534
- Problem: The backend runtime needs packaging, CLI propagation,
worktree provisioning, release manifests, and remaining adapter/plugin
consumers.
- Proposed solution: Adds the remaining runtime/deployment integration
after compile-required contracts and concrete MCP injection moved into
lower server levels.
- Alternatives considered: keeping #9534 as one 403-file review, or
rewriting the feature to manufacture seams; both were rejected in favor
of path extraction plus compile-driven boundary moves.
- Roadmap alignment: this advances the existing governed MCP/tool-access
work already represented by #9534; it does not introduce a separate
roadmap initiative.
- Stack position: base branch is
`pap10341-split/04-server-runtime-wiring`.
- Merge policy: merge bottom-up, in order, only after the complete
eight-PR stack has been reviewed and the top-of-stack parity gate
remains empty.
- Requested review: QA for CLI, packaging, and worktree behavior;
Greptile on every PR.

## What Changed

- Adds the remaining runtime/deployment integration after
compile-required contracts and concrete MCP injection moved into lower
server levels.
- Keeps this PR below 100 changed files and independently typecheckable.
- Preserves the final tree from #9534 when combined with the other seven
stack levels.

## Verification

- `pnpm typecheck`
- Focused CLI Vitest run — 4 files, 49 tests passed

## Risks

- Packaging omissions could make the feature work in source but fail in
Docker, worktrees, or release assembly.
- Stack risk: merging out of order can expose incomplete layers;
mitigate by following the documented bottom-up merge policy.
- Parity risk: later edits to an intermediate branch can drift from
#9534; mitigate by re-running the empty top-of-stack diff before merge.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, exact model ID `gpt-5.4`; runtime-managed context
window; medium reasoning with repository, shell, Git, GitHub CLI, and
code-execution tools 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] Internal references are omitted except the execution-plan link
explicitly required for this coordinated split stack
- [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
- [ ] 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


## Stack Coordination

- Internal execution plan:
[PAP-13874](/PAP/issues/PAP-13874#document-plan)
- Parity reference: #9534
- Stack: #9556 → #9557 → #9558 → #9559 → #9560 → #9561 → #9562 → #9563
- Merge bottom-up only after full-stack review and an empty parity diff
at #9563.

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.714.0-canary.11
2026-07-14 15:15:43 -05:00
DottaandPaperclip 931eec3fbf feat(mcp) [split 4/8]: wire gateway runtime and Smoke Lab (#9559)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Governed MCP access spans contracts, runtime enforcement, adapters,
UI surfaces, and operator verification
> - The parity reference PR #9534 is too large for effective automated
or human review
> - The feature therefore needs a linear stack whose individual diffs
stay below the 100-file review limit
> - This pull request is split 4/8 and focuses on gateway runtime, Smoke
Lab, plugins, and server wiring
> - The benefit is a standalone, testable review boundary while
preserving byte-for-byte parity at the top of the stack

## Linked Issues or Issue Description

- Related parity reference: #9534
- Problem: The policy core needs runtime execution, endpoint guards,
route registration, heartbeat integration, and adapter MCP injection to
become operational.
- Proposed solution: Adds the remaining server routes/wiring/consumers,
runtime tests, adapter-utils MCP contracts, and Claude/Codex injection
implementations required by the server layer.
- Alternatives considered: keeping #9534 as one 403-file review, or
rewriting the feature to manufacture seams; both were rejected in favor
of path extraction plus compile-driven boundary moves.
- Roadmap alignment: this advances the existing governed MCP/tool-access
work already represented by #9534; it does not introduce a separate
roadmap initiative.
- Stack position: base branch is `pap10341-split/03-server-tool-access`.
- Merge policy: merge bottom-up, in order, only after the complete
eight-PR stack has been reviewed and the top-of-stack parity gate
remains empty.
- Requested review: SecurityEngineer for gateway, endpoint guard, token
issuance, and runtime wiring; Greptile on every PR.

## What Changed

- Adds the remaining server routes/wiring/consumers, runtime tests,
adapter-utils MCP contracts, and Claude/Codex injection implementations
required by the server layer.
- Keeps this PR below 100 changed files and independently typecheckable.
- Preserves the final tree from #9534 when combined with the other seven
stack levels.

## Verification

- `pnpm typecheck`
- Changed server test set — 26 files, 382 tests passed
- Affected server adapter tests — 38 tests passed after concrete adapter
boundary move
- Adapter-utils and Codex focused tests — 76 tests passed

## Risks

- Remote endpoint validation, token handling, and runtime supervision
are security-sensitive and can fail closed or deny legitimate access if
misconfigured.
- Stack risk: merging out of order can expose incomplete layers;
mitigate by following the documented bottom-up merge policy.
- Parity risk: later edits to an intermediate branch can drift from
#9534; mitigate by re-running the empty top-of-stack diff before merge.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, exact model ID `gpt-5.4`; runtime-managed context
window; medium reasoning with repository, shell, Git, GitHub CLI, and
code-execution tools 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] Internal references are omitted except the execution-plan link
explicitly required for this coordinated split stack
- [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
- [ ] 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


## Stack Coordination

- Internal execution plan:
[PAP-13874](/PAP/issues/PAP-13874#document-plan)
- Parity reference: #9534
- Stack: #9556 → #9557 → #9558 → #9559 → #9560 → #9561 → #9562 → #9563
- Merge bottom-up only after full-stack review and an empty parity diff
at #9563.

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-14 15:07:30 -05:00
DottaandPaperclip cfa5e0704e feat(mcp) [split 3/8]: add tool access policy core (#9558)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Governed MCP access spans contracts, runtime enforcement, adapters,
UI surfaces, and operator verification
> - The parity reference PR #9534 is too large for effective automated
or human review
> - The feature therefore needs a linear stack whose individual diffs
stay below the 100-file review limit
> - This pull request is split 3/8 and focuses on tool-access policy and
authorization core
> - The benefit is a standalone, testable review boundary while
preserving byte-for-byte parity at the top of the stack

## Linked Issues or Issue Description

- Related parity reference: #9534
- Problem: Authorization, OAuth binding, secret projection, content
guards, and policy evaluation need a security-reviewable server
boundary.
- Proposed solution: Adds tool-access services/routes/tests plus the
runtime service dependencies directly imported by the core, without
registering the routes in the application.
- Alternatives considered: keeping #9534 as one 403-file review, or
rewriting the feature to manufacture seams; both were rejected in favor
of path extraction plus compile-driven boundary moves.
- Roadmap alignment: this advances the existing governed MCP/tool-access
work already represented by #9534; it does not introduce a separate
roadmap initiative.
- Stack position: base branch is `pap10341-split/02-schema-shared`.
- Merge policy: merge bottom-up, in order, only after the complete
eight-PR stack has been reviewed and the top-of-stack parity gate
remains empty.
- Requested review: SecurityEngineer for authz, OAuth, secrets, and
content guards; Greptile on every PR.

## What Changed

- Adds tool-access services/routes/tests plus the runtime service
dependencies directly imported by the core, without registering the
routes in the application.
- Keeps this PR below 100 changed files and independently typecheckable.
- Preserves the final tree from #9534 when combined with the other seven
stack levels.

## Verification

- `pnpm typecheck`
- Focused server Vitest run — 4 files, 143 tests passed

## Risks

- Authorization bugs could permit cross-company or over-broad tool
access; the PR remains inert until PR 4 wiring and requires dedicated
security review.
- Stack risk: merging out of order can expose incomplete layers;
mitigate by following the documented bottom-up merge policy.
- Parity risk: later edits to an intermediate branch can drift from
#9534; mitigate by re-running the empty top-of-stack diff before merge.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, exact model ID `gpt-5.4`; runtime-managed context
window; medium reasoning with repository, shell, Git, GitHub CLI, and
code-execution tools 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] Internal references are omitted except the execution-plan link
explicitly required for this coordinated split stack
- [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
- [ ] 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


## Stack Coordination

- Internal execution plan:
[PAP-13874](/PAP/issues/PAP-13874#document-plan)
- Parity reference: #9534
- Stack: #9556 → #9557 → #9558 → #9559 → #9560 → #9561 → #9562 → #9563
- Merge bottom-up only after full-stack review and an empty parity diff
at #9563.

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-14 14:22:39 -05:00
Dotta c6d4ee10f7 test: align current-master regression expectations (#9577)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Its server and UI test suites protect company-scoped plugin access
and instance settings behavior
> - Recent governed-access contracts intentionally added company
invocation scope and new experimental-setting defaults
> - Four existing tests were not updated consistently with those
contracts, causing current-master CI failures unrelated to the changes
under review
> - The runtime behavior is intentional, so changing production code
would weaken the new authorization and settings contracts
> - This pull request aligns the stale tests with current behavior and
removes one UI assertion accidentally pulled forward from a later
stacked feature
> - The benefit is a focused, low-risk repair that restores master CI
without changing application behavior

## Linked Issues or Issue Description

- **Bug:** Current master has four regression failures in plugin
authorization, plugin execution-workspace bridging, instance settings
normalization, and experimental settings UI tests.
- **Expected behavior:** Tests provide required company/invocation
scope, use the governed object-shaped secret reference contract, include
all current defaults, and only assert UI controls implemented at this
stack level.
- **Actual behavior:** Tests exercised obsolete request shapes or
expected a later-stack Apps toggle that is not present on current
master.
- **Reproduction:** Run the four test files listed in the Verification
section on master before this commit.

## What Changed

- Updates plugin config authorization coverage to include company scope
and an object-shaped `secret_ref` binding.
- Supplies invocation company scope to execution-workspace host-client
tests.
- Adds `enableApps` and `enableSmokeLab` to normalized settings
expectations.
- Removes the premature Apps toggle UI test introduced without its
later-stack implementation.

## Verification

- `pnpm exec vitest run server/src/__tests__/plugin-routes-authz.test.ts
server/src/__tests__/plugin-execution-workspace-bridge.test.ts
server/src/__tests__/instance-settings-service.test.ts
ui/src/pages/InstanceExperimentalSettings.test.tsx` — 73 tests passed.
- `pnpm exec vitest run
packages/plugins/sdk/tests/host-client-factory.test.ts
server/src/__tests__/plugin-secrets-handler.test.ts
server/src/__tests__/instance-settings-routes.test.ts
ui/src/lib/instance-settings.test.ts` — 39 tests passed.
- `git diff --check` — passed.

## Risks

- Low risk: test-only changes with no production runtime, schema, API,
or UI behavior changes.
- The removed Apps toggle assertion should return in the later stacked
change that introduces the actual control.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, exact model ID `gpt-5.4`; runtime-managed context
window; medium reasoning with repository, shell, GitHub CLI, and
code-execution tools 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
canary/v2026.714.0-canary.10
2026-07-14 14:03:03 -05:00
github-actions[bot]andlockfile-bot b0e9e3664f chore(lockfile): refresh pnpm-lock.yaml (#9305)
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-14 13:19:59 -05:00
DottaandPaperclip 1de0a3bb1e feat(mcp) [split 2/8]: add governed access contracts (#9557)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Governed MCP access spans contracts, runtime enforcement, adapters,
UI surfaces, and operator verification
> - The parity reference PR #9534 is too large for effective automated
or human review
> - The feature therefore needs a linear stack whose individual diffs
stay below the 100-file review limit
> - This pull request is split 2/8 and focuses on database schema and
shared governance contracts
> - The benefit is a standalone, testable review boundary while
preserving byte-for-byte parity at the top of the stack

## Linked Issues or Issue Description

- Related parity reference: #9534
- Problem: The governed access model needs additive persistence and
synchronized shared types before server enforcement can compile.
- Proposed solution: Adds migrations 0148–0169, tool-access and Smoke
Lab schema, shared types/validators/gallery helpers, and the minimal
compile-required contract consumers identified by boundary testing.
- Alternatives considered: keeping #9534 as one 403-file review, or
rewriting the feature to manufacture seams; both were rejected in favor
of path extraction plus compile-driven boundary moves.
- Roadmap alignment: this advances the existing governed MCP/tool-access
work already represented by #9534; it does not introduce a separate
roadmap initiative.
- Stack position: base branch is `pap10341-split/01-demo-servers`.
- Merge policy: merge bottom-up, in order, only after the complete
eight-PR stack has been reviewed and the top-of-stack parity gate
remains empty.
- Requested review: QA for migrations/validators; Greptile on every PR.

## What Changed

- Adds migrations 0148–0169, tool-access and Smoke Lab schema, shared
types/validators/gallery helpers, and the minimal compile-required
contract consumers identified by boundary testing.
- Keeps this PR below 100 changed files and independently typecheckable.
- Preserves the final tree from #9534 when combined with the other seven
stack levels.

## Verification

- `pnpm typecheck` — passed, including migration numbering and safety
checks
- `pnpm --filter @paperclipai/db test` — passed
- `pnpm --filter @paperclipai/shared test` — passed

## Risks

- Migration or contract mistakes could affect every upper layer; all
migrations are additive/idempotent and compile consumers are included in
this boundary.
- Stack risk: merging out of order can expose incomplete layers;
mitigate by following the documented bottom-up merge policy.
- Parity risk: later edits to an intermediate branch can drift from
#9534; mitigate by re-running the empty top-of-stack diff before merge.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, exact model ID `gpt-5.4`; runtime-managed context
window; medium reasoning with repository, shell, Git, GitHub CLI, and
code-execution tools 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] Internal references are omitted except the execution-plan link
explicitly required for this coordinated split stack
- [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
- [ ] 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


## Stack Coordination

- Internal execution plan:
[PAP-13874](/PAP/issues/PAP-13874#document-plan)
- Parity reference: #9534
- Stack: #9556 → #9557 → #9558 → #9559 → #9560 → #9561 → #9562 → #9563
- Merge bottom-up only after full-stack review and an empty parity diff
at #9563.

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-14 12:57:20 -05:00
DottaandPaperclip 7b35de65aa feat(mcp) [split 1/8]: add fixture demo servers (#9556)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Governed MCP access spans contracts, runtime enforcement, adapters,
UI surfaces, and operator verification
> - The parity reference PR #9534 is too large for effective automated
or human review
> - The feature therefore needs a linear stack whose individual diffs
stay below the 100-file review limit
> - This pull request is split 1/8 and focuses on fixture and demo MCP
servers
> - The benefit is a standalone, testable review boundary while
preserving byte-for-byte parity at the top of the stack

## Linked Issues or Issue Description

- Related parity reference: #9534
- Problem: Developers need deterministic local MCP fixtures and visible
demo servers without pulling in the governed production runtime.
- Proposed solution: Adds the Google Sheets and KV demo MCP packages,
fixture catalog/servers, smoke harness, guide, and the root
smoke/typecheck registration hunks.
- Alternatives considered: keeping #9534 as one 403-file review, or
rewriting the feature to manufacture seams; both were rejected in favor
of path extraction plus compile-driven boundary moves.
- Roadmap alignment: this advances the existing governed MCP/tool-access
work already represented by #9534; it does not introduce a separate
roadmap initiative.
- Stack position: base branch is `master`.
- Merge policy: merge bottom-up, in order, only after the complete
eight-PR stack has been reviewed and the top-of-stack parity gate
remains empty.
- Requested review: QA for fixture and smoke coverage; Greptile on every
PR.

## What Changed

- Adds the Google Sheets and KV demo MCP packages, fixture
catalog/servers, smoke harness, guide, and the root smoke/typecheck
registration hunks.
- Keeps this PR below 100 changed files and independently typecheckable.
- Preserves the final tree from #9534 when combined with the other seven
stack levels.

## Verification

- `pnpm typecheck`
- `pnpm --filter @paperclipai/google-sheets-mcp-server test` — 27 tests
passed
- `pnpm --filter @paperclipai/kv-demo-mcp-server test` — 12 tests passed

## Risks

- The new packages add dependencies that are intentionally not committed
to `pnpm-lock.yaml`, per repository policy.
- Stack risk: merging out of order can expose incomplete layers;
mitigate by following the documented bottom-up merge policy.
- Parity risk: later edits to an intermediate branch can drift from
#9534; mitigate by re-running the empty top-of-stack diff before merge.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, exact model ID `gpt-5.4`; runtime-managed context
window; medium reasoning with repository, shell, Git, GitHub CLI, and
code-execution tools 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] Internal references are omitted except the execution-plan link
explicitly required for this coordinated split stack
- [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
- [ ] 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


## Stack Coordination

- Internal execution plan:
[PAP-13874](/PAP/issues/PAP-13874#document-plan)
- Parity reference: #9534
- Stack: #9556 → #9557 → #9558 → #9559 → #9560 → #9561 → #9562 → #9563
- Merge bottom-up only after full-stack review and an empty parity diff
at #9563.

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.714.0-canary.9
2026-07-14 12:56:21 -05:00
DottaandClaude Opus 4.8 f49a3f9924 fix(ui): cap live agent-run transcript buffers to bound tab memory (#9569)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents stream their run output live into the web UI, viewed per-run
in the `AgentDetail` transcript viewer
> - Browser tabs holding these views were sitting at 8–16 GB of memory
footprint while their JS heap stayed at ~256 MB — a 60×+ gap, meaning
the cost is in retained DOM / render objects, not JS objects
> - The `LogViewer` in `AgentDetail.tsx` kept every streamed
stdout/stderr line and structured event in unbounded React state and
rendered each into a rich DOM block (the default "nice" mode has no
virtualization), so a run streaming for hours grew an unbounded live DOM
tree
> - The sibling `useLiveRunTranscripts` hook (used by `IssueChatThread`)
already bounds its buffers and virtualizes; `LogViewer` bypassed it and
managed its own uncapped state — that inconsistency is the bug
> - This pull request caps the live buffers and bounds the live DOM
render, aligning `LogViewer` with the already-bounded path
> - The benefit is that long-lived streaming tabs no longer grow without
bound, cutting multi-GB tabs back to a bounded footprint

## Linked Issues or Issue Description

No public GitHub issue exists; describing inline per CONTRIBUTING.md →
"Link Issues or Describe Them In-PR", following the bug report template.

**What happened?**

Chrome's Task Manager showed multiple long-lived Paperclip tabs
(agent-run / task views) each consuming 8–16 GB of memory footprint,
while each tab's JS heap stayed at only ~150–256 MB. Memory grew
monotonically the longer a run streamed.

**Expected behavior**

A tab viewing a live agent run should hold a bounded amount of memory
regardless of how long the run streams.

**Steps to reproduce**

Open an agent run with a long-running / high-volume stream in
`AgentDetail`, leave the tab open while output streams for an extended
period, and watch the tab's memory footprint climb without bound in
Chrome's Task Manager.

**Paperclip version or commit**

`3991a19a` (branch `fix/agent-run-transcript-memory`, off `master`).

**Deployment mode**

Local dev (`pnpm dev`), web UI. Not adapter-specific — core UI bug in
the shared transcript viewer.

## What Changed

- Add `ui/src/lib/live-log-buffer.ts`: a pure `appendCapped(prev,
additions, max)` helper plus caps `MAX_LIVE_LOG_LINES=5000`,
`MAX_LIVE_EVENTS=2000`, and `LIVE_TRANSCRIPT_RENDER_LIMIT=1500`, with
rationale documented in the module.
- Add `ui/src/lib/live-log-buffer.test.ts`: 6 unit tests (append,
trim-to-cap, oversized batch, exact-cap, no-mutation, referential
bail-out).
- `ui/src/pages/AgentDetail.tsx` (`LogViewer`): route all four
live-append sites (WebSocket log / progress / event, plus the poll
fallback) through `appendCapped`, and pass
`limit={LIVE_TRANSCRIPT_RENDER_LIMIT}` to `RunTranscriptView` for live
runs so the "nice" view mounts only the most recent blocks.
- The terminated-run "Load more log" pagination is deliberately left
**uncapped** (guarded by `isLive`), so no historical output is lost —
older output remains on the server and reachable there.

## Verification

- `vitest run src/lib/live-log-buffer.test.ts` → 6/6 pass.
- Existing suites `RunTranscriptView.test.tsx`,
`AgentDetail.instructions.test.tsx`, `useLiveRunTranscripts.test.tsx` →
22/22 pass.
- `tsc -b` (UI) → clean.
- Manual/behavioral: live runs tail the last ~1500 blocks; terminated
runs still render full history via "Load more log". Follow-up planned to
profile before/after with the Chrome DevTools MCP.

## Risks

Low risk. Changes only bound **in-memory state for live runs**; the
terminated-run paginated path is untouched (still uncapped, guarded by
`isLive`). No API, schema, or persistence changes. Worst case for a live
run is that only the most recent 5000 lines / 1500 rendered blocks are
visible in the tab — which is the intended "tail" behavior, and full
history remains on the server.

## Model Used

- **Provider:** Anthropic, via the Claude Code CLI.
- **Model:** Claude Opus 4.8 (`claude-opus-4-8`).
- **Reasoning mode:** Extended thinking enabled.
- **Capabilities used:** tool use (shell execution, file editing),
sub-agent fan-out for the codebase memory sweep, and the Chrome DevTools
MCP for the diagnosis phase.

## 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 (the ROADMAP "Memory" item is about company/agent
knowledge, unrelated to this browser-tab memory fix)
- [x] I have searched GitHub for duplicate or related PRs and linked
them above (none found among open PRs)
- [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 considered and documented any risks above
- [ ] I have updated relevant documentation to reflect my changes (N/A —
no user-facing docs affected; rationale is documented inline in
`live-log-buffer.ts`)
- [ ] All Paperclip CI gates are green (in progress at time of writing)
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
(the only open P2 was this missing template, which this update resolves;
awaiting re-review)
- [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 <noreply@anthropic.com>
canary/v2026.714.0-canary.8
2026-07-14 12:43:05 -05:00
dependabot[bot] 2617bee422 build(deps-dev): bump @storybook/addon-docs from 10.4.6 to 10.5.0 (#9483)
Bumps
[@storybook/addon-docs](https://github.com/storybookjs/storybook/tree/HEAD/code/addons/docs)
from 10.4.6 to 10.5.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/storybookjs/storybook/releases">@​storybook/addon-docs's
releases</a>.</em></p>
<blockquote>
<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>
<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 `@types/node` to packages installed during
`storybook init` - <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>
<li>Angular: Fix custom paths for stats.json on angular - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34551">#34551</a>,
thanks <a
href="https://github.com/mrginglymus"><code>@​mrginglymus</code></a>!</li>
<li>Angular: Fix zone.js drop in angular-to-angular-vite migration +
schema sync + transform widening - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35386">#35386</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Angular: Install <code>@​analogjs/vite-plugin-angular</code> in
angular-to-angular-vite automigration - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35432">#35432</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Angular: Introduce <code>@​storybook/angular-vite</code> package -
<a
href="https://redirect.github.com/storybookjs/storybook/pull/34202">#34202</a>,
thanks <a
href="https://github.com/brandonroberts"><code>@​brandonroberts</code></a>!</li>
<li>Angular: Support Angular 22 in Webpack framework - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35318">#35318</a>,
thanks <a
href="https://github.com/EtiennePasteur"><code>@​EtiennePasteur</code></a>!</li>
<li>Angular: Use future-proof API for component reflection - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35228">#35228</a>,
thanks <a
href="https://github.com/Sidnioulz"><code>@​Sidnioulz</code></a>!</li>
<li>Babel: Remove bugfixes from preset-env in v8 - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35266">#35266</a>,
thanks <a
href="https://github.com/Sidnioulz"><code>@​Sidnioulz</code></a>!</li>
<li>Builder Vite: Fix empty external globals imports - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34348">#34348</a>,
thanks <a
href="https://github.com/raashish1601"><code>@​raashish1601</code></a>!</li>
<li>Builder Vite: Support configLoader via builder options - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34080">#34080</a>,
thanks <a
href="https://github.com/holvi-sebastian"><code>@​holvi-sebastian</code></a>!</li>
<li>CLI: Add `storybook ai <!-- raw HTML omitted -->` MCP passthrough
behind `STORYBOOK_FEATURE_AI_CLI` - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35125">#35125</a>,
thanks <a
href="https://github.com/kasperpeulen"><code>@​kasperpeulen</code></a>!</li>
<li>CLI: Add telemetry for the `storybook ai <!-- raw HTML omitted -->`
passthrough - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35138">#35138</a>,
thanks <a
href="https://github.com/kasperpeulen"><code>@​kasperpeulen</code></a>!</li>
<li>CLI: Allow -p shorthand to --port for ai command - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35390">#35390</a>,
thanks <a
href="https://github.com/huang-julien"><code>@​huang-julien</code></a>!</li>
<li>CLI: Bundle the `ai` command in core so it never downloads
`@storybook/cli` - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35147">#35147</a>,
thanks <a
href="https://github.com/kasperpeulen"><code>@​kasperpeulen</code></a>!</li>
<li>CLI: Do not auto-open the browser in storybook dev under AI agents -
<a
href="https://redirect.github.com/storybookjs/storybook/pull/35412">#35412</a>,
thanks <a
href="https://github.com/kasperpeulen"><code>@​kasperpeulen</code></a>!</li>
<li>CLI: Exit process after successful build - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34735">#34735</a>,
thanks <a
href="https://github.com/torleifhalseth"><code>@​torleifhalseth</code></a>!</li>
<li>CLI: Fix angular-to-angular-vite migration failing to configure
addon-vitest - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35404">#35404</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>CLI: Fix silent hang in deferred addon configuration during upgrade
- <a
href="https://redirect.github.com/storybookjs/storybook/pull/35423">#35423</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>CLI: Fix upgrade crash on Storybook latest version check - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35156">#35156</a>,
thanks <a
href="https://github.com/yatishgoel"><code>@​yatishgoel</code></a>!</li>
<li>CLI: Handle nested array schema for AI help - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35424">#35424</a>,
thanks <a
href="https://github.com/huang-julien"><code>@​huang-julien</code></a>!</li>
<li>CLI: Install MCP when upgrade is ran by agent - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35215">#35215</a>,
thanks <a
href="https://github.com/huang-julien"><code>@​huang-julien</code></a>!</li>
<li>CLI: Load Storybook AI help from preset metadata - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35212">#35212</a>,
thanks <a
href="https://github.com/kasperpeulen"><code>@​kasperpeulen</code></a>!</li>
<li>CLI: Match `storybook ai` instances by config dir as well as cwd -
<a
href="https://redirect.github.com/storybookjs/storybook/pull/35392">#35392</a>,
thanks <a
href="https://github.com/kasperpeulen"><code>@​kasperpeulen</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-docs's
changelog</a>.</em></p>
<blockquote>
<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>
<li>Angular: Fix custom paths for stats.json on angular - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34551">#34551</a>,
thanks <a
href="https://github.com/mrginglymus"><code>@​mrginglymus</code></a>!</li>
<li>Angular: Fix zone.js drop in angular-to-angular-vite migration +
schema sync + transform widening - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35386">#35386</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Angular: Install <code>@​analogjs/vite-plugin-angular</code> in
angular-to-angular-vite automigration - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35432">#35432</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Angular: Introduce <code>@​storybook/angular-vite</code> package -
<a
href="https://redirect.github.com/storybookjs/storybook/pull/34202">#34202</a>,
thanks <a
href="https://github.com/brandonroberts"><code>@​brandonroberts</code></a>!</li>
<li>Angular: Support Angular 22 in Webpack framework - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35318">#35318</a>,
thanks <a
href="https://github.com/EtiennePasteur"><code>@​EtiennePasteur</code></a>!</li>
<li>Angular: Use future-proof API for component reflection - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35228">#35228</a>,
thanks <a
href="https://github.com/Sidnioulz"><code>@​Sidnioulz</code></a>!</li>
<li>Babel: Remove bugfixes from preset-env in v8 - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35266">#35266</a>,
thanks <a
href="https://github.com/Sidnioulz"><code>@​Sidnioulz</code></a>!</li>
<li>Builder Vite: Fix empty external globals imports - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34348">#34348</a>,
thanks <a
href="https://github.com/raashish1601"><code>@​raashish1601</code></a>!</li>
<li>Builder Vite: Support configLoader via builder options - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34080">#34080</a>,
thanks <a
href="https://github.com/holvi-sebastian"><code>@​holvi-sebastian</code></a>!</li>
<li>CLI: Add <code>storybook ai &lt;tool&gt;</code> MCP passthrough
behind <code>STORYBOOK_FEATURE_AI_CLI</code> - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35125">#35125</a>,
thanks <a
href="https://github.com/kasperpeulen"><code>@​kasperpeulen</code></a>!</li>
<li>CLI: Add telemetry for the <code>storybook ai &lt;command&gt;</code>
passthrough - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35138">#35138</a>,
thanks <a
href="https://github.com/kasperpeulen"><code>@​kasperpeulen</code></a>!</li>
<li>CLI: Allow -p shorthand to --port for ai command - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35390">#35390</a>,
thanks <a
href="https://github.com/huang-julien"><code>@​huang-julien</code></a>!</li>
<li>CLI: Bundle the <code>ai</code> command in core so it never
downloads <code>@storybook/cli</code> - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35147">#35147</a>,
thanks <a
href="https://github.com/kasperpeulen"><code>@​kasperpeulen</code></a>!</li>
<li>CLI: Do not auto-open the browser in storybook dev under AI agents -
<a
href="https://redirect.github.com/storybookjs/storybook/pull/35412">#35412</a>,
thanks <a
href="https://github.com/kasperpeulen"><code>@​kasperpeulen</code></a>!</li>
<li>CLI: Exit process after successful build - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34735">#34735</a>,
thanks <a
href="https://github.com/torleifhalseth"><code>@​torleifhalseth</code></a>!</li>
<li>CLI: Fix angular-to-angular-vite migration failing to configure
addon-vitest - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35404">#35404</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>CLI: Fix silent hang in deferred addon configuration during upgrade
- <a
href="https://redirect.github.com/storybookjs/storybook/pull/35423">#35423</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>CLI: Fix upgrade crash on Storybook latest version check - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35156">#35156</a>,
thanks <a
href="https://github.com/yatishgoel"><code>@​yatishgoel</code></a>!</li>
<li>CLI: Handle nested array schema for AI help - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35424">#35424</a>,
thanks <a
href="https://github.com/huang-julien"><code>@​huang-julien</code></a>!</li>
<li>CLI: Install MCP when upgrade is ran by agent - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35215">#35215</a>,
thanks <a
href="https://github.com/huang-julien"><code>@​huang-julien</code></a>!</li>
<li>CLI: Load Storybook AI help from preset metadata - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35212">#35212</a>,
thanks <a
href="https://github.com/kasperpeulen"><code>@​kasperpeulen</code></a>!</li>
<li>CLI: Match <code>storybook ai</code> instances by config dir as well
as cwd - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35392">#35392</a>,
thanks <a
href="https://github.com/kasperpeulen"><code>@​kasperpeulen</code></a>!</li>
<li>CLI: Prefer agent-matched Storybook instances - <a
href="https://redirect.github.com/storybookjs/storybook/pull/35235">#35235</a>,
thanks <a
href="https://github.com/kasperpeulen"><code>@​kasperpeulen</code></a>!</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/storybookjs/storybook/commit/9dafcd22ed55947bc4c2fa1d5066b552baa0ebf4"><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="https://github.com/storybookjs/storybook/commit/448db85e651a09ca55f978356c4f1593f261f82a"><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="https://github.com/storybookjs/storybook/commit/a4ce9790a783d8e7720e9de980a08576de9555db"><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><a
href="https://github.com/storybookjs/storybook/commit/f0bf138a0a83443c177f4b6882d74440829de42e"><code>f0bf138</code></a>
Bump version from &quot;10.5.0-alpha.11&quot; to
&quot;10.5.0-beta.0&quot; [skip ci]</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/fac05a57415eec36b0a72b383befd7ef5071572c"><code>fac05a5</code></a>
Bump version from &quot;10.5.0-alpha.10&quot; to
&quot;10.5.0-alpha.11&quot; [skip ci]</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/4057c4169f1e63d746d86349fcf4463e321b546e"><code>4057c41</code></a>
Bump version from &quot;10.5.0-alpha.9&quot; to
&quot;10.5.0-alpha.10&quot; [skip ci]</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/91b9c34e58bc91126baff5e184cefc20f9ada1ec"><code>91b9c34</code></a>
Merge pull request <a
href="https://github.com/storybookjs/storybook/tree/HEAD/code/addons/docs/issues/35321">#35321</a>
from storybookjs/sidnioulz/fix-html-lang-refreshed</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/383d5905dbefbdbb673568ae06ea2afef07ce59e"><code>383d590</code></a>
Merge branch 'next' into sidnioulz/fix-html-lang-refreshed</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/520c70129d6fa0b5ede737ee0b1f16166096e6b8"><code>520c701</code></a>
UI: Add docs.lang and htmlLang parameters</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/d71aa77e16e650371a41f12f82cdc75e77d0ac1f"><code>d71aa77</code></a>
Merge origin/next into docgen/worker-threading</li>
<li>Additional commits viewable in <a
href="https://github.com/storybookjs/storybook/commits/v10.5.0/code/addons/docs">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-14 10:08:29 -07:00
dependabot[bot] d7961919f5 build(deps): bump react-i18next from 17.0.8 to 17.0.9 (#9481)
Bumps [react-i18next](https://github.com/i18next/react-i18next) from
17.0.8 to 17.0.9.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md">react-i18next's
changelog</a>.</em></p>
<blockquote>
<h2>17.0.9</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. Fixes <a
href="https://redirect.github.com/i18next/react-i18next/issues/1927">#1927</a>,
thanks <a
href="https://github.com/andikapradanaarif"><code>@​andikapradanaarif</code></a>.</li>
<li>fix(types): <code>&lt;Trans t={t} ns=&quot;ns&quot; …&gt;</code>
with a <code>t</code> from <code>useTranslation(['ns'])</code> now
typechecks under TypeScript 7. TS7 intersects the <code>Ns</code>
inference candidates coming from the <code>t</code> prop (<code>readonly
['ns']</code>) and the <code>ns</code> prop (<code>'ns'</code>) into an
unsatisfiable <code>'ns' &amp; readonly ['ns']</code>, where TS6
resolved them. The <code>ns</code> prop on <code>TransProps</code>,
<code>TransSelectorProps</code> and
<code>IcuTransWithoutContextProps</code> now also accepts a single
namespace out of an array-typed <code>Ns</code> (<code>Ns | (Ns extends
readonly (infer S extends string)[] ? S : never)</code>) — which matches
runtime behavior and is unchanged under TS5/TS6.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/i18next/react-i18next/commit/8b4a9ea139b73309471737e5ba9c423f82d5c0cc"><code>8b4a9ea</code></a>
17.0.9</li>
<li><a
href="https://github.com/i18next/react-i18next/commit/422bab13d4c9664e51c0c1025df2da37c0912075"><code>422bab1</code></a>
fix: support typescript 7 — widen peer range and fix Trans ns inference
under...</li>
<li><a
href="https://github.com/i18next/react-i18next/commit/6e18aa95b5ff9257b477301283819697f249ea25"><code>6e18aa9</code></a>
README: mention npx i18next-cli localize as the zero-to-localized
path</li>
<li>See full diff in <a
href="https://github.com/i18next/react-i18next/compare/v17.0.8...v17.0.9">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=react-i18next&package-manager=npm_and_yarn&previous-version=17.0.8&new-version=17.0.9)](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>
canary/v2026.714.0-canary.7
2026-07-14 10:06:00 -07:00
dependabot[bot] 072f1e9b8e build(deps): bump dompurify from 3.4.8 to 3.4.12 (#9478)
[//]: # (dependabot-start)
⚠️  **Dependabot is rebasing this PR** ⚠️ 

Rebasing might not happen immediately, so don't worry if this takes some
time.

Note: if you make any changes to this PR yourself, they will take
precedence over the rebase.

---

[//]: # (dependabot-end)

Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.4.8 to
3.4.12.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/cure53/DOMPurify/releases">dompurify's
releases</a>.</em></p>
<blockquote>
<h2>DOMPurify 3.4.12</h2>
<ul>
<li>Fixed an issue where a hook would not get called for custom
elements, thanks <a
href="https://github.com/Rikuxx0"><code>@​Rikuxx0</code></a></li>
<li>Hardened the handling of hooks removing elements, <a
href="https://github.com/mkrause-bee360"><code>@​mkrause-bee360</code></a></li>
<li>Added support for a few new SVG attributes, thanks <a
href="https://github.com/cbn-falias"><code>@​cbn-falias</code></a> &amp;
<a
href="https://github.com/Develop-KIM"><code>@​Develop-KIM</code></a></li>
<li>Hardened the handling of declarative partial updates</li>
<li>Updated the documentation is several spots, README, wiki, etc.</li>
<li>Bumped several dependencies where possible</li>
</ul>
<h2>DOMPurify 3.4.11</h2>
<ul>
<li>Fixed an issue with a leaky config for hooks via
<code>setConfig</code>, thanks <a
href="https://github.com/trace37labs"><code>@​trace37labs</code></a></li>
<li>Bumped vulnerable development dependencies to arrive at plain 0 with
<code>npm audit</code></li>
<li>Updated the <code>osv-scanner</code> suppression list as no
vulnerable dependencies are left for now</li>
<li>Updated up the linting tool-chain and removed now-redundant lint
directives</li>
<li>Updated the documentation is several spots, README, wiki, etc.</li>
<li>Bumped several dependencies where possible</li>
</ul>
<h2>DOMPurify 3.4.10</h2>
<ul>
<li>Refactored codebase for clarity: extracted the public type
declarations into <code>types.ts</code></li>
<li>Decomposed the three largest sanitizer functions into focused
helpers</li>
<li>Removed duplicated defaults and dead branches, consolidated
<code>SAFE_FOR_TEMPLATES</code> scrubbing into single shared path</li>
<li>Improved per-node performance by hoisting the mXSS probe regexes and
testing <code>textContent</code> before <code>innerHTML</code></li>
<li>Added a deterministic micro-benchmark harness (<code>npm run
bench</code>) with a <code>--compare</code> mode</li>
<li>Reduced CI cost by running the full three-engine browser suite once
per PR</li>
<li>Refreshed the <code>demos/</code> folder so every demo runs again,
and added a SVG-via-<code>&lt;img&gt;</code> demo</li>
<li>Documented the bench and <code>test:happydom</code> scripts in the
README</li>
<li>Completed the Attack Classes &amp; Bypass History wiki page</li>
<li>Bumped several dependencies where possible</li>
</ul>
<h2>DOMPurify 3.4.9</h2>
<ul>
<li>Further improved the handling of Trusted Types config options,
thanks <a
href="https://github.com/offset"><code>@​offset</code></a></li>
<li>Further improved the handling of <code>IN_PLACE</code> sanitization,
thanks <a
href="https://github.com/mozfreddyb"><code>@​mozfreddyb</code></a></li>
<li>Added more test coverage for <code>IN_PLACE</code> and Trusted Types
related usage</li>
<li>Bumped several dependencies where possible</li>
<li>Updated README and wiki with more accurate documentation &amp;
attack samples</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/cure53/DOMPurify/commit/a9ca1e537422319a557a9a2aa61f003b23b4a197"><code>a9ca1e5</code></a>
release: 3.4.12 (<a
href="https://redirect.github.com/cure53/DOMPurify/issues/1537">#1537</a>)</li>
<li><a
href="https://github.com/cure53/DOMPurify/commit/0cae5187403132f96a6d357649e4b15633fc210a"><code>0cae518</code></a>
release: 3.4.11 (<a
href="https://redirect.github.com/cure53/DOMPurify/issues/1494">#1494</a>)</li>
<li><a
href="https://github.com/cure53/DOMPurify/commit/6ee5716f8336989753611beeca364957c0eb0c3e"><code>6ee5716</code></a>
release: 3.4.10 (<a
href="https://redirect.github.com/cure53/DOMPurify/issues/1478">#1478</a>)</li>
<li><a
href="https://github.com/cure53/DOMPurify/commit/52102472d46035857c52df19e44285f8a1e102fc"><code>5210247</code></a>
release: 3.4.9 (<a
href="https://redirect.github.com/cure53/DOMPurify/issues/1459">#1459</a>)</li>
<li>See full diff in <a
href="https://github.com/cure53/DOMPurify/compare/3.4.8...3.4.12">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dompurify&package-manager=npm_and_yarn&previous-version=3.4.8&new-version=3.4.12)](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-14 10:03:46 -07:00
dependabot[bot] ff09d8c1d8 build(deps): bump lexical from 0.46.0 to 0.47.0 (#9486)
Bumps
[lexical](https://github.com/facebook/lexical/tree/HEAD/packages/lexical)
from 0.46.0 to 0.47.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/facebook/lexical/releases">lexical's
releases</a>.</em></p>
<blockquote>
<p>v0.47.0 is a monthly release with a lot of bug fixes, particularly
related to IME and composition, and is headlined by two new experimental
packages:</p>
<ul>
<li><a
href="https://lexical.dev/docs/api/modules/lexical_mdast"><code>@lexical/mdast</code></a>
(<a
href="https://redirect.github.com/facebook/lexical/pull/8794">#8794</a>)
— a <a href="https://github.com/micromark/micromark">micromark</a>/<a
href="https://github.com/syntax-tree/mdast">mdast</a>-based alternative
to <code>@lexical/markdown</code>. Parsing, serialization, and markdown
shortcuts all go through the same parser used by <code>remark</code>, so
CommonMark + GFM compliance comes for free and there is no second
grammar to keep in sync. The original syntax of each construct is
preserved on the nodes, so re-serializing produces minimally different
Markdown. <code>@lexical/markdown</code> remains the supported default
for production apps. See the new <a
href="https://lexical.dev/docs/serialization/markdown-mdast">Markdown
with <code>@lexical/mdast</code> guide</a>.</li>
<li><a
href="https://lexical.dev/docs/api/modules/lexical_a11y"><code>@lexical/a11y</code></a>
(<a
href="https://redirect.github.com/facebook/lexical/pull/8591">#8591</a>)
— framework-agnostic accessibility helpers (ARIA live regions, focus
management, roving tab index, focus trap) usable from React, Svelte,
Vue, Solid, or vanilla DOM, with React wrappers shipping from
<code>@lexical/react</code>. The playground adopts them as part of a
WCAG AA reference pass, and the keyboard contracts Lexical follows are
documented in the new <a
href="https://lexical.dev/docs/concepts/keyboard-accessibility">Keyboard
Accessibility guide</a>.</li>
</ul>
<p>Beyond the headliners: React 18 is now the baseline (see Breaking
Changes), the playground gains Find and Replace and a Ruby annotation
node with a floating editor, tables learn to spread pasted TSV across
cells and get row/column header utilities, and there is a long list of
IME/composition, selection, and navigation fixes.</p>
<p>Special recognition once again goes to <a
href="https://github.com/mayrang"><code>@​mayrang</code></a> who has
been plowing through IME, accessibility, and other input related issues
as well as the really cool new Find and Replace and Ruby Annotations
playground features.</p>
<h2>Breaking Changes</h2>
<h3><code>@lexical/react</code> / <code>@lexical/devtools-core</code> —
React 17 support dropped (<a
href="https://redirect.github.com/facebook/lexical/pull/8782">#8782</a>)</h3>
<p>React 18 is now the minimum supported version; the <code>react</code>
/ <code>react-dom</code> peerDependencies require <code>&gt;=18</code>,
and React 17 compatibility code paths were removed. If you are already
on React 18 or 19, no changes are required.</p>
<h3><code>lexical</code> — DOM element preserved when composing on a
segmented TextNode (<a
href="https://redirect.github.com/facebook/lexical/pull/8784">#8784</a>)</h3>
<p>Starting IME composition in the middle of a segmented
<code>TextNode</code> (e.g. a mention) previously replaced the node —
destroying its DOM element and breaking the browser's composition
tracking (caret flashing and styling bleed on Chrome). The node now
temporarily switches to <code>normal</code> mode for the duration of
composition, keeping the same node key and DOM element, and is cleaned
up when composition ends. Subclass transforms or method overrides that
assume a segmented node is always in segmented mode must account for
this transient state — see the updated <a
href="https://lexical.dev/docs/api/classes/lexical.TextNode#setmode"><code>TextNode.setMode()</code>
documentation</a>.</p>
<h2>New APIs</h2>
<ul>
<li><a
href="https://lexical.dev/docs/api/modules/lexical"><code>lexical</code></a>
— <code>$getDocument()</code> returns the owner document of the active
editor (correct inside a <a
href="https://lexical.dev/docs/concepts/shadow-dom">Shadow DOM or
iframe</a>), falling back to the global document when there is no active
editor; a new <code>@lexical/eslint-plugin</code> rule enforces its use
over the <code>document</code> global (<a
href="https://redirect.github.com/facebook/lexical/pull/8788">#8788</a>,
<a
href="https://redirect.github.com/facebook/lexical/pull/8813">#8813</a>)</li>
<li><a
href="https://lexical.dev/docs/api/modules/lexical"><code>lexical</code></a>
— <code>registerEventListener</code> /
<code>registerEventListeners</code>, type-safe
<code>addEventListener</code> helpers that return cleanup functions, now
used throughout the codebase — see the updated <a
href="https://lexical.dev/docs/concepts/dom-events">Working with DOM
Events guide</a> (<a
href="https://redirect.github.com/facebook/lexical/pull/8767">#8767</a>)</li>
<li><a
href="https://lexical.dev/docs/api/modules/lexical"><code>lexical</code></a>
— <code>SET_TEXT_FORMAT_COMMAND</code> sets (rather than toggles) the
selection's text format (see <a
href="https://lexical.dev/docs/concepts/commands">Commands</a>); the
same PR fixes <code>formatText</code> toggle direction (<a
href="https://redirect.github.com/facebook/lexical/pull/8807">#8807</a>)</li>
<li><a
href="https://lexical.dev/docs/api/modules/lexical_markdown"><code>@lexical/markdown</code></a>
— <code>$generateNodesFromMarkdownString</code> parses a markdown string
into Lexical nodes without inserting them into the document or modifying
the selection (<a
href="https://redirect.github.com/facebook/lexical/pull/8789">#8789</a>)</li>
<li><a
href="https://lexical.dev/docs/api/modules/lexical_table"><code>@lexical/table</code></a>
— <code>$setTableRowIsHeader</code> and
<code>$setTableColumnIsHeader</code> utilities (<a
href="https://redirect.github.com/facebook/lexical/pull/8815">#8815</a>);
<code>$insertTableRowAtNode</code> and
<code>$insertTableColumnAtNode</code> are now exported (<a
href="https://redirect.github.com/facebook/lexical/pull/8791">#8791</a>)</li>
</ul>
<h2>Notable Fixes</h2>
<p><strong>IME, composition &amp; mobile</strong></p>
<ul>
<li>Prevent text duplication on iOS Safari when formatting during
composition (<a
href="https://redirect.github.com/facebook/lexical/pull/8755">#8755</a>)</li>
<li>Skip ZWSP insertion for format mismatch on Android Chrome (<a
href="https://redirect.github.com/facebook/lexical/pull/8769">#8769</a>);
deduplicate speech-to-text insertion on Android Chrome (<a
href="https://redirect.github.com/facebook/lexical/pull/8759">#8759</a>)</li>
<li>Event module globals moved into per-editor <code>InputState</code>
(<a
href="https://redirect.github.com/facebook/lexical/pull/8809">#8809</a>);
refactored IME composition test infrastructure with browser-level
coverage (<a
href="https://redirect.github.com/facebook/lexical/pull/8793">#8793</a>)</li>
</ul>
<p><strong>Selection &amp; navigation</strong></p>
<ul>
<li>ArrowUp/Down no longer skip block decorators (<a
href="https://redirect.github.com/facebook/lexical/pull/8775">#8775</a>);
<code>deleteLine</code> no longer removes adjacent block decorators (<a
href="https://redirect.github.com/facebook/lexical/pull/8744">#8744</a>)</li>
<li>Keep selection inside single-child inline elements (<a
href="https://redirect.github.com/facebook/lexical/pull/8772">#8772</a>);
fix navigation across unmergeable TextNode boundaries in inline-grid
containers (<a
href="https://redirect.github.com/facebook/lexical/pull/8797">#8797</a>)</li>
<li><code>$setBlocksType</code> properly handles block-end focus in
backward selections (<a
href="https://redirect.github.com/facebook/lexical/pull/8753">#8753</a>);
<code>insertNodes</code> re-resolves a detached firstBlock (<a
href="https://redirect.github.com/facebook/lexical/pull/8764">#8764</a>)</li>
<li>Place the block cursor between decorators and shadow roots (<a
href="https://redirect.github.com/facebook/lexical/pull/8758">#8758</a>);
clean up the trailing shadow root after select-all delete (<a
href="https://redirect.github.com/facebook/lexical/pull/8751">#8751</a>)</li>
<li><code>deleteCharacter</code> no longer overwrites the X11 PRIMARY
selection via <code>Selection.modify</code> (<a
href="https://redirect.github.com/facebook/lexical/pull/8774">#8774</a>)</li>
<li>Defer <code>onUpdate</code> callbacks during nested commits (<a
href="https://redirect.github.com/facebook/lexical/pull/8672">#8672</a>)</li>
</ul>
<p><strong>Markdown, code &amp; tables</strong></p>
<ul>
<li>Fence-like lines inside a code block stay content (<a
href="https://redirect.github.com/facebook/lexical/pull/8734">#8734</a>);
prevent formatting on <code>TabNode</code> inside code blocks (<a
href="https://redirect.github.com/facebook/lexical/pull/8752">#8752</a>)</li>
<li>Pasted TSV text spreads across table cells (<a
href="https://redirect.github.com/facebook/lexical/pull/8780">#8780</a>)</li>
</ul>
<p><strong>Playground &amp; website</strong></p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/facebook/lexical/blob/main/CHANGELOG.md">lexical's
changelog</a>.</em></p>
<blockquote>
<h2>v0.47.0 (2026-07-10)</h2>
<ul>
<li>lexicallexical-rich-text Bug Fix Fix formatText toggle direction and
add SETTEXTFORMATCOMMAND (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8807">#8807</a>)
mayrang</li>
<li>scripts Bug Fix Let npm prompt for OTP when publishing bootstrap
stubs (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8820">#8820</a>)
Bob Ippolito</li>
<li>lexical-playground Bug Fix Clear inline font-size when converting to
heading (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8800">#8800</a>)
mayrang</li>
<li>lexical-tablelexical-playground Feature setTableRowIsHeader and
setTableColumnIsHeader utilities (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8815">#8815</a>)
mayrang</li>
<li>lexical-website Documentation Update Rewrite testing guide (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8811">#8811</a>)
mayrang</li>
<li>lexical-mdastlexical-rich-text Feature lexicalmdast, a
micromarkmdast-based alternative to lexicalmarkdown (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8794">#8794</a>)
Bob Ippolito</li>
<li>Make dependency-check resilient to transient registry errors (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8818">#8818</a>)
Gerard Rovira</li>
<li>lexical Refactor Move event module globals into per-editor
InputState (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8809">#8809</a>)
mayrang</li>
<li>lexical Bug Fix getDocument() should fall back to the global
document when there is no active editor (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8813">#8813</a>)
Sherry</li>
<li>lexical-playground Bug Fix Keep cell background color modal open on
first click (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8806">#8806</a>)
sahir</li>
<li>lexical-playground Bug Fix Use consistent default maxWidth for
markdown-imported images (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8810">#8810</a>)
mayrang</li>
<li>lexical-devtoolslexical-playground Chore Update flow, hermes, and
babel packages to latest (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8795">#8795</a>)
Bob Ippolito</li>
<li>Add a 7-day pnpm minimumReleaseAge to match the Dependabot cooldown
(<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8808">#8808</a>)
Gerard Rovira</li>
<li>lexical Chore Fix tmp package dependency vulnerability (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8802">#8802</a>)
vijay ojha</li>
<li>lexical Chore Add missing Flow type declarations (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8799">#8799</a>)
mayrang</li>
<li>lexical-markdown Feature Add generateNodesFromMarkdownString (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8789">#8789</a>)
mayrang</li>
<li>lexicallexical-playground Chore Refactor IME composition test
infrastructure and add browser-level coverage (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8793">#8793</a>)
mayrang</li>
<li>lexical-playground Bug Fix Use viewBox dimensions for unsized
Excalidraw output (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8798">#8798</a>)
mayrang</li>
<li>lexical-table Bug Fix Export insertTableRowAtNode and
insertTableColumnAtNode (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8791">#8791</a>)</li>
<li>lexical-playgroundlexical-website Feature Add Vercel Analytics and
Speed Insights (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8796">#8796</a>)
Gerard Rovira</li>
<li>lexicallexical-eslint-plugin Feature Add getDocument() API and
Shadow DOM lint enforcement (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8788">#8788</a>)
mayrang</li>
<li>scripts Bug Fix strip misplaced pure annotations from prod builds
(<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8786">#8786</a>)
Bob Ippolito</li>
<li>lexical Bug Fix deleteCharacter overwrites X11 PRIMARY selection via
Selection.modify (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8774">#8774</a>)
Bob Ippolito</li>
<li>lexical-playground Bug Fix Support Unicode URLs in autolink matcher
(<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8787">#8787</a>)
mayrang</li>
<li>lexical-table Feature Spread pasted TSV text across table cells (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8780">#8780</a>)
mayrang</li>
<li>Breaking Changelexical Bug Fix Preserve DOM element when composing
on segmented TextNode middle (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8784">#8784</a>)
mayrang</li>
<li>Breaking Changelexical-reactlexical-devtools-core Chore Drop React
17 support, baseline is now React 18 (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8782">#8782</a>)
Bob Ippolito</li>
<li>lexical-playgroundlexical Feature Ruby annotation node with floating
editor (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8741">#8741</a>)
mayrang</li>
<li>lexical-playground Feature Find and Replace (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8779">#8779</a>)
mayrang</li>
<li>lexical-playground Bug Fix restore RTL checkbox position in
checklist (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8783">#8783</a>)
Aldo Ryanda</li>
<li>lexical-rich-text Bug Fix Stop ArrowUpDown from skipping block
decorators (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8775">#8775</a>)
mayrang</li>
<li>lexical-playground Bug Fix Convert remaining icon glyphs to
mask-image for forced-colors support (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8781">#8781</a>)
mayrang</li>
<li>fix(lexical) use extends for type parameter bound in
registerEventListeners flow type (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8778">#8778</a>)
Sherry</li>
<li>lexical Bug Fix Keep selection inside single-child inline elements
(<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8772">#8772</a>)
mayrang</li>
<li>lexical Feature registerEventListener registerEventListeners DOM
helpers (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8767">#8767</a>)
Bob Ippolito</li>
<li>lexical-playground Bug Fix Restore floating toolbar comment icon
after mask-image conversion (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8773">#8773</a>)
mayrang</li>
<li>lexical Bug Fix Skip ZWSP insertion for format mismatch on Android
Chrome (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8769">#8769</a>)
mayrang</li>
<li>lexical-a11ylexical-reactlexical-playgroundlexical-website Feature
lexicala11y framework-agnostic accessibility helpers WCAG AA reference
adoption (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8591">#8591</a>)
mayrang</li>
<li>Add missing copyright headers to 4 source files (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8768">#8768</a>)
xiezhenjia-meta</li>
<li>lexical-website Bug Fix Remove horizontal scroll on homepage hero
(<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8760">#8760</a>)
Bakhtiyar</li>
<li>lexical-selection Bug Fix re-resolve detached firstBlock in insert
(<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8764">#8764</a>)
Olivier Chevallier</li>
<li>lexical Modernize InlineFormattableNode Flow stub syntax rejected by
fb-www flow strict (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8763">#8763</a>)
Sherry</li>
<li>lexical-utils Bug Fix positionNodeOnRange leaking orphan rect nodes
when rects shrink (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8762">#8762</a>)
Durvesh Pilankar</li>
<li>docs fix duplicated words in comments and docs (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8761">#8761</a>)
Durvesh Pilankar</li>
<li>lexical-selection Bug Fix Properly handle block end focus in
backward selections during setBlocksType (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8753">#8753</a>)
Olivier Chevallier</li>
<li>lexicallexical-extension Bug Fix Align DecoratorTextNode format with
TextNode in mixed selections (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8737">#8737</a>)
sahir</li>
<li>lexical Bug Fix Clean up trailing shadow root after select-all
delete (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8751">#8751</a>)
mayrang</li>
<li>lexicallexical-rich-text Bug Fix Place block cursor between
decorators and shadow roots (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8758">#8758</a>)
mayrang</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/facebook/lexical/commit/77ccc19b1e65dbd8a7a2e1c6f5628ee84551b0ef"><code>77ccc19</code></a>
v0.47.0</li>
<li><a
href="https://github.com/facebook/lexical/commit/18a0abf202786afc4dc23ef8aa8494f74e359422"><code>18a0abf</code></a>
[lexical][lexical-rich-text][lexical-selection] Bug Fix: Fix navigation
acros...</li>
<li><a
href="https://github.com/facebook/lexical/commit/02d2562c99028cf2c0494c8f1c7301bed0e1c558"><code>02d2562</code></a>
[lexical][lexical-rich-text] Bug Fix: Fix formatText toggle direction
and add...</li>
<li><a
href="https://github.com/facebook/lexical/commit/932aa67ec95dd86384d2e7e5ed80544e06f60e0f"><code>932aa67</code></a>
[lexical] Refactor: Move event module globals into per-editor InputState
(<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8809">#8809</a>)</li>
<li><a
href="https://github.com/facebook/lexical/commit/b00510c74a98fbc46dea13ef42afff2218ad7ea9"><code>b00510c</code></a>
[lexical] Bug Fix: $getDocument() should fall back to the global
document whe...</li>
<li><a
href="https://github.com/facebook/lexical/commit/a7666ab11f5e8c674a3f5ca8a83d2e92f1b171d0"><code>a7666ab</code></a>
[*][lexical-devtools][lexical-playground] Chore: Update flow, hermes,
and bab...</li>
<li><a
href="https://github.com/facebook/lexical/commit/c07e832ab8dfee640e5348335f7210a1edac5917"><code>c07e832</code></a>
[lexical] Chore: Add missing Flow type declarations (<a
href="https://github.com/facebook/lexical/tree/HEAD/packages/lexical/issues/8799">#8799</a>)</li>
<li><a
href="https://github.com/facebook/lexical/commit/38051a7498461da265a9b670ef1f3585319d4543"><code>38051a7</code></a>
[lexical][lexical-playground] Chore: Refactor IME composition test
infrastruc...</li>
<li><a
href="https://github.com/facebook/lexical/commit/e649ab28b7e2dd58c1b4798c446e611f54356518"><code>e649ab2</code></a>
[lexical][lexical-eslint-plugin] Feature: Add $getDocument() API and
Shadow D...</li>
<li><a
href="https://github.com/facebook/lexical/commit/69abb09cec921e73512d17d6a53bb5e2064d7b72"><code>69abb09</code></a>
[lexical] Bug Fix: deleteCharacter overwrites X11 PRIMARY selection via
Selec...</li>
<li>Additional commits viewable in <a
href="https://github.com/facebook/lexical/commits/v0.47.0/packages/lexical">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=lexical&package-manager=npm_and_yarn&previous-version=0.46.0&new-version=0.47.0)](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-14 10:02:57 -07:00
dependabot[bot] 753544d704 build(deps): bump @clack/prompts from 0.10.1 to 0.11.0 (#9485)
Bumps
[@clack/prompts](https://github.com/bombshell-dev/clack/tree/HEAD/packages/prompts)
from 0.10.1 to 0.11.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/bombshell-dev/clack/releases">@​clack/prompts's
releases</a>.</em></p>
<blockquote>
<h2><code>@​clack/prompts</code><a
href="https://github.com/0"><code>@​0</code></a>.11.0</h2>
<h3>Minor Changes</h3>
<ul>
<li>07ca32d: Reverted a change where placeholders were being set as
values on return.</li>
</ul>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies [07ca32d]
<ul>
<li><code>@​clack/core</code><a
href="https://github.com/0"><code>@​0</code></a>.5.0</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/bombshell-dev/clack/blob/@clack/prompts@0.11.0/packages/prompts/CHANGELOG.md">@​clack/prompts's
changelog</a>.</em></p>
<blockquote>
<h2>0.11.0</h2>
<h3>Minor Changes</h3>
<ul>
<li>07ca32d: Reverted a change where placeholders were being set as
values on return.</li>
</ul>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies [07ca32d]
<ul>
<li><code>@​clack/core</code><a
href="https://github.com/0"><code>@​0</code></a>.5.0</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bombshell-dev/clack/commit/737f1725696b595c791e73ca51ee0ac4bf0ee289"><code>737f172</code></a>
[ci] release (<a
href="https://github.com/bombshell-dev/clack/tree/HEAD/packages/prompts/issues/325">#325</a>)</li>
<li><a
href="https://github.com/bombshell-dev/clack/commit/07ca32dcfca0ab8dc8c42c25117b4109f381621f"><code>07ca32d</code></a>
fix: revert placeholder-on-return change (<a
href="https://github.com/bombshell-dev/clack/tree/HEAD/packages/prompts/issues/324">#324</a>)</li>
<li>See full diff in <a
href="https://github.com/bombshell-dev/clack/commits/@clack/prompts@0.11.0/packages/prompts">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@clack/prompts&package-manager=npm_and_yarn&previous-version=0.10.1&new-version=0.11.0)](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-14 10:02:53 -07:00
dependabot[bot] f92a6648d5 build(deps): bump better-auth from 1.6.20 to 1.6.23 (#9479)
Bumps
[better-auth](https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth)
from 1.6.20 to 1.6.23.
<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.23</h2>
<h2><code>better-auth</code></h2>
<h3>Features</h3>
<ul>
<li>Added Yandex as a social OAuth provider (<a
href="https://redirect.github.com/better-auth/better-auth/pull/9138">#9138</a>)</li>
</ul>
<p>For detailed changes, see <a
href="https://github.com/better-auth/better-auth/blob/9dfceee14021fc15a2fb93023f39635f25b0b5ba/packages/better-auth/CHANGELOG.md"><code>CHANGELOG</code></a></p>
<h2><code>@better-auth/drizzle-adapter</code></h2>
<h3>Bug Fixes</h3>
<ul>
<li>Fixed affected row counting for D1 and postgres-js adapters (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10257">#10257</a>)</li>
</ul>
<p>For detailed changes, see <a
href="https://github.com/better-auth/better-auth/blob/9dfceee14021fc15a2fb93023f39635f25b0b5ba/packages/drizzle-adapter/CHANGELOG.md"><code>CHANGELOG</code></a></p>
<h2><code>@better-auth/stripe</code></h2>
<h3>Bug Fixes</h3>
<ul>
<li>Fixed organization subscription actions (cancel, upgrade, restore,
and the billing portal) that could act on the wrong organization.</li>
</ul>
<p>For detailed changes, see <a
href="https://github.com/better-auth/better-auth/blob/9dfceee14021fc15a2fb93023f39635f25b0b5ba/packages/stripe/CHANGELOG.md"><code>CHANGELOG</code></a></p>
<h2><code>auth</code></h2>
<h3>Bug Fixes</h3>
<ul>
<li>Fixed string default values not being properly escaped in the
generated Drizzle schema (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10259">#10259</a>)</li>
</ul>
<p>For detailed changes, see <a
href="https://github.com/better-auth/better-auth/blob/9dfceee14021fc15a2fb93023f39635f25b0b5ba/packages/cli/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/bytaesu"><code>@​bytaesu</code></a>, <a
href="https://github.com/vladflotsky"><code>@​vladflotsky</code></a></p>
<p><strong>Full changelog:</strong> <a
href="https://github.com/better-auth/better-auth/compare/v1.6.22...v1.6.23"><code>v1.6.22...v1.6.23</code></a></p>
<h2>v1.6.22</h2>
<h2><code>better-auth</code></h2>
<h3>Bug Fixes</h3>
<ul>
<li>Fixed unproven credentials not being revoked during magic link and
email OTP sign-in (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10239">#10239</a>)</li>
<li>Fixed server-side OAuth requests to refuse redirect responses
instead of following them (<a
href="https://redirect.github.com/better-auth/better-auth/pull/10241">#10241</a>)</li>
</ul>
<p>For detailed changes, see <a
href="https://github.com/better-auth/better-auth/blob/a90d061de7cdbd60e796230aadf5d1082add1fe2/packages/better-auth/CHANGELOG.md"><code>CHANGELOG</code></a></p>
<!-- 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.23</h2>
<h3>Patch Changes</h3>
<ul>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/9138">#9138</a>
<a
href="https://github.com/better-auth/better-auth/commit/8581f97ea0000e03edd6aa7911efabf694a9ff95"><code>8581f97</code></a>
Thanks <a
href="https://github.com/vladflotsky"><code>@​vladflotsky</code></a>! -
Add a pre-configured Yandex provider helper for the generic OAuth
plugin.</p>
</li>
<li>
<p>Updated dependencies [<a
href="https://github.com/better-auth/better-auth/commit/930b260cfd402e9f8886719a3ced503b9ceff7f6"><code>930b260</code></a>]:</p>
<ul>
<li><code>@​better-auth/drizzle-adapter</code><a
href="https://github.com/1"><code>@​1</code></a>.6.23</li>
<li><code>@​better-auth/core</code><a
href="https://github.com/1"><code>@​1</code></a>.6.23</li>
<li><code>@​better-auth/kysely-adapter</code><a
href="https://github.com/1"><code>@​1</code></a>.6.23</li>
<li><code>@​better-auth/memory-adapter</code><a
href="https://github.com/1"><code>@​1</code></a>.6.23</li>
<li><code>@​better-auth/mongo-adapter</code><a
href="https://github.com/1"><code>@​1</code></a>.6.23</li>
<li><code>@​better-auth/prisma-adapter</code><a
href="https://github.com/1"><code>@​1</code></a>.6.23</li>
<li><code>@​better-auth/telemetry</code><a
href="https://github.com/1"><code>@​1</code></a>.6.23</li>
</ul>
</li>
</ul>
<h2>1.6.22</h2>
<h3>Patch Changes</h3>
<ul>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10239">#10239</a>
<a
href="https://github.com/better-auth/better-auth/commit/c06a56d83a40bbaeac12d3a8b8b67e59f92a9110"><code>c06a56d</code></a>
Thanks <a
href="https://github.com/gustavovalverde"><code>@​gustavovalverde</code></a>!
- Magic-link and email-OTP sign-in now reset the credentials on an
account whose email had never been confirmed. When verification resolves
to such an account, any existing password on it is removed and its
sessions are revoked before the user is signed in, so proven control of
the mailbox is the source of truth for the account.</p>
<p>If you signed up with email and password but first signed in through
a magic link or email OTP rather than confirming the verification email,
your password is cleared and you will need to set a new one through
password reset.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10240">#10240</a>
<a
href="https://github.com/better-auth/better-auth/commit/3a035e968e27bfdee1e53ad857e5569090d9f2d1"><code>3a035e9</code></a>
Thanks <a
href="https://github.com/gustavovalverde"><code>@​gustavovalverde</code></a>!
- Add account-level lockout for two-factor verification. The attempt
limit applies per account across sign-in challenges and across factors:
TOTP, email-OTP, and backup codes share one counter, and a successful
verification resets it.</p>
<p>Enabled by default: an account locks for 15 minutes after 10
consecutive failed verifications, and locked attempts return
<code>429</code> with the <code>ACCOUNT_TEMPORARILY_LOCKED</code> error
code. Configure it with <code>twoFactor({ accountLockout: { enabled,
maxFailedAttempts, durationSeconds } })</code>.</p>
<p>Run a database migration after upgrading: this adds
<code>failedVerificationCount</code> and <code>lockedUntil</code>
columns to the <code>twoFactor</code> table.</p>
</li>
<li>
<p>Updated dependencies [<a
href="https://github.com/better-auth/better-auth/commit/8bd43d9d8312fd9ddbfb8fb5c827cf0a0e55132d"><code>8bd43d9</code></a>]:</p>
<ul>
<li><code>@​better-auth/core</code><a
href="https://github.com/1"><code>@​1</code></a>.6.22</li>
<li><code>@​better-auth/drizzle-adapter</code><a
href="https://github.com/1"><code>@​1</code></a>.6.22</li>
<li><code>@​better-auth/kysely-adapter</code><a
href="https://github.com/1"><code>@​1</code></a>.6.22</li>
<li><code>@​better-auth/memory-adapter</code><a
href="https://github.com/1"><code>@​1</code></a>.6.22</li>
<li><code>@​better-auth/mongo-adapter</code><a
href="https://github.com/1"><code>@​1</code></a>.6.22</li>
<li><code>@​better-auth/prisma-adapter</code><a
href="https://github.com/1"><code>@​1</code></a>.6.22</li>
<li><code>@​better-auth/telemetry</code><a
href="https://github.com/1"><code>@​1</code></a>.6.22</li>
</ul>
</li>
</ul>
<h2>1.6.21</h2>
<h3>Patch Changes</h3>
<ul>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10212">#10212</a>
<a
href="https://github.com/better-auth/better-auth/commit/e0762a127ce351a96614e60866b3455e6eddffa1"><code>e0762a1</code></a>
Thanks <a href="https://github.com/bytaesu"><code>@​bytaesu</code></a>!
- In root-mounted deployments, requests whose path does not start with
the configured <code>basePath</code> now return 404 instead of resolving
to an endpoint.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10187">#10187</a>
<a
href="https://github.com/better-auth/better-auth/commit/882cf9e592d1d305b5b78cadbb10aaeee7acd6dc"><code>882cf9e</code></a>
Thanks <a
href="https://github.com/ping-maxwell"><code>@​ping-maxwell</code></a>!
- Admin permission changes and bans now take effect immediately for
admin APIs, even when session cookie cache is enabled. Sensitive session
checks also continue to work in stateless apps where signed cookies are
the session record.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/9939">#9939</a>
<a
href="https://github.com/better-auth/better-auth/commit/f52e1ab50b60d289b64d6b06f1bff5a4358cdfd0"><code>f52e1ab</code></a>
Thanks <a
href="https://github.com/benpsnyder"><code>@​benpsnyder</code></a>! -
fixes a bug causing deviceAuthorization() throwing a ZodError at
construction when called without a schema option</p>
</li>
<li>
<p><a
href="https://redirect.github.com/better-auth/better-auth/pull/10196">#10196</a>
<a
href="https://github.com/better-auth/better-auth/commit/b5bec193a56cec2f7b71c84d71dacb632f0b96a0"><code>b5bec19</code></a>
Thanks <a
href="https://github.com/Paola3stefania"><code>@​Paola3stefania</code></a>!
- OAuth sign-up and account-link profile sync now ignore provider
profile values for user fields marked <code>input: false</code>.
Input-allowed additional fields still persist from
<code>mapProfileToUser</code>, and schema defaults still apply when
OAuth creates a user. Apps that used <code>mapProfileToUser</code> to
fill <code>input: false</code> fields should set those fields in
server-side provisioning code instead.</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/better-auth/better-auth/commit/9dfceee14021fc15a2fb93023f39635f25b0b5ba"><code>9dfceee</code></a>
chore: release v1.6.23 (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/10260">#10260</a>)</li>
<li><a
href="https://github.com/better-auth/better-auth/commit/8581f97ea0000e03edd6aa7911efabf694a9ff95"><code>8581f97</code></a>
feat(oauth): add Yandex social provider (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/9138">#9138</a>)</li>
<li><a
href="https://github.com/better-auth/better-auth/commit/a90d061de7cdbd60e796230aadf5d1082add1fe2"><code>a90d061</code></a>
chore: release v1.6.22 (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/10245">#10245</a>)</li>
<li><a
href="https://github.com/better-auth/better-auth/commit/3a035e968e27bfdee1e53ad857e5569090d9f2d1"><code>3a035e9</code></a>
fix(two-factor): add account-level verification lockout (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/10240">#10240</a>)</li>
<li><a
href="https://github.com/better-auth/better-auth/commit/c06a56d83a40bbaeac12d3a8b8b67e59f92a9110"><code>c06a56d</code></a>
fix: revoke unproven credentials on magic-link/email-OTP sign-in (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/10239">#10239</a>)</li>
<li><a
href="https://github.com/better-auth/better-auth/commit/414169d95a88a6e1fac41688bc7011e96feb0d2a"><code>414169d</code></a>
chore: release v1.6.21 (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/10184">#10184</a>)</li>
<li><a
href="https://github.com/better-auth/better-auth/commit/f52e1ab50b60d289b64d6b06f1bff5a4358cdfd0"><code>f52e1ab</code></a>
fix(device-authorization): make <code>schema</code> option optional
under Zod v4 (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/9939">#9939</a>)</li>
<li><a
href="https://github.com/better-auth/better-auth/commit/882cf9e592d1d305b5b78cadbb10aaeee7acd6dc"><code>882cf9e</code></a>
fix(admin): use authoritative session reads for authorization (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/10187">#10187</a>)</li>
<li><a
href="https://github.com/better-auth/better-auth/commit/b5bec193a56cec2f7b71c84d71dacb632f0b96a0"><code>b5bec19</code></a>
fix(oauth): apply user input rules to provider profiles (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/10196">#10196</a>)</li>
<li><a
href="https://github.com/better-auth/better-auth/commit/471f81c1ab088368de07383491535c1288fa6543"><code>471f81c</code></a>
refactor: centralize request IP resolver in core (<a
href="https://github.com/better-auth/better-auth/tree/HEAD/packages/better-auth/issues/10216">#10216</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/better-auth/better-auth/commits/v1.6.23/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.20&new-version=1.6.23)](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-14 10:02:48 -07:00
dependabot[bot] b41e992a12 build(deps): bump actions/cache from 5 to 6 (#9476)
Bumps [actions/cache](https://github.com/actions/cache) from 5 to 6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/cache/releases">actions/cache's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update packages, migrate to ESM by <a
href="https://github.com/Samirat"><code>@​Samirat</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1760">actions/cache#1760</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v6.0.0">https://github.com/actions/cache/compare/v5...v6.0.0</a></p>
<h2>v5.1.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Bump <code>@​actions/cache</code> to v5.1.0 - handle read-only cache
access by <a
href="https://github.com/jasongin"><code>@​jasongin</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1775">actions/cache#1775</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v5.1.0">https://github.com/actions/cache/compare/v5...v5.1.0</a></p>
<h2>v5.0.5</h2>
<h2>What's Changed</h2>
<ul>
<li>Update ts-http-runtime dependency by <a
href="https://github.com/yacaovsnc"><code>@​yacaovsnc</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1747">actions/cache#1747</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v5.0.5">https://github.com/actions/cache/compare/v5...v5.0.5</a></p>
<h2>v5.0.4</h2>
<h2>What's Changed</h2>
<ul>
<li>Add release instructions and update maintainer docs by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1696">actions/cache#1696</a></li>
<li>Potential fix for code scanning alert no. 52: Workflow does not
contain permissions by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1697">actions/cache#1697</a></li>
<li>Fix workflow permissions and cleanup workflow names / formatting by
<a href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1699">actions/cache#1699</a></li>
<li>docs: Update examples to use the latest version by <a
href="https://github.com/XZTDean"><code>@​XZTDean</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1690">actions/cache#1690</a></li>
<li>Fix proxy integration tests by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1701">actions/cache#1701</a></li>
<li>Fix cache key in examples.md for bun.lock by <a
href="https://github.com/RyPeck"><code>@​RyPeck</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1722">actions/cache#1722</a></li>
<li>Update dependencies &amp; patch security vulnerabilities by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1738">actions/cache#1738</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/XZTDean"><code>@​XZTDean</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/cache/pull/1690">actions/cache#1690</a></li>
<li><a href="https://github.com/RyPeck"><code>@​RyPeck</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/cache/pull/1722">actions/cache#1722</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v5.0.4">https://github.com/actions/cache/compare/v5...v5.0.4</a></p>
<h2>v5.0.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Bump <code>@actions/cache</code> to v5.0.5 (Resolves: <a
href="https://github.com/actions/cache/security/dependabot/33">https://github.com/actions/cache/security/dependabot/33</a>)</li>
<li>Bump <code>@actions/core</code> to v2.0.3</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v5.0.3">https://github.com/actions/cache/compare/v5...v5.0.3</a></p>
<h2>v.5.0.2</h2>
<h1>v5.0.2</h1>
<h2>What's Changed</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/cache/blob/main/RELEASES.md">actions/cache's
changelog</a>.</em></p>
<blockquote>
<h1>Releases</h1>
<h2>How to prepare a release</h2>
<blockquote>
<p>[!NOTE]
Relevant for maintainers with write access only.</p>
</blockquote>
<ol>
<li>Switch to a new branch from <code>main</code>.</li>
<li>Run <code>npm test</code> to ensure all tests are passing.</li>
<li>Update the version in <a
href="https://github.com/actions/cache/blob/main/package.json"><code>https://github.com/actions/cache/blob/main/package.json</code></a>.</li>
<li>Run <code>npm run build</code> to update the compiled files.</li>
<li>Update this <a
href="https://github.com/actions/cache/blob/main/RELEASES.md"><code>https://github.com/actions/cache/blob/main/RELEASES.md</code></a>
with the new version and changes in the <code>## Changelog</code>
section.</li>
<li>Run <code>licensed cache</code> to update the license report.</li>
<li>Run <code>licensed status</code> and resolve any warnings by
updating the <a
href="https://github.com/actions/cache/blob/main/.licensed.yml"><code>https://github.com/actions/cache/blob/main/.licensed.yml</code></a>
file with the exceptions.</li>
<li>Commit your changes and push your branch upstream.</li>
<li>Open a pull request against <code>main</code> and get it reviewed
and merged.</li>
<li>Draft a new release <a
href="https://github.com/actions/cache/releases">https://github.com/actions/cache/releases</a>
use the same version number used in <code>package.json</code>
<ol>
<li>Create a new tag with the version number.</li>
<li>Auto generate release notes and update them to match the changes you
made in <code>RELEASES.md</code>.</li>
<li>Toggle the set as the latest release option.</li>
<li>Publish the release.</li>
</ol>
</li>
<li>Navigate to <a
href="https://github.com/actions/cache/actions/workflows/release-new-action-version.yml">https://github.com/actions/cache/actions/workflows/release-new-action-version.yml</a>
<ol>
<li>There should be a workflow run queued with the same version
number.</li>
<li>Approve the run to publish the new version and update the major tags
for this action.</li>
</ol>
</li>
</ol>
<h2>Changelog</h2>
<h3>6.1.0</h3>
<ul>
<li>Bump <code>@actions/cache</code> to v6.1.0 to pick up <a
href="https://redirect.github.com/actions/toolkit/pull/2435">actions/toolkit#2435
Handle cache write error due to read-only token</a></li>
<li>Switch redundant &quot;Cache save failed&quot; warning to debug log
in save-only</li>
</ul>
<h3>6.0.0</h3>
<ul>
<li>Updated <code>@actions/cache</code> to ^6.0.1,
<code>@actions/core</code> to ^3.0.1, <code>@actions/exec</code> to
^3.0.0, <code>@actions/io</code> to ^3.0.2</li>
<li>Migrated to ESM module system</li>
<li>Upgraded Jest to v30 and test infrastructure to be ESM
compatible</li>
</ul>
<h3>5.0.4</h3>
<ul>
<li>Bump <code>minimatch</code> to v3.1.5 (fixes ReDoS via globstar
patterns)</li>
<li>Bump <code>undici</code> to v6.24.1 (WebSocket decompression bomb
protection, header validation fixes)</li>
<li>Bump <code>fast-xml-parser</code> to v5.5.6</li>
</ul>
<h3>5.0.3</h3>
<ul>
<li>Bump <code>@actions/cache</code> to v5.0.5 (Resolves: <a
href="https://github.com/actions/cache/security/dependabot/33">https://github.com/actions/cache/security/dependabot/33</a>)</li>
<li>Bump <code>@actions/core</code> to v2.0.3</li>
</ul>
<h3>5.0.2</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/cache/commit/55cc8345863c7cc4c66a329aec7e433d2d1c52a9"><code>55cc834</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/cache/issues/1768">#1768</a>
from jasongin/readonly-cache</li>
<li><a
href="https://github.com/actions/cache/commit/d8cd72f230726cdf4457ebb61ec1b593a8d12337"><code>d8cd72f</code></a>
Bump <code>@​actions/cache</code> to v6.1.0 - handle cache write error
due to RO token</li>
<li><a
href="https://github.com/actions/cache/commit/2c8a9bd7457de244a408f35966fab2fb45fda9c8"><code>2c8a9bd</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/cache/issues/1760">#1760</a>
from actions/samirat/esm_migration_and_package_update</li>
<li><a
href="https://github.com/actions/cache/commit/e9b91fdc3fea7d79165fceb79042ef45c2d51023"><code>e9b91fd</code></a>
Prettier fixes</li>
<li><a
href="https://github.com/actions/cache/commit/e4884b8ff7f92ef6b52c79eda480bbc86e685adb"><code>e4884b8</code></a>
Rebuild dist</li>
<li><a
href="https://github.com/actions/cache/commit/10baf0191a3c426ea0fa4a3253a5c04233b6e18f"><code>10baf01</code></a>
Fixed licenses</li>
<li><a
href="https://github.com/actions/cache/commit/e39b386c9004d72a15d864ade8c0b3a702d47a37"><code>e39b386</code></a>
Fix test mock return order</li>
<li><a
href="https://github.com/actions/cache/commit/b6928203372a8571ff984c0c883ef3a1adfb0c06"><code>b692820</code></a>
PR feedback</li>
<li><a
href="https://github.com/actions/cache/commit/60749128a44d25d3c520a489e576380cf00ff3f1"><code>6074912</code></a>
Rebuild dist bundles as ESM to match type:module</li>
<li><a
href="https://github.com/actions/cache/commit/5a912e8b4af820fa082a0e75cfd2c782f8fbfe0e"><code>5a912e8</code></a>
Fix lint and jest issues</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/cache/compare/v5...v6">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/cache&package-manager=github_actions&previous-version=5&new-version=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-14 10:02:46 -07:00
dependabot[bot] dcb7c323ed build(deps-dev): bump @storybook/react-vite from 10.4.6 to 10.5.0 (#9482)
Bumps
[@storybook/react-vite](https://github.com/storybookjs/storybook/tree/HEAD/code/frameworks/react-vite)
from 10.4.6 to 10.5.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/storybookjs/storybook/releases">@​storybook/react-vite's
releases</a>.</em></p>
<blockquote>
<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 -->
</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/react-vite's
changelog</a>.</em></p>
<blockquote>
<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 -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/storybookjs/storybook/commit/9dafcd22ed55947bc4c2fa1d5066b552baa0ebf4"><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="https://github.com/storybookjs/storybook/commit/448db85e651a09ca55f978356c4f1593f261f82a"><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="https://github.com/storybookjs/storybook/commit/a4ce9790a783d8e7720e9de980a08576de9555db"><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><a
href="https://github.com/storybookjs/storybook/commit/f0bf138a0a83443c177f4b6882d74440829de42e"><code>f0bf138</code></a>
Bump version from &quot;10.5.0-alpha.11&quot; to
&quot;10.5.0-beta.0&quot; [skip ci]</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/fac05a57415eec36b0a72b383befd7ef5071572c"><code>fac05a5</code></a>
Bump version from &quot;10.5.0-alpha.10&quot; to
&quot;10.5.0-alpha.11&quot; [skip ci]</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/4057c4169f1e63d746d86349fcf4463e321b546e"><code>4057c41</code></a>
Bump version from &quot;10.5.0-alpha.9&quot; to
&quot;10.5.0-alpha.10&quot; [skip ci]</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/da84210b49cdbb1de724c6c5d590ae3d6945887f"><code>da84210</code></a>
Bump version from &quot;10.5.0-alpha.8&quot; to
&quot;10.5.0-alpha.9&quot; [skip ci]</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/c347410b9f96f3526cf72d20a7f3762153039694"><code>c347410</code></a>
Bump version from &quot;10.5.0-alpha.7&quot; to
&quot;10.5.0-alpha.8&quot; [skip ci]</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/d16ab3008ac721c8311f940183687cc86643a053"><code>d16ab30</code></a>
React: Align react-docgen versions</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/c9a1ac9f72fc5c03b70180a247d42691b26c6904"><code>c9a1ac9</code></a>
Bump version from &quot;10.5.0-alpha.6&quot; to
&quot;10.5.0-alpha.7&quot; [skip ci]</li>
<li>Additional commits viewable in <a
href="https://github.com/storybookjs/storybook/commits/v10.5.0/code/frameworks/react-vite">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@storybook/react-vite&package-manager=npm_and_yarn&previous-version=10.4.6&new-version=10.5.0)](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-14 10:02:39 -07:00
dependabot[bot] 26bd07400b build(deps-dev): bump tailwindcss from 4.3.0 to 4.3.2 (#9477)
Bumps
[tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss)
from 4.3.0 to 4.3.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/releases">tailwindcss's
releases</a>.</em></p>
<blockquote>
<h2>v4.3.2</h2>
<h3>Fixed</h3>
<ul>
<li>Support bare spacing values for <code>auto-rows-*</code> and
<code>auto-cols-*</code> utilities (e.g. <code>auto-rows-12</code> and
<code>auto-cols-16</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20229">#20229</a>)</li>
<li>Prevent <code>@tailwindcss/cli</code> in <code>--watch</code> mode
from crashing on Windows when <code>@source</code> points to a directory
that doesn't exist (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20242">#20242</a>)</li>
<li>Prevent <code>@tailwindcss/vite</code> from crashing in Deno v2.8.x
when <code>context.parentURL</code> is not a valid URL (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20245">#20245</a>)</li>
<li>Ensure <code>@tailwindcss/cli</code> in <code>--watch</code> mode
rebuilds when the input CSS file changes in an ignored directory (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20246">#20246</a>)</li>
<li>Allow <code>@variant</code> rules used in <code>addBase(…)</code> to
use custom variants defined later (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20247">#20247</a>)</li>
<li>Prevent <code>@tailwindcss/vite</code> from crashing during HMR when
scanned files or directories are deleted (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20259">#20259</a>)</li>
<li>Generate <code>font-size</code> instead of <code>color</code>
declarations for <code>text-[--spacing(…)]</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20260">#20260</a>)</li>
<li>Prevent <code>@source</code> patterns from scanning unrelated
sibling files and folders (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20263">#20263</a>)</li>
<li>Extract class candidates adjacent to Template Toolkit delimiters
like <code>%]…[%</code> in <code>.tt</code>, <code>.tt2</code>, and
<code>.tx</code> files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20269">#20269</a>)</li>
<li>Extract class candidates from conditional Maud syntax like
<code>p.text-black[condition]</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20269">#20269</a>)</li>
<li>Prevent <code>@position-try</code> rules from triggering unknown
at-rule warnings when optimizing CSS (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20277">#20277</a>)</li>
<li>Support class suggestions for named opacity modifiers from
<code>--opacity</code> theme values (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20287">#20287</a>)</li>
<li>Prevent type errors in <code>@tailwindcss/postcss</code> when used
with newer PostCSS patch releases (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20289">#20289</a>)</li>
</ul>
<h2>v4.3.1</h2>
<h3>Added</h3>
<ul>
<li>Add <code>--silent</code> option to suppress output in
<code>@tailwindcss/cli</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20100">#20100</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Remove deprecation warnings by using
<code>Module#registerHooks</code> instead of
<code>Module#register</code> on Node 26+ (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20028">#20028</a>)</li>
<li>Canonicalization: don't crash when plugin utilities throw for
unsupported values (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20052">#20052</a>)</li>
<li>Allow <code>@apply</code> to be used with CSS mixins (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19427">#19427</a>)</li>
<li>Ensure <code>not-*</code> correctly negates <code>@container</code>
queries, including <code>style(…)</code> queries (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20059">#20059</a>)</li>
<li>Ensure <code>drop-shadow-*</code> color utilities work with custom
shadow values containing <code>calc(…)</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20080">#20080</a>)</li>
<li>Fix 'Sourcemap is likely to be incorrect' warnings when using
<code>@tailwindcss/vite</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20103">#20103</a>)</li>
<li>Ensure <code>@tailwindcss/webpack</code> can be installed in Rspack
projects without requiring <code>webpack</code> as a peer dependency (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20027">#20027</a>)</li>
<li>Canonicalization: don't suggest invalid <code>calc(…)</code>
expressions (e.g. <code>px-[calc(1rem+0px)]</code> →
<code>px-[calc(1rem+0)]</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20127">#20127</a>)</li>
<li>Canonicalization: avoid suggesting large spacing-scale values for
arbitrary lengths (e.g. <code>left-[99999px]</code> →
<code>left-[99999px]</code>, not <code>left-24999.75</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20130">#20130</a>)</li>
<li>Ensure <code>@tailwindcss/cli</code> in <code>--watch</code> mode
recovers when a tracked dependency is deleted and restored (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20137">#20137</a>)</li>
<li>Ensure standalone <code>@tailwindcss/cli</code> binaries are ignored
when scanning for class candidates (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20139">#20139</a>)</li>
<li>Ensure class candidates are extracted from Twig
<code>addClass(…)</code> and <code>removeClass(…)</code> calls (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20198">#20198</a>)</li>
<li>Don't crash in the Ruby or Vue preprocessors when scanning files
containing invalid UTF-8 bytes (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19588">#19588</a>)</li>
<li>Allow <code>@variant</code> to be used inside <code>addBase</code>
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19480">#19480</a>)</li>
<li>Ensure <code>@source</code> globs with symlinks are preserved (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20203">#20203</a>)</li>
<li>Ensure later <code>@source</code> rules can re-include files
excluded by earlier <code>@source not</code> rules (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20203">#20203</a>)</li>
<li>Upgrade: don't migrate empty class rules to invalid
<code>@utility</code> rules (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20205">#20205</a>)</li>
<li>Ensure transitions between <code>inset-shadow-none</code> and other
inset shadows work correctly (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20208">#20208</a>)</li>
<li>Ensure explicitly referenced <code>@source</code> directories are
scanned even when ignored by git (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20214">#20214</a>)</li>
<li>Ensure <code>@source</code> globs ending in <code>**/*</code>
preserve dynamic path segments to avoid scanning too many files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20217">#20217</a>)</li>
<li>Canonicalization: don't fold <code>calc(…)</code> divisions when the
result would require high precision (e.g.
<code>w-[calc(100%/3.5)]</code> → <code>w-[calc(100%/3.5)]</code>, not
<code>w-[28.571428571428573%]</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20221">#20221</a>)</li>
<li>Serve ESM type declarations to ESM importers of
<code>@tailwindcss/postcss</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20228">#20228</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Generate <code>0</code> instead of <code>calc(var(--spacing) *
0)</code> for spacing utilities like <code>m-0</code> and
<code>left-0</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20196">#20196</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md">tailwindcss's
changelog</a>.</em></p>
<blockquote>
<h2>[4.3.2] - 2026-06-26</h2>
<h3>Fixed</h3>
<ul>
<li>Support bare spacing values for <code>auto-rows-*</code> and
<code>auto-cols-*</code> utilities (e.g. <code>auto-rows-12</code> and
<code>auto-cols-16</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20229">#20229</a>)</li>
<li>Prevent <code>@tailwindcss/cli</code> in <code>--watch</code> mode
from crashing on Windows when <code>@source</code> points to a directory
that doesn't exist (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20242">#20242</a>)</li>
<li>Prevent <code>@tailwindcss/vite</code> from crashing in Deno v2.8.x
when <code>context.parentURL</code> is not a valid URL (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20245">#20245</a>)</li>
<li>Ensure <code>@tailwindcss/cli</code> in <code>--watch</code> mode
rebuilds when the input CSS file changes in an ignored directory (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20246">#20246</a>)</li>
<li>Allow <code>@variant</code> rules used in <code>addBase(…)</code> to
use custom variants defined later (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20247">#20247</a>)</li>
<li>Prevent <code>@tailwindcss/vite</code> from crashing during HMR when
scanned files or directories are deleted (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20259">#20259</a>)</li>
<li>Generate <code>font-size</code> instead of <code>color</code>
declarations for <code>text-[--spacing(…)]</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20260">#20260</a>)</li>
<li>Prevent <code>@source</code> patterns from scanning unrelated
sibling files and folders (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20263">#20263</a>)</li>
<li>Extract class candidates adjacent to Template Toolkit delimiters
like <code>%]…[%</code> in <code>.tt</code>, <code>.tt2</code>, and
<code>.tx</code> files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20269">#20269</a>)</li>
<li>Extract class candidates from conditional Maud syntax like
<code>p.text-black[condition]</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20269">#20269</a>)</li>
<li>Prevent <code>@position-try</code> rules from triggering unknown
at-rule warnings when optimizing CSS (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20277">#20277</a>)</li>
<li>Support class suggestions for named opacity modifiers from
<code>--opacity</code> theme values (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20287">#20287</a>)</li>
<li>Prevent type errors in <code>@tailwindcss/postcss</code> when used
with newer PostCSS patch releases (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20289">#20289</a>)</li>
</ul>
<h2>[4.3.1] - 2026-06-12</h2>
<h3>Added</h3>
<ul>
<li>Add <code>--silent</code> option to suppress output in
<code>@tailwindcss/cli</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20100">#20100</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Remove deprecation warnings by using
<code>Module#registerHooks</code> instead of
<code>Module#register</code> on Node 26+ (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20028">#20028</a>)</li>
<li>Canonicalization: don't crash when plugin utilities throw for
unsupported values (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20052">#20052</a>)</li>
<li>Allow <code>@apply</code> to be used with CSS mixins (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19427">#19427</a>)</li>
<li>Ensure <code>not-*</code> correctly negates <code>@container</code>
queries, including <code>style(…)</code> queries (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20059">#20059</a>)</li>
<li>Ensure <code>drop-shadow-*</code> color utilities work with custom
shadow values containing <code>calc(…)</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20080">#20080</a>)</li>
<li>Fix 'Sourcemap is likely to be incorrect' warnings when using
<code>@tailwindcss/vite</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20103">#20103</a>)</li>
<li>Ensure <code>@tailwindcss/webpack</code> can be installed in Rspack
projects without requiring <code>webpack</code> as a peer dependency (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20027">#20027</a>)</li>
<li>Canonicalization: don't suggest invalid <code>calc(…)</code>
expressions (e.g. <code>px-[calc(1rem+0px)]</code> →
<code>px-[calc(1rem+0)]</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20127">#20127</a>)</li>
<li>Canonicalization: avoid suggesting large spacing-scale values for
arbitrary lengths (e.g. <code>left-[99999px]</code> →
<code>left-[99999px]</code>, not <code>left-24999.75</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20130">#20130</a>)</li>
<li>Ensure <code>@tailwindcss/cli</code> in <code>--watch</code> mode
recovers when a tracked dependency is deleted and restored (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20137">#20137</a>)</li>
<li>Ensure standalone <code>@tailwindcss/cli</code> binaries are ignored
when scanning for class candidates (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20139">#20139</a>)</li>
<li>Ensure class candidates are extracted from Twig
<code>addClass(…)</code> and <code>removeClass(…)</code> calls (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20198">#20198</a>)</li>
<li>Don't crash in the Ruby or Vue preprocessors when scanning files
containing invalid UTF-8 bytes (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19588">#19588</a>)</li>
<li>Allow <code>@variant</code> to be used inside <code>addBase</code>
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19480">#19480</a>)</li>
<li>Ensure <code>@source</code> globs with symlinks are preserved (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20203">#20203</a>)</li>
<li>Ensure later <code>@source</code> rules can re-include files
excluded by earlier <code>@source not</code> rules (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20203">#20203</a>)</li>
<li>Upgrade: don't migrate empty class rules to invalid
<code>@utility</code> rules (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20205">#20205</a>)</li>
<li>Ensure transitions between <code>inset-shadow-none</code> and other
inset shadows work correctly (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20208">#20208</a>)</li>
<li>Ensure explicitly referenced <code>@source</code> directories are
scanned even when ignored by git (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20214">#20214</a>)</li>
<li>Ensure <code>@source</code> globs ending in <code>**/*</code>
preserve dynamic path segments to avoid scanning too many files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20217">#20217</a>)</li>
<li>Canonicalization: don't fold <code>calc(…)</code> divisions when the
result would require high precision (e.g.
<code>w-[calc(100%/3.5)]</code> → <code>w-[calc(100%/3.5)]</code>, not
<code>w-[28.571428571428573%]</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20221">#20221</a>)</li>
<li>Serve ESM type declarations to ESM importers of
<code>@tailwindcss/postcss</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20228">#20228</a>)</li>
</ul>
<h3>Changed</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/056a1550721d4bf79ff732d5ab9414fa83f7064f"><code>056a155</code></a>
4.3.2 (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20281">#20281</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/c8b081d96376871acb0157923e894b7a929cad5b"><code>c8b081d</code></a>
Add suggestions for named opacity modifiers (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20287">#20287</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/c46f654fa0039ad4741c6ecefbe4e2a208a665c3"><code>c46f654</code></a>
Ensure <code>--alpha(…)</code> is seen as a <code>color</code>, and
<code>--spacing(…)</code> is seen as a `le...</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/5e9f66e4284164c62e80d74e69e0cbd8d9c645cc"><code>5e9f66e</code></a>
Ensure <code>@variant</code> can be used in JS based APIs (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20252">#20252</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/707c23b955bdfa7854a03195e503b95dd730b3d2"><code>707c23b</code></a>
Ensure custom variants can be used via <code>@variant</code> in
<code>addBase</code> (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20247">#20247</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/127d17033a0518701dac8332667b12e0980870ec"><code>127d170</code></a>
Add bare value support for <code>auto-rows-*</code> and
<code>auto-cols-*</code> (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20229">#20229</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/8a14a710102cae195f6811e8578bef9477bc6be9"><code>8a14a71</code></a>
4.3.1 (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20226">#20226</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/12833aa4b3a8813fd32da74be7a2fd75aa706ab7"><code>12833aa</code></a>
Fix canonicalization bug where we end up with a high precision number
(<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20221">#20221</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/97a5b3abfb75ce9722266cd323a24eee057634fc"><code>97a5b3a</code></a>
docs: fix double word 'to to' in test comment (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20216">#20216</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/d01e103cc4741c29764afaa287d2fb21356f7eea"><code>d01e103</code></a>
Add missing <code>inset</code> keyword for
<code>inset-shadow-none</code> (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20208">#20208</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/tailwindlabs/tailwindcss/commits/v4.3.2/packages/tailwindcss">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=tailwindcss&package-manager=npm_and_yarn&previous-version=4.3.0&new-version=4.3.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>
canary/v2026.714.0-canary.6
2026-07-14 10:02:37 -07:00
DottaandPaperclip 98d9360658 feat(adapters): confine local coding processes (#9504)
## Thinking Path

> - Paperclip is the open source control plane people use to manage AI
agents for work.
> - Local coding adapters currently spawn their CLI processes directly
on the Paperclip host.
> - CLI-native approval and sandbox flags do not provide a reliable host
filesystem or network boundary.
> - An agent can therefore inspect unrelated host files or fetch
external material when an operator needs stronger isolation.
> - The confinement must stay opt-in so existing local adapter behavior
does not change unexpectedly.
> - This pull request adds a shared Linux Bubblewrap spawn layer for
workspace filesystem and deny/allowlist network scopes.
> - The benefit is enforceable defense in depth around Codex and Claude
local runs while preserving explicit provider connectivity.

## Linked Issues or Issue Description

### What happened?

`codex_local` and `claude_local` processes could read arbitrary host
paths and make unrestricted outbound network requests because Paperclip
did not impose a spawn-level boundary.

### Expected behavior

Operators can opt into a workspace-only filesystem view and either deny
network egress or allow exact provider/API hosts, independently of CLI
approval flags.

### Steps to reproduce

1. Run current `master` on Linux and configure a Codex or Claude local
adapter.
2. Ask the agent to read a canary file outside its active workspace.
3. Ask the agent to `curl` a public host.
4. Observe that both operations succeed without a Paperclip-level
confinement option.

### Environment

- Paperclip commit: `c36f1a4af` / current `master` base.
- Deployment mode: Linux local dev or self-hosted server.
- Installation: built from source.
- Adapters: Codex and Claude Code.
- Database: not related.

## What Changed

- Added a shared Bubblewrap process wrapper with opt-in
`filesystemScope: "workspace"`, managed/extra path mounts, private
`/tmp`, and Linux-only validation.
- Added `networkScope: "deny" | "allowlist"`; both use a private network
namespace, while allowlist mode exposes an exact-host HTTP(S) proxy over
a Unix-socket bridge.
- Wired Codex and Claude local CLI execution through the wrapper and
forced scoped auto runs onto the CLI lane because ACP processes are not
covered.
- Added unit and gated Bubblewrap canaries for outside-file denial,
workspace writes, direct network denial, allowlisted forwarding, and
rejected destinations.
- Documented both scopes, provider allowlist examples, Bubblewrap
requirements, and default-off behavior.

## Verification

- `pnpm exec vitest run
packages/adapter-utils/src/local-process-sandbox.test.ts
packages/adapters/codex-local/src/server/acp.test.ts
packages/adapters/claude-local/src/server/acp.test.ts` — 34 passed, 4
gated Bubblewrap tests skipped by default.
- `pnpm --filter @paperclipai/adapter-utils typecheck`
- `pnpm --filter @paperclipai/adapter-codex-local typecheck`
- `pnpm --filter @paperclipai/adapter-claude-local typecheck`
- `pnpm --filter @paperclipai/adapter-utils build`
- `pnpm --filter @paperclipai/adapter-codex-local build`
- `pnpm --filter @paperclipai/adapter-claude-local build`
- Attempted the gated tests with a vendored Bubblewrap binary; this
container blocks unprivileged namespace setup (`setting up uid map:
Permission denied` / loopback `RTM_NEWADDR: Operation not permitted`),
so kernel-level execution remains for CI or a namespace-enabled Linux
host.

## Risks

- Bubblewrap must be installed and unprivileged user/mount/network
namespaces must be enabled on the host; scoped runs fail clearly if the
prerequisite is missing.
- Allowlist mode depends on the coding CLI honoring standard
`HTTP_PROXY` / `HTTPS_PROXY` variables; custom providers must list every
required exact hostname and port.
- Exact-host allowlists intentionally reject wildcards, which is safer
but may require operators to enumerate multi-host provider setups.
- No behavior changes unless an operator enables `filesystemScope` or
`networkScope`.

> This aligns with the ROADMAP direction toward safer remote and
sandboxed agent environments and does not duplicate an open PR or issue
found in the repository search.

## Model Used

- OpenAI GPT-5.5 (`gpt-5.5`) via Codex CLI, with reasoning, repository
tool use, shell execution, code editing, and test execution. The serving
context-window size is not exposed to the 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
- [ ] 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>
canary/v2026.714.0-canary.5
2026-07-14 11:01:19 -05:00
c4eb5339e7 fix(worktree): require target attestation before repair (#9414)
## Thinking Path

> - Paperclip is the open source control plane people use to manage AI
agents for work
> - Local agent execution uses isolated git worktrees with
worktree-specific config, environment, storage, and ports
> - Legacy worktree repair and runtime-port persistence must mutate only
the worktree they are serving
> - A leaked ambient `PAPERCLIP_IN_WORKTREE=true` could be combined with
config resolution pointing at the default instance
> - The server test suite reproduced that combination and repeatedly
rewrote the live default instance `.env` with its old fixture name
> - Existing PR #3071 guards configs under Paperclip home, but does not
require the target itself to attest worktree ownership and does not
cover runtime-port persistence
> - This pull request requires both a worktree config layout and
target-local persisted worktree attestation before either writer adopts
the target
> - The benefit is that ambient process state can never turn the main
instance into a worktree on its next restart

## Linked Issues or Issue Description

Related implementation: Refs #3071

**Pre-submission checklist**
- [x] Searched open and closed issues and pull requests; #3071 is the
only direct related implementation.
- [x] Reproduced on current `master` before applying the fix.
- [x] Confirmed the mutation originates in Paperclip's worktree config
repair path.

**What happened?**

A process with leaked `PAPERCLIP_IN_WORKTREE=true` could resolve
`PAPERCLIP_CONFIG` to the default instance and cause worktree repair to
rewrite that instance's `.env`. The recurring trigger was
`server/src/__tests__/worktree-config.test.ts`: an ambient config path
from the developer shell survived into a test whose fixture worktree
name was `PAP-884-ai-commits-component`, explaining the stale name
repeatedly written to the live file.

**Expected behavior**

Worktree repair and worktree runtime-port persistence must mutate a
target only when that target is independently provisioned and persisted
as a worktree. Ambient environment flags alone must never authorize
writes to the default instance or a normal repository-local `.paperclip`
config.

**Steps to reproduce on unpatched `master`**

1. Export `PAPERCLIP_CONFIG` pointing to a default instance config and
set `PAPERCLIP_IN_WORKTREE=true`.
2. Run `server/src/__tests__/worktree-config.test.ts` from that shell.
3. Observe that the default instance `.env` is rewritten with the test
fixture's worktree marker and name.

**Environment**

- Version: `master` at `e4e12bfb8`
- Deployment/install: local source checkout with pnpm
- Adapter: not adapter-specific; core server config
- Database/access context: not applicable
- OS: Linux

**Privacy**

- [x] All paths and values in this description are generic and contain
no credentials or personally identifying data.

## What Changed

- Reject config targets unless their parent directory is the
worktree-specific `.paperclip` layout.
- Require the target's own persisted `.env` to declare
`PAPERCLIP_IN_WORKTREE=true` before repair or runtime-port persistence
can mutate it.
- Scrub ambient `PAPERCLIP_*` variables before every worktree-config
test so developer-machine exports cannot escape test isolation.
- Add regressions for default-instance config poisoning, runtime-port
persistence, and unattested repository-local `.paperclip` targets.
- Preserve valid provisioned worktree behavior by adding persisted
worktree markers to the existing positive fixtures.

## Verification

- `NODE_ENV=test pnpm --filter @paperclipai/server exec vitest run
src/__tests__/worktree-config.test.ts` — 12 tests passed.
- Branch is based directly on current `origin/master`; only two server
files changed.
- No `pnpm-lock.yaml`, workflow, migration, UI, or generated asset
changes.

## Risks

- Low risk: the new guard intentionally refuses repair for targets that
lack provisioning evidence.
- A manually assembled worktree that sets only ambient flags but never
writes its worktree marker will no longer be auto-repaired; the
supported provisioning path already writes that marker.
- No schema, API, migration, or user-facing command changes.

> This is a focused correctness fix and does not overlap with planned
core work in `ROADMAP.md`.

## Model Used

- Implementation and root-cause investigation: Anthropic Claude through
the `claude_local`/Claude Code runtime, reported by the producing agent
as “Claude Fable 5”; the runtime did not expose a more specific provider
model ID or context-window value. Capabilities used: extended reasoning,
shell tool use, code editing, and test execution.
- PR preparation and verification: OpenAI Codex CLI runtime; the harness
did not expose the exact underlying model ID or context-window value.
Capabilities used: repository inspection, shell tool use, Git/GitHub
operations, 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 all model details exposed by
the runtimes
- [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
#3071 above
- [x] I have described the issue in-PR following the bug report template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal
ticket ID
- [x] I have run the focused tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have assessed documentation impact; no documentation change is
required for this internal guard
- [x] I have considered and documented 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: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.714.0-canary.4
2026-07-14 10:59:06 -05:00
Nicky LeachandPaperclip 24bbc0f57e docs: add telemetry marker workflow (#9543)
## Thinking Path

> - Paperclip is an open-source agentic AI management platform that
ships anonymous usage telemetry to understand product health and
adoption.
> - The telemetry system has a generated contract
(`packages/shared/src/telemetry/generated/paperclip-telemetry.ts`) that
types every first-party event the product emits.
> - When a product change needs a new first-party event that is not yet
in the generated contract, contributors had no public workflow
explaining how to propose an event or later promote it into the contract
once accepted.
> - The gap leads to confusion at call sites: contributors either skip
tracking entirely or emit untyped events that bypass the privacy and
governance safeguards built into the contract.
> - This PR fills that gap by adding `doc/TELEMETRY_WORKFLOW.md` — a
public contributor guide that covers the full propose → promote
lifecycle: the `@ts-expect-error -- proposed-telemetry(...)` marker, the
canonical multi-line `track()` shape, the TS2578 expiry signal, and the
look-up-by-event-name promotion step.
> - `packages/shared/src/telemetry/README.md` gains a cross-reference so
readers of the data-contract doc can find the workflow guide without
searching.
> - `README.md` gains a one-line pointer in the telemetry section so the
workflow is discoverable from the project entry point.

## Linked Issues or Issue Description

No pre-existing public GitHub issue covers this doc gap. Inline
description:

**Problem:** Contributors adding product telemetry for events not yet in
the generated contract have no documented workflow. The
`@ts-expect-error -- proposed-telemetry(...)` pattern exists in the
codebase but is undocumented, leading to inconsistent usage and missing
adoption signals.

**Solution:** A new public guide (`doc/TELEMETRY_WORKFLOW.md`) documents
the marker format, the recommended multi-line `track()` shape that
preserves the TS2578 expiry signal, the dimension rules, and the
promotion checklist. Cross-references are added to
`packages/shared/src/telemetry/README.md` and the top-level `README.md`.

No related open PRs found.

## What Changed

- **New file `doc/TELEMETRY_WORKFLOW.md`** — public contributor guide
for the propose/promote lifecycle: marker format, canonical multi-line
example, TS2578 single-line trap, dimension rules, and step-by-step
promotion checklist.
- **`packages/shared/src/telemetry/README.md`** — added one-line
cross-reference pointing at `doc/TELEMETRY_WORKFLOW.md` for proposed
events not yet in the generated contract.
- **`README.md`** — added one-line pointer in the telemetry section so
the new workflow guide is reachable from the top-level project entry.

## Verification

This is a docs-only change. Verification steps:

1. Open `doc/TELEMETRY_WORKFLOW.md` and confirm it contains:
   - The `^[a-z0-9][a-z0-9._:-]{1,63}$` event-name grammar.
- The exact `// @ts-expect-error -- proposed-telemetry(<issue>):
<rationale>` marker.
- The multi-line `client.track()` copy-paste example (directive on line
before event-name string).
- The explanation of the TS2578 single-line trap and the
look-up-by-event-name step.
   - The promotion checklist in the "Promote An Event" section.
2. Confirm `packages/shared/src/telemetry/README.md` cross-references
`doc/TELEMETRY_WORKFLOW.md`.
3. Confirm the `README.md` telemetry section links to
`doc/TELEMETRY_WORKFLOW.md`.

## Risks

Low risk — docs-only change. No runtime behavior, schema, or existing
telemetry emission is affected. The risk is that the guidance could
diverge from the actual enforcement in the codebase over time; mitigated
by linking to the generated contract and keeping the doc in the same
repo.

## Model Used

Claude — `claude-sonnet-4-6` (Anthropic Claude Sonnet 4.6). Tool use
enabled. Extended context. Produced via the Paperclip agentic workflow
with `Co-authored-by: Paperclip <noreply@paperclip.ing>`.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.714.0-canary.3
2026-07-14 08:25:53 -07:00
Nicky LeachandPaperclip 90f85a7d11 Add telemetry proposal extractor (#9544)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - It emits telemetry events to understand product usage — registered
event names are gated by a generated `PAPERCLIP_EVENTS` registry so the
client only enqueues known, schema-approved events
> - When product teams want to instrument a new behaviour, they must
first register the event name — but schema registration is a
commit-and-release cycle, which creates friction in fast-moving product
iterations
> - A proposal lane is needed: let developers mark a `track()` call with
a typed `@ts-expect-error` proposal marker so the event name can be
reviewed and tracked in CI before the schema is formally registered
> - The existing client had no guard against unregistered event names,
so any call with an out-of-registry name (or a prototype-inherited key)
would silently enter the queue, state, and network flush path
> - This PR adds an `Object.hasOwn(PAPERCLIP_EVENTS, eventName)` guard
at the entry point of `track()` to swallow unregistered calls before any
side effects, adds `scripts/extract-proposed-events.mjs` to scan source
for proposal markers and emit a v2 JSON manifest with provenance and
rationale, and documents the complete proposal workflow
> - The benefit is that new instrumentation can be proposed and reviewed
in code without touching the registered schema, and tooling can surface
missing rationale before events graduate to stable

## Linked Issues or Issue Description

No existing GitHub issue covers this change. This PR introduces a new
feature.

**Feature motivation:** Paperclip's telemetry schema is intentionally
stable — registered event names are code-generated and gated. Product
engineers who want to instrument a new behaviour today must land a
schema change first, creating a two-step process that slows iteration. A
proposal lane lets developers write the instrumentation call ahead of
schema registration, protected by a compile-time `@ts-expect-error`
marker that an extractor script can surface for review. This PR
implements both the client-side safety gate and the extraction tooling.

Refs: #9518 (closed predecessor — docs-only; this PR supersedes it with
the full implementation)

## What Changed

- Added `Object.hasOwn(PAPERCLIP_EVENTS, eventName)` guard at the top of
`TelemetryClient.track()`: unregistered event names (including
prototype-inherited keys) are now swallowed before any state, queue, or
network operation
- Added `scripts/extract-proposed-events.mjs`: scans TypeScript source
for `@ts-expect-error -- proposed-telemetry(<issue>): <rationale>`
markers; emits a v2 JSON manifest per proposed event including name,
rationale, provenance (repo-relative file + line), and a
`rationale_missing` flag for CI enforcement
- Added `scripts/extract-proposed-events.test.mjs`: test suite covering
marker parsing, multi-line markers, path validation, out-of-repo
rejection, and the v2 schema output contract
- Added `doc/TELEMETRY_WORKFLOW.md`: documents the proposal workflow,
the canonical multi-line marker example, rationale requirements, and how
to graduate a proposed event to stable schema
- Updated `packages/shared/src/telemetry/README.md`: added "Proposed
Events" section to the Telemetry Data Contract per the contributing
guide requirement for telemetry changes

## Verification

Run all of the following from the repo root:

```sh
# Extractor unit tests
node --test scripts/extract-proposed-events.test.mjs

# Telemetry client + types tests
pnpm exec vitest run --config vitest.config.ts \
  src/telemetry/client.test.ts src/telemetry/client-types.test.ts \
  --reporter=verbose
# (run from packages/shared)

# Type-check
pnpm --filter @paperclipai/shared typecheck

# Smoke-run the extractor in local-test mode
node scripts/extract-proposed-events.mjs --ref local-test
```

All four commands pass locally.

## Risks

- **Silent drop on unregistered events:** The `Object.hasOwn` guard
fails closed — any event name not in `PAPERCLIP_EVENTS` is silently
dropped. If the generated registry is missing an event that was
previously tracked, those calls will be silently lost. Mitigation: the
extractor script surfaces proposed events that need registration; the
TypeScript type system already enforces `TelemetryEventName ⊆
PAPERCLIP_EVENTS` at compile time.
- **Extractor is read-only:** `extract-proposed-events.mjs` reads source
and emits JSON; it does not modify any files. No runtime or schema risk.
- Overall risk: **low**. The guard is additive and defensive; the
extractor and docs are additive only.

## Model Used

- Provider: Anthropic
- Model ID: `claude-sonnet-4-6`
- Context window: 200 K tokens
- Capabilities: tool use, extended context, code generation

## 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>
canary/v2026.714.0-canary.2
2026-07-13 23:47:27 -07:00
DottaandPaperclip 6a36ae47fe Fix stable release dry-run notes gate (#9334)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The release subsystem uses GitHub Actions dry-run previews so
maintainers can validate stable and canary release behavior before
publishing.
> - Stable release publishing needs a release notes gate so real
`latest` publishes never happen without authored notes.
> - The same gate was also blocking stable dry-run previews, which made
release QA fail before publish-sensitive work could be previewed.
> - This pull request narrows the notes requirement to real non-dry-run
stable publishes.
> - The benefit is that stable dry-run dispatches can preview the
release without same-day notes, while real stable publishes remain
protected.

## Linked Issues or Issue Description

No public GitHub issue exists for this release-QA blocker, so the bug is
described inline below.

### What happened?

Stable dry-run release previews fail when the same-day release notes
file is absent. The release script runs the stable notes-file gate
before release preview work even when `--dry-run` is set.

### Expected behavior

`./scripts/release.sh stable --dry-run` should preview the stable
release without requiring `releases/vYYYY.MDD.P.md`. Real non-dry-run
stable publishes must still fail before build/publish work starts when
the notes file is missing.

### Steps to reproduce

1. Check out current `master` before this fix.
2. Ensure the computed same-day stable release notes file does not exist
under `releases/`.
3. Run `./scripts/release.sh stable --skip-verify --dry-run`.
4. Observe that the script exits with `stable release notes file is
required` instead of reaching the release preview plan.

### Paperclip version or commit

Reproduced on `master` at `9a1d4b7983dfd50e8eb40ee9770e44999d405f60`.

### Deployment mode

Built from source / GitHub Actions release workflow.

## What Changed

- Narrowed the stable release notes gate to `channel=stable` and
`dry_run=false`.
- Updated the release script usage note to say the notes file is
required for non-dry-run stable releases.
- Added a targeted Node test covering dry-run allowed behavior and
non-dry-run blocked behavior.
- Stubbed release fixture registry-version checks so the test isolates
the notes gate without hitting npm.

## Verification

- `node --test scripts/__tests__/release-dry-run-notes.test.mjs` passed
with 2/2 subtests.
- `bash -n scripts/release.sh` exited 0.

## Risks

Low risk. The behavior change only relaxes the notes-file gate for
stable dry-runs. The new test verifies real non-dry-run stable publish
still fails before build/publish work starts when notes are missing.

## Model Used

OpenAI Codex, GPT-5-based coding agent, with shell/tool execution in a
local repository 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>
canary/v2026.714.0-canary.1
2026-07-13 21:11:07 -05:00
DottaandPaperclip 6f204605ad fix(ui): show source SHA for unreleased builds (#9508)
## Thinking Path

> - Paperclip is the open source control plane people use to manage
AI-agent companies
> - Operators need to identify the exact build running from the
persistent account menu
> - Formal releases already have a concise public version, but source
builds include a long derived version string
> - The derived version identifies a commit but does not expose the
source branch or a direct path to inspect the code
> - Server Git metadata is auth-sensitive, so the UI must also refresh
it when the current session changes
> - This pull request shows linked branch and commit metadata for source
builds while preserving `v<version>` for formal releases
> - The benefit is faster build diagnosis with correct metadata across
sign-in and sign-out transitions

## Linked Issues or Issue Description

### Pre-submission checklist

- [x] I searched existing open and closed issues and found no duplicate
implementing this exact account-menu behavior.
- [x] The behavior reproduces on `master`.
- [x] The behavior originates in Paperclip's core UI, not an adapter,
provider, or local configuration.

### What happened?

Source builds displayed the full derived version, such as
`2026.626.0+58.git.518fc71ce`, without linking the operator to the
corresponding source branch or commit.

### Expected behavior

Source builds should show the concise branch and short commit SHA with
links to GitHub, while formal releases should continue showing their
public version. Auth transitions should refresh the health metadata that
supplies those Git details.

### Steps to reproduce

1. Run Paperclip from a commit after a release tag.
2. Open the account menu.
3. Inspect the build label beneath the user identity.
4. Sign in or out and reopen the menu.

### Paperclip version or commit

Any source build whose server version uses the
`<version>+<count>.git.<sha>[.dirty]` format.

### Deployment mode

Local dev (`pnpm dev`) or authenticated deployments.

### Installation method

Built from source.

## What Changed

- Detect source-derived version strings and render the source branch
plus seven-character commit SHA in `SidebarAccountMenu`.
- Link source branches and commits to the canonical
`paperclipai/paperclip` GitHub repository.
- Extend server Git metadata with the full SHA and expose it through
health/OpenAPI contracts.
- Refresh auth-sensitive health metadata after sign-in and every
sign-out entry point.
- Preserve the existing `v<version>` label for formal releases and add
focused regression coverage.

## Verification

- `pnpm --filter @paperclipai/ui exec vitest run src/pages/Auth.test.tsx
src/components/SidebarAccountMenu.test.tsx
src/components/SidebarServerInfo.test.tsx`
- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/health.test.ts src/__tests__/server-info.test.ts`
- `pnpm --filter @paperclipai/ui typecheck`
- `pnpm check:token-gates`
- `git diff --check public/master...HEAD`

## Risks

- Low risk: formal release rendering retains the existing fallback
behavior when the source-version pattern does not match.
- Source links assume the build came from the canonical public
repository; fork-only branches or commits may not resolve there.
- Health metadata is invalidated after auth transitions, adding one
bounded refetch so the displayed Git details match the new session.

> 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 medium reasoning, repository/tool
access, shell execution, and code editing; context-window size was 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>
canary/v2026.714.0-canary.0
2026-07-13 20:55:54 -05:00
DottaandPaperclip efcce9cc8e fix(adapters): record unpriced CLI usage (#9505)
## Thinking Path

> - Paperclip is the open source control plane people use to manage
AI-agent companies
> - Budgets and spend telemetry are control-plane safety features, not
just reporting
> - Local Codex and Claude adapters can execute through either ACP or
their native CLI engines
> - The ACP lane records usage and reported cost, but CLI JSON output
often reports tokens without a price
> - The CLI lane was either losing per-run usage semantics or coercing
missing cost to zero, making real usage indistinguishable from a
genuinely free run
> - This pull request preserves CLI usage as per-run totals and records
token-bearing runs without a reported price as explicitly unpriced
ledger events
> - The benefit is accurate usage accounting and a visible pricing gap
instead of silently misleading zero-cost telemetry

## Linked Issues or Issue Description

Refs #9471
Refs #9230

**Bug description**

A `codex_local` run using the CLI engine can emit a final
`turn.completed` event with millions of input tokens and tens of
thousands of output tokens while the agent's spend ledger remains
indistinguishable from a true zero-usage, zero-cost run. Claude CLI
output has the same missing-price edge case.

**Expected behavior**

Token-bearing CLI runs should persist their usage. If the adapter
reports a price, the ledger should record it as reported; if the CLI
reports usage but no price, the ledger should explicitly mark the event
as unpriced rather than silently treating missing price data as a
reported `$0` cost.

**Reproduction shape**

1. Configure `codex_local` with `engine: cli`.
2. Run a task that produces a `turn.completed` usage payload.
3. Observe token usage in the run stream.
4. Before this change, missing price data is represented as ordinary
zero-cost spend and the CLI usage basis is not consistently propagated.

## What Changed

- Mark Codex and Claude native CLI usage totals as `per_run` and
propagate that basis through success and failure results.
- Stop coercing missing Claude CLI cost to `0`.
- Add `cost_status` to cost events with `reported` and `unpriced`
values, including an idempotent migration and shared validation/types.
- Persist token-bearing runs without a reported price as `unpriced`
ledger events while retaining zero cents until an authoritative price
exists.
- Add parser, execute-path, heartbeat-accounting, and cost-service
regression coverage for both local CLI adapters.
- Document the cost-status invariant and CLI accounting behavior.

## Verification

- `pnpm exec vitest run
packages/adapters/codex-local/src/server/parse.test.ts
packages/adapters/claude-local/src/server/parse.test.ts
server/src/__tests__/codex-local-execute.test.ts
server/src/__tests__/claude-local-execute.test.ts
server/src/__tests__/heartbeat-cost-accounting.test.ts
server/src/__tests__/costs-service.test.ts` — 6 files / 102 tests
passed.
- `pnpm --filter @paperclipai/shared typecheck`
- `pnpm --filter @paperclipai/db typecheck` — includes migration
numbering and safety checks.
- `pnpm --filter @paperclipai/adapter-codex-local typecheck`
- `pnpm --filter @paperclipai/adapter-claude-local typecheck`
- `pnpm --filter @paperclipai/server typecheck`

## Risks

- Existing cost rows default to `reported`, preserving current
interpretation; only new token-bearing events with absent cost are
marked `unpriced`.
- This change does not invent model pricing. Budget hard stops still
cannot charge an unknown amount, but operators and evals can now
distinguish missing pricing from a genuinely reported zero cost.
- Consumers that enumerate cost-event fields should tolerate the
additive `costStatus` field.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, exact model `gpt-5.3-codex`, with repository tool use
and code execution; default reasoning mode.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have 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-13 20:44:38 -05:00
Devin FoleyandClaude ce7dedf33d perf(ci): balance general-server test shards by recorded suite duration (#9516)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Its PR CI runs the general-server vitest lane pinned to
`maxWorkers=1` and sharded across 3 runners (introduced in #8360)
> - Suites were assigned to shards round-robin by sorted file index, so
shard test time was unbalanced: a recent PR run split 73s / 153s / 115s,
and the heaviest shard made "General tests (server 2/3)" the slowest
check in the whole workflow at 314s wall
> - The slowest shard sets the lane's wall time, so unbalanced
partitions waste the other two runners and stretch the PR critical path
> - This pull request replaces the round-robin assignment with a
deterministic longest-processing-time partition weighted by a checked-in
per-suite duration manifest
> - The benefit is near-even shard weights (projected 113s / 113s / 113s
with the current manifest), taking roughly 40s off the PR critical path
with no reduction in coverage

## Linked Issues or Issue Description

- Refs #8360 (introduced the 3-way general-server sharding this PR
rebalances)
- No public issue exists. Problem: the general-server test lane's
round-robin shard assignment ignores per-suite duration, so one shard
can carry multiple 30s+ suites while another finishes in half the time;
the slowest shard alone determines the check's wall time.

## What Changed

- `scripts/general-server-shard.mjs` (new): manifest loader and
deterministic LPT (longest-processing-time) partitioner; suites missing
from the manifest get the median recorded weight, and a missing or
malformed manifest degrades to uniform weights so the lane never fails
on stale data
- `scripts/general-server-shard-durations.json` (new): per-suite
duration manifest sampled from a real PR run (240 suites); the
`$comment` field documents how to regenerate it
- `scripts/run-vitest-stable.mjs`: both shard-selection sites (run and
`--dry-run`) now use the balanced partition instead of index round-robin
- `scripts/__tests__/run-vitest-stable-shard.test.mjs`: 6 new tests
covering skew-balance vs round-robin, determinism, median fallback for
unlisted suites, malformed-manifest degradation, manifest coverage of
the current suite set, and real-partition balance
- `server/src/__tests__/heartbeat-issue-rewake-throttle.test.ts`:
hardened the `afterEach` sweep — post-run bookkeeping (run-event
records, follow-up wake scheduling) can still insert rows briefly after
a run reaches a terminal status, and a late insert landing between the
`agent_wakeup_requests` and `agents` deletes failed teardown with a
foreign-key violation on the first CI attempt of this PR; the sweep now
retries so a late background write cannot take down the shard
- `release-verify.yml` shares the same runner script and inherits the
balancing with no workflow change

## Verification

- `node --test scripts/__tests__/run-vitest-stable-shard.test.mjs` — 9/9
pass (run against current master)
- `npx vitest run src/__tests__/heartbeat-issue-rewake-throttle.test.ts`
— 6/6 pass against embedded Postgres with the hardened teardown
- `node --test scripts/__tests__/release-verify-workflow.test.mjs` — 2/2
pass
- `node scripts/run-vitest-stable.mjs --dry-run` with each shard flag
shows every suite assigned exactly once across the 3 shards, with
projected weights ~113s each

## Risks

- Low risk: partition changes which runner executes which suite, not
what runs; a completeness test asserts every suite is assigned to
exactly one shard
- The duration manifest will drift as suites are added/changed; unlisted
suites get the median weight and a coverage test flags when the manifest
covers less than half the suite set, so drift degrades balance
gracefully rather than breaking the lane

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- Claude Fable 5 (`claude-fable-5`, Anthropic), extended thinking
enabled, agentic tool use (file edits, shell, test execution) via Claude
Code

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [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: Claude (Paperclip SWE) <noreply@paperclip.ing>
2026-07-13 12:25:54 -07:00
Devin FoleyandCody b49d178c46 fix(ui): experiments auto-recovery dialog leaves UI dimmed and locked after enabling (#9513)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Operators tune instance behavior through Settings → Experiments,
where experimental features are toggled on and off
> - The task graph liveness auto-recovery experiment shows a
confirmation dialog (preview of what would be recovered) before it is
enabled
> - After confirming with "Enable only" or "Enable and run", the
dialog's Radix overlay and the `pointer-events: none` body lock were
left behind, dimming the page and blocking all interaction until a
refresh
> - The dialog was unconditionally mounted and only closed inside the
mutation's `onSuccess`, so the overlay teardown depended on the mutation
outcome and could race or never happen
> - This pull request closes the dialog before the mutation fires in
both confirm flows, clears the pending preview alongside the open flag,
and mounts the dialog conditionally so its overlay fully unmounts
> - The benefit is that enabling an experiment behaves like every other
settings change: the dialog goes away, the page stays interactive, and
errors surface in the page-level error banner instead of a dead UI

## Linked Issues or Issue Description

No public GitHub issue exists for this bug; description follows the bug
report template. Refs #4587 (the PR that introduced the configurable
liveness auto-recovery controls this dialog belongs to).

**What happened?** In Settings → Experiments, toggling on "Task graph
liveness auto-recovery" and confirming via "Enable only" left the whole
UI dimmed and unclickable. The dialog content disappeared, but the modal
overlay and the `pointer-events: none` lock on `<body>` remained until a
full page refresh.

**Expected behavior:** Confirming (or dismissing) the auto-recovery
dialog should close it completely and return the page to a fully
interactive state, with the toggle reflecting the new setting.

**Steps to reproduce:**
1. Open Settings → Experiments.
2. Toggle on "Task graph liveness auto-recovery"; the confirmation
dialog with the recovery preview appears.
3. Click "Enable only".
4. The dialog content disappears but the page stays dimmed and nothing
is clickable; refreshing restores the UI and shows the setting was
applied.

**Paperclip version or commit:** master @ 634ae12 · **Deployment mode:**
local instance · **Area:** UI only
(`ui/src/pages/InstanceExperimentalSettings.tsx`).

## What Changed

- Added a `closeRecoveryPreview()` helper that resets both
`previewDialogOpen` and `pendingPreview` together, and used it
everywhere the dialog closes (confirm flows, run-mutation success, and
user dismissal).
- "Enable only" and "Enable and run" now close the dialog *before*
firing the mutation, so overlay teardown no longer depends on the
mutation outcome; mutation errors roll back the optimistic toggle and
surface in the existing page-level error banner.
- The `RecoveryPreviewDialog` is now conditionally mounted
(`previewDialogOpen ? <RecoveryPreviewDialog … /> : null`), guaranteeing
the Radix overlay and body pointer-events lock are fully removed when
closed.
- Added a regression test that walks the real flow — toggle on → preview
dialog appears → "Enable only" — and asserts the update payload, that
the dialog text and `[data-slot="dialog-overlay"]` element are gone, and
that the toggle reads enabled.

Credit: the implementation commit was authored by Cody — thanks! This PR
packages that fix for upstream review.

## Verification

- `pnpm vitest run src/pages/InstanceExperimentalSettings.test.tsx` in
`ui/` — 17/17 tests pass, including the new regression test.
- Independently re-verified beyond the committed assertions: with a
temporary assertion (not committed), confirmed
`document.body.style.pointerEvents` is `none` while the dialog is open
and released after "Enable only" — the actual "can't interact with
anything" symptom, not just overlay DOM removal.
- Manual check: open Settings → Experiments, toggle the auto-recovery
feature, click "Enable only" — the dialog closes, the page stays
interactive, and the toggle shows enabled without a refresh.

## Risks

- Low risk: change is confined to one page component's dialog lifecycle;
no API, schema, or shared-package changes.
- Behavioral shift: the dialog now closes immediately on confirm instead
of staying open with a pending spinner until the mutation resolves.
Errors are still surfaced via the page-level error banner, and the
optimistic toggle rolls back on failure.

## Model Used

- Implementation commit authored by the AI coding agent "Cody"
(Anthropic Claude-based agent). Review, independent verification, and PR
preparation by Claude (Anthropic), model ID `claude-fable-5`, extended
thinking with tool use (code execution, test runs).

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [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: Cody <noreply@paperclip.ing>
2026-07-13 11:52:59 -07:00
machjesusmotoandZephyr 0e21a27301 fix: forward onSpawn to hermes and process adapters for PID persistence (#8722)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The adapter layer (hermes-local, process adapters) delegates agent
execution to child processes via `runChildProcess()`
> - `runChildProcess()` accepts an `onSpawn` callback to report child
PID and process group info, but the hermes and process adapters were not
forwarding `ctx.onSpawn` to this call
> - Without PID persistence, the orphan reaper cannot distinguish live
runs from abandoned processes, causing false-positive reaps and 5-minute
timeout errors for active runs
> - This pull request adds `onSpawn: ctx.onSpawn` to both adapter call
sites and declares the option in the `runChildProcess` wrapper type
> - The benefit is that the orphan reaper can now correctly track live
child processes, eliminating false-positive reaps

## Linked Issues or Issue Description

Fixes #8723

Fixes false-positive orphan reaps in hermes-local and process adapters
by forwarding the `onSpawn` callback to `runChildProcess()`. All other
adapters (claude-local, codex-local, cursor-local, gemini-local,
grok-local, opencode-local, pi-local) already forward `ctx.onSpawn` —
these two were the only ones missing it.

## What Changed

- `server/src/adapters/utils.ts`: Added `onSpawn?` to the
`runChildProcess()` options type so callers can forward the callback
- `server/src/adapters/process/execute.ts`: Forward `ctx.onSpawn` to
`runChildProcess()`
- `packages/adapters/hermes/src/server/execute.ts`: Forward
`ctx.onSpawn` to `runChildProcess()`

## Verification

- `pnpm -r typecheck` passes across all packages
- Confirmed all other adapters already forward `ctx.onSpawn` (12 grep
matches across 9 adapter files)
- The 3-line diff is additive only — no existing behavior is changed,
only a previously-ignored callback is now forwarded

## Risks

Low risk. This is a 3-line additive change. The `onSpawn` parameter is
optional (`?`) so existing callers are unaffected. The callback is
already well-established across all other adapters.

## Model Used

Hermes Agent (by Nous Research) — xiaomi/mimo-v2.5-pro via OpenRouter,
with tool use (file editing, git, GitHub API).

## 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
- [x] My branch name describes the change and contains no internal
ticket id
- [x] I have run tests locally and they pass (typecheck passes)
- [x] I have added or updated tests where applicable (N/A — type-level
fix only, no behavioral change)
- [x] I have updated relevant documentation to reflect my changes (N/A —
internal fix)
- [x] I have considered and documented any risks above

---------

Co-authored-by: Zephyr <zephyr@motoyuki.dev>
canary/v2026.713.0-canary.2
2026-07-13 12:33:08 -05:00
scotttongandClaude Fable 5 634ae1298f fix(ui): consolidate live/running blues; stop inbox unread badge indenting the row (#9383)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The web UI leans on a shared design-token + component system so
surfaces stay visually consistent as they grow
> - Two small inconsistencies had crept in: several distinct blues were
used to signal "live/running" agent state across the sidebar, task
header, and chat thread; and in the Inbox an unread task's mark-read dot
was pushing that row's status icon and title one column right of read
rows
> - Both read as "not quite aligned" in daily use and undercut the
polish of the lists work that just landed
> - This pull request consolidates the live/running blues onto one
shared recipe and stops the unread dot from indenting the row
> - The benefit is one consistent "live" blue everywhere and Inbox rows
that line up whether read or unread

## Linked Issues or Issue Description

No public GitHub issue exists for this work; describing inline per the
bug-report template.

- **Problem**: (1) the same concept — an agent actively working —
rendered in three visibly different blues: the sidebar `N live` dot, the
task-detail "Live" badge, and the chat-thread "RUNNING" badge each used
a different token/recipe. (2) In the Inbox, unread rows carry a leading
mark-read dot that occupies the chevron column, but a per-row spacer was
still rendering in that same column — so on unread rows the status icon
+ title were shifted one column (~24px) further right than read rows.
Most visible when grouped by workspace.
- **Steps to reproduce**: open the Inbox with a mix of read and unread
tasks (group by workspace). The unread rows' status icons sit further
right than the read rows'. Separately, compare the blue of the sidebar
`N live` dot, a task's "Live" header badge, and a chat "RUNNING" badge —
they don't match.
- **Expected behavior**: unread and read rows align on the same status
column, with the unread dot centered on the workspace group chevron; and
all three "live/running" affordances share one blue.

## What Changed

- Added a shared `liveBlueBadge` recipe in `ui/src/lib/status-colors.ts`
and pointed the task-detail **Live** badge (`IssueDetail.tsx`) and the
chat-thread **RUNNING** badge (`IssueChatThread.tsx`) at it; removed the
now-redundant `brandChipBadge` usage from the chat thread and a stray
`🔵` breadcrumb prefix.
- Changed the sidebar **`N live`** dot (`SidebarNavItem.tsx`) to the
same `blue-600 / dark:blue-400` as its adjacent label text.
- **Inbox** (`Inbox.tsx`): skip the per-row leading spacer when the
unread mark-read dot is present, so the dot alone fills the chevron
column. Unread rows' status icon + title now sit in the same column as
read rows, and the dot centers on the workspace group chevron.
- **Test** (`Inbox.test.tsx`): added a regression test asserting an
unread leaf row renders the mark-read dot and drops the spacer, while a
read row keeps the spacer.

## Verification

- `pnpm typecheck` — clean (all packages)
- `pnpm check:token-gates` — 3/3 CLEAN
- `cd ui && pnpm vitest run src/pages/Inbox.test.tsx` — 14/14 (includes
the new regression test)
- Full Storybook visual suite (514 stories, both themes) — green locally
(CI cannot run this suite yet — the baseline-manifest archive is
unpublished, a pre-existing condition from #9134)
- Manual (workspace-grouped Inbox, 2× dark): measured the unread badge
center at the same x as the workspace chevron (276 = 276) and the
unread-row status icon at the same x as read-row status icons (292 =
292). Before/after screenshots in a PR comment below.

## Risks

Low risk — presentation only. No data, routing, or state changes. The
blue consolidation is a token/class swap; the Inbox change removes a
redundant spacer element on unread rows only (read rows and
non-grouped/mobile views are unaffected). The unread-row behavior is
covered by the new unit test.

## Model Used

Claude (Anthropic), Opus 4.8 — model id `claude-opus-4-8`; extended
thinking + tool use, driving local verification (typecheck, token gates,
vitest, Playwright visual suite + pixel measurements).

## 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: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 08:53:03 -07:00
Nicky LeachandPaperclip 8775bde4ce Add runtime asset build-gap guard
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The server package ships runtime asset trees used by built-in agents
and onboarding templates.
> - A prior server build omitted those source asset trees from `dist`,
allowing a built artifact to differ from runtime expectations.
> - The copy step is now present, but the existing build-gap gate only
checked TypeScript coverage for packages whose build skips `tsc`.
> - This pull request extends that standing gate so source asset files
under the server runtime asset trees must exist at the matching `dist`
paths after build.
> - The benefit is that future server asset additions fail loudly in CI
instead of silently shipping an incomplete `dist`.

## Linked Issues or Issue Description

### What happened?

After a server build, runtime asset files under
`server/src/built-ins/**` and `server/src/onboarding-assets/**` could be
missing from `dist/` with no build failure. The existing build-gap gate
only checked TypeScript coverage for packages that skip `tsc`; it did
not verify that non-TypeScript source assets were copied to `dist`. A
server build that forgot the `cp -R` step, or that added a new asset
tree without updating the copy command, would produce an incomplete
`dist` without any CI signal.

### Expected behavior

After `pnpm --filter @paperclipai/server build`, every
non-TypeScript/non-JavaScript source file under `server/src/built-ins/`
and `server/src/onboarding-assets/` must exist at the matching path
under `server/dist/`. If any file is missing, the build-gap gate must
exit non-zero with a diagnostic listing the missing files and the
command to fix them.

### Steps to reproduce

1. Remove a copied runtime asset: `rm
server/dist/built-ins/agents/reflection-coach/AGENTS.md`
2. Run the guard: `node scripts/run-typecheck-build-gaps.mjs
--runtime-assets-only`
3. Before this fix: the command exits 0 and the missing file goes
undetected.

### Paperclip version or commit

Reproduced on `master` at `c36f1a4af` (`@paperclipai/server` 0.3.1).

### Deployment mode

Not deployment-specific — the build-gap check runs in CI on any
checkout.

## What Changed

- Extended `scripts/run-typecheck-build-gaps.mjs` with a source-derived
server runtime asset parity check for non-`.ts`/non-`.js` files under
`server/src/built-ins/**` and `server/src/onboarding-assets/**`.
- Added a guard-only mode, `--runtime-assets-only`, for focused
pass/fail verification after a server build.
- Wired `pnpm run typecheck:build-gaps` to prepare plugin SDK build
deps, build the server package, then run the existing build-gap gate
plus the new asset check.

## Verification

Pass path:

```text
$ pnpm --filter @paperclipai/plugin-sdk ensure-build-deps
> @paperclipai/plugin-sdk@1.0.0 ensure-build-deps .../packages/plugins/sdk
> node ../../../scripts/ensure-plugin-build-deps.mjs

$ pnpm --filter @paperclipai/server build
> @paperclipai/server@0.3.1 build .../server
> tsc && mkdir -p dist/onboarding-assets dist/built-ins && cp -R src/onboarding-assets/. dist/onboarding-assets/ && cp -R src/built-ins/. dist/built-ins/

$ node scripts/run-typecheck-build-gaps.mjs --runtime-assets-only
[typecheck:build-gaps] server runtime assets present in dist: 7 file(s)
```

Regression simulation (guard catches the missing file):

```text
$ rm server/dist/built-ins/agents/reflection-coach/AGENTS.md
$ node scripts/run-typecheck-build-gaps.mjs --runtime-assets-only
[typecheck:build-gaps] Missing server runtime asset(s) in dist:
  - source: server/src/built-ins/agents/reflection-coach/AGENTS.md
    expected dist: server/dist/built-ins/agents/reflection-coach/AGENTS.md
Run pnpm --filter @paperclipai/server build and ensure source runtime asset trees are copied into dist.
```

Standing gate (full end-to-end):

```text
$ pnpm run typecheck:build-gaps
[typecheck:build-gaps] typechecking 4 workspace(s): paperclipai, @paperclipai/plugin-authoring-smoke-example, @paperclipai/plugin-llm-wiki, @paperclipai/ui
[typecheck:build-gaps] server runtime assets present in dist: 7 file(s)
```

## Risks

Low risk. The check only reads source and dist files during the
build-gap gate. The main tradeoff is that the gate now builds
`@paperclipai/server` so a clean checkout has generated `dist` content
to validate.

## Model Used

OpenAI Codex, GPT-5 based coding agent with repository tool use and
shell 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
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [ ] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.713.0-canary.1
2026-07-13 08:35:30 -07:00
DottaandPaperclip c36f1a4afd fix(ui): make mobile decision rows readable (#9472)
## Thinking Path

> - Paperclip is the open source control plane people use to coordinate
AI-agent companies
> - Human operators use the Decisions attention queue to review and
resolve work that needs them
> - Decision rows were composed as a fixed content column plus a
right-side controls column
> - At phone widths, timestamps, actions, menus, and evidence thumbnails
compressed the decision headline until it was barely readable
> - This pull request makes each row respond to its own container width
and stacks metadata, content, evidence, and actions on narrow surfaces
while preserving the dense desktop layout
> - The benefit is a useful, thumb-reachable Decisions workflow on
phones and narrow side panels without regressing wide-screen density or
scrolling performance

## Linked Issues or Issue Description

No public GitHub issue exactly matches this bug, so it is described here
using the bug-report fields.

**What happened**

Decision rows used a fixed two-column layout. On narrow screens, the
right-hand timestamp, overflow menu, decision buttons, and optional
thumbnails squeezed the headline into a truncated sliver.

**Expected behavior**

Decision headlines should remain readable on mobile, supporting context
should flow below the headline, and primary actions should remain easy
to tap. Wide rows should retain the compact desktop presentation.

**Steps to reproduce**

1. Open the Decisions / What needs me surface with populated attention
items.
2. Reduce the row container to a phone-width layout (approximately
390px).
3. Observe rows with multiple actions or evidence thumbnails.

**Paperclip version / deployment mode**

Current `master`, board UI in local or hosted deployments.

**Related public work found during dedup search**

- Refs: #9311 — original What needs me attention queue work.
- Refs: #9468 — recent Decisions scrolling performance work preserved by
this change.

## What Changed

- Reworked `AttentionQueueRow` into a container-query-driven vertical
stack on narrow surfaces, with the existing compact layout restored at
wide row widths.
- Made decision titles wrap to two lines, moved project/evidence context
below the headline, and promoted actions to full-width mobile tap
targets.
- Preserved upstream row memoization and `content-visibility` scrolling
optimizations while rebasing onto current `master`.
- Added three 390px Storybook scenarios covering populated rows,
type/detail variants, and snoozed/dismissed curtains.
- Updated the focused row test to assert the new thumbnail/context
alignment.

## Verification

- `pnpm exec vitest run ui/src/components/AttentionQueueRow.test.tsx` —
1 file passed, 16 tests passed.
- `pnpm check:token-gates` — all token gates clean.
- `pnpm --filter @paperclipai/ui typecheck` — passed.
- `pnpm --filter @paperclipai/ui build-storybook` — completed
successfully.
- `git diff --check public/master...HEAD` — passed.

## Risks

- Low risk: the behavior is isolated to the Decisions row presentation
and its Storybook coverage.
- Container-query breakpoints could need future visual tuning for
unusual embedded widths, but the wide layout remains available at the
row-level breakpoint.
- The mobile layout increases row height by design in exchange for
readable content and usable actions.

> 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 coding agent. The exact model ID and context-window
size are not exposed to this runtime; reasoning, repository editing,
shell execution, and test execution capabilities 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-12 21:28:38 -05:00
8a0db228a6 perf(ui): improve Decisions scrolling performance (#9468)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Operators use the Decisions page to review an uncapped attention
feed across active, snoozed, and dismissed items
> - Large feeds mounted every row eagerly, and routine interactions
re-rendered the full queue
> - That made initial paint and scrolling progressively slower as
decision history accumulated
> - This pull request bounds rendering, stabilizes row props, and lets
off-screen rows skip layout and paint work
> - The benefit is a responsive Decisions page even for companies with
large attention histories

## Linked Issues or Issue Description

### What happened?

Opening `/decisions` for a company with a large attention history
eagerly mounted every visible-feed row. Expanding, selecting,
dismissing, snoozing, or restoring an item could also re-render the
entire queue.

### Expected behavior

The page should render a bounded initial window, progressively reveal
more rows near the scroll boundary, and avoid re-rendering unaffected
rows during interactions.

### Steps to reproduce

1. Populate a company with hundreds of attention items.
2. Open `/decisions`.
3. Scroll and interact with individual rows.
4. Observe increasing initial render, layout, paint, and interaction
cost on the previous implementation.

### Paperclip version or commit

Reproduced on `master` before this PR.

### Deployment and installation

Local development, built from source. This is a core UI issue, not
adapter- or database-specific.

### Additional context

Searched open public issues and PRs; no duplicate was found.

## What Changed

- Added a pure `planAttentionRenderRows` helper that allocates one
render budget across active groups and open snoozed/dismissed curtains
in document order.
- Render 50 rows initially and add 100 more when the Decisions page
approaches the scroll boundary.
- Memoized `AttentionQueueRow`, stabilized parent callbacks and inbox
dismissal actions, and passed row items through a shared expand
callback.
- Added `content-visibility: auto` and intrinsic containment so
accumulated off-screen rows avoid unnecessary layout and paint work.
- Added render-plan coverage and a regression test proving identical row
props do not re-render after a parent update.

## Verification

- `pnpm -C ui typecheck`
- `pnpm -C ui exec vitest run src/lib/attention.test.ts
src/components/AttentionQueueRow.test.tsx
src/components/Sidebar.test.tsx src/pages/Inbox.test.tsx` — 96 tests
passed
- `pnpm check:token-gates` — all gates clean

## Risks

- Low risk: the change is UI-only and does not alter API or database
contracts.
- The main behavioral risk is incorrect row-budget accounting across
collapsed groups or open curtains; the pure planner has focused tests
for ordering, truncation, and collapsed/closed sections.
- Progressive rendering means rows beyond the current budget are
intentionally absent until scrolling nears the boundary, matching the
existing Issues list pattern.

> This is a targeted performance fix and does not overlap planned core
feature work in `ROADMAP.md`.

## Model Used

- Anthropic Claude Fable 5 assisted with the implementation using
repository tools and code execution.
- OpenAI Codex `gpt-5.6-sol` prepared and verified the PR with high
reasoning effort, repository tools, shell execution, and
GitHub/Paperclip API 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)
- [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
documentation changes were required for this UI-only behavior)
- [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: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-12 20:44:52 -05:00
DottaandPaperclip c8253e3641 fix(adapters): inject execution contract once per fresh heartbeat (#9469)
## Thinking Path

> - Paperclip coordinates AI-agent work through repeated heartbeat runs.
> - Adapter prompts combine a default heartbeat template with scoped
wake context.
> - Fresh heartbeats received the same execution contract from both
layers, wasting prompt tokens and obscuring which layer owns the
contract.
> - Resume deltas and template-less adapters do not share that
composition path, so removing the wake-payload copy unconditionally
would drop required guidance.
> - Empty comment batches also emitted instructions and metadata that
only matter when comments exist.
> - This pull request makes execution-contract inclusion explicit by
prompt path, preserves OpenClaw gateway behavior, and suppresses no-op
comment boilerplate.
> - The benefit is one contract per heartbeat path and roughly 300 fewer
prompt tokens on a fresh zero-comment wake.

## Linked Issues or Issue Description

- Fixes #9221
- Refs #9200
- Refs #7634

## What Changed

- Stop emitting the execution-contract paragraph from fresh scoped wake
payloads because the default heartbeat template already contains the
full contract.
- Keep the contract in resume deltas, and add `includeExecutionContract`
for adapters that do not render the default heartbeat template.
- Opt `openclaw-gateway` into wake-payload contract rendering so
template-less gateway runs retain the guidance.
- Omit comment-batch acknowledgement/fetch guidance and empty `pending
comments` / `latest comment id` metadata when a fresh wake has no
pending comments.
- Add regression and acceptance coverage proving composed fresh prompts
contain `Execution contract` exactly once while resume and template-less
paths retain it.

Measured effect: the fresh zero-comment wake block drops from 1,840 to
855 characters (about 300 tokens saved per fresh heartbeat; about 220 on
comment wakes), and the composed fresh prompt contains `Execution
contract` once instead of twice.

## Verification

- `npx vitest run packages/adapter-utils/src/server-utils.test.ts` — 63
passed
- `npx vitest run server/src/__tests__/codex-local-execute.test.ts` — 13
passed
- `npx vitest run
server/src/__tests__/heartbeat-comment-wake-batching.test.ts
server/src/__tests__/openclaw-gateway-adapter.test.ts
server/src/__tests__/low-trust-red-team-routes.test.ts` — 27 passed
- `pnpm --filter @paperclipai/adapter-utils typecheck` — passed
- `pnpm --filter @paperclipai/adapter-openclaw-gateway typecheck` —
passed

## Risks

- Low risk: prompt text and adapter composition only; no database or API
migration.
- The main compatibility risk is a template-less adapter losing the
contract. The explicit option and OpenClaw gateway regression coverage
protect the known template-less path.
- External adapters that call `renderPaperclipWakePrompt` directly can
opt into `includeExecutionContract: true` when they do not render the
default template.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, GPT-5.4, reasoning mode with tool use and code
execution; context-window size is 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-12 20:41:52 -05:00
DottaandPaperclip 5dff52631d fix(heartbeat): throttle redundant issue re-wakes (#9470)
## Thinking Path

> - Paperclip is the open source control plane people use to coordinate
AI agents and their work
> - Heartbeat admission decides when an agent should start another
adapter session for an issue
> - After process-loss recovery, assignment pollers and reconcilers can
repeatedly request another wake while the issue remains `in_progress`
> - When the preceding runs succeeded without issue-visible progress,
those event-free wakes provide no new information but still pay the full
cost of an adapter session
> - Existing liveness evidence is too broad for this case because
workspace tool calls can make a run look active without moving the issue
> - This pull request adds an issue-scoped admission throttle for
consecutive no-progress re-wakes while preserving every wake that
carries new information or recovery intent
> - The benefit is bounded recovery cost without delaying comments,
operator actions, failures, or other meaningful events

## Linked Issues or Issue Description

No public GitHub issue exists for this bug.

**What happened?**

After a process died, external wake drivers could re-wake the same agent
for the same `in_progress` issue every few seconds. Each succeeded run
that produced no issue-visible progress could be followed by another
full adapter session despite no new issue input. In the observed
recovery smoke, one recovery consumed 25 sessions and 2.4× the
direct-run cost.

**Expected behavior**

Repeated event-free re-wakes should back off after consecutive
successful runs produce no issue-visible progress. Any new information,
explicit operator intent, or failed-run recovery should continue
immediately.

**Steps to reproduce**

1. Start an issue heartbeat and simulate process loss while the issue
remains `in_progress`.
2. Allow assignment/reconciliation drivers to request repeated
event-free wakes for the same agent and issue.
3. Complete each follow-up run successfully without adding a comment,
issue mutation, document, work product, interaction, or continuation.
4. Observe repeated adapter sessions starting every few seconds without
new issue input.

**Environment**

- Version: reproduced on `master` before this change
- Deployment: local development, built from source
- Adapter scope: core bug; not adapter-specific
- Database: reproduced and tested with embedded Postgres

## What Changed

- Add a pure issue re-wake throttle that detects consecutive succeeded
runs without issue-visible progress and applies a 120-second exponential
cooldown capped at 30 minutes.
- Gate event-free `enqueueWakeup` requests and return the explicit skip
reason `issue_rewake_throttled` while the cooldown is active.
- Always bypass throttling for comment wakes, new issue activity,
explicit resumes, `forceFreshSession`, event-shaped reasons, and
post-failure recovery.
- Add focused pure unit coverage and database-backed heartbeat admission
coverage for throttle and bypass behavior.

## Verification

- `cd server && pnpm vitest run
src/__tests__/issue-rewake-throttle.test.ts` — 12 passed.
- `cd server && pnpm vitest run
src/__tests__/heartbeat-issue-rewake-throttle.test.ts` — 6 passed with
embedded Postgres.
- `cd server && pnpm run typecheck` — passed.
- Neighbor suites previously verified:
`heartbeat-dependency-scheduling`, `heartbeat-process-recovery`,
`run-continuations`, `heartbeat-issue-liveness-escalation`,
`recovery-stale-issue-lock-sweep`, and `heartbeat-comment-wake-batching`
— 131 tests passed.

## Risks

- A progress classifier that is too narrow could defer a legitimate
event-free poll; the cooldown is bounded and new issue activity bypasses
it immediately.
- A progress classifier that is too broad could allow the original
heartbeat storm; tests intentionally distinguish issue-visible mutations
from workspace-only activity.
- Low compatibility risk: no schema, API contract, or migration 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 coding agent. The runtime does not expose the exact
underlying model ID or context-window size; reasoning, terminal tool
use, code inspection, GitHub CLI access, 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 public PR 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-12 20:38:27 -05:00