From 3580e7db133212adfb92cbf6949d4f293508b6e0 Mon Sep 17 00:00:00 2001 From: Igor Magdich Date: Fri, 7 Aug 2026 01:07:11 +0300 Subject: [PATCH 1/3] docs: state the registry-revision bump condition as rendered bytes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The module header told a contributor that any change to docs/design/setup-integration.md is a registry-revision bump. Read literally that requires a bump for a doc edit that changes no rendered byte — correcting stale prose, syncing a description — and a bump reclassifies every already-installed artifact as `managed-outdated`, sending every user through a regenerate for a file whose content did not change. The comment is the wrong side: §7 of that document states the rule as "whenever any generated file's bytes change", and it is the bytes rule the code implements — `markerLine` stamps `REGISTRY_REVISION` into each artifact and `classifyArtifact` compares the stored value against it. The header keeps the point it exists to make (the doc is the source of the platform facts this module mirrors) and now states the bump condition the way the code and §7 both do. Refs #73 --- src/platforms/shared.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/platforms/shared.ts b/src/platforms/shared.ts index 7be06d2..cb2d3a7 100644 --- a/src/platforms/shared.ts +++ b/src/platforms/shared.ts @@ -6,7 +6,9 @@ * (ADR-0006). `setup`, `doctor`, Team display, and the Launcher read these * records; they never keep parallel path/invocation tables. Official platform * facts and sources live in docs/design/setup-integration.md, which this module - * mirrors verbatim — a change there is a registry-revision bump here. + * mirrors verbatim; REGISTRY_REVISION is bumped whenever a change alters a + * generated artifact's rendered bytes (setup-integration.md §7) — a doc-only + * edit that changes no rendered byte must not bump it. */ import { createHash } from 'node:crypto'; import { closeSync, constants, fstatSync, openSync, readSync, realpathSync } from 'node:fs'; From 82c739024e88c2cdb129142ec2c4821594793226 Mon Sep 17 00:00:00 2001 From: Igor Magdich Date: Fri, 7 Aug 2026 01:07:24 +0300 Subject: [PATCH 2/3] fix: key the shared workflow's resume step off the token the pane can see MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A Participant CLI has no view of tmux session history, so "if the pane is recovering a clean stop" named a state it cannot observe. The only evidence a resumed pane gets is the ` --resume` token the Launcher appends to its invocation — and step 1's parse rule admitted ` [id]` only, telling the model to ignore the very token step 2 depended on. A model following step 1 literally drops it and joins without `--resume`; the roster gate then fails the relaunch with `LAUNCH_FAILED` because the planned archived ids never come back active. The parse rule is the side that moves. Removing step 2's resume sentence would break the mechanism FR-U47 rests on, since the Launcher does append the flag and the pane is the only thing that can forward it to `crew join`. Step 1 now admits an optional trailing `--resume`, and step 2 keys off that token instead of an unobservable session state. This alters the rendered bytes of all eight Participant artifacts, so REGISTRY_REVISION goes 5 -> 6 per setup-integration.md §7 and the per-platform content-hash snapshots move with it. §4.0 of that document is a byte-for-byte mirror of the source text (verified mechanically) and §3's prose summary follows; the revision literals in its examples, marker grammar, and §7 track the bump, as does the derived docs-site facts file. Refs #75 --- docs-site/generated/facts.json | 2 +- docs/design/setup-integration.md | 33 ++++++++++---------- src/platforms/shared.ts | 8 ++--- tests/integration/commands/setup.test.ts | 2 +- tests/unit/platforms.test.ts | 39 ++++++++++++++++++------ 5 files changed, 53 insertions(+), 31 deletions(-) diff --git a/docs-site/generated/facts.json b/docs-site/generated/facts.json index 7b5d46b..b5c3205 100644 --- a/docs-site/generated/facts.json +++ b/docs-site/generated/facts.json @@ -25,7 +25,7 @@ ] }, "registry": { - "revision": 5, + "revision": 6, "participants": [ { "id": "claude-code", diff --git a/docs/design/setup-integration.md b/docs/design/setup-integration.md index c25dfe4..ec7ea03 100644 --- a/docs/design/setup-integration.md +++ b/docs/design/setup-integration.md @@ -84,12 +84,13 @@ they replaced are recorded once in Every generated customization file teaches the tool the same fixed, bounded workflow: -1. Parse ` [id]`; when no id is given, the id defaults to the role. +1. Parse ` [id] [--resume]`; when no id is given, the id defaults to the role. 2. Confirm the current directory is inside a crew Workspace by running `crew doctor`; if it is not, report that the operator must run `crew init` in the intended root. 3. Run `crew join --role --platform ` once, and remember the actual - id it prints — it may carry a suffix. Add `--resume` when the pane is recovering a - clean stop. + id it prints — it may carry a suffix. Add `--resume` when the parsed arguments included + it; that trailing token is the only signal the pane has that it is recovering a clean + stop. 4. Run `crew receive ` once. 5. For a Task, use `task start`, do the work, then `task submit`; only the Inspector uses `task approve` or `task requeue`. @@ -110,13 +111,13 @@ Every Participant template embeds the block below, word for word, where its generators are reproducible. ```text -Parse {{ROLE_ARGS}} as ` [id]`; if no id is given, the id defaults to the role. +Parse {{ROLE_ARGS}} as ` [id] [--resume]`; if no id is given, the id defaults to the role. 1. Confirm this is a crew Workspace: run `crew doctor`. If it is not, tell the operator to run `crew init` in the intended repository root, then stop. 2. Join once: `crew join --role --platform `. Retain the actual id it - prints; it may carry a `-2`..`-99` suffix after a collision. If the pane is recovering - a clean stop, add `--resume` to the join command. + prints; it may carry a `-2`..`-99` suffix after a collision. If the arguments included + `--resume` (this pane is recovering a clean stop), add `--resume` to the join command. 3. Read your inbox once: `crew receive `. 4. Act only within your Role: - Worker: `crew task start `, do the work, then @@ -166,7 +167,7 @@ allowed-tools: Bash(crew *) argument-hint: [agent-id] --- - + Use the finite crew workflow below for `$ARGUMENTS`. [shared workflow rendered here] @@ -191,7 +192,7 @@ name: crew description: Join and coordinate through the local crew inbox and reviewed task workflow. Use when the user asks to start or act as a crew role. --- - + Use the finite crew workflow below for the role and optional id supplied by the user. [shared workflow rendered here] @@ -224,7 +225,7 @@ Gemini custom commands are TOML files under `.gemini/commands`; a project file w a user file with the same name. crew generates: ```toml -# generated-by: crew setup; registry-revision: 5 +# generated-by: crew setup; registry-revision: 6 description = "Join and coordinate through the local crew inbox and reviewed task workflow" prompt = """ Role and optional id: {{args}} @@ -254,7 +255,7 @@ tools: - execute --- - + [shared finite workflow rendered here] ``` @@ -304,7 +305,7 @@ description: Join and coordinate through the local crew inbox and reviewed task argument-hint: [agent-id] --- - + [shared finite workflow rendered here] ``` @@ -361,7 +362,7 @@ operator's ` [id]`. crew generates: description: Join and coordinate through the local crew inbox and reviewed task workflow. --- - + [shared finite workflow rendered here] ``` @@ -476,8 +477,8 @@ file's own format, with three fields separated by semicolons: generated-by: crew setup; registry-revision: ; content-hash: sha256:<64-hex> ``` -- Markdown / `SKILL.md` / `*.agent.md`: `` -- TOML (`crew.toml`): `# generated-by: crew setup; registry-revision: 5; content-hash: sha256:…` +- Markdown / `SKILL.md` / `*.agent.md`: `` +- TOML (`crew.toml`): `# generated-by: crew setup; registry-revision: 6; content-hash: sha256:…` `content-hash` is the SHA-256 of the **rendered file with the `content-hash:` value replaced by an empty string**, written as lower-case hex, after line endings are @@ -530,9 +531,9 @@ starts as `copilot --agent=crew --prompt …`; nothing is pasted into an already Copilot interface. The Team display and setup keep the guidance about selecting crew via `/agent`. -The registry lives in `src/platforms/` and is currently at **registry-revision 5** +The registry lives in `src/platforms/` and is currently at **registry-revision 6** (the revision started at 1; adding Participants and launch facts since then bumped it, -most recently the `little-coder` target). +most recently the shared workflow's `[--resume]` parse rule). `registry.ts` looks up targets; `shared.ts` holds the record types, the shared workflow text, the marker and content-hash rules, and the version probe; each target has its own module supplying its facts and rendering (`agent-skills.ts` holds the single renderer diff --git a/src/platforms/shared.ts b/src/platforms/shared.ts index cb2d3a7..a3ac277 100644 --- a/src/platforms/shared.ts +++ b/src/platforms/shared.ts @@ -18,7 +18,7 @@ import type { ParticipantId } from '../participants.js'; import { resolveExecutableOnPath } from '../which.js'; /** Integer revision of the platform registry record set; bumped on any artifact change. */ -export const REGISTRY_REVISION = 5; +export const REGISTRY_REVISION = 6; /** Date the documented paths/invocations were last re-verified (setup-integration.md). */ export const VERIFIED_ON = '2026-06-29'; @@ -120,13 +120,13 @@ export type SetupTarget = ParticipantTarget | BackendTarget; * ``, and `` runtime placeholders the model fills — is stable * so generator snapshots are reproducible. */ -const SHARED_WORKFLOW = `Parse {{ROLE_ARGS}} as \` [id]\`; if no id is given, the id defaults to the role. +const SHARED_WORKFLOW = `Parse {{ROLE_ARGS}} as \` [id] [--resume]\`; if no id is given, the id defaults to the role. 1. Confirm this is a crew Workspace: run \`crew doctor\`. If it is not, tell the operator to run \`crew init\` in the intended repository root, then stop. 2. Join once: \`crew join --role --platform \`. Retain the actual id it - prints; it may carry a \`-2\`..\`-99\` suffix after a collision. If the pane is recovering - a clean stop, add \`--resume\` to the join command. + prints; it may carry a \`-2\`..\`-99\` suffix after a collision. If the arguments included + \`--resume\` (this pane is recovering a clean stop), add \`--resume\` to the join command. 3. Read your inbox once: \`crew receive \`. 4. Act only within your Role: - Worker: \`crew task start \`, do the work, then diff --git a/tests/integration/commands/setup.test.ts b/tests/integration/commands/setup.test.ts index 8ee9585..542c610 100644 --- a/tests/integration/commands/setup.test.ts +++ b/tests/integration/commands/setup.test.ts @@ -126,7 +126,7 @@ describe('crew setup (install, FR-G04/G05)', () => { expect(rec.action).toBe('written'); expect(rec.scope).toBe('global'); expect(rec.path).toBe('~/.claude/skills/crew/SKILL.md'); - expect(rec.registry_revision).toBe(5); + expect(rec.registry_revision).toBe(6); const body = readFileSync(join(home, '.claude/skills/crew/SKILL.md'), 'utf8'); expect(classifyArtifact(body)).toBe('managed-current'); }); diff --git a/tests/unit/platforms.test.ts b/tests/unit/platforms.test.ts index e498b9c..f73031b 100644 --- a/tests/unit/platforms.test.ts +++ b/tests/unit/platforms.test.ts @@ -139,6 +139,27 @@ describe('participant artifact rendering', () => { expect(inv('opencode-cli')).toBe('/crew worker worker-2 --resume'); }); + it('teaches every artifact to read the resume signal off its own arguments (FR-U47)', () => { + // A Participant CLI cannot see tmux session history, so the appended `--resume` + // token is the pane's only evidence that it is recovering a clean stop. The + // workflow's parse rule must therefore admit that token, and the join step must + // key off it rather than off a state the pane has no way to observe. + const claude = PARTICIPANT_TARGETS.find((t) => t.id === 'claude-code')!; + expect(claude.invocation('worker', 'worker-2', { resume: true }).split(' ').at(-1)).toBe( + '--resume', + ); + for (const t of PARTICIPANT_TARGETS) { + const body = t.render(); + expect(body, `${t.id} parse rule hides the appended --resume`).toContain( + 'as ` [id] [--resume]`', + ); + expect(body, `${t.id} join step ignores the --resume token`).toContain( + 'If the arguments included', + ); + expect(body).toContain('add `--resume` to the join command.'); + } + }); + it('keeps Copilot interactive guidance separate from its startup command', () => { const copilot = PARTICIPANT_TARGETS.find((target) => target.id === 'copilot-cli')!; expect(copilot.launchArgs?.('worker', 'worker-2')).toEqual([ @@ -232,16 +253,16 @@ describe('participant artifact rendering', () => { // bytes, the digest changes and this fails, forcing both an update here AND a // REGISTRY_REVISION bump so previously-installed artifacts read as managed-outdated. const expected: Record = { - 'claude-code': '836139943f352f9666e8f4a571800f25d1b5a13074bd138b9e6ed364ccba9846', - 'codex-cli': '23d654db4c2f3a9154a9dfdb73ede7205eee16b6613fd2e42adf77eb4e597163', - 'gemini-cli': '94ff656f119473d85dfc90858584d88e7555b262b72edd7bb65552a205abdf29', - 'copilot-cli': '7ae9e5276e6894dd5f18a8f0a6e8ba8ee767b947370acb8e3eec7a9f84d8a779', - 'antigravity-cli': '23d654db4c2f3a9154a9dfdb73ede7205eee16b6613fd2e42adf77eb4e597163', - 'pi-cli': '26853d7cfaafcc613c568bfa5ca07edee3914040745ab2d0e6cb8c9cef5cdd20', - 'little-coder': '26853d7cfaafcc613c568bfa5ca07edee3914040745ab2d0e6cb8c9cef5cdd20', - 'opencode-cli': 'dbe88df8e72e1fb719cc6d3b7667cf0fb0361a81ac0efdbb61cfbbfa4fd3541e', + 'claude-code': '63a59d4a434ccb72948e8dbdef60c9254e942ae7c18e102d04272036193e64e4', + 'codex-cli': '01d9c942ba8f095d6a7853d41a91c719e45e0c558526869f4c89670f15de5e88', + 'gemini-cli': 'e86bd4ae9a7dec4932b136105affeafedf446e07d13d5dacc89813924b099682', + 'copilot-cli': '1ee19562275914d4ff059bfe0d1cd67696b53d4ccec07f6c4eb1ea03d8e90e87', + 'antigravity-cli': '01d9c942ba8f095d6a7853d41a91c719e45e0c558526869f4c89670f15de5e88', + 'pi-cli': 'daa2e6e6604eeab67b5c7a279ddf088ab92c1837b46da11bc0ffee77c6da65f4', + 'little-coder': 'daa2e6e6604eeab67b5c7a279ddf088ab92c1837b46da11bc0ffee77c6da65f4', + 'opencode-cli': 'b3be65a516d2ac14f90f120e23c0e86e96d1171e7bf852efe6b9693eef3366c0', }; - expect(REGISTRY_REVISION).toBe(5); // bump together with the digests above + expect(REGISTRY_REVISION).toBe(6); // bump together with the digests above for (const t of PARTICIPANT_TARGETS) { const hash = /content-hash: sha256:([0-9a-f]{64})/.exec(t.render())![1]; expect(hash, `${t.id} artifact bytes changed`).toBe(expected[t.id]); From eea9187ae7e0d4601650d2aae5c58e49e120b137 Mon Sep 17 00:00:00 2001 From: Igor Magdich Date: Fri, 7 Aug 2026 11:20:08 +0300 Subject: [PATCH 3/3] fix: cover the launchArgs resume path and record the revision bump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review round 1 on PR #114. The new FR-U47 guard checked only claude-code's `invocation`, which exempted the one Participant the issue singles out: Copilot is the sole target supplying `launchArgs`, and `paneLaunch` takes that branch first, so a resumed Copilot pane's prompt never passes through `invocation` at all. Mutating Copilot's suffix to ` --resume-clean` left the whole unit and command suite green. The guard now mirrors `paneLaunch` — launchArgs when defined, else invocation — for every target, and the same mutation now fails it by name. CHANGELOG's `[Unreleased]` is the accumulator that becomes the release notes, and both prior registry bumps are recorded there. Leaving revision 6 unrecorded would have shipped a section still ending "advances to revision 5" while the registry sat at 6, for a change users feel: every installed artifact reclassifies to `managed-outdated` and doctor starts reporting it. Also: the Claude Code and Pi/Little Coder artifacts still rendered `argument-hint: [agent-id]` into their own frontmatter — the two-argument grammar this change widened, contradicting the parse rule in the same generated file. Widening it moves those three artifacts' bytes (pi and little-coder share one artifact); revision 6 already covers them, since no revision-6 artifact has shipped. Two overstatements are softened to "only reliable signal" (a pane can see its own archived row via `crew agents --all`, though that evidence is ambiguous), and §7's enumerating clause now admits artifact text alongside Participants and launch facts. Refs #75 --- CHANGELOG.md | 18 ++++++++++++++++-- docs/design/setup-integration.md | 12 ++++++------ src/platforms/claude.ts | 2 +- src/platforms/pi.ts | 2 +- tests/unit/platforms.test.ts | 26 ++++++++++++++++---------- 5 files changed, 40 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 492d01d..709b707 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,20 @@ All notable changes to this project are documented in this file. The format foll ## [Unreleased] +### Fixed + +- The shared Participant workflow told a pane to add `--resume` to its `crew join` when + "the pane is recovering a clean stop" — a state a Participant CLI cannot observe — while + its own parse rule admitted only ` [id]` and so hid the appended `--resume` token + that is the pane's only reliable signal. A pane following that rule literally dropped the + flag and joined without it, and the roster gate then failed the relaunch with + `LAUNCH_FAILED` because the planned archived ids never came back active. The parse rule + now reads ` [id] [--resume]` and the join step keys off that token; the Claude Code + and Pi/Little Coder artifacts widen their `argument-hint` to match. **Because every + Participant artifact's bytes change, the registry advances to revision 6, so a + previously installed artifact is reported as outdated until `crew setup` is re-run** — + that regeneration is in place and needs neither `--force` nor a backup. + ### Added - Little Coder 1.11.0 is now a first-class Participant CLI (`little-coder`), bringing @@ -14,8 +28,8 @@ All notable changes to this project are documented in this file. The format foll tmux launcher, and is included in the Ollama / LM Studio local-model recipes. Setup prints the narrow additive `LITTLE_CODER_BASH_ALLOW` opt-in and never enables `accept-all`. Because Little Coder forwards `--version` to bundled Pi, crew reads the - adjacent installed package metadata for its 1.11.0 version floor. The registry advances - to revision 5. + adjacent installed package metadata for its 1.11.0 version floor. This addition took the + registry to revision 5. - Two new Participant CLI engines, `pi-cli` (Pi) and `opencode-cli` (opencode), bringing the registry to seven Participant CLIs. Each ships a Markdown customization artifact (`crew.md`) that exposes the `/crew [id]` command: pi as a Prompt Template under diff --git a/docs/design/setup-integration.md b/docs/design/setup-integration.md index ec7ea03..6a7ccfe 100644 --- a/docs/design/setup-integration.md +++ b/docs/design/setup-integration.md @@ -89,8 +89,8 @@ Every generated customization file teaches the tool the same fixed, bounded work it is not, report that the operator must run `crew init` in the intended root. 3. Run `crew join --role --platform ` once, and remember the actual id it prints — it may carry a suffix. Add `--resume` when the parsed arguments included - it; that trailing token is the only signal the pane has that it is recovering a clean - stop. + it; that trailing token is the pane's only reliable signal that it is recovering a + clean stop. 4. Run `crew receive ` once. 5. For a Task, use `task start`, do the work, then `task submit`; only the Inspector uses `task approve` or `task requeue`. @@ -164,7 +164,7 @@ name: crew description: Join and coordinate through the local crew inbox and reviewed task workflow. disable-model-invocation: true allowed-tools: Bash(crew *) -argument-hint: [agent-id] +argument-hint: [agent-id] [--resume] --- @@ -302,7 +302,7 @@ operator's ` [id]` with `$ARGUMENTS`. crew generates: ```markdown --- description: Join and coordinate through the local crew inbox and reviewed task workflow. -argument-hint: [agent-id] +argument-hint: [agent-id] [--resume] --- @@ -532,8 +532,8 @@ Copilot interface. The Team display and setup keep the guidance about selecting `/agent`. The registry lives in `src/platforms/` and is currently at **registry-revision 6** -(the revision started at 1; adding Participants and launch facts since then bumped it, -most recently the shared workflow's `[--resume]` parse rule). +(the revision started at 1; adding Participants, launch facts, and artifact text since +then bumped it, most recently the shared workflow's `[--resume]` parse rule). `registry.ts` looks up targets; `shared.ts` holds the record types, the shared workflow text, the marker and content-hash rules, and the version probe; each target has its own module supplying its facts and rendering (`agent-skills.ts` holds the single renderer diff --git a/src/platforms/claude.ts b/src/platforms/claude.ts index 2d2de4c..ef4a3c8 100644 --- a/src/platforms/claude.ts +++ b/src/platforms/claude.ts @@ -41,7 +41,7 @@ name: crew description: Join and coordinate through the local crew inbox and reviewed task workflow. disable-model-invocation: true allowed-tools: Bash(crew *) -argument-hint: [agent-id] +argument-hint: [agent-id] [--resume] --- ${marker} diff --git a/src/platforms/pi.ts b/src/platforms/pi.ts index f40c936..47fb22f 100644 --- a/src/platforms/pi.ts +++ b/src/platforms/pi.ts @@ -14,7 +14,7 @@ export function renderPiPromptArtifact(): string { 'markdown', (marker) => `--- description: Join and coordinate through the local crew inbox and reviewed task workflow. -argument-hint: [agent-id] +argument-hint: [agent-id] [--resume] --- ${marker} diff --git a/tests/unit/platforms.test.ts b/tests/unit/platforms.test.ts index f73031b..9126c6c 100644 --- a/tests/unit/platforms.test.ts +++ b/tests/unit/platforms.test.ts @@ -141,14 +141,20 @@ describe('participant artifact rendering', () => { it('teaches every artifact to read the resume signal off its own arguments (FR-U47)', () => { // A Participant CLI cannot see tmux session history, so the appended `--resume` - // token is the pane's only evidence that it is recovering a clean stop. The - // workflow's parse rule must therefore admit that token, and the join step must - // key off it rather than off a state the pane has no way to observe. - const claude = PARTICIPANT_TARGETS.find((t) => t.id === 'claude-code')!; - expect(claude.invocation('worker', 'worker-2', { resume: true }).split(' ').at(-1)).toBe( - '--resume', - ); + // token is the pane's only reliable evidence that it is recovering a clean stop. + // The workflow's parse rule must therefore admit that token, and the join step + // must key off it rather than off a state the pane cannot reliably observe. for (const t of PARTICIPANT_TARGETS) { + // Mirror paneLaunch (src/launcher/session.ts): launchArgs wins when it is + // defined, so Copilot's resumed pane never goes through `invocation` at all. + // Checking only `invocation` here would exempt the one target whose token + // travels the other path. + const resuming = { resume: true }; + const launched = + t.launchArgs?.('worker', 'worker-2', resuming)?.join(' ') ?? + t.invocation('worker', 'worker-2', resuming); + expect(launched.split(' ').at(-1), `${t.id} pane is never handed --resume`).toBe('--resume'); + const body = t.render(); expect(body, `${t.id} parse rule hides the appended --resume`).toContain( 'as ` [id] [--resume]`', @@ -253,13 +259,13 @@ describe('participant artifact rendering', () => { // bytes, the digest changes and this fails, forcing both an update here AND a // REGISTRY_REVISION bump so previously-installed artifacts read as managed-outdated. const expected: Record = { - 'claude-code': '63a59d4a434ccb72948e8dbdef60c9254e942ae7c18e102d04272036193e64e4', + 'claude-code': '22001355596469c2e0d8484f8254496a829d8fa83e77de2b28ad5ca97d05bccc', 'codex-cli': '01d9c942ba8f095d6a7853d41a91c719e45e0c558526869f4c89670f15de5e88', 'gemini-cli': 'e86bd4ae9a7dec4932b136105affeafedf446e07d13d5dacc89813924b099682', 'copilot-cli': '1ee19562275914d4ff059bfe0d1cd67696b53d4ccec07f6c4eb1ea03d8e90e87', 'antigravity-cli': '01d9c942ba8f095d6a7853d41a91c719e45e0c558526869f4c89670f15de5e88', - 'pi-cli': 'daa2e6e6604eeab67b5c7a279ddf088ab92c1837b46da11bc0ffee77c6da65f4', - 'little-coder': 'daa2e6e6604eeab67b5c7a279ddf088ab92c1837b46da11bc0ffee77c6da65f4', + 'pi-cli': '359ff24755556eccb155d5ec2b858d41ebbe98f9ecb10f9fc09862c98e9ae3d6', + 'little-coder': '359ff24755556eccb155d5ec2b858d41ebbe98f9ecb10f9fc09862c98e9ae3d6', 'opencode-cli': 'b3be65a516d2ac14f90f120e23c0e86e96d1171e7bf852efe6b9693eef3366c0', }; expect(REGISTRY_REVISION).toBe(6); // bump together with the digests above