peaks-cli 1.3.1 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -2
- package/bin/peaks.js +0 -0
- package/dist/src/cli/commands/core-artifact-commands.js +49 -11
- package/dist/src/cli/commands/gate-commands.js +28 -19
- package/dist/src/cli/commands/hook-handle.d.ts +17 -0
- package/dist/src/cli/commands/hook-handle.js +111 -0
- package/dist/src/cli/commands/hooks-commands.js +72 -21
- package/dist/src/cli/commands/progress-commands.js +9 -2
- package/dist/src/cli/commands/progress-start-spawn.js +30 -4
- package/dist/src/cli/commands/slice-commands.js +4 -2
- package/dist/src/cli/commands/statusline-commands.js +75 -17
- package/dist/src/cli/commands/sub-agent-commands.d.ts +5 -0
- package/dist/src/cli/commands/sub-agent-commands.js +488 -0
- package/dist/src/cli/commands/sub-agent-dispatch-guard.d.ts +55 -0
- package/dist/src/cli/commands/sub-agent-dispatch-guard.js +57 -0
- package/dist/src/cli/commands/workspace-commands.js +70 -14
- package/dist/src/cli/program.js +9 -0
- package/dist/src/hooks/pre-tool-use-sub-agent.d.ts +28 -0
- package/dist/src/hooks/pre-tool-use-sub-agent.js +105 -0
- package/dist/src/services/artifacts/artifact-prerequisites.d.ts +12 -0
- package/dist/src/services/artifacts/artifact-prerequisites.js +39 -8
- package/dist/src/services/artifacts/request-artifact-service.js +116 -76
- package/dist/src/services/config/config-types.d.ts +1 -1
- package/dist/src/services/context/artifact-meta.d.ts +72 -0
- package/dist/src/services/context/artifact-meta.js +105 -0
- package/dist/src/services/context/context-guard.d.ts +49 -0
- package/dist/src/services/context/context-guard.js +91 -0
- package/dist/src/services/context/dispatch-context-guard.d.ts +27 -0
- package/dist/src/services/context/dispatch-context-guard.js +192 -0
- package/dist/src/services/context/headroom-client.d.ts +34 -0
- package/dist/src/services/context/headroom-client.js +117 -0
- package/dist/src/services/context/shared-channel.d.ts +92 -0
- package/dist/src/services/context/shared-channel.js +285 -0
- package/dist/src/services/context/threshold.d.ts +35 -0
- package/dist/src/services/context/threshold.js +76 -0
- package/dist/src/services/dispatch/batch-counter.d.ts +27 -0
- package/dist/src/services/dispatch/batch-counter.js +85 -0
- package/dist/src/services/dispatch/dispatch-record-writer.d.ts +93 -0
- package/dist/src/services/dispatch/dispatch-record-writer.js +261 -0
- package/dist/src/services/dispatch/heartbeat-truncator.d.ts +26 -0
- package/dist/src/services/dispatch/heartbeat-truncator.js +13 -0
- package/dist/src/services/dispatch/leak-detector.d.ts +11 -0
- package/dist/src/services/dispatch/leak-detector.js +72 -0
- package/dist/src/services/dispatch/sub-agent-dispatcher.d.ts +127 -0
- package/dist/src/services/dispatch/sub-agent-dispatcher.js +98 -0
- package/dist/src/services/doctor/doctor-service.d.ts +62 -0
- package/dist/src/services/doctor/doctor-service.js +276 -1
- package/dist/src/services/ide/adapters/claude-code-adapter.d.ts +18 -0
- package/dist/src/services/ide/adapters/claude-code-adapter.js +53 -0
- package/dist/src/services/ide/adapters/trae-adapter.d.ts +34 -0
- package/dist/src/services/ide/adapters/trae-adapter.js +70 -0
- package/dist/src/services/ide/hook-protocol.d.ts +44 -0
- package/dist/src/services/ide/hook-protocol.js +71 -0
- package/dist/src/services/ide/hook-translator.d.ts +72 -0
- package/dist/src/services/ide/hook-translator.js +128 -0
- package/dist/src/services/ide/ide-detector.d.ts +10 -0
- package/dist/src/services/ide/ide-detector.js +19 -0
- package/dist/src/services/ide/ide-registry.d.ts +14 -0
- package/dist/src/services/ide/ide-registry.js +45 -0
- package/dist/src/services/ide/ide-types.d.ts +120 -0
- package/dist/src/services/ide/ide-types.js +2 -0
- package/dist/src/services/ide/shared/atomic-json.d.ts +15 -0
- package/dist/src/services/ide/shared/atomic-json.js +58 -0
- package/dist/src/services/ide/shared/safe-path.d.ts +11 -0
- package/dist/src/services/ide/shared/safe-path.js +29 -0
- package/dist/src/services/progress/progress-service.d.ts +1 -1
- package/dist/src/services/progress/progress-service.js +18 -14
- package/dist/src/services/security/safe-settings-path.d.ts +12 -0
- package/dist/src/services/security/safe-settings-path.js +104 -0
- package/dist/src/services/session/session-manager.d.ts +22 -1
- package/dist/src/services/session/session-manager.js +137 -28
- package/dist/src/services/signal/cancel-handler.d.ts +14 -0
- package/dist/src/services/signal/cancel-handler.js +76 -0
- package/dist/src/services/skill/resume-detector.d.ts +54 -0
- package/dist/src/services/skill/resume-detector.js +334 -0
- package/dist/src/services/skill/skill-scheduler.d.ts +40 -0
- package/dist/src/services/skill/skill-scheduler.js +53 -0
- package/dist/src/services/skills/hooks-settings-service.d.ts +47 -29
- package/dist/src/services/skills/hooks-settings-service.js +190 -144
- package/dist/src/services/skills/statusline-settings-service.d.ts +33 -6
- package/dist/src/services/skills/statusline-settings-service.js +31 -34
- package/dist/src/services/slice/slice-archive-service.d.ts +20 -0
- package/dist/src/services/slice/slice-archive-service.js +111 -0
- package/dist/src/services/slice/slice-check-service.js +20 -1
- package/dist/src/services/slice/slice-check-types.d.ts +9 -0
- package/dist/src/services/solo/batch-heartbeat-poller.d.ts +51 -0
- package/dist/src/services/solo/batch-heartbeat-poller.js +88 -0
- package/dist/src/services/solo/status-line-renderer.d.ts +34 -0
- package/dist/src/services/solo/status-line-renderer.js +55 -0
- package/dist/src/services/workspace/migrate-service.js +124 -2
- package/dist/src/services/workspace/migrate-types.d.ts +50 -7
- package/dist/src/services/workspace/reconcile-service.d.ts +69 -0
- package/dist/src/services/workspace/reconcile-service.js +267 -48
- package/dist/src/services/workspace/reconcile-types.d.ts +37 -0
- package/dist/src/services/workspace/workspace-service.js +29 -62
- package/dist/src/shared/version.d.ts +1 -1
- package/dist/src/shared/version.js +1 -1
- package/package.json +2 -1
- package/schemas/doctor-report.schema.json +2 -2
- package/skills/peaks-ide/SKILL.md +159 -0
- package/skills/peaks-qa/SKILL.md +58 -1
- package/skills/peaks-qa/references/qa-fanout-contract.md +150 -0
- package/skills/peaks-rd/SKILL.md +52 -9
- package/skills/peaks-solo/SKILL.md +83 -20
- package/skills/peaks-solo/references/context-governance.md +144 -0
- package/skills/peaks-solo/references/headroom-integration.md +107 -0
- package/skills/peaks-solo/references/runbook.md +3 -3
- package/skills/peaks-solo/references/sub-agent-dispatch.md +218 -0
- package/skills/peaks-solo/references/swarm-dispatch-contract.md +3 -37
- package/skills/peaks-txt/SKILL.md +19 -0
- package/skills/peaks-ui/SKILL.md +28 -1
|
@@ -44,7 +44,7 @@ peaks-solo (orchestrate only)
|
|
|
44
44
|
|
|
45
45
|
| Mode | Swarm side (after PRD) | Repair loop side (RD↔QA) |
|
|
46
46
|
|---|---|---|
|
|
47
|
-
| `full-auto` / `swarm` | `
|
|
47
|
+
| `full-auto` / `swarm` | `peaks sub-agent dispatch <role>` — IDE-agnostic dispatch primitive; CLI returns a tool-call descriptor the LLM executes in its own environment | `peaks sub-agent dispatch <role>` per cycle |
|
|
48
48
|
| `assisted` / `strict` / inline-fallback | Solo executes the role steps inline in the main loop (the `peaks-solo` skill IS the role's owner) | Solo executes inline |
|
|
49
49
|
|
|
50
50
|
In all modes, the work itself follows the same `peaks-rd` and `peaks-qa` contracts. The only difference is whether the role's body is being read by a sub-agent Task prompt or by Solo's own main loop. **Never bypass the role contracts regardless of which path runs.**
|
|
@@ -192,7 +192,7 @@ done
|
|
|
192
192
|
**Strict quality guarantee (per user's hard rule: "严格要保证不能比当前的效果差")**:
|
|
193
193
|
- If no in-flight slice is detected, this step is a no-op: zero extra commands beyond the existing Step 0 probe, zero extra token cost.
|
|
194
194
|
- If an in-flight slice is detected, the cost is one `find` + one `grep` loop (sub-millisecond) + one `AskUserQuestion` (one round-trip). The savings are 3-5k tokens (the cost of manually re-reading 3-5 artifact files).
|
|
195
|
-
- The dogfood test in `tests/unit/skill-resume-mode.test.ts` (
|
|
195
|
+
- The dogfood test in `tests/unit/skill-resume-mode.test.ts` (8 cases, bash-fixture shim — the legacy interface used by `skills/peaks-solo-resume`) and `tests/unit/services/skill/resume-detector.test.ts` (24 cases, the canonical TypeScript classifier at `src/services/skill/resume-detector.ts`) together cover: (a) fresh / complete / resume:rd-planning / resume:qa-validation / resume:txt-handoff state-based classifications, (b) the "Other resume triggers" overrides (missing `rd/tech-doc.md` → `rd-planning`; missing `rd/code-review.md` or `rd/security-review.md` → `rd-review-fanout`; missing `qa/test-reports/<rid>.md` → `qa-execution`), (c) the mid-implementation distinction (`spec-locked` / `implemented` / `running` / `blocked` all return `in-flight:<state>`), (d) the primary-vs-abandoned filter (multiple RDs → spec-locked wins; single blocked RD stays primary; 2+ all-abandoned → fresh), (e) the legacy `.peaks/<sid>/` path fallback, and (f) determinism across two invocations on the same fixture.
|
|
196
196
|
|
|
197
197
|
### Peaks-Cli Step 1: Mode selection
|
|
198
198
|
|
|
@@ -262,6 +262,12 @@ peaks session title $(cat .peaks/.session.json | python3 -c "import sys,json; pr
|
|
|
262
262
|
|
|
263
263
|
If the session directory already has a title (check via `peaks session list --json`), skip this step — the title is already set.
|
|
264
264
|
|
|
265
|
+
## Sub-agent session sharing (MANDATORY — one conversation = one sid)
|
|
266
|
+
|
|
267
|
+
When peaks-solo dispatches a sub-agent (peaks-rd, peaks-qa, peaks-ui, peaks-txt, peaks-sc), the sub-agent prompt MUST include the parent's session id. The sub-agent then passes `--session-id <parent-sid>` for any session-creating CLI call (e.g. `peaks request init --session-id <parent-sid>`). The sub-agent MUST NOT call `peaks workspace init` — that would create a new session dir and orphan the parent's binding. The sub-agent reads `.peaks/_runtime/session.json` to discover the parent's sid (or the orchestrator passes it explicitly). Sub-agents also accept the parent's sid via the new `peaks session info --active` primitive when they need a one-shot read.
|
|
268
|
+
|
|
269
|
+
Note: `peaks request init` is **dry-run by default** — the JSON response has `applied: false` and no file is written unless `--apply` is passed. This is the same safe-by-default pattern as `peaks workspace migrate --apply`. Sub-agents that need to actually create a slice must add `--apply`.
|
|
270
|
+
|
|
265
271
|
## Boundaries
|
|
266
272
|
|
|
267
273
|
Peaks-Cli Solo may:
|
|
@@ -618,24 +624,26 @@ Sub-agent presence in this list = Solo launched a Task for it. Absence = the rol
|
|
|
618
624
|
|
|
619
625
|
In all modes, **the plan must be written to `sc/swarm-plan.json` before any Task call.** Solo updates `.peaks/.active-skill.json` to `gate=swarm-fan-out` at this point.
|
|
620
626
|
|
|
621
|
-
### Sub-agent mechanism (
|
|
627
|
+
### Sub-agent mechanism (IDE-agnostic dispatch, NOT Skill tool)
|
|
622
628
|
|
|
623
|
-
**Solo is itself a skill running in the current session. To invoke a role in the Swarm, Solo MUST
|
|
629
|
+
**Solo is itself a skill running in the current session. To invoke a role in the Swarm, Solo MUST call the IDE-agnostic dispatch primitive `peaks sub-agent dispatch <role>` — NOT the `Skill` tool, NOT any IDE-private sub-agent literal.** The `Skill` tool is single-stack and blocking; using it for "parallel" work was the v1.x illusion of concurrency. The dispatch CLI is the only mechanism that keeps SKILL.md free of IDE-private tool names and lets the same prompt work on every registered IDE.
|
|
624
630
|
|
|
625
|
-
Each sub-agent
|
|
631
|
+
Each sub-agent dispatch call looks like:
|
|
626
632
|
|
|
627
633
|
```
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
634
|
+
peaks sub-agent dispatch <role> \
|
|
635
|
+
--prompt "<paste peaks-<role>/SKILL.md body, minus the self-presence / Step 0 blocks,
|
|
636
|
+
plus the runtime arguments: project=<repo>, session-id=<sid>, request-id=<rid>, mode=<mode>,
|
|
637
|
+
plus the explicit output contract: 'Write your artefacts to the paths listed below and
|
|
638
|
+
return only the list of paths. Do not call Skill(...). Do not set presence. Do not
|
|
639
|
+
hand back prose.', plus the heartbeat instruction: 'While running, call
|
|
640
|
+
peaks sub-agent heartbeat --record <dispatchRecordPath> --status <state> --progress <pct> --note \"<text>\"
|
|
641
|
+
at least every 30 seconds.'>" \
|
|
642
|
+
--request-id <rid> --session-id <sid> --project <repo> --json
|
|
637
643
|
```
|
|
638
644
|
|
|
645
|
+
Then the LLM takes `data.toolCall` from the envelope (a `{name, args}` descriptor), looks up the tool by `name` in its environment, and invokes it with `args` — IDE-private, no SKILL.md hardcoding.
|
|
646
|
+
|
|
639
647
|
The role's required artefact paths (also see peaks-ui/rd/qa SKILL.md and `references/swarm-dispatch-contract.md`):
|
|
640
648
|
|
|
641
649
|
| Role | Writes | Reads (PRD-side) |
|
|
@@ -644,16 +652,17 @@ The role's required artefact paths (also see peaks-ui/rd/qa SKILL.md and `refere
|
|
|
644
652
|
| `rd-planning` | `.peaks/<sid>/rd/tech-doc.md` (feature/refactor) or `.peaks/<sid>/rd/bug-analysis.md` (bugfix) | PRD body, project-scan, existing-system, codegraph |
|
|
645
653
|
| `qa-test-cases` | `.peaks/<sid>/qa/test-cases/<rid>.md` | PRD body, RD planning artefact, project-scan, codegraph |
|
|
646
654
|
|
|
647
|
-
**Solo launches all sub-agents in the swarm plan in a single message (multiple
|
|
655
|
+
**Solo launches all sub-agents in the swarm plan in a single message (multiple `peaks sub-agent dispatch` calls in parallel, each followed by execution of the returned toolCall)** — this is what gives real concurrency. Do not sequentialize them. The CLI returns N toolCall descriptors; the LLM fires all N in the same message; the IDE dispatches them concurrently; Solo then waits for all to return, runs `ls` checks against the paths above (Peaks-Cli Gate B), and only then advances to RD implementation.
|
|
648
656
|
|
|
649
|
-
**Hard prohibitions on sub-agents** (also passed in each
|
|
657
|
+
**Hard prohibitions on sub-agents** (also passed in each dispatch prompt):
|
|
650
658
|
|
|
651
659
|
- Do NOT call `Skill(skill="...")` — sub-agents must not recursively activate skills, that defeats the fan-out.
|
|
652
660
|
- Do NOT call `peaks skill presence:set` — only the main Solo loop owns `.peaks/.active-skill.json`. Sub-agents write to a per-agent marker file `.peaks/<sid>/system/sub-agent-<role>.json` if they need to record state, but never the main presence file.
|
|
653
661
|
- Do NOT open interactive user prompts. If a sub-agent needs clarification, it must return a `blocked` verdict in its return string and let Solo handle the user message.
|
|
654
662
|
- Do NOT commit, push, install hooks, or apply settings.json mutations. Only Solo holds those permissions.
|
|
663
|
+
- **Do write heartbeats** — call `peaks sub-agent heartbeat --record <dispatchRecordPath> --status running --progress <pct> --note "<text>"` at least every 30s (see `references/sub-agent-dispatch.md` §G6 for the full contract). The parent Dispatcher uses these to render the live status line during the wait.
|
|
655
664
|
|
|
656
|
-
After every sub-agent
|
|
665
|
+
After every sub-agent dispatch returns, Solo **restores presence** once (not per-agent), then continues to Gate B verification:
|
|
657
666
|
|
|
658
667
|
```bash
|
|
659
668
|
peaks skill presence:set peaks-solo --project <repo> --mode <mode> --gate swarm-converged
|
|
@@ -700,7 +709,7 @@ After `peaks-rd` finishes any implementation, repair, or code-output slice, Peak
|
|
|
700
709
|
|
|
701
710
|
Solo is itself a skill running in the current session. There are **two distinct mechanisms** in this skill, and they MUST NOT be confused:
|
|
702
711
|
|
|
703
|
-
1. **Swarm fan-out (planning side, after PRD confirmed)** — uses
|
|
712
|
+
1. **Swarm fan-out (planning side, after PRD confirmed)** — uses `peaks sub-agent dispatch <role>` to launch real concurrent sub-agents. The CLI returns a per-IDE tool-call descriptor that the LLM executes in its environment. See "Peaks-Cli Swarm parallel phase" above for the full contract. Sub-agents do NOT call Skill(...) back into the role; they execute the role's instructions inline from the prompt.
|
|
704
713
|
2. **Sequential handoff (execution side, RD↔QA repair loop)** — Solo is the only loop, and after RD or QA finishes (whether as a sub-agent or directly), Solo drives the next step from the orchestrator seat. Do NOT use the `Skill` tool to "reactivate" peaks-rd or peaks-qa in the main loop; doing so is the v1.x anti-pattern that masqueraded as "calling the role" but actually just re-prompted the same session. From v1.3 onward, the main loop drives roles via the CLI gate (`peaks request transition`) and reads back artefacts (`peaks request show ... --json`); the actual RD/QA work is either done inline by Solo (when Solo has just been re-invoked by the user) or by a Task sub-agent (in swarm mode).
|
|
705
714
|
|
|
706
715
|
After RD completes (whether inline or sub-agent), Solo does not stop — it must advance to QA. There is no "RD done, ask the user" state in full-auto mode. The only valid stops are: (a) QA verdict=pass, (b) repair cap hit, (c) explicit user cancel.
|
|
@@ -715,7 +724,7 @@ peaks skill presence:set peaks-solo --project <repo> --mode <mode> --gate <curre
|
|
|
715
724
|
|
|
716
725
|
This keeps the CLAUDE.md status header accurate (`Peaks-Cli Skill: peaks-solo`) instead of showing a stale role name. Use the current mode and gate values; the gate may have advanced since startup. Skipping this step causes the header to display the last-known gate permanently.
|
|
717
726
|
|
|
718
|
-
**Full-auto auto-proceed rule**: In the `full-auto` profile, when RD transitions to `qa-handoff`, Solo immediately drives QA — by launching a `
|
|
727
|
+
**Full-auto auto-proceed rule**: In the `full-auto` profile, when RD transitions to `qa-handoff`, Solo immediately drives QA — by launching a `peaks sub-agent dispatch qa` sub-agent carrying the `peaks-qa` body (swarm path), then executing the returned toolCall, or by running QA inline in the main loop (assisted/strict path). Do not pause, do not ask the user, do not summarize RD results as if they were final. The only valid reason to skip QA is when `--type` is `docs` or `chore` (no acceptance surface).
|
|
719
728
|
|
|
720
729
|
A QA report with any failing, blocked, missing, or unverified acceptance item is not a pass.
|
|
721
730
|
|
|
@@ -732,7 +741,7 @@ When `peaks-qa` returns `verdict=return-to-rd`, Solo does NOT manually rewrite R
|
|
|
732
741
|
```
|
|
733
742
|
`spec-locked` is the canonical "needs more RD work" state. The reason is mandatory in repair cycles so the artifact history shows the loop.
|
|
734
743
|
3. Re-launch `peaks-rd` work. Two paths, mode-driven:
|
|
735
|
-
- **Swarm / full-auto**: launch a fresh `
|
|
744
|
+
- **Swarm / full-auto**: launch a fresh `peaks sub-agent dispatch rd` sub-agent (then execute the returned toolCall) with the same `peaks-rd` body used in the Swarm phase, plus the QA findings path so it can read the failure list. Solo restores presence after the sub-agent returns.
|
|
736
745
|
- **Assisted / strict / inline-fallback**: Solo executes the RD repair steps directly in the main loop, since there is no concurrent fan-out to coordinate.
|
|
737
746
|
In both paths, pass the QA findings path so the repair sees what failed.
|
|
738
747
|
4. peaks-rd fixes the reported issues only (red-line scope: do not modify unrelated surfaces), regenerates code-review and security-review evidence if changes touched reviewed surfaces, then transitions `rd → implemented → qa-handoff` again.
|
|
@@ -850,3 +859,57 @@ Do not run upstream installer flows, mutate agent settings, or commit `.codegrap
|
|
|
850
859
|
**MCP lifecycle**: `list → plan → apply --yes → call → rollback`. `apply` backs up settings and refuses non-peaks entries unless `--claim` is passed.
|
|
851
860
|
|
|
852
861
|
Detailed rules: `references/external-skill-invocation.md`, `references/openspec-mcp-workflow.md`, `references/workflow.md`, `references/existing-system-extraction.md`. For an informational mapping of peaks artefact paths to the A2A (Agent2Agent) protocol's Task / Artifact / Part / Message / AgentCard vocabulary (no A2A implementation, just a shared naming layer), see `references/a2a-artifact-mapping.md`.
|
|
862
|
+
|
|
863
|
+
## Sub-agent context governance (G7 + G7.7 + G8 + G9 — slice #010)
|
|
864
|
+
|
|
865
|
+
> Slice #010 adds the **layer 3.5** context-governance push to the slice #009 sub-agent dispatch primitives. This section is the MANDATORY reference for the main LLM reducer. Detailed protocol: `references/context-governance.md` + `references/headroom-integration.md`.
|
|
866
|
+
|
|
867
|
+
### G7 — sub-agent context minimal-occupation (metadata-only + 按需 Read)
|
|
868
|
+
|
|
869
|
+
Sub-agent artifacts (rd/tech-doc.md, qa/test-cases/<rid>.md, ui/design-draft.md) MUST NOT be inlined into dispatch records and fed back to the main LLM during reduce.
|
|
870
|
+
|
|
871
|
+
- Sub-agent writes artifact to disk at a known path (path convention: `.peaks/_sub_agents/<sid>/artifacts/<rid>-<role>-<idx>.<ext>`).
|
|
872
|
+
- Sub-agent calls `peaks sub-agent dispatch --write-artifact <path>` (or via dispatch CLI flag). The CLI computes sha256 + size + writes `ArtifactMeta` to record.
|
|
873
|
+
- Main LLM reduces the batch and sees ONLY the metadata view (~200 chars per sub-agent, vs ~1MB if content were inlined) — a 3000-5000× reduction.
|
|
874
|
+
- Main LLM decides whether to `Read <path>` for full content (LLM tool call, NOT via peaks CLI).
|
|
875
|
+
|
|
876
|
+
Main LLM view format (G7.4.e):
|
|
877
|
+
```
|
|
878
|
+
[peaks-solo] batch 3/3 done in 47.3s
|
|
879
|
+
- rd → .peaks/_sub_agents/2026-06-06-session-5b1095/artifacts/003-rd-001.md (12KB, sha256:abc123) summary: "wrote RD tech-doc with 4 sub-roles"
|
|
880
|
+
- qa-business → .../artifacts/003-qa-business-001.md (8KB, sha256:def456) summary: "wrote 12 API test cases"
|
|
881
|
+
- qa-perf → .../artifacts/003-qa-perf-001.md (5KB, sha256:ghi789) summary: "p95 latency target ≤ 200ms"
|
|
882
|
+
```
|
|
883
|
+
|
|
884
|
+
### G7.7 — headroom-ai integration (opt-in compression)
|
|
885
|
+
|
|
886
|
+
If a sub-agent prompt is too large even after G7 metadata-only (e.g. 1MB artifact description, 5MB mid-prompt analysis), use `--use-headroom`:
|
|
887
|
+
- Default `false` (G7 remains default).
|
|
888
|
+
- Modes: `balanced` (default) | `aggressive` | `conservative`.
|
|
889
|
+
- Failure: `HEADROOM_UNAVAILABLE` warning + G7 metadata-only fallback (NOT blocking).
|
|
890
|
+
|
|
891
|
+
### G8 — cross sub-agent shared channel (dispatcher-mediated indirect signal)
|
|
892
|
+
|
|
893
|
+
Sub-agent A's completion **immediately** writes a shared entry; sub-agent B (still in flight) can read shared entries from sibling sub-agents. **This is NOT peer-to-peer messaging.** The dispatcher stores, the sub-agents read/write; A and B never directly talk.
|
|
894
|
+
|
|
895
|
+
- Path: `.peaks/_sub_agents/<sid>/shared/<batchId>.json`.
|
|
896
|
+
- Two new CLI atoms (NO new top-level CLI): `peaks sub-agent share` + `peaks sub-agent shared-read`.
|
|
897
|
+
- RL-23 strong constraint: when sub-agent calls `peaks sub-agent heartbeat --status done`, it MUST also call `peaks sub-agent share --key "<role>.completed" --value <artifact-meta>`.
|
|
898
|
+
|
|
899
|
+
### G9 — forced compression gate (CLI 兜底 + hook double-guard)
|
|
900
|
+
|
|
901
|
+
Threshold table (256K default context capacity):
|
|
902
|
+
|
|
903
|
+
| Threshold | Prompt size | Behavior |
|
|
904
|
+
|---|---|---|
|
|
905
|
+
| 50% (early warn) | ≥ 128KB | Soft warning, suggest `--use-headroom` |
|
|
906
|
+
| **75% (user red line)** | ≥ 192KB | Soft warn + `warnings: ["CONTEXT_NEAR_LIMIT"]` |
|
|
907
|
+
| **80% (hard reject)** | ≥ 204KB | Hard reject `code: "PROMPT_TOO_LARGE"`; `--force` allowed at CLI |
|
|
908
|
+
| 90% (emergency) | ≥ 230KB | Hard reject + `contextWarning: 'high'` |
|
|
909
|
+
|
|
910
|
+
Two layers:
|
|
911
|
+
- **CLI 兜底** — `peaks sub-agent dispatch` validates prompt size; `--force` allowed.
|
|
912
|
+
- **PreToolUse hook** — `peaks sub-agent-dispatch-guard` re-validates; **NO `--force`** at hook layer (RL-30 strict).
|
|
913
|
+
|
|
914
|
+
The sub-agent prompt template (G8.6 + G9 self-check) is in `references/context-governance.md`.
|
|
915
|
+
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Context Governance — G7 + G7.7 + G8 + G9 protocol details
|
|
2
|
+
|
|
3
|
+
> Slice #010 (G7 + G7.7 + G8 + G9 context-governance push).
|
|
4
|
+
> See: `.peaks/memory/sub-agent-context-minimal-occupation.md` + `sub-agent-shared-channel-cross-completion.md` + `sub-agent-headroom-forced-compression-gate.md` for the red lines.
|
|
5
|
+
|
|
6
|
+
## G7 — sub-agent context minimal-occupation (metadata-only + 按需 Read)
|
|
7
|
+
|
|
8
|
+
### Path convention
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
.peaks/_sub_agents/<sid>/artifacts/<rid>-<role>-<idx>.<ext>
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
### ArtifactMeta schema
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
interface ArtifactMeta {
|
|
18
|
+
readonly path: string;
|
|
19
|
+
readonly size: number;
|
|
20
|
+
readonly sha256: string;
|
|
21
|
+
readonly status: 'created' | 'finalized' | 'partial' | 'failed';
|
|
22
|
+
readonly contentInlined: false; // mandatory literal
|
|
23
|
+
readonly summary: string | null; // ≤ 200 chars
|
|
24
|
+
readonly writtenAt: string;
|
|
25
|
+
readonly rid: string;
|
|
26
|
+
readonly role: string;
|
|
27
|
+
readonly idx: number;
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Sub-agent completion protocol (G3 + G7.4.g)
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
On completion:
|
|
35
|
+
1. Write artifact to .peaks/_sub_agents/<sid>/artifacts/<rid>-<role>-<idx>.<ext>
|
|
36
|
+
2. Call `peaks sub-agent dispatch --write-artifact <path>` (or via --write-artifact on dispatch)
|
|
37
|
+
→ CLI computes sha256 + size + writes ArtifactMeta to record
|
|
38
|
+
3. Call `peaks sub-agent share --key "<role>.completed" --value <artifact-meta>` (G8.6)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Main LLM reducer view (G7.4.e)
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
[peaks-solo] batch 3/3 done in 47.3s
|
|
45
|
+
- rd → .peaks/_sub_agents/2026-06-06-session-5b1095/artifacts/003-rd-001.md (12KB, sha256:abc123) summary: "wrote RD tech-doc with 4 sub-roles and dispatcher interface"
|
|
46
|
+
- qa-business → .../artifacts/003-qa-business-001.md (8KB, sha256:def456) summary: "wrote 12 API test cases covering happy + 3 error paths"
|
|
47
|
+
- qa-perf → .../artifacts/003-qa-perf-001.md (5KB, sha256:ghi789) summary: "wrote perf baseline; p95 latency target ≤ 200ms"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Numerical budget
|
|
51
|
+
|
|
52
|
+
| 方案 | Per sub-agent | 3-sub-agent batch | 6-sub-agent batch |
|
|
53
|
+
|---|---|---|---|
|
|
54
|
+
| Old: inline full content | 1MB typical | 3MB | 6MB |
|
|
55
|
+
| **G7 metadata-only (this slice)** | ~200 chars | **600 chars** | **1.2KB** |
|
|
56
|
+
|
|
57
|
+
3000-5000× improvement. Main LLM full-slice context net increase: < 10KB for 5 batches × 6 sub-agents.
|
|
58
|
+
|
|
59
|
+
## G7.7 — headroom-ai integration (opt-in)
|
|
60
|
+
|
|
61
|
+
### `--use-headroom` flag
|
|
62
|
+
|
|
63
|
+
Opt-in flag on `peaks sub-agent dispatch`. Default `false` (G7 metadata-only remains the default).
|
|
64
|
+
|
|
65
|
+
### Mode table
|
|
66
|
+
|
|
67
|
+
| Mode | tokenBudget | Use case |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| `balanced` (default) | promptSize * 0.40 / 4 | General sub-agent dispatch |
|
|
70
|
+
| `aggressive` | promptSize * 0.20 / 4 | Last-resort large prompt |
|
|
71
|
+
| `conservative` | promptSize * 0.70 / 4 | Sensitive code analysis |
|
|
72
|
+
|
|
73
|
+
### Failure mode (RL-22d / RL-32)
|
|
74
|
+
|
|
75
|
+
- headroom daemon dead / proxy unreachable / times out
|
|
76
|
+
- → `code: "HEADROOM_UNAVAILABLE"` warning + G7 metadata-only fallback
|
|
77
|
+
- → NOT blocking (warn, then continue dispatch)
|
|
78
|
+
|
|
79
|
+
## G8 — cross sub-agent shared channel
|
|
80
|
+
|
|
81
|
+
### Path convention
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
.peaks/_sub_agents/<sid>/shared/<rid>-<batchId>.json
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Two new CLI atoms
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
peaks sub-agent share --batch <batchId> --key <k> --value <json> --json
|
|
91
|
+
Writes a shared entry. Last-write-wins by key. value ≤ 1KB soft warn, ≥ 64KB rejected.
|
|
92
|
+
|
|
93
|
+
peaks sub-agent shared-read --batch <batchId> [--since <iso>] [--key <pattern>] --json
|
|
94
|
+
Reads entries. --key is a glob pattern with * wildcard.
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Sub-agent prompt template (G8.6)
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
You are sub-agent role <role>, batch <batchId>.
|
|
101
|
+
|
|
102
|
+
PROTOCOL (mandatory):
|
|
103
|
+
1. On start: peek at shared channel: `peaks sub-agent shared-read --batch <batchId> --json`
|
|
104
|
+
to see what other sub-agents in this batch have shared so far.
|
|
105
|
+
2. While running: if you find a blocker or partial work, write share entry
|
|
106
|
+
`peaks sub-agent share --key "<role>.found-blocker" --value {"reason": "..."}`
|
|
107
|
+
so other in-flight sub-agents can avoid duplicating effort.
|
|
108
|
+
3. On completion: write share entry
|
|
109
|
+
`peaks sub-agent share --key "<role>.completed" --value <artifact-meta>`
|
|
110
|
+
BEFORE the final `peaks sub-agent heartbeat --status done` heartbeat.
|
|
111
|
+
4. The shared channel is your only visibility into sibling sub-agents.
|
|
112
|
+
Do NOT attempt to read other sub-agents' dispatch records directly.
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### RL-23 completion-time mandatory write
|
|
116
|
+
|
|
117
|
+
- When sub-agent calls `peaks sub-agent heartbeat --status done`, it MUST also call `peaks sub-agent share --key "<role>.completed" --value <artifact-meta>`.
|
|
118
|
+
- If sub-agent omits the share, heartbeat still succeeds but emit warning `code: "COMPLETED_WITHOUT_SHARE"`.
|
|
119
|
+
|
|
120
|
+
## G9 — forced compression gate
|
|
121
|
+
|
|
122
|
+
### Threshold table (256K default context capacity)
|
|
123
|
+
|
|
124
|
+
| Threshold | Prompt size | Behavior |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| 50% (early warn) | ≥ 128KB | Soft warning, suggest `--use-headroom` |
|
|
127
|
+
| **75% (user red line)** | ≥ 192KB | Soft warn + mandatory suggest `--use-headroom`; `warnings: ["CONTEXT_NEAR_LIMIT"]` |
|
|
128
|
+
| **80% (hard reject)** | ≥ 204KB | Hard reject `code: "PROMPT_TOO_LARGE"`; `--force` allowed at CLI |
|
|
129
|
+
| 90% (emergency) | ≥ 230KB | Hard reject + `contextWarning: 'high'` |
|
|
130
|
+
|
|
131
|
+
### Two-layer enforcement (G9.2)
|
|
132
|
+
|
|
133
|
+
- **CLI 兜底** — `peaks sub-agent dispatch` validates prompt size; `--force` allowed.
|
|
134
|
+
- **PreToolUse hook** — `peaks sub-agent-dispatch-guard` re-validates; **NO `--force`** allowed at hook layer (RL-30 strict).
|
|
135
|
+
|
|
136
|
+
### `--force` semantics
|
|
137
|
+
|
|
138
|
+
- At CLI: `--force` allowed; emits `code: "FORCED_OVER_THRESHOLD"` warning + records `forcedAt: ISO8601`.
|
|
139
|
+
- At PreToolUse hook: `--force` is REJECTED (RL-30 strict). The hook's CLI does not declare a `--force` flag; the override path is physically not available.
|
|
140
|
+
|
|
141
|
+
## AC mapping
|
|
142
|
+
|
|
143
|
+
- AC-38..AC-43 (G7) + AC-44..AC-46 (G7.7) + AC-47..AC-49 (G8) + AC-50..AC-65 (G9)
|
|
144
|
+
- See PRD §Acceptance criteria.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Headroom Integration — G7.7 opt-in compression channel
|
|
2
|
+
|
|
3
|
+
> Slice #010 (G7.7 headroom-ai integration route).
|
|
4
|
+
> Source: https://github.com/chopratejas/headroom
|
|
5
|
+
> Package: `headroom-ai@0.22.4` (Apache-2.0, MIT-compatible).
|
|
6
|
+
> See: `THIRD_PARTY_LICENSES.md` for the license record.
|
|
7
|
+
|
|
8
|
+
## Why headroom-ai is justified (R-14)
|
|
9
|
+
|
|
10
|
+
The dev-preference red line "非必要不添加新的 dep" is preserved:
|
|
11
|
+
headroom-ai is the only opt-in mechanism for G7.7 + G9 to compress
|
|
12
|
+
sub-agent prompts that exceed the 75% / 80% threshold. Without
|
|
13
|
+
headroom-ai, `--use-headroom` is a no-op and the only fallback is
|
|
14
|
+
`--force` override at CLI.
|
|
15
|
+
|
|
16
|
+
The user's explicit reference (https://github.com/chopratejas/headroom)
|
|
17
|
+
is the basis for the dev-preference override.
|
|
18
|
+
|
|
19
|
+
## API shape (real SDK, not the PRD's spec)
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { compress } from 'headroom-ai';
|
|
23
|
+
|
|
24
|
+
const result = await compress(messages, {
|
|
25
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
26
|
+
baseUrl: 'http://localhost:8787', // local proxy; not used in slice #010
|
|
27
|
+
apiKey: 'hr_...', // Headroom Cloud; not used in slice #010
|
|
28
|
+
timeout: 30_000,
|
|
29
|
+
fallback: true, // CRITICAL: return original messages if proxy is dead
|
|
30
|
+
retries: 1,
|
|
31
|
+
tokenBudget: 4000, // compress to fit this limit
|
|
32
|
+
hooks: new MyHooks(), // pre/post compression hooks
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
result.messages // compressed messages
|
|
36
|
+
result.tokensBefore // original token count
|
|
37
|
+
result.tokensAfter // compressed token count
|
|
38
|
+
result.tokensSaved // tokens removed
|
|
39
|
+
result.compressionRatio // tokensAfter / tokensBefore
|
|
40
|
+
result.transformsApplied // e.g. ['router:smart_crusher:0.35']
|
|
41
|
+
result.compressed // false if fallback kicked in
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`fallback: true` is the key option: if the proxy is unavailable, the SDK
|
|
45
|
+
returns the original messages + `result.compressed: false` instead of
|
|
46
|
+
throwing. This makes the failure mode non-blocking (RL-22d / RL-32).
|
|
47
|
+
|
|
48
|
+
## Mode table (peaks wrapper)
|
|
49
|
+
|
|
50
|
+
The peaks wrapper maps the user-facing `HeadroomMode` to the SDK's
|
|
51
|
+
`tokenBudget` option. Slice #010 does not consume the SDK's internal
|
|
52
|
+
"audit" / "optimize" / "simulate" modes (those are SDK-internal);
|
|
53
|
+
|
|
54
|
+
| Mode | tokenBudget | Use case |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `balanced` (default) | promptSize * 0.40 / 4 | General sub-agent dispatch |
|
|
57
|
+
| `aggressive` | promptSize * 0.20 / 4 | Last-resort large prompt |
|
|
58
|
+
| `conservative` | promptSize * 0.70 / 4 | Sensitive code analysis, accuracy-critical |
|
|
59
|
+
|
|
60
|
+
The `0.40 / 4` factor approximates 60% byte reduction (1 token ≈ 4 bytes
|
|
61
|
+
for English text). The SDK does its own tokenization internally; the
|
|
62
|
+
`tokenBudget` is a hint, not a hard cap.
|
|
63
|
+
|
|
64
|
+
## Failure semantics (RL-22d / RL-32)
|
|
65
|
+
|
|
66
|
+
- `result.compressed === false` → `code: "HEADROOM_UNAVAILABLE"` warning
|
|
67
|
+
- `compress()` throws (network error, JSON parse error) → caught and treated as `HEADROOM_UNAVAILABLE`
|
|
68
|
+
- Import failure (headroom-ai not installed) → caught and treated as `HEADROOM_UNAVAILABLE`
|
|
69
|
+
- **NOT blocking** — peak falls back to G7 metadata-only and continues dispatch
|
|
70
|
+
|
|
71
|
+
## CCR reversible hydration (slice #011+ TODO)
|
|
72
|
+
|
|
73
|
+
The PRD mentions "CCR (Cross-Context Reversible)" as a benefit of
|
|
74
|
+
headroom. In the SDK, this is implemented via the `hooks` option on
|
|
75
|
+
`compress()`. A pre/post hook can persist the `ccrHashes` to disk,
|
|
76
|
+
and a later `rehydrate()` call can re-hydrate the compressed prompt
|
|
77
|
+
to the original. Slice #010 does NOT consume CCR — it only uses
|
|
78
|
+
compression. R-17 (CCR for aggressive / conservative modes) is
|
|
79
|
+
deferred to slice #011+.
|
|
80
|
+
|
|
81
|
+
## Cross-platform behavior (R-19)
|
|
82
|
+
|
|
83
|
+
- In-process compression (the SDK's library mode) is platform-agnostic.
|
|
84
|
+
- The long-running `headroom proxy` daemon is platform-specific
|
|
85
|
+
(Unix socket on Linux/macOS, named pipe on Windows). Slice #010
|
|
86
|
+
does NOT consume the proxy daemon.
|
|
87
|
+
- All headroom-ai calls in slice #010 go through the in-process SDK
|
|
88
|
+
with `fallback: true`. The peak wrapper at
|
|
89
|
+
`src/services/context/headroom-client.ts` catches all errors and
|
|
90
|
+
treats them as fallback.
|
|
91
|
+
|
|
92
|
+
## What slice #010 does NOT do
|
|
93
|
+
|
|
94
|
+
- Does NOT install the `headroom proxy` daemon (N-7).
|
|
95
|
+
- Does NOT consume headroom's `SharedContext` directly (G7.7.3 in the
|
|
96
|
+
PRD); the peak-internal `SharedChannel` (G8) is the cross-sub-agent
|
|
97
|
+
state store. `buildSharedContextBridge()` is a stub that returns
|
|
98
|
+
the peak-internal channel ID + a placeholder headroom context ID.
|
|
99
|
+
- Does NOT use the SDK's `audit` / `optimize` / `simulate` modes
|
|
100
|
+
(those are SDK-internal; the peak wrapper exposes
|
|
101
|
+
`balanced` / `aggressive` / `conservative` to the user).
|
|
102
|
+
|
|
103
|
+
## Security + license
|
|
104
|
+
|
|
105
|
+
- License: Apache-2.0 (MIT-compatible) — see `THIRD_PARTY_LICENSES.md`.
|
|
106
|
+
- Pinned version: exact `0.22.4` (no `^` / `~` range) per dev-preference.
|
|
107
|
+
- `pnpm audit` ran on install; no new high-severity vulnerabilities.
|
|
@@ -53,10 +53,10 @@ peaks request lint <rid> --role prd --project <repo> --json
|
|
|
53
53
|
peaks request transition <rid> --role prd --state confirmed-by-user --project <repo> --json
|
|
54
54
|
peaks request transition <rid> --role prd --state handed-off --project <repo> --json
|
|
55
55
|
|
|
56
|
-
# 3. Peaks-Cli Swarm parallel — sub-agent fan-out (
|
|
56
|
+
# 3. Peaks-Cli Swarm parallel — sub-agent fan-out (peaks sub-agent dispatch, NOT Skill tool)
|
|
57
57
|
# Solo computes the swarm plan from --type + frontendOnly + frontend-keyword scan,
|
|
58
58
|
# writes it to .peaks/<sid>/sc/swarm-plan.json, then launches one
|
|
59
|
-
#
|
|
59
|
+
# `peaks sub-agent dispatch <role>` call per sub-agent in the same message.
|
|
60
60
|
# See "Peaks-Cli Swarm parallel phase" above for the full decision table and the
|
|
61
61
|
# prompt template; the role's required artefact paths are listed there.
|
|
62
62
|
# Hard rule: do NOT call Skill(skill="peaks-rd" | "peaks-qa" | "peaks-ui") from
|
|
@@ -75,7 +75,7 @@ peaks skill presence:set peaks-solo --project <repo> --mode <mode> --gate swarm-
|
|
|
75
75
|
# e.g. if plan = [ui, rd, qa]: run init for ui, rd, qa.
|
|
76
76
|
# If plan = [rd, qa]: run for rd, qa only.
|
|
77
77
|
# If plan = [] (config|docs|chore skip): no inits here, jump to step 4 directly.
|
|
78
|
-
# 3b. Solo issues N
|
|
78
|
+
# 3b. Solo issues N `peaks sub-agent dispatch <role>` calls in ONE message
|
|
79
79
|
# (N = len(swarm-plan.subAgents)). Each prompt embeds the role's body minus
|
|
80
80
|
# Step 0 / presence, plus the runtime args (rid / sid / mode / type / paths).
|
|
81
81
|
# 3c. After fan-out, Solo restores presence once and runs Gate B (ls checks):
|