From a8bd012635dc0a7955ec45aae7479d0c1369b8ba Mon Sep 17 00:00:00 2001 From: Dotta <34892728+cryppadotta@users.noreply.github.com> Date: Tue, 27 Oct 2026 20:55:13 -0500 Subject: [PATCH] fix(evals): apply reviewed lock corrections to reports and qualification images (#17937) https://entire.com/gh/paperclipai/-/trails/98/changes/paperclip/98 ## Thinking Path > - Paperclip manages agents and records their work. > - Product E2E campaigns measure real agent behavior and model spend. > - A paid hosted run completed both cases and all ten model receipts. > - Its report job could not install dependencies from the committed lock. > - The trusted checkout needs a reviewed dependency correction. > - This change applies a reviewed lock correction before the frozen report install. ## Linked Issues or Issue Description Refs: #17928 **Description** The report in [run 40576181788](https://github.com/paperclipai/paperclip/actions/runs/40576181788) failed with `ERR_PNPM_LOCKFILE_CONFIG_MISMATCH`. Both paid cases had passed. The worker and build jobs already restored the resolved source lock, but the report did not. **Steps to reproduce** Dispatch the bounded daily campaign on the default branch with a stale committed lock configuration. Workers use the resolved lock. The report uses the stale lock and fails before report generation. **Expected behavior** The report installs frozen dependencies from a verified lock for the exact trusted source. Evidence can be reported without repeating paid work. ## What Changed - Apply a reviewed lock correction from the trusted report checkout before its frozen install. Use the same correction for the qualification image build, which also requires a compatible frozen lock. - Pin the original lock, correction and output SHA-256. The trusted authorization job rejects unknown inputs before any paid work. - Apply the same correction to trusted manual history publication. Qualification image builds apply it only when their target equals the workflow revision; other targets keep their own lock. - Update existing Claude ACP and postgres patch identities and link the declared yaml dependency. Existing package tarball integrity entries stay unchanged; the declared yaml dependency adds exactly yaml@2.9.1 with pinned integrity. - Keep runtime registry resolution and worker target locks out of the credential-bearing report. - Test valid correction, idempotence and changed-lock, changed-patch and wrong-output rejection. ## Verification - Focused workflow and lock-correction tests: 36 passed. - `actionlint .github/workflows/runner-full-stack-e2e.yml` passed. - Original worker evidence: 2/2 passed, ten final model receipts, zero unresolved model requests. - The original report was regenerated from retained evidence with zero provider calls and saved privately with replay provenance. - Broader repository checks run in CI. Prior full Product checks passed for #17928. ## Risks The correction is tied to the reviewed committed lock. Dependency input changes need a reviewed correction update. No new registry version or lifecycle script can enter the privileged report through this fix. The original failed workflow stays failed. No root lockfile is committed. ## Model Used OpenAI Codex, GPT-6 family, with reasoning, repository inspection and code execution. The exact serving model ID and context window are not exposed to this session. ## 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 --- .github/workflows/docker-runner-check.yml | 10 + .github/workflows/runner-full-stack-e2e.yml | 18 + tests/runner-e2e/OPERATIONS.md | 16 + tests/runner-e2e/README.md | 14 +- tests/runner-e2e/prepare-report-lock.d.mts | 1 + tests/runner-e2e/prepare-report-lock.mjs | 31 + tests/runner-e2e/prepare-report-lock.test.ts | 40 ++ tests/runner-e2e/report-lock.json | 6 + tests/runner-e2e/report-lock.patch | 612 +++++++++++++++++++ tests/runner-e2e/workflow-security.test.ts | 23 +- tests/runner-e2e/workflow-target.test.ts | 20 +- 11 files changed, 784 insertions(+), 7 deletions(-) create mode 100644 tests/runner-e2e/prepare-report-lock.d.mts create mode 100644 tests/runner-e2e/prepare-report-lock.mjs create mode 100644 tests/runner-e2e/prepare-report-lock.test.ts create mode 100644 tests/runner-e2e/report-lock.json create mode 100644 tests/runner-e2e/report-lock.patch diff --git a/.github/workflows/docker-runner-check.yml b/.github/workflows/docker-runner-check.yml index f9a2e44e408..5dfc132f576 100644 --- a/.github/workflows/docker-runner-check.yml +++ b/.github/workflows/docker-runner-check.yml @@ -164,6 +164,16 @@ jobs: with: node-version: 24 package-manager-cache: false + - name: Apply reviewed qualification lock corrections + if: inputs.release_run_id == '' && (inputs.build_eval_image || inputs.publish_eval_image) + env: + TARGET_SHA: ${{ needs.authorize_manual.outputs.target_sha }} + run: | + set -euo pipefail + if [ "$TARGET_SHA" = "$GITHUB_SHA" ]; then + node tests/runner-e2e/prepare-report-lock.mjs + fi + - name: Resolve source dependencies without lifecycle scripts if: inputs.release_run_id == '' run: | diff --git a/.github/workflows/runner-full-stack-e2e.yml b/.github/workflows/runner-full-stack-e2e.yml index bc285f4b695..c1a402d1a4c 100644 --- a/.github/workflows/runner-full-stack-e2e.yml +++ b/.github/workflows/runner-full-stack-e2e.yml @@ -187,6 +187,18 @@ jobs: echo '::notice title=Paid runner routing::Using a standard GitHub-hosted runner' fi + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + ref: ${{ github.sha }} + persist-credentials: false + + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 + with: + node-version: 24 + + - name: Preflight reviewed report dependencies before paid admission + run: node tests/runner-e2e/prepare-report-lock.mjs + target_lock: name: Resolve target pnpm lockfile needs: authorize @@ -1273,6 +1285,9 @@ jobs: with: version: 9.15.4 + - name: Apply reviewed reporting lock corrections + run: node tests/runner-e2e/prepare-report-lock.mjs + - name: Install pinned reporting dependencies run: pnpm install --frozen-lockfile --ignore-scripts --store-dir "${{ runner.temp }}/eval-report-store" @@ -1500,6 +1515,9 @@ jobs: # Use a job-local store and disable lifecycle scripts throughout install. # OIDC is available to every step, even before the AWS credential exchange. + - name: Apply reviewed publication lock corrections + run: node tests/runner-e2e/prepare-report-lock.mjs + - name: Install pinned publication dependencies run: pnpm install --frozen-lockfile --ignore-scripts --store-dir "${{ runner.temp }}/eval-publisher-store" diff --git a/tests/runner-e2e/OPERATIONS.md b/tests/runner-e2e/OPERATIONS.md index 53dfa5b570f..9ba8341a49c 100644 --- a/tests/runner-e2e/OPERATIONS.md +++ b/tests/runner-e2e/OPERATIONS.md @@ -951,3 +951,19 @@ this eval project. Keep it limited to the trusted harness/provider runtime; never expose it to test prompts or unrelated clients. The project check is not an attempt-isolation guarantee. Indexing verification is a separate retained or scheduled check; the manual launcher alone does not perform it. + +### Hosted report dependencies + +The trusted report job applies a reviewed `report-lock.patch` before its frozen +install. `report-lock.json` pins the input lock, patch and resulting lock hashes. +This updates existing patch identities and the already declared yaml dependency +without registry resolution. The worker target and its lock artifact never +control report dependencies. An unknown committed lock fails before install; +update and review this correction when dependency inputs change. The original +failed run remains failed when retained evidence gets a new presentation. + +The trusted authorization job checks this correction before catalog/build and +paid work. Unknown dependency locks fail before model admission. Manual history +publication applies the same correction before its frozen install. Qualification +image builds apply it only when target and workflow revisions match; a different +target keeps its own lock and does not require these reporting helper files. diff --git a/tests/runner-e2e/README.md b/tests/runner-e2e/README.md index af2ba3758b4..5ef908f975f 100644 --- a/tests/runner-e2e/README.md +++ b/tests/runner-e2e/README.md @@ -1272,9 +1272,17 @@ intentionally uncommitted workspace patch while keeping every target job on one identical dependency resolution. The shared-build job compiles the selected campaign's TypeScript outputs and native binaries once, then each paid cell verifies and extracts the immutable bundle. Remote native cells similarly reuse -one verified provider pack. Report -sanitization and AWS history publication do not consume the target lockfile; -they explicitly check out and install from the trusted workflow commit. The +one verified provider pack. Report sanitization and AWS history publication +explicitly check out the trusted workflow commit. The report applies the +reviewed, hash-pinned `report-lock.patch` to the committed lock before its +frozen install. It does not resolve registry versions at run time or accept a +worker target lock. The patch changes existing package patch identities and +links the already declared yaml dependency; existing package tarball integrity entries +stay unchanged. The correction adds exactly yaml@2.9.1 with pinned integrity. The +trusted authorization job rejects unknown locks before paid work. Manual history +publication uses the same reviewed correction. Qualification image builds apply +it only to a target equal to the workflow revision; other targets keep their own +lock. Unknown lock contents fail before installation. The workflow definition, runner-group permission, and protected-environment deployment still come from the default branch. Do not select the target branch in GitHub's **Use workflow from** control. diff --git a/tests/runner-e2e/prepare-report-lock.d.mts b/tests/runner-e2e/prepare-report-lock.d.mts new file mode 100644 index 00000000000..a6314304c3f --- /dev/null +++ b/tests/runner-e2e/prepare-report-lock.d.mts @@ -0,0 +1 @@ +export function prepareReportLock(root?: string): Promise<'already-reviewed' | 'reviewed-correction'>; diff --git a/tests/runner-e2e/prepare-report-lock.mjs b/tests/runner-e2e/prepare-report-lock.mjs new file mode 100644 index 00000000000..587a1428592 --- /dev/null +++ b/tests/runner-e2e/prepare-report-lock.mjs @@ -0,0 +1,31 @@ +import { createHash } from 'node:crypto'; +import { execFileSync } from 'node:child_process'; +import { readFile, writeFile, mkdtemp, rm } from 'node:fs/promises'; +import path from 'node:path'; +import { tmpdir } from 'node:os'; +import { pathToFileURL } from 'node:url'; + +const sha256 = value => createHash('sha256').update(value).digest('hex'); +export async function prepareReportLock(root = path.resolve(import.meta.dirname, '../..')) { + const policy = JSON.parse(await readFile(path.join(root, 'tests/runner-e2e/report-lock.json'), 'utf8')); + const lockPath = path.join(root, 'pnpm-lock.yaml'); + const bytes = await readFile(lockPath), current = sha256(bytes); + if (current === policy.outputSha256) return 'already-reviewed'; + if (current !== policy.inputSha256) throw new Error('Reporting lock changed; review the dependency correction before install'); + const patch = await readFile(path.join(root, 'tests/runner-e2e/report-lock.patch')); + if (sha256(patch) !== policy.patchSha256) throw new Error('Reviewed reporting lock patch changed'); + const result = execFileSync('git', ['apply', '--numstat', '-'], { cwd: root, input: patch, encoding: 'utf8' }); + if (!/^\d+\s+\d+\s+pnpm-lock\.yaml\n$/.test(result)) throw new Error('Reporting correction must change only the lockfile'); + const temporary = await mkdtemp(path.join(tmpdir(), 'eval-reviewed-lock-')); + try { + await writeFile(path.join(temporary, 'pnpm-lock.yaml'), bytes); + execFileSync('git', ['apply', '-'], { cwd: temporary, input: patch }); + const corrected = await readFile(path.join(temporary, 'pnpm-lock.yaml')); + if (sha256(corrected) !== policy.outputSha256) throw new Error('Reviewed reporting lock result changed'); + await writeFile(lockPath, corrected); + return 'reviewed-correction'; + } finally { await rm(temporary, { recursive: true, force: true }); } +} +if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) { + console.log(await prepareReportLock()); +} diff --git a/tests/runner-e2e/prepare-report-lock.test.ts b/tests/runner-e2e/prepare-report-lock.test.ts new file mode 100644 index 00000000000..d56c0d263d0 --- /dev/null +++ b/tests/runner-e2e/prepare-report-lock.test.ts @@ -0,0 +1,40 @@ +import { mkdtemp, mkdir, readFile, writeFile, copyFile, rm } from 'node:fs/promises'; +import { createHash } from 'node:crypto'; +import { execFileSync } from 'node:child_process'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { expect, it } from 'vitest'; +import { parse } from 'yaml'; +import { prepareReportLock } from './prepare-report-lock.mjs'; + +it.each(['valid', 'unknown-lock', 'changed-patch', 'wrong-output'])( + 'installs only the reviewed dependency correction: %s', async variant => { + const root = await mkdtemp(path.join(tmpdir(), 'eval-report-lock-test-')); + const here = import.meta.dirname, relative = path.join(root, 'tests/runner-e2e'); + try { + await mkdir(relative, { recursive: true }); + for (const file of ['report-lock.json', 'report-lock.patch']) await copyFile(path.join(here, file), path.join(relative, file)); + const input = execFileSync('git', ['show', 'HEAD:pnpm-lock.yaml'], { cwd: path.resolve(here, '../..') }); + const policy = JSON.parse(await readFile(path.join(relative, 'report-lock.json'), 'utf8')); + expect(createHash('sha256').update(input).digest('hex')).toBe(policy.inputSha256); + const lock = path.join(root, 'pnpm-lock.yaml'); + await writeFile(lock, variant === 'unknown-lock' ? 'unknown\n' : input); + if (variant === 'changed-patch') await writeFile(path.join(relative, 'report-lock.patch'), 'changed'); + if (variant === 'wrong-output') { policy.outputSha256 = '0'.repeat(64); await writeFile(path.join(relative, 'report-lock.json'), JSON.stringify(policy)); } + if (variant === 'valid') { + expect(await prepareReportLock(root)).toBe('reviewed-correction'); + expect(createHash('sha256').update(await readFile(lock)).digest('hex')).toBe(policy.outputSha256); + expect(await prepareReportLock(root)).toBe('already-reviewed'); + const before = parse(input.toString()).packages; + const after = parse(await readFile(lock, 'utf8')).packages; + expect(Object.keys(after).filter(key => !Object.hasOwn(before, key))).toEqual(['yaml@2.9.1']); + for (const [key, value] of Object.entries(before)) expect(after[key]).toEqual(value); + expect(after['yaml@2.9.1'].resolution.integrity).toBe('sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw=='); + + } else { + await expect(prepareReportLock(root)).rejects.toThrow(); + expect(await readFile(lock)).toEqual(variant === 'unknown-lock' ? Buffer.from('unknown\n') : input); + } + } finally { await rm(root, { recursive: true, force: true }); } + }, +); diff --git a/tests/runner-e2e/report-lock.json b/tests/runner-e2e/report-lock.json new file mode 100644 index 00000000000..4dd5d2bdeff --- /dev/null +++ b/tests/runner-e2e/report-lock.json @@ -0,0 +1,6 @@ +{ + "inputSha256": "893496dddc21c31bd812ea106ac30d1515dda305eb1dd183007d89cf5b1bab4d", + "outputSha256": "c7f23021335b60da0cff1dd4c75cf8b948333ef3165d7d1703eb79a589edb798", + "patchSha256": "c7c11e899c12e6a030fe1554a8ceee5f21689a3a4f19956746e852050049cc49", + "basis": "Reviewed corrections to existing patch hashes and the already declared yaml workspace dependency. Existing package tarball integrity entries are unchanged. The only added package is yaml@2.9.1 with its exact integrity pinned by this reviewed correction." +} diff --git a/tests/runner-e2e/report-lock.patch b/tests/runner-e2e/report-lock.patch new file mode 100644 index 00000000000..84a0bcac131 --- /dev/null +++ b/tests/runner-e2e/report-lock.patch @@ -0,0 +1,612 @@ +--- a/pnpm-lock.yaml ++++ b/pnpm-lock.yaml +@@ -16,7 +16,7 @@ + + patchedDependencies: + '@agentclientprotocol/claude-agent-acp@0.73.0': +- hash: riqgguivxjxydoydnzpedjy5au ++ hash: xjlrz3rllh2ztafbdiywpfh2rq + path: patches/@agentclientprotocol__claude-agent-acp@0.73.0.patch + '@agentclientprotocol/codex-acp@1.6.2': + hash: 2iynuypg76nxmydiylgtffhr7e +@@ -49,7 +49,7 @@ + hash: 55uhvnotpqyiy37rn3pqpukhei + path: patches/embedded-postgres@18.1.0-beta.16.patch + postgres@3.4.9: +- hash: sryle6qd5qfmnxvoebal4gashi ++ hash: 6q4cic6qawywsyeo2spgnjamda + path: patches/postgres@3.4.9.patch + + importers: +@@ -73,7 +73,10 @@ + version: 7.0.2 + vitest: + specifier: ^5.0.3 +- version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) ++ yaml: ++ specifier: ^2.8.1 ++ version: 2.9.1 + + cli: + dependencies: +@@ -133,7 +136,7 @@ + version: 17.4.2 + drizzle-orm: + specifier: 0.45.2 +- version: 0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=sryle6qd5qfmnxvoebal4gashi)) ++ version: 0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=6q4cic6qawywsyeo2spgnjamda)) + embedded-postgres: + specifier: ^18.1.0-beta.16 + version: 18.1.0-beta.16(patch_hash=55uhvnotpqyiy37rn3pqpukhei) +@@ -180,7 +183,7 @@ + dependencies: + '@agentclientprotocol/claude-agent-acp': + specifier: ^0.73.0 +- version: 0.73.0(patch_hash=riqgguivxjxydoydnzpedjy5au)(@anthropic-ai/sdk@0.129.0(zod@4.6.5))(@modelcontextprotocol/sdk@1.31.0(zod@4.6.5)) ++ version: 0.73.0(patch_hash=xjlrz3rllh2ztafbdiywpfh2rq)(@anthropic-ai/sdk@0.129.0(zod@4.6.5))(@modelcontextprotocol/sdk@1.31.0(zod@4.6.5)) + '@anthropic-ai/sdk': + specifier: 0.129.0 + version: 0.129.0(zod@4.6.5) +@@ -310,7 +313,7 @@ + version: 7.0.2 + vitest: + specifier: ^5.0.3 +- version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + + packages/adapters/hermes-gateway: + dependencies: +@@ -326,7 +329,7 @@ + version: 7.0.2 + vitest: + specifier: ^5.0.3 +- version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + + packages/adapters/kimi-local: + dependencies: +@@ -405,13 +408,13 @@ + version: link:../shared + drizzle-orm: + specifier: ^0.45.2 +- version: 0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=sryle6qd5qfmnxvoebal4gashi)) ++ version: 0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=6q4cic6qawywsyeo2spgnjamda)) + embedded-postgres: + specifier: ^18.1.0-beta.16 + version: 18.1.0-beta.16(patch_hash=55uhvnotpqyiy37rn3pqpukhei) + postgres: + specifier: ^3.4.9 +- version: 3.4.9(patch_hash=sryle6qd5qfmnxvoebal4gashi) ++ version: 3.4.9(patch_hash=6q4cic6qawywsyeo2spgnjamda) + devDependencies: + '@types/node': + specifier: ^24.0.0 +@@ -427,7 +430,7 @@ + version: 7.0.2 + vitest: + specifier: ^5.0.3 +- version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + + packages/google-sheets-mcp-server: + dependencies: +@@ -449,7 +452,7 @@ + version: 7.0.2 + vitest: + specifier: ^5.0.3 +- version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + + packages/kv-demo-mcp-server: + dependencies: +@@ -468,7 +471,7 @@ + version: 7.0.2 + vitest: + specifier: ^5.0.3 +- version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + + packages/mcp-server: + dependencies: +@@ -490,7 +493,7 @@ + version: 7.0.2 + vitest: + specifier: ^5.0.3 +- version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + + packages/paperclip-eval-kernel: + devDependencies: +@@ -505,7 +508,7 @@ + dependencies: + '@agentclientprotocol/claude-agent-acp': + specifier: 0.73.0 +- version: 0.73.0(patch_hash=riqgguivxjxydoydnzpedjy5au)(@anthropic-ai/sdk@0.129.0(zod@4.6.5))(@modelcontextprotocol/sdk@1.31.0(zod@4.6.5)) ++ version: 0.73.0(patch_hash=xjlrz3rllh2ztafbdiywpfh2rq)(@anthropic-ai/sdk@0.129.0(zod@4.6.5))(@modelcontextprotocol/sdk@1.31.0(zod@4.6.5)) + '@agentclientprotocol/codex-acp': + specifier: 1.6.2 + version: 1.6.2(patch_hash=2iynuypg76nxmydiylgtffhr7e) +@@ -561,7 +564,7 @@ + version: 19.2.5(@types/react@19.2.18) + '@vitejs/plugin-react': + specifier: ^4.7.0 +- version: 4.7.0(vite@6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)) ++ version: 4.7.0(vite@6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)(yaml@2.9.1)) + axe-core: + specifier: ^4.12.1 + version: 4.13.0 +@@ -579,10 +582,10 @@ + version: 7.0.2 + vite: + specifier: ^6.1.0 +- version: 6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15) ++ version: 6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)(yaml@2.9.1) + vitest: + specifier: ^5.0.3 +- version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)) ++ version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)(yaml@2.9.1)) + + packages/plugins/create-paperclip-plugin: + dependencies: +@@ -629,7 +632,7 @@ + version: 7.0.2 + vitest: + specifier: ^5.0.3 +- version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + + packages/plugins/examples/plugin-file-browser-example: + dependencies: +@@ -747,7 +750,7 @@ + version: 7.0.2 + vitest: + specifier: ^5.0.3 +- version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + + packages/plugins/plugin-llm-wiki: + devDependencies: +@@ -786,7 +789,7 @@ + version: 7.0.2 + vitest: + specifier: ^5.0.3 +- version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + + packages/plugins/plugin-workspace-diff: + dependencies: +@@ -820,7 +823,7 @@ + version: 7.0.2 + vitest: + specifier: ^5.0.3 +- version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + + packages/plugins/sdk: + dependencies: +@@ -880,7 +883,7 @@ + version: 7.0.2 + vitest: + specifier: ^5.0.3 +- version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + + packages/teams-catalog: + devDependencies: +@@ -895,7 +898,7 @@ + version: 0.5.0 + '@agentclientprotocol/claude-agent-acp': + specifier: 0.73.0 +- version: 0.73.0(patch_hash=riqgguivxjxydoydnzpedjy5au)(@anthropic-ai/sdk@0.129.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.31.0(zod@4.4.3)) ++ version: 0.73.0(patch_hash=xjlrz3rllh2ztafbdiywpfh2rq)(@anthropic-ai/sdk@0.129.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.31.0(zod@4.4.3)) + '@agentclientprotocol/codex-acp': + specifier: 1.6.2 + version: 1.6.2(patch_hash=2iynuypg76nxmydiylgtffhr7e) +@@ -1006,7 +1009,7 @@ + version: 2.1.0(@grpc/grpc-js@1.14.5)(nice-grpc-common@2.0.4)(nice-grpc@2.1.17) + '@vercel/connect': + specifier: 2.3.3 +- version: 2.3.3(@chat-adapter/slack@4.39.0(patch_hash=226jj24akljccsfbw7bcxujz4u)(ai@7.0.130(zod@4.4.3))(zod@4.4.3))(@modelcontextprotocol/sdk@1.31.0(zod@4.4.3))(ai@7.0.130(zod@4.4.3))(better-auth@1.7.2(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=sryle6qd5qfmnxvoebal4gashi)))(pg@8.18.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)))) ++ version: 2.3.3(@chat-adapter/slack@4.39.0(patch_hash=226jj24akljccsfbw7bcxujz4u)(ai@7.0.130(zod@4.4.3))(zod@4.4.3))(@modelcontextprotocol/sdk@1.31.0(zod@4.4.3))(ai@7.0.130(zod@4.4.3))(better-auth@1.7.2(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=6q4cic6qawywsyeo2spgnjamda)))(pg@8.18.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)))) + acorn: + specifier: 8.18.0 + version: 8.18.0 +@@ -1024,7 +1027,7 @@ + version: 3.0.1(ajv@8.20.0) + better-auth: + specifier: 1.7.2 +- version: 1.7.2(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=sryle6qd5qfmnxvoebal4gashi)))(pg@8.18.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))) ++ version: 1.7.2(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=6q4cic6qawywsyeo2spgnjamda)))(pg@8.18.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))) + chat: + specifier: 4.39.0 + version: 4.39.0(ai@7.0.130(zod@4.4.3))(zod@4.4.3) +@@ -1045,7 +1048,7 @@ + version: 17.4.2 + drizzle-orm: + specifier: ^0.45.2 +- version: 0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=sryle6qd5qfmnxvoebal4gashi)) ++ version: 0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=6q4cic6qawywsyeo2spgnjamda)) + embedded-postgres: + specifier: ^18.1.0-beta.16 + version: 18.1.0-beta.16(patch_hash=55uhvnotpqyiy37rn3pqpukhei) +@@ -1167,10 +1170,10 @@ + version: 7.0.2 + vite: + specifier: ^8.2.2 +- version: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15) ++ version: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1) + vitest: + specifier: ^5.0.3 +- version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + + ui: + dependencies: +@@ -1321,10 +1324,10 @@ + version: 10.6.0(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(storybook@10.6.0(@types/react@19.2.18)(react@19.2.8)) + '@storybook/react-vite': + specifier: 10.5.10 +- version: 10.5.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(esbuild@0.28.2)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(rollup@4.63.1)(storybook@10.6.0(@types/react@19.2.18)(react@19.2.8))(typescript@7.0.2)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ version: 10.5.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(esbuild@0.28.2)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(rollup@4.63.1)(storybook@10.6.0(@types/react@19.2.18)(react@19.2.8))(typescript@7.0.2)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + '@tailwindcss/vite': + specifier: ^4.3.3 +- version: 4.3.3(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ version: 4.3.3(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + '@types/node': + specifier: ^24.0.0 + version: 24.13.3 +@@ -1336,7 +1339,7 @@ + version: 19.2.5(@types/react@19.2.18) + '@vitejs/plugin-react': + specifier: ^6.1.1 +- version: 6.1.1(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ version: 6.1.1(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + storybook: + specifier: 10.6.0 + version: 10.6.0(@types/react@19.2.18)(react@19.2.8) +@@ -1348,10 +1351,10 @@ + version: 7.0.2 + vite: + specifier: ^8.2.2 +- version: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15) ++ version: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1) + vitest: + specifier: ^5.0.3 +- version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + + packages: + +@@ -9256,6 +9259,11 @@ + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + ++ yaml@2.9.1: ++ resolution: {integrity: sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==} ++ engines: {node: '>= 14.6'} ++ hasBin: true ++ + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} +@@ -9316,7 +9324,7 @@ + + '@adobe/css-tools@4.5.0': {} + +- '@agentclientprotocol/claude-agent-acp@0.73.0(patch_hash=riqgguivxjxydoydnzpedjy5au)(@anthropic-ai/sdk@0.129.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.31.0(zod@4.4.3))': ++ '@agentclientprotocol/claude-agent-acp@0.73.0(patch_hash=xjlrz3rllh2ztafbdiywpfh2rq)(@anthropic-ai/sdk@0.129.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.31.0(zod@4.4.3))': + dependencies: + '@agentclientprotocol/sdk': 1.4.0(zod@4.4.3) + '@anthropic-ai/claude-agent-sdk': 0.3.286(@anthropic-ai/sdk@0.129.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.31.0(zod@4.4.3))(zod@4.4.3) +@@ -9325,7 +9333,7 @@ + - '@anthropic-ai/sdk' + - '@modelcontextprotocol/sdk' + +- '@agentclientprotocol/claude-agent-acp@0.73.0(patch_hash=riqgguivxjxydoydnzpedjy5au)(@anthropic-ai/sdk@0.129.0(zod@4.6.5))(@modelcontextprotocol/sdk@1.31.0(zod@4.6.5))': ++ '@agentclientprotocol/claude-agent-acp@0.73.0(patch_hash=xjlrz3rllh2ztafbdiywpfh2rq)(@anthropic-ai/sdk@0.129.0(zod@4.6.5))(@modelcontextprotocol/sdk@1.31.0(zod@4.6.5))': + dependencies: + '@agentclientprotocol/sdk': 1.4.0(zod@4.4.3) + '@anthropic-ai/claude-agent-sdk': 0.3.286(@anthropic-ai/sdk@0.129.0(zod@4.6.5))(@modelcontextprotocol/sdk@1.31.0(zod@4.6.5))(zod@4.4.3) +@@ -9907,12 +9915,12 @@ + optionalDependencies: + '@opentelemetry/api': 1.9.1 + +- '@better-auth/drizzle-adapter@1.7.2(@better-auth/core@1.7.2(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.10)(kysely@0.29.5)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=sryle6qd5qfmnxvoebal4gashi)))': ++ '@better-auth/drizzle-adapter@1.7.2(@better-auth/core@1.7.2(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.10)(kysely@0.29.5)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=6q4cic6qawywsyeo2spgnjamda)))': + dependencies: + '@better-auth/core': 1.7.2(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.10)(kysely@0.29.5)(nanostores@1.5.3) + '@better-auth/utils': 0.4.2 + optionalDependencies: +- drizzle-orm: 0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=sryle6qd5qfmnxvoebal4gashi)) ++ drizzle-orm: 0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=6q4cic6qawywsyeo2spgnjamda)) + + '@better-auth/kysely-adapter@1.7.2(@better-auth/core@1.7.2(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.10)(kysely@0.29.5)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(kysely@0.29.5)': + dependencies: +@@ -10974,11 +10982,11 @@ + '@img/sharp-win32-x64@0.35.4': + optional: true + +- '@joshwooding/vite-plugin-react-docgen-typescript@0.7.0(typescript@7.0.2)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))': ++ '@joshwooding/vite-plugin-react-docgen-typescript@0.7.0(typescript@7.0.2)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))': + dependencies: + glob: 13.0.6 + react-docgen-typescript: 2.4.0(typescript@7.0.2) +- vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15) ++ vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1) + optionalDependencies: + typescript: 7.0.2 + +@@ -13184,25 +13192,25 @@ + transitivePeerDependencies: + - '@types/react-dom' + +- '@storybook/builder-vite@10.5.10(esbuild@0.28.2)(rollup@4.63.1)(storybook@10.6.0(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))': +- dependencies: +- '@storybook/csf-plugin': 10.5.10(esbuild@0.28.2)(rollup@4.63.1)(storybook@10.6.0(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ '@storybook/builder-vite@10.5.10(esbuild@0.28.2)(rollup@4.63.1)(storybook@10.6.0(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))': ++ dependencies: ++ '@storybook/csf-plugin': 10.5.10(esbuild@0.28.2)(rollup@4.63.1)(storybook@10.6.0(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + storybook: 10.6.0(@types/react@19.2.18)(react@19.2.8) + ts-dedent: 2.3.0 +- vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15) ++ vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1) + transitivePeerDependencies: + - esbuild + - rollup + - webpack + +- '@storybook/csf-plugin@10.5.10(esbuild@0.28.2)(rollup@4.63.1)(storybook@10.6.0(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))': ++ '@storybook/csf-plugin@10.5.10(esbuild@0.28.2)(rollup@4.63.1)(storybook@10.6.0(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))': + dependencies: + storybook: 10.6.0(@types/react@19.2.18)(react@19.2.8) + unplugin: 2.3.11 + optionalDependencies: + esbuild: 0.28.2 + rollup: 4.63.1 +- vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15) ++ vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1) + + '@storybook/global@5.0.0': {} + +@@ -13228,11 +13236,11 @@ + '@types/react': 19.2.18 + '@types/react-dom': 19.2.5(@types/react@19.2.18) + +- '@storybook/react-vite@10.5.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(esbuild@0.28.2)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(rollup@4.63.1)(storybook@10.6.0(@types/react@19.2.18)(react@19.2.8))(typescript@7.0.2)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))': +- dependencies: +- '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@7.0.2)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ '@storybook/react-vite@10.5.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(esbuild@0.28.2)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(rollup@4.63.1)(storybook@10.6.0(@types/react@19.2.18)(react@19.2.8))(typescript@7.0.2)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))': ++ dependencies: ++ '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@7.0.2)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + '@rollup/pluginutils': 5.4.0(rollup@4.63.1) +- '@storybook/builder-vite': 10.5.10(esbuild@0.28.2)(rollup@4.63.1)(storybook@10.6.0(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ '@storybook/builder-vite': 10.5.10(esbuild@0.28.2)(rollup@4.63.1)(storybook@10.6.0(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + '@storybook/react': 10.5.10(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(storybook@10.6.0(@types/react@19.2.18)(react@19.2.8))(typescript@7.0.2) + empathic: 2.0.1 + magic-string: 0.30.21 +@@ -13242,7 +13250,7 @@ + resolve: 1.22.12 + storybook: 10.6.0(@types/react@19.2.18)(react@19.2.8) + tsconfig-paths: 4.2.0 +- vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15) ++ vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1) + optionalDependencies: + typescript: 7.0.2 + transitivePeerDependencies: +@@ -13335,12 +13343,12 @@ + postcss-selector-parser: 6.0.10 + tailwindcss: 4.3.3 + +- '@tailwindcss/vite@4.3.3(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))': ++ '@tailwindcss/vite@4.3.3(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))': + dependencies: + '@tailwindcss/node': 4.3.3 + '@tailwindcss/oxide': 4.3.3 + tailwindcss: 4.3.3 +- vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15) ++ vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1) + + '@tanstack/query-core@5.102.8': {} + +@@ -13758,14 +13766,14 @@ + dependencies: + execa: 5.1.1 + +- '@vercel/connect@2.3.3(@chat-adapter/slack@4.39.0(patch_hash=226jj24akljccsfbw7bcxujz4u)(ai@7.0.130(zod@4.4.3))(zod@4.4.3))(@modelcontextprotocol/sdk@1.31.0(zod@4.4.3))(ai@7.0.130(zod@4.4.3))(better-auth@1.7.2(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=sryle6qd5qfmnxvoebal4gashi)))(pg@8.18.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))))': ++ '@vercel/connect@2.3.3(@chat-adapter/slack@4.39.0(patch_hash=226jj24akljccsfbw7bcxujz4u)(ai@7.0.130(zod@4.4.3))(zod@4.4.3))(@modelcontextprotocol/sdk@1.31.0(zod@4.4.3))(ai@7.0.130(zod@4.4.3))(better-auth@1.7.2(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=6q4cic6qawywsyeo2spgnjamda)))(pg@8.18.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))))': + dependencies: + '@vercel/oidc': 3.8.9 + optionalDependencies: + '@chat-adapter/slack': 4.39.0(patch_hash=226jj24akljccsfbw7bcxujz4u)(ai@7.0.130(zod@4.4.3))(zod@4.4.3) + '@modelcontextprotocol/sdk': 1.31.0(zod@4.4.3) + ai: 7.0.130(zod@4.4.3) +- better-auth: 1.7.2(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=sryle6qd5qfmnxvoebal4gashi)))(pg@8.18.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))) ++ better-auth: 1.7.2(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=6q4cic6qawywsyeo2spgnjamda)))(pg@8.18.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))) + + '@vercel/oidc@3.2.0': {} + +@@ -13775,7 +13783,7 @@ + '@vercel/cli-exec': 1.0.1 + jose: 5.10.0 + +- '@vitejs/plugin-react@4.7.0(vite@6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15))': ++ '@vitejs/plugin-react@4.7.0(vite@6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)(yaml@2.9.1))': + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7) +@@ -13783,14 +13791,14 @@ + '@rolldown/pluginutils': 1.0.0-beta.27 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 +- vite: 6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15) ++ vite: 6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)(yaml@2.9.1) + transitivePeerDependencies: + - supports-color + +- '@vitejs/plugin-react@6.1.1(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))': ++ '@vitejs/plugin-react@6.1.1(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))': + dependencies: + '@rolldown/pluginutils': 1.0.1 +- vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15) ++ vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1) + + '@vitest/expect@3.2.4': + dependencies: +@@ -13800,23 +13808,23 @@ + chai: 5.3.3 + tinyrainbow: 2.0.0 + +- '@vitest/mocker@5.0.3(vite@6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15))': ++ '@vitest/mocker@5.0.3(vite@6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)(yaml@2.9.1))': + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + '@vitest/spy': 5.0.3 + estree-walker: 3.0.3 + magic-string: 1.4.3 + optionalDependencies: +- vite: 6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15) +- +- '@vitest/mocker@5.0.3(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))': ++ vite: 6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)(yaml@2.9.1) ++ ++ '@vitest/mocker@5.0.3(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))': + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + '@vitest/spy': 5.0.3 + estree-walker: 3.0.3 + magic-string: 1.4.3 + optionalDependencies: +- vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15) ++ vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1) + + '@vitest/pretty-format@3.2.4': + dependencies: +@@ -14042,10 +14050,10 @@ + + before-after-hook@4.0.0: {} + +- better-auth@1.7.2(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=sryle6qd5qfmnxvoebal4gashi)))(pg@8.18.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))): ++ better-auth@1.7.2(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=6q4cic6qawywsyeo2spgnjamda)))(pg@8.18.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))): + dependencies: + '@better-auth/core': 1.7.2(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.10)(kysely@0.29.5)(nanostores@1.5.3) +- '@better-auth/drizzle-adapter': 1.7.2(@better-auth/core@1.7.2(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.10)(kysely@0.29.5)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=sryle6qd5qfmnxvoebal4gashi))) ++ '@better-auth/drizzle-adapter': 1.7.2(@better-auth/core@1.7.2(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.10)(kysely@0.29.5)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=6q4cic6qawywsyeo2spgnjamda))) + '@better-auth/kysely-adapter': 1.7.2(@better-auth/core@1.7.2(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.10)(kysely@0.29.5)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(kysely@0.29.5) + '@better-auth/memory-adapter': 1.7.2(@better-auth/core@1.7.2(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.10)(kysely@0.29.5)(nanostores@1.5.3))(@better-auth/utils@0.4.2) + '@better-auth/mongo-adapter': 1.7.2(@better-auth/core@1.7.2(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.10)(kysely@0.29.5)(nanostores@1.5.3))(@better-auth/utils@0.4.2) +@@ -14063,11 +14071,11 @@ + zod: 4.4.3 + optionalDependencies: + drizzle-kit: 0.31.10 +- drizzle-orm: 0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=sryle6qd5qfmnxvoebal4gashi)) ++ drizzle-orm: 0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=6q4cic6qawywsyeo2spgnjamda)) + pg: 8.18.0 + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) +- vitest: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ vitest: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + transitivePeerDependencies: + - '@cloudflare/workers-types' + - '@opentelemetry/api' +@@ -14654,12 +14662,12 @@ + esbuild: 0.25.12 + tsx: 4.23.15 + +- drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=sryle6qd5qfmnxvoebal4gashi)): ++ drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9(patch_hash=6q4cic6qawywsyeo2spgnjamda)): + optionalDependencies: + '@opentelemetry/api': 1.9.1 + kysely: 0.29.5 + pg: 8.18.0 +- postgres: 3.4.9(patch_hash=sryle6qd5qfmnxvoebal4gashi) ++ postgres: 3.4.9(patch_hash=6q4cic6qawywsyeo2spgnjamda) + + dunder-proto@1.0.1: + dependencies: +@@ -16542,7 +16550,7 @@ + dependencies: + xtend: 4.0.2 + +- postgres@3.4.9(patch_hash=sryle6qd5qfmnxvoebal4gashi): {} ++ postgres@3.4.9(patch_hash=6q4cic6qawywsyeo2spgnjamda): {} + + powershell-utils@0.1.0: {} + +@@ -17587,7 +17595,7 @@ + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + +- vite@6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15): ++ vite@6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)(yaml@2.9.1): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.7) +@@ -17601,8 +17609,9 @@ + jiti: 2.7.0 + lightningcss: 1.33.0 + tsx: 4.23.15 +- +- vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15): ++ yaml: 2.9.1 ++ ++ vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1): + dependencies: + lightningcss: 1.33.0 + picomatch: 4.0.7 +@@ -17615,11 +17624,12 @@ + fsevents: 2.3.3 + jiti: 2.7.0 + tsx: 4.23.15 +- +- vitest@5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)): ++ yaml: 2.9.1 ++ ++ vitest@5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)(yaml@2.9.1)): + dependencies: + '@types/chai': 5.2.3 +- '@vitest/mocker': 5.0.3(vite@6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)) ++ '@vitest/mocker': 5.0.3(vite@6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)(yaml@2.9.1)) + chai: 6.3.0 + es-module-lexer: 2.3.2 + expect-type: 1.4.0 +@@ -17630,7 +17640,7 @@ + tinybench: 6.2.0 + tinyexec: 1.3.1 + tinyglobby: 0.2.17 +- vite: 6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15) ++ vite: 6.4.3(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.33.0)(tsx@4.23.15)(yaml@2.9.1) + why-is-node-running: 3.2.1 + optionalDependencies: + '@opentelemetry/api': 1.9.1 +@@ -17639,10 +17649,10 @@ + transitivePeerDependencies: + - msw + +- vitest@5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)): ++ vitest@5.0.3(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.4.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)): + dependencies: + '@types/chai': 5.2.3 +- '@vitest/mocker': 5.0.3(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) ++ '@vitest/mocker': 5.0.3(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) + chai: 6.3.0 + es-module-lexer: 2.3.2 + expect-type: 1.4.0 +@@ -17653,7 +17663,7 @@ + tinybench: 6.2.0 + tinyexec: 1.3.1 + tinyglobby: 0.2.17 +- vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15) ++ vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1) + why-is-node-running: 3.2.1 + optionalDependencies: + '@opentelemetry/api': 1.9.1 +@@ -17748,6 +17758,8 @@ + yallist@3.1.1: {} + + yallist@4.0.0: {} ++ ++ yaml@2.9.1: {} + + yargs-parser@21.1.1: {} + diff --git a/tests/runner-e2e/workflow-security.test.ts b/tests/runner-e2e/workflow-security.test.ts index bc740e62bd3..d68df923c6a 100644 --- a/tests/runner-e2e/workflow-security.test.ts +++ b/tests/runner-e2e/workflow-security.test.ts @@ -56,6 +56,10 @@ describe("public repository paid workflow security", () => { expect(manual).toContain('pnpm install --resolution-only --ignore-scripts --no-frozen-lockfile'); expect(manual).toContain('PAPERCLIP_RUNNER_LOCK_SHA256=$lock_sha'); expect(manual).toContain('docker logout ghcr.io'); + expect(manual.indexOf('Apply reviewed qualification lock corrections')).toBeLessThan(manual.indexOf('Resolve source dependencies without lifecycle scripts')); + expect(manual).toContain('node tests/runner-e2e/prepare-report-lock.mjs'); + expect(manual).toContain('if [ "$TARGET_SHA" = "$GITHUB_SHA" ]; then'); + }); it("uses the reviewed master branch for the first-party trusted PR workflow", async () => { @@ -275,7 +279,9 @@ describe("public repository paid workflow security", () => { "target_ref: ${{ steps.target.outputs.ref }}", ); expect(authorizeJob).toContain('echo "ref=refs/heads/$TARGET_BRANCH"'); - expect(authorizeJob).not.toContain("actions/checkout@"); + expect(authorizeJob.match(/actions\/checkout@/gu)).toHaveLength(1); + expect(authorizeJob).toContain("ref: ${{ github.sha }}"); + expect(authorizeJob).not.toContain("ref: ${{ needs.authorize.outputs.target_sha }}"); expect(authorizeJob).not.toContain("pnpm install"); expect(targetLockJob).toContain("name: Resolve target pnpm lockfile"); expect(targetLockJob).toContain("needs: authorize"); @@ -537,8 +543,8 @@ describe("public repository paid workflow security", () => { /ref: \$\{\{ needs\.authorize\.outputs\.target_sha \}\}/g, ), ).toHaveLength(6); - expect(fullStack.match(/ref: \$\{\{ github\.sha \}\}/g)).toHaveLength(2); - expect(fullStack.match(/persist-credentials: false/g)).toHaveLength(8); + expect(fullStack.match(/ref: \$\{\{ github\.sha \}\}/g)).toHaveLength(3); + expect(fullStack.match(/persist-credentials: false/g)).toHaveLength(9); expect(fullStack).not.toContain("ref: ${{ inputs.target_branch }}"); expect(fullStack).toContain( "PAPERCLIP_RUNNER_SOURCE_REVISION=${TARGET_SHA}", @@ -553,11 +559,22 @@ describe("public repository paid workflow security", () => { "ref: ${{ needs.authorize.outputs.target_sha }}", ); expect(reportJob).not.toContain("Download resolved target lockfile"); + expect(reportJob).toContain("run: node tests/runner-e2e/prepare-report-lock.mjs"); + expect(reportJob.indexOf("Apply reviewed reporting lock corrections")).toBeLessThan(reportJob.indexOf("Install pinned reporting dependencies")); + expect(reportJob).not.toContain("needs.target_lock.outputs"); + expect(historyJob).toContain("ref: ${{ github.sha }}"); expect(historyJob).not.toContain( "ref: ${{ needs.authorize.outputs.target_sha }}", ); expect(historyJob).not.toContain("Download resolved target lockfile"); + expect(historyJob).toContain("run: node tests/runner-e2e/prepare-report-lock.mjs"); + const authorization = fullStack.split(" authorize:\n")[1]!.split(" target_lock:\n")[0]!; + expect(authorization).toContain("ref: ${{ github.sha }}"); + expect(authorization).toContain("Preflight reviewed report dependencies before paid admission"); + expect(authorization).toContain("run: node tests/runner-e2e/prepare-report-lock.mjs"); + expect(authorization).not.toContain("environment:"); + expect(fullStack).toContain( "if: always() && !cancelled() && needs.catalog.result == 'success'", ); diff --git a/tests/runner-e2e/workflow-target.test.ts b/tests/runner-e2e/workflow-target.test.ts index 88aa5b6cb5c..8abc9f95e3e 100644 --- a/tests/runner-e2e/workflow-target.test.ts +++ b/tests/runner-e2e/workflow-target.test.ts @@ -1,5 +1,5 @@ import { spawnSync } from "node:child_process"; -import { mkdtemp, readFile, rm } from "node:fs/promises"; +import { mkdtemp, readFile, rm, access } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { describe, expect, it } from "vitest"; @@ -47,3 +47,21 @@ describe("paid workflow target authorization", () => { expect(result.output).toContain("ref=refs/heads/development\n"); }); }); + +describe("qualification image dependency correction", () => { + it.each([true, false])("applies the workflow correction only to its own source: %s", async sameSource => { + const workflow = await readFile(new URL("../../.github/workflows/docker-runner-check.yml", import.meta.url), "utf8"); + const step = workflow.split(" - name: Apply reviewed qualification lock corrections\n")[1]!.split("\n - ")[0]!; + const script = step.split(" run: |\n")[1]!.replace(/^ {10}/gm, ""); + const directory = await mkdtemp(path.join(os.tmpdir(), "eval-image-lock-target-")); + try { + const marker = path.join(directory, "called"); + const result = spawnSync("bash", ["-c", `node() { touch "$CALLED"; }\n${script}`], { + cwd: directory, encoding: "utf8", env: { ...process.env, GITHUB_SHA: queuedSha, + TARGET_SHA: sameSource ? queuedSha : advancedSha, CALLED: marker }, + }); + expect(result.status, result.stderr).toBe(0); + expect(await access(marker).then(() => true, () => false)).toBe(sameSource); + } finally { await rm(directory, { recursive: true, force: true }); } + }); +});