opencode-swarm 7.193.0 → 7.195.0

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.
Files changed (116) hide show
  1. package/.opencode/skills/commit-pr/SKILL.md +8 -0
  2. package/.opencode/skills/issue-tracer/references/acceptance-checks.md +20 -0
  3. package/.opencode/skills/issue-tracer/references/full-resolution-contract.md +12 -0
  4. package/.opencode/skills/swarm-pr-feedback/SKILL.md +2 -2
  5. package/.opencode/skills/swarm-pr-feedback/references/operational-gotchas.md +18 -0
  6. package/.opencode/skills/swarm-pr-review/SKILL.md +11 -10
  7. package/.opencode/skills/swarm-pr-review/references/counterbalancing.md +68 -0
  8. package/.opencode/skills/swarm-pr-review/references/findings-persistence-contract.md +21 -0
  9. package/.opencode/skills/swarm-pr-review/references/parser-dry-run.md +11 -0
  10. package/.opencode/skills/swarm-pr-review/references/prompt-templates.md +8 -0
  11. package/README.md +1 -1
  12. package/binaries/win32-arm64/swarm-sandbox-runner.exe +0 -0
  13. package/binaries/win32-x64/swarm-sandbox-runner.exe +0 -0
  14. package/dist/background/pending-delegations.d.ts +8 -0
  15. package/dist/background/pr-review-collection-receipt.d.ts +7 -1
  16. package/dist/background/pr-review-contract.d.ts +10 -0
  17. package/dist/cli/{auto-checkpoint-taay16xe.js → auto-checkpoint-anf21wwa.js} +9 -9
  18. package/dist/cli/{checkpoint-6229g3jq.js → checkpoint-ngdw2qx2.js} +17 -17
  19. package/dist/cli/{coder-settlement-hexmmefv.js → coder-settlement-bqb059y2.js} +13 -13
  20. package/dist/cli/{config-doctor-3ghvthh5.js → config-doctor-vetg215g.js} +16 -16
  21. package/dist/cli/{core-0k7t9fw0.js → core-8qgvsm6x.js} +4 -4
  22. package/dist/cli/{curation-policy-8j6qn6nt.js → curation-policy-5hm6328s.js} +6 -6
  23. package/dist/cli/{curator-drift-a5142x0d.js → curator-drift-3gjycbkv.js} +9 -9
  24. package/dist/cli/{curator-kwwnkyr7.js → curator-hh0n9wgz.js} +43 -43
  25. package/dist/cli/curator-llm-factory-d17ybmgm.js +82 -0
  26. package/dist/cli/{doctor-knowledge-receipt-phase-id-11nsf9tz.js → doctor-knowledge-receipt-phase-id-1d465vkg.js} +9 -9
  27. package/dist/cli/{evidence-summary-service-y2ykc6ta.js → evidence-summary-service-rkd3yc5x.js} +20 -20
  28. package/dist/cli/{gate-evidence-cd5299js.js → gate-evidence-wtjrerkh.js} +8 -8
  29. package/dist/cli/guardrail-explain-8xh3r0dn.js +83 -0
  30. package/dist/cli/{guardrail-log-g6krx0s2.js → guardrail-log-jrey2myg.js} +8 -8
  31. package/dist/cli/{guardrail-reset-a3xv675m.js → guardrail-reset-m5qbg30j.js} +43 -43
  32. package/dist/cli/{hive-promoter-90svfzvs.js → hive-promoter-36yhdfre.js} +43 -43
  33. package/dist/cli/{index-5ev6f1gj.js → index-1hcjxz6w.js} +5 -5
  34. package/dist/cli/{index-6dn16dre.js → index-3k65kdfp.js} +13 -11
  35. package/dist/cli/{index-x2phyvcv.js → index-479kf368.js} +4 -4
  36. package/dist/cli/{index-5rkh69f3.js → index-4gmxdkcd.js} +2 -2
  37. package/dist/cli/{index-bg19b84s.js → index-5gf2wx2c.js} +7 -7
  38. package/dist/cli/{index-qh93qjc2.js → index-6183at3v.js} +2 -2
  39. package/dist/cli/{index-1p24bfn2.js → index-6vpqe4ws.js} +5 -5
  40. package/dist/cli/{index-ma71x1aa.js → index-780g1hht.js} +5 -5
  41. package/dist/cli/{index-jx80ed6g.js → index-7kbpzg05.js} +318 -95
  42. package/dist/cli/{index-mtqwyjrg.js → index-7rtq2t5n.js} +1 -1
  43. package/dist/cli/{index-vbp35frb.js → index-82aj6gaj.js} +3 -3
  44. package/dist/cli/{index-prvancd0.js → index-8448vj9w.js} +2 -2
  45. package/dist/cli/{index-d2emv8ap.js → index-863hst4e.js} +3 -3
  46. package/dist/cli/{index-db786kn6.js → index-9teqkkp4.js} +43 -43
  47. package/dist/cli/{index-bkpyff61.js → index-akb436kn.js} +4 -4
  48. package/dist/cli/{index-0e318vgt.js → index-app2rmxv.js} +1 -1
  49. package/dist/cli/{index-tr47q89d.js → index-bftpd2m5.js} +4 -4
  50. package/dist/cli/{index-rd9th57y.js → index-bpq6z8qe.js} +4 -4
  51. package/dist/cli/{index-cs0p582p.js → index-c4hx57tz.js} +5 -5
  52. package/dist/cli/{index-668npagp.js → index-c5xvm318.js} +1 -1
  53. package/dist/cli/{index-ngk8hpc3.js → index-c6hyd8hg.js} +1 -1
  54. package/dist/cli/{index-vg8sxg12.js → index-crz772sx.js} +1 -1
  55. package/dist/cli/{index-6s3ab22d.js → index-dfrcc46h.js} +2 -2
  56. package/dist/cli/{index-he2nyr7x.js → index-epdzvp4w.js} +11 -11
  57. package/dist/cli/{index-ymnathfr.js → index-fk4j26km.js} +7 -7
  58. package/dist/cli/{index-ndec8akq.js → index-gc0aeth5.js} +2 -2
  59. package/dist/cli/{index-fd6b9f38.js → index-ghckhk16.js} +2 -2
  60. package/dist/cli/{index-4mq8r4be.js → index-gns3gc87.js} +4 -4
  61. package/dist/cli/{index-5n760fzn.js → index-gz16dke1.js} +6 -6
  62. package/dist/cli/{index-3xj89bf0.js → index-h7275akd.js} +45 -45
  63. package/dist/cli/{index-cpt38e0e.js → index-ha8xc5d3.js} +2 -2
  64. package/dist/cli/{index-py8wpe81.js → index-hqrkr9ag.js} +2 -2
  65. package/dist/cli/{index-w2vbaczx.js → index-hy2fqapm.js} +1 -1
  66. package/dist/cli/{index-st80sjg7.js → index-j8t1g5qd.js} +1 -1
  67. package/dist/cli/{index-ntmnse4d.js → index-jatgbm7k.js} +1 -1
  68. package/dist/cli/{index-1dx5zyss.js → index-jn4mmhqc.js} +2 -2
  69. package/dist/cli/{index-nz6ehpjn.js → index-kmvy5fr8.js} +4 -4
  70. package/dist/cli/{index-84k9zzv1.js → index-kphy4we7.js} +1 -1
  71. package/dist/cli/{index-7njm9jk1.js → index-necqa5bj.js} +2 -2
  72. package/dist/cli/{index-bgtfvst1.js → index-peyz4k9k.js} +1 -1
  73. package/dist/cli/{index-3atkcqpb.js → index-ry5g9s8d.js} +1 -1
  74. package/dist/cli/{index-jxs9qnad.js → index-tc8x0zc5.js} +4 -4
  75. package/dist/cli/{index-e8k0v19e.js → index-xmbtwtgw.js} +1 -1
  76. package/dist/cli/{index-nktwf2xm.js → index-xs9cn3c0.js} +6 -6
  77. package/dist/cli/{index-hfssjyxs.js → index-yf2z4j7s.js} +2 -2
  78. package/dist/cli/{index-hfnyykvm.js → index-ypkfhqbc.js} +7 -7
  79. package/dist/cli/{index-r3mffz78.js → index-yryy781f.js} +4 -4
  80. package/dist/cli/{index-4gacy6y6.js → index-z59414gv.js} +2 -2
  81. package/dist/cli/index.js +44 -44
  82. package/dist/cli/{knowledge-escalator-2d7g3hs0.js → knowledge-escalator-6sgrjbcj.js} +15 -15
  83. package/dist/cli/{knowledge-events-hjeaevc9.js → knowledge-events-hztjt63y.js} +13 -13
  84. package/dist/cli/{knowledge-link-srnt95wh.js → knowledge-link-8bn2b7vr.js} +5 -5
  85. package/dist/cli/{knowledge-store-g9cb2m0v.js → knowledge-store-3sd2034v.js} +6 -6
  86. package/dist/cli/{knowledge-validator-dghf9pcj.js → knowledge-validator-3fe82zy4.js} +8 -8
  87. package/dist/cli/{mcp-f5myvd7r.js → mcp-spbx3efe.js} +1 -1
  88. package/dist/cli/{model-preflight-4w4wd6dj.js → model-preflight-k2bw7rt1.js} +43 -43
  89. package/dist/cli/{pending-delegations-adm6gf3n.js → pending-delegations-kcvd9t41.js} +14 -12
  90. package/dist/cli/{pr-subscriptions-n1hks854.js → pr-subscriptions-nqby87en.js} +12 -12
  91. package/dist/cli/{pr-workflow-gate-59cr6gve.js → pr-workflow-gate-cgbc0x1z.js} +59 -43
  92. package/dist/cli/{runner-b2e89cp1.js → runner-rt2smh14.js} +6 -6
  93. package/dist/cli/{scan-cursor-t26xmfhd.js → scan-cursor-sphr9phs.js} +7 -7
  94. package/dist/cli/{schema-cr120ar5.js → schema-x892aatt.js} +2 -2
  95. package/dist/cli/{scope-persistence-mrnz8j43.js → scope-persistence-n9xksct2.js} +16 -16
  96. package/dist/cli/{server-mwk6zn83.js → server-am2y11yn.js} +43 -43
  97. package/dist/cli/{skill-generator-svs4k0g8.js → skill-generator-p71b6h5k.js} +17 -17
  98. package/dist/cli/{snapshot-coordination-init-xzrahhsb.js → snapshot-coordination-init-x9b4t9sk.js} +43 -43
  99. package/dist/cli/{speckit-checkoff-g2qrb1tn.js → speckit-checkoff-xp9vsp9k.js} +5 -5
  100. package/dist/cli/{telemetry-qaymh4gg.js → telemetry-vapc5q4p.js} +1 -1
  101. package/dist/cli/{workspace-snapshot-p69t9zn7.js → workspace-snapshot-e3kw9kpg.js} +3 -3
  102. package/dist/cli/{worktree-collision-ownership-d145wmpg.js → worktree-collision-ownership-2pmyww6g.js} +13 -13
  103. package/dist/cli/{worktree-isolation-pt1rws6p.js → worktree-isolation-379tmkta.js} +43 -43
  104. package/dist/commands/registry.d.ts +1 -1
  105. package/dist/epic/start.d.ts +8 -5
  106. package/dist/hooks/pr-workflow-gate.d.ts +190 -0
  107. package/dist/host/v2/session-client.d.ts +96 -0
  108. package/dist/host/v2/types.d.ts +7 -5
  109. package/dist/index.js +36 -32
  110. package/dist/pr-review/legacy-transcript-adapter.d.ts +54 -0
  111. package/dist/pr-review/render-review-body.d.ts +20 -0
  112. package/dist/tools/dispatch-lanes.d.ts +16 -1
  113. package/dist/tools/pr-workflow-status.d.ts +24 -1
  114. package/package.json +1 -1
  115. package/dist/cli/curator-llm-factory-8gt3mvg9.js +0 -82
  116. package/dist/cli/guardrail-explain-hpgecr7x.js +0 -83
@@ -25,77 +25,77 @@ import {
25
25
  sanitizeWorktreeTaskId,
26
26
  standardWorktreeByCallID,
27
27
  standardWorktreeSerializationSessions
28
- } from "./index-jx80ed6g.js";
29
- import"./index-bkpyff61.js";
30
- import"./index-4mq8r4be.js";
31
- import"./index-ma71x1aa.js";
28
+ } from "./index-7kbpzg05.js";
29
+ import"./index-akb436kn.js";
30
+ import"./index-gns3gc87.js";
31
+ import"./index-780g1hht.js";
32
32
  import"./index-j2vv0h13.js";
33
- import"./index-668npagp.js";
34
- import"./index-7njm9jk1.js";
33
+ import"./index-c5xvm318.js";
34
+ import"./index-necqa5bj.js";
35
35
  import"./index-txdagbh7.js";
36
- import"./index-prvancd0.js";
36
+ import"./index-8448vj9w.js";
37
37
  import"./index-rdec0y3z.js";
38
- import"./index-d2emv8ap.js";
39
- import"./index-ymnathfr.js";
40
- import"./index-r3mffz78.js";
41
- import"./index-5n760fzn.js";
42
- import"./index-fd6b9f38.js";
43
- import"./index-hfnyykvm.js";
38
+ import"./index-863hst4e.js";
39
+ import"./index-fk4j26km.js";
40
+ import"./index-yryy781f.js";
41
+ import"./index-gz16dke1.js";
42
+ import"./index-ghckhk16.js";
43
+ import"./index-ypkfhqbc.js";
44
44
  import"./index-cjapb4hy.js";
45
- import"./index-6s3ab22d.js";
45
+ import"./index-dfrcc46h.js";
46
46
  import"./index-pt7h91zc.js";
47
47
  import"./index-q7sjgr1y.js";
48
- import"./index-nktwf2xm.js";
49
- import"./index-he2nyr7x.js";
48
+ import"./index-xs9cn3c0.js";
49
+ import"./index-epdzvp4w.js";
50
50
  import"./index-6b295cas.js";
51
51
  import"./index-9nyqt3kb.js";
52
- import"./index-bgtfvst1.js";
52
+ import"./index-peyz4k9k.js";
53
53
  import"./index-v3bmwmqw.js";
54
- import"./index-4gacy6y6.js";
55
- import"./index-nz6ehpjn.js";
56
- import"./index-x2phyvcv.js";
54
+ import"./index-z59414gv.js";
55
+ import"./index-kmvy5fr8.js";
56
+ import"./index-479kf368.js";
57
57
  import"./index-g4fs6z4e.js";
58
- import"./index-6dn16dre.js";
59
- import"./index-tr47q89d.js";
60
- import"./index-cs0p582p.js";
58
+ import"./index-3k65kdfp.js";
59
+ import"./index-bftpd2m5.js";
60
+ import"./index-c4hx57tz.js";
61
61
  import"./index-m9zzj4ee.js";
62
- import"./index-84k9zzv1.js";
62
+ import"./index-kphy4we7.js";
63
63
  import"./index-2s7dvzff.js";
64
- import"./index-jxs9qnad.js";
65
- import"./index-w2vbaczx.js";
64
+ import"./index-tc8x0zc5.js";
65
+ import"./index-hy2fqapm.js";
66
66
  import"./index-rtry5xyf.js";
67
67
  import {
68
68
  resolveWorktreeIsolationConfig
69
- } from "./index-vbp35frb.js";
69
+ } from "./index-82aj6gaj.js";
70
70
  import"./index-g22dps7x.js";
71
71
  import"./index-0725jpp7.js";
72
- import"./index-1p24bfn2.js";
73
- import"./index-5ev6f1gj.js";
74
- import"./index-qh93qjc2.js";
75
- import"./index-st80sjg7.js";
76
- import"./index-vg8sxg12.js";
77
- import"./index-0e318vgt.js";
72
+ import"./index-6vpqe4ws.js";
73
+ import"./index-1hcjxz6w.js";
74
+ import"./index-6183at3v.js";
75
+ import"./index-j8t1g5qd.js";
76
+ import"./index-crz772sx.js";
77
+ import"./index-app2rmxv.js";
78
78
  import"./index-ry16d01s.js";
79
79
  import"./index-rdm3px0g.js";
80
80
  import"./index-7pmbnjvj.js";
81
- import"./index-ndec8akq.js";
82
- import"./index-bg19b84s.js";
81
+ import"./index-gc0aeth5.js";
82
+ import"./index-5gf2wx2c.js";
83
83
  import"./index-vzm6zre7.js";
84
84
  import"./index-ae75rja9.js";
85
- import"./index-3atkcqpb.js";
86
- import"./index-5rkh69f3.js";
87
- import"./index-e8k0v19e.js";
85
+ import"./index-ry5g9s8d.js";
86
+ import"./index-4gmxdkcd.js";
87
+ import"./index-xmbtwtgw.js";
88
88
  import"./index-t7hmqgjy.js";
89
- import"./index-mtqwyjrg.js";
89
+ import"./index-7rtq2t5n.js";
90
90
  import"./index-fzpt2djt.js";
91
91
  import"./index-ejhxgyvm.js";
92
92
  import"./index-7g4c7s5r.js";
93
- import"./index-hfssjyxs.js";
93
+ import"./index-yf2z4j7s.js";
94
94
  import"./index-gx2vp8gx.js";
95
- import"./index-ngk8hpc3.js";
95
+ import"./index-c6hyd8hg.js";
96
96
  import"./index-zxdawwc7.js";
97
- import"./index-1dx5zyss.js";
98
- import"./index-py8wpe81.js";
97
+ import"./index-jn4mmhqc.js";
98
+ import"./index-hqrkr9ag.js";
99
99
  import"./index-bk5tah7q.js";
100
100
  import"./index-gknz3bv1.js";
101
101
  import"./index-zpsr8rpc.js";
@@ -715,7 +715,7 @@ export declare const COMMAND_REGISTRY: {
715
715
  readonly epic: {
716
716
  readonly handler: (ctx: CommandContext) => Promise<string>;
717
717
  readonly description: "Open, inspect, and close a plan-scoped epic (coupling-aware parallel execution of the current plan)";
718
- readonly details: "An epic is bound to ONE plan: `start` opens it for the current plan, `close` ends it. Requires `epic.mode.enabled: true` in config (top-level `epic` block; no `turbo` block needed — the legacy `turbo.epic` path is still accepted and migrated). `start [--force]` refuses, in order: epic-disabled-by-config, host-unsupported (the host gives the plugin no OpenCode SDK client — OpenCode 2 does not yet — so worktree-isolated coders and the phase review cannot run), no-plan / plan-ledger-unreadable, epic-already-open (idempotent for the same plan) / epic-open-for-other-plan, turbo-active (config turbo_mode, a session with Turbo on, or a running Lean run — Epic enables neither Lean nor Turbo and never waives per-task QA), dirty-baseline (git: uncommitted changes outside .swarm/), detached-head / epic-branch-exists (epic-branch policy), in-flight-coders (any coder dispatch, background delegation, unsettled settlement, or preserved/recovery lane), not-epic-sized (too few pending tasks, insufficient scope coverage, or insufficient effective speedup — run it in Balanced, or reshape it with the plan-shaping suggestions shown; `--force` overrides and is recorded). Non-git projects run an epic serially (one task per wave). Git epics default to `epic.commit_policy: \"epic-branch\"`: start checks out `swarm/epic/<epicKey>` and every Epic commit goes there (epic_next_wave blocks with epic-branch-mismatch, and no landing or residue is committed, while HEAD is elsewhere); `current-branch` keeps commits on the starting branch. In a git epic every coder runs in an isolated worktree (refused EPIC_ISOLATION_DEGRADED when isolation is unavailable) and lands as a `swarm(task <id>): …` merge commit; main-tree files a non-coder writer (test_engineer, docs) wrote for a task are committed as residue of that task; update_task_status writes nothing to git; wave close records the commit of each task as `refs/swarm/epics/<epicKey>/tasks/<id>` (deleted at close unless `epic.retain_refs`; never pushed by default). While open, the architect calls epic_next_wave and does what its status says: it issues one wave at a time (tasks with non-conflicting declared scopes — exclusive tasks alone, at most one task per densely coupled component; phases strictly in order), the architect dispatches one Task per taskId in ONE message and runs per-task QA (pre_check_batch → reviewer + test_engineer → update_task_status(completed)), and the next epic_next_wave closes the wave (recording outcomes and declared-vs-actual divergence) and issues the next; when a phase is done it returns phase-ready-for-review → epic_phase_review → phase_complete. `close [--abandon] [--land squash|merge|none]` refuses while tasks are pending (or the epic is orphaned / unreadable) unless `--abandon`, refuses a dirty tree before landing, writes a close report (epic-report-v2, embedding the epic scorecard) to .swarm/epic/reports/ and .swarm/epic-prior/reports/ (newest 50 kept), and lands the epic branch onto the original branch: squash (default — staged, uncommitted changes for you to review and commit), merge (a --no-ff merge commit), or none (switch back only). The epic branch is kept (remove it with `git branch -D` once committed). A landing conflict is rolled back (the attempted squash or merge is undone) and the epic stays closing — rerun close to resume. `--abandon` never lands; it switches back to the original branch when the tree is clean. `status [--repair-refs]` (also bare /swarm epic) shows the epic, its waves, phases, the task components recorded with the latest wave and recorded divergence, orphan detection (plan renamed or replaced), sentinel/row repair, recorded worktree merge failures, and retires legacy Epic v1 session state once; `--repair-refs` re-adopts task commits a rebase or amend made unreachable from HEAD. `report [<key>|last] [--format json]` shows the epic scorecard: live for the open epic (bare `report`), else from the close report of a past epic in .swarm/epic-prior/reports/ (`last` = newest; `<key>` = a report or epic key) — tasks completed in the epic, waves (count, width), time over closed waves (wave span, task issue→resolve time, and their ratio, a concurrency factor that is NOT a speedup: it includes queueing behind serialized QA), conflicts (merge-back failures, undeclared writes), rework (extra generations, reopens), first-pass gate rates (upper bounds: the failure history is bounded), forced/sizing at start and learned hot files. Epics learn from their outcomes: undeclared writes teach learned co-writes (a task declaring D that also wrote f makes later tasks declaring D conflict with tasks on f — planner analysis only, never write authorization) and incidents (undeclared writes, merge conflicts, Stage B failures, rework, reopens) in excess of clean exposures make a file hot (a task declaring it runs alone) — undeclared writes its strongest learned co-writer explains are discounted (expansion already separates them), so one declarer writing a file is not heat; an empty history learns nothing (neutral start). Each wave close updates the posterior of the epic; close merges it into the project prior .swarm/epic-prior/learning.json (decayed per epic and by age; kept across /swarm close; `epic.learning.*`). `learning` shows what the planner learned and uses now; `prior [show]` shows the project prior; `prior reset` previews and prints a single-use confirm token (15 minutes); `prior reset --confirm=<token>` clears it. Also: clear-merge-failure <taskId> [--confirm]. The former `on` / `off` toggles, the `decide` / `last` subcommands and `calibration` (renamed `learning`) were removed.";
718
+ readonly details: "An epic is bound to ONE plan: `start` opens it for the current plan, `close` ends it. Requires `epic.mode.enabled: true` in config (top-level `epic` block; no `turbo` block needed — the legacy `turbo.epic` path is still accepted and migrated). `start [--force]` refuses, in order: epic-disabled-by-config, host-unsupported (the host gives the plugin no OpenCode SDK client; on OpenCode 2 the v2 adapter now ships one, so this refusal no longer fires there — v2 is held by the child-session placement work instead), no-plan / plan-ledger-unreadable, epic-already-open (idempotent for the same plan) / epic-open-for-other-plan, turbo-active (config turbo_mode, a session with Turbo on, or a running Lean run — Epic enables neither Lean nor Turbo and never waives per-task QA), dirty-baseline (git: uncommitted changes outside .swarm/), detached-head / epic-branch-exists (epic-branch policy), in-flight-coders (any coder dispatch, background delegation, unsettled settlement, or preserved/recovery lane), not-epic-sized (too few pending tasks, insufficient scope coverage, or insufficient effective speedup — run it in Balanced, or reshape it with the plan-shaping suggestions shown; `--force` overrides and is recorded). Non-git projects run an epic serially (one task per wave). Git epics default to `epic.commit_policy: \"epic-branch\"`: start checks out `swarm/epic/<epicKey>` and every Epic commit goes there (epic_next_wave blocks with epic-branch-mismatch, and no landing or residue is committed, while HEAD is elsewhere); `current-branch` keeps commits on the starting branch. In a git epic every coder runs in an isolated worktree (refused EPIC_ISOLATION_DEGRADED when isolation is unavailable) and lands as a `swarm(task <id>): …` merge commit; main-tree files a non-coder writer (test_engineer, docs) wrote for a task are committed as residue of that task; update_task_status writes nothing to git; wave close records the commit of each task as `refs/swarm/epics/<epicKey>/tasks/<id>` (deleted at close unless `epic.retain_refs`; never pushed by default). While open, the architect calls epic_next_wave and does what its status says: it issues one wave at a time (tasks with non-conflicting declared scopes — exclusive tasks alone, at most one task per densely coupled component; phases strictly in order), the architect dispatches one Task per taskId in ONE message and runs per-task QA (pre_check_batch → reviewer + test_engineer → update_task_status(completed)), and the next epic_next_wave closes the wave (recording outcomes and declared-vs-actual divergence) and issues the next; when a phase is done it returns phase-ready-for-review → epic_phase_review → phase_complete. `close [--abandon] [--land squash|merge|none]` refuses while tasks are pending (or the epic is orphaned / unreadable) unless `--abandon`, refuses a dirty tree before landing, writes a close report (epic-report-v2, embedding the epic scorecard) to .swarm/epic/reports/ and .swarm/epic-prior/reports/ (newest 50 kept), and lands the epic branch onto the original branch: squash (default — staged, uncommitted changes for you to review and commit), merge (a --no-ff merge commit), or none (switch back only). The epic branch is kept (remove it with `git branch -D` once committed). A landing conflict is rolled back (the attempted squash or merge is undone) and the epic stays closing — rerun close to resume. `--abandon` never lands; it switches back to the original branch when the tree is clean. `status [--repair-refs]` (also bare /swarm epic) shows the epic, its waves, phases, the task components recorded with the latest wave and recorded divergence, orphan detection (plan renamed or replaced), sentinel/row repair, recorded worktree merge failures, and retires legacy Epic v1 session state once; `--repair-refs` re-adopts task commits a rebase or amend made unreachable from HEAD. `report [<key>|last] [--format json]` shows the epic scorecard: live for the open epic (bare `report`), else from the close report of a past epic in .swarm/epic-prior/reports/ (`last` = newest; `<key>` = a report or epic key) — tasks completed in the epic, waves (count, width), time over closed waves (wave span, task issue→resolve time, and their ratio, a concurrency factor that is NOT a speedup: it includes queueing behind serialized QA), conflicts (merge-back failures, undeclared writes), rework (extra generations, reopens), first-pass gate rates (upper bounds: the failure history is bounded), forced/sizing at start and learned hot files. Epics learn from their outcomes: undeclared writes teach learned co-writes (a task declaring D that also wrote f makes later tasks declaring D conflict with tasks on f — planner analysis only, never write authorization) and incidents (undeclared writes, merge conflicts, Stage B failures, rework, reopens) in excess of clean exposures make a file hot (a task declaring it runs alone) — undeclared writes its strongest learned co-writer explains are discounted (expansion already separates them), so one declarer writing a file is not heat; an empty history learns nothing (neutral start). Each wave close updates the posterior of the epic; close merges it into the project prior .swarm/epic-prior/learning.json (decayed per epic and by age; kept across /swarm close; `epic.learning.*`). `learning` shows what the planner learned and uses now; `prior [show]` shows the project prior; `prior reset` previews and prints a single-use confirm token (15 minutes); `prior reset --confirm=<token>` clears it. Also: clear-merge-failure <taskId> [--confirm]. The former `on` / `off` toggles, the `decide` / `last` subcommands and `calibration` (renamed `learning`) were removed.";
719
719
  readonly args: "start [--force] | close [--abandon] [--land squash|merge|none] | status [--repair-refs] | report [<key>|last] [--format json] | learning | prior [show|reset [--confirm=<token>]] | clear-merge-failure <taskId> [--confirm]";
720
720
  readonly category: "diagnostics";
721
721
  readonly toolPolicy: "human-only";
@@ -97,7 +97,7 @@ export interface EpicStartOptions {
97
97
  * with `client: undefined` (`src/host/v2/setup.ts`), so an epic there could
98
98
  * neither dispatch a coder nor complete a phase.
99
99
  */
100
- export declare const EPIC_HOST_UNSUPPORTED_MESSAGE = "This OpenCode host gives the plugin no SDK client (OpenCode 2 does not yet, see docs/host/v2-hook-inventory.md). Epic needs it for worktree-isolated coders and for the epic_phase_review reviewer/critic, so an epic here could neither run its coders nor complete a phase. Run the plan in Balanced, or use an OpenCode 1.x host (1.18.29+).";
100
+ export declare const EPIC_HOST_UNSUPPORTED_MESSAGE = "This OpenCode host gives the plugin no SDK client. Epic needs it for worktree-isolated coders and for the epic_phase_review reviewer/critic, so an epic here could neither run its coders nor complete a phase. Run the plan in Balanced, or use an OpenCode 1.x host (1.18.29+). (On OpenCode 2 the v2 adapter now ships a session-capable client, so this refusal no longer fires there \u2014 Epic on v2 is held by the #3169 child-session placement work instead.)";
101
101
  /** Durable Lean run marked `running` — read without the migrating Lean reader. */
102
102
  declare function findRunningLeanRun(directory: string): string | null;
103
103
  /** Why Turbo blocks the start, or null (M-a). */
@@ -163,10 +163,13 @@ export declare const _internals: {
163
163
  hasActiveTurboMode: () => boolean;
164
164
  /**
165
165
  * False only when the plugin was initialized on a host that supplies no
166
- * SDK client: the v1 init stores the host client, the OpenCode 2 adapter
167
- * stores `undefined`, and an uninitialized process (tests, scripts) keeps
168
- * the initial `null` — which is not a host verdict, so it is allowed.
169
- * Capability-based: once a v2 client is wired, Epic starts there too.
166
+ * SDK client: the v1 init stores the host client, an uninitialized process
167
+ * (tests, scripts) keeps the initial `null`, and only a genuinely
168
+ * client-less host stores `undefined` — which is not a host verdict, so
169
+ * it is allowed. Capability-based: the v2 adapter now ships a
170
+ * session-capable client (the #3169 session shim), so this passes on v2;
171
+ * Epic's v2 execution is held by the entry-point double-gate and the
172
+ * child-session placement work, not by this check.
170
173
  */
171
174
  hostProvidesClient: () => boolean;
172
175
  findRunningLeanRun: typeof findRunningLeanRun;
@@ -464,6 +464,20 @@ interface PrReviewBatchCoherenceRecord {
464
464
  reviewerItemBindings?: Record<string, string>;
465
465
  /** Key encoding for reviewerItemBindings; absent means legacy raw item IDs. */
466
466
  reviewerItemBindingKeyEncoding?: 'prefixed-v1';
467
+ /**
468
+ * Issue #2906: reviewer batches only. The presentation order this batch's
469
+ * candidates were counterbalanced into — 'A' renders the canonical sorted
470
+ * inventory, 'B' the exact reverse — alternating by reviewer-batch ordinal
471
+ * within the reviewer window so repeated passes observe order effects.
472
+ */
473
+ presentationOrder?: 'A' | 'B';
474
+ /**
475
+ * Issue #2906: critic batches only. AUDIT-ONLY snapshot of the
476
+ * order-unstable item ids the critic prompt for this batch was flagged
477
+ * with (the prompt re-derives them live via
478
+ * `derivePrReviewOrderUnstableItems`); no runtime reader consumes this.
479
+ */
480
+ orderUnstableItemIds?: string[];
467
481
  }
468
482
  /** One rejected `submit_pr_review_result` attempt (issue #2859 F3 journal). */
469
483
  export interface PrReviewSubmitRejectionRecord {
@@ -474,6 +488,22 @@ export interface PrReviewSubmitRejectionRecord {
474
488
  }
475
489
  /** FIFO cap for the gate-state submit-rejection journal (issue #2859 F3). */
476
490
  export declare const MAX_PR_REVIEW_SUBMIT_REJECTIONS = 24;
491
+ /**
492
+ * One rejected `write_pr_review_artifact` attempt (issue #3098 verdict-lane
493
+ * journal, mirroring the #2859 discovery journal). `sessionId` is the gate
494
+ * owner (the orchestrator session that called the tool) — provenance only;
495
+ * the composition joins entries to lanes via `workflowLane`/`laneId`.
496
+ */
497
+ export interface PrReviewVerdictRejectionRecord {
498
+ sessionId: string;
499
+ laneId?: string;
500
+ workflowLane?: string;
501
+ boundary?: 'post_explorer' | 'post_reviewer' | 'post_critic';
502
+ at: number;
503
+ message: string;
504
+ }
505
+ /** FIFO cap for the gate-state verdict-write-rejection journal (issue #3098). */
506
+ export declare const MAX_PR_REVIEW_VERDICT_REJECTIONS = 24;
477
507
  export interface PrWorkflowGateState {
478
508
  schemaVersion: 1;
479
509
  /** Monotonic durable revision used to reject stale same-session transitions. */
@@ -588,6 +618,17 @@ export interface PrWorkflowGateState {
588
618
  * to 300 chars at write time.
589
619
  */
590
620
  prReviewSubmitRejections?: PrReviewSubmitRejectionRecord[];
621
+ /**
622
+ * Bounded FIFO journal of rejected `write_pr_review_artifact` attempts
623
+ * (issue #3098, the verdict-lane mirror of the #2859 journal above).
624
+ * Observability only — surfaced in the verdict composition diagnostic so
625
+ * the orchestrator can see WHY a declared reviewer/critic lane produced no
626
+ * successful exact artifact; never consulted for artifact validity. Capped
627
+ * by {@link MAX_PR_REVIEW_VERDICT_REJECTIONS}; each entry's message is
628
+ * bounded to 300 chars at write time. `sessionId` is the gate-owner caller
629
+ * (provenance); lane join happens via `workflowLane`/`laneId`.
630
+ */
631
+ prReviewVerdictRejections?: PrReviewVerdictRejectionRecord[];
591
632
  prReviewHandoffPath?: string;
592
633
  prReviewHandoffRequired?: boolean;
593
634
  checkoutRecovery?: PrWorkflowCheckoutRecoveryRecord;
@@ -714,6 +755,38 @@ export declare function recordPrReviewSubmitRejection(directory: string, childSe
714
755
  * ever see its most recent rejections.
715
756
  */
716
757
  export declare function latestPrReviewSubmitRejectionMessage(state: Pick<PrWorkflowGateState, 'prReviewSubmitRejections'>, childSessionId: string): string | undefined;
758
+ /**
759
+ * Issue #3098: best-effort, fail-open journal of one rejected
760
+ * `write_pr_review_artifact` attempt onto the CALLER's own PR_REVIEW gate
761
+ * state (the tool is a controller tool invoked by the gate-owner session —
762
+ * no delegation parent-hop, unlike the #2859 discovery journal).
763
+ * Observability only — never changes the rejection outcome, never creates
764
+ * gate state for a session that has none (the pre-read outside the
765
+ * session-state lock means a non-gated caller gets no lock file either).
766
+ */
767
+ export declare function recordPrReviewVerdictRejection(directory: string, sessionID: string, message: string, attribution?: {
768
+ laneId?: string;
769
+ workflowLane?: string;
770
+ boundary?: 'post_explorer' | 'post_reviewer' | 'post_critic';
771
+ }): Promise<void>;
772
+ /**
773
+ * Issue #3098: latest journal message for a failing obligation, or undefined.
774
+ * Newest wins. Join keys are `workflowLane` (the declared obligation) and
775
+ * `laneId`; the recorded `sessionId` is the gate-owner caller (provenance),
776
+ * never a lane child session, so it is deliberately not a join key.
777
+ *
778
+ * The production writer only ever stamps `boundary` (the write args name the
779
+ * boundary, never a lane), so in practice the phase-scoped fallback below is
780
+ * what resolves: it reports the newest rejection recorded for the failing
781
+ * lane's PHASE, which is honest about being phase-scoped rather than
782
+ * lane-scoped. The lane-exact arms stay because a future attribution producer
783
+ * (or a hand-seeded state) can populate them.
784
+ */
785
+ export declare function latestPrReviewVerdictRejectionForLane(state: Pick<PrWorkflowGateState, 'prReviewVerdictRejections'>, matchers: {
786
+ workflowLane?: string;
787
+ laneIds?: readonly string[];
788
+ boundary?: 'post_explorer' | 'post_reviewer' | 'post_critic';
789
+ }): string | undefined;
717
790
  /**
718
791
  * Issue #2859 (F3): single wrap point over every gate-layer rejection path in
719
792
  * `submitPrReviewResultCore` (all 15 `{ status: 'rejected' }` return sites —
@@ -1253,6 +1326,13 @@ export declare function recordPrReviewMicroFamilyDispatch(directory: string, ses
1253
1326
  export declare function recordPrReviewValidationBatch(directory: string, sessionID: string, phase: PrReviewValidationPhase, lanes: readonly PrWorkflowLaneSpec[], options: {
1254
1327
  batchId: string;
1255
1328
  prHeadSha: string;
1329
+ /**
1330
+ * Issue #2906: reviewer batches only. The presentation order the dispatch
1331
+ * prompt was counterbalanced for (from `derivePrReviewPresentationOrder`).
1332
+ * When supplied and the re-derived ordinal disagrees, recording fails
1333
+ * closed so the prompt can never misrepresent the stamped receipt.
1334
+ */
1335
+ expectedPresentationOrder?: 'A' | 'B';
1256
1336
  }): Promise<PrWorkflowGateState>;
1257
1337
  /**
1258
1338
  * Validate that every declared council obligation has a successful retry, and
@@ -1491,6 +1571,27 @@ export declare function markPrReviewHandoffComplete(directory: string, sessionID
1491
1571
  state: PrWorkflowGateState;
1492
1572
  alreadyOffered: boolean;
1493
1573
  }>;
1574
+ interface PrReviewFindingPolicyAuthority {
1575
+ policyFindings: Array<{
1576
+ id: string;
1577
+ status: string;
1578
+ severity: string;
1579
+ action: string;
1580
+ [key: string]: unknown;
1581
+ }>;
1582
+ criticSettlements: Array<{
1583
+ findingId: string;
1584
+ terminal: boolean;
1585
+ status: CriticOutcome;
1586
+ }>;
1587
+ }
1588
+ /**
1589
+ * Read the policy sidecar as an integrity-bound projection of the final
1590
+ * findings artifact. A write-only sidecar is not evidence: the route receipt
1591
+ * pins the PR head and exact findings bytes, while the sidecar digest pins the
1592
+ * synthesized projection itself.
1593
+ */
1594
+ export declare function readAuthoritativeFindingPolicy(directory: string, state: PrWorkflowGateState): Promise<PrReviewFindingPolicyAuthority>;
1494
1595
  /** Read-only final finding-policy projection for completion reports. */
1495
1596
  export declare function readPrReviewFinalFindingPolicyForReport(directory: string, sessionID: string): Promise<{
1496
1597
  policyVersion: 1;
@@ -1677,6 +1778,8 @@ export declare const _test_exports: {
1677
1778
  validatedInventory: string[];
1678
1779
  reviewerItemBindings?: Record<string, string> | undefined;
1679
1780
  reviewerItemBindingKeyEncoding?: "prefixed-v1" | undefined;
1781
+ presentationOrder?: "A" | "B" | undefined;
1782
+ orderUnstableItemIds?: string[] | undefined;
1680
1783
  }> | undefined;
1681
1784
  prReviewRetiredReviewerSessionIds?: string[] | undefined;
1682
1785
  prReviewRetiredConsolidatedLanes?: string[] | undefined;
@@ -1721,6 +1824,15 @@ export declare const _test_exports: {
1721
1824
  message: string;
1722
1825
  laneId?: string | undefined;
1723
1826
  }[] | undefined;
1827
+ prReviewVerdictRejections?: {
1828
+ [x: string]: unknown;
1829
+ sessionId: string;
1830
+ at: number;
1831
+ message: string;
1832
+ laneId?: string | undefined;
1833
+ workflowLane?: string | undefined;
1834
+ boundary?: "post_explorer" | "post_reviewer" | "post_critic" | undefined;
1835
+ }[] | undefined;
1724
1836
  prReviewArtifactBoundaries?: ("post_explorer" | "post_reviewer" | "post_critic")[] | undefined;
1725
1837
  prReviewHandoffPath?: string | undefined;
1726
1838
  prReviewHandoffRequired?: boolean | undefined;
@@ -2208,6 +2320,32 @@ interface PrReviewGateContext {
2208
2320
  */
2209
2321
  candidateSeverities?: Map<string, CandidateSeverity>;
2210
2322
  }
2323
+ /**
2324
+ * Issue #3095: read-surface reuse of the derivation above for
2325
+ * `pr_workflow_status`. The derivation itself stays single-sourced: every
2326
+ * production caller is a validation/enforcement path that must keep throwing,
2327
+ * so this wrapper exists only to thread the SAME result to a read-only status
2328
+ * tool and to degrade fail-soft instead of blocking an observation. A status
2329
+ * read must never fail the whole tool for an unbound head or an unreadable
2330
+ * revision digest — the caller renders the `unavailable` arm (with the
2331
+ * bounded reason) and still projects boundaries and lane coverage.
2332
+ *
2333
+ * Read-only by construction: it performs no writes and mutates no state.
2334
+ * COST DISCLOSURE (not free): resolving the derivation context runs the
2335
+ * revision-digest computation on every bound PR_REVIEW call — three bounded
2336
+ * git processes plus a re-read/hash of every changed file
2337
+ * (`createPrReviewGateContext` → `resolvePrWorkflowRevisionDigestForGate` →
2338
+ * the workspace-snapshot digest path). An observation surface pays the same
2339
+ * digest price an enforcement call would.
2340
+ */
2341
+ export type PrReviewCandidateInventoryForStatus = {
2342
+ state: 'available';
2343
+ inventory: string[];
2344
+ } | {
2345
+ state: 'unavailable';
2346
+ reason: string;
2347
+ };
2348
+ export declare function derivePrReviewCandidateInventoryForStatus(directory: string, state: PrWorkflowGateState): Promise<PrReviewCandidateInventoryForStatus>;
2211
2349
  /**
2212
2350
  * Extract candidate ids from a discovery artifact's [CANDIDATE] rows. When
2213
2351
  * `scopeToLanes` is given (base-dimension sources credited for only a subset
@@ -2307,6 +2445,47 @@ export declare function readAuthoritativePrReviewCriticVerdicts(directory: strin
2307
2445
  status: string;
2308
2446
  severity: string;
2309
2447
  }>>;
2448
+ /**
2449
+ * Issue #2906: the presentation order the NEXT reviewer batch will be
2450
+ * counterbalanced into — 'A' when the reviewer window holds an even number of
2451
+ * batches, 'B' when odd. Pure function of the persisted window state; the
2452
+ * dispatch tool derives it before prompt assembly and passes the same value to
2453
+ * `recordPrReviewValidationBatch` as `expectedPresentationOrder`, which
2454
+ * re-derives and fails closed on divergence.
2455
+ *
2456
+ * Issue #2906 review finding F-03: at the `MAX_WORKFLOW_BATCHES` cap the
2457
+ * record guard counts the window of the PRUNED state (its read-prune-append
2458
+ * transaction applies `prunePrWorkflowBatchesForCapacity` before deriving the
2459
+ * stamped ordinal), while this derivation used to count the unpruned persisted
2460
+ * window. When the prune flipped the window parity the guard threw — before
2461
+ * `persistState`, so the prune was never durable — and every retry re-derived
2462
+ * the same divergent value: a permanent liveness wedge that failed closed.
2463
+ * This derivation therefore applies the SAME pure prune under the SAME
2464
+ * >= cap condition, so both sides count the identical window. The prune is
2465
+ * pure with respect to durable state (it reads artifacts and returns a
2466
+ * candidate state; only the record path persists it), so running it here
2467
+ * cannot violate the BL-6 single-transaction rule. Every prune-abort path
2468
+ * (inventory inequality, unreadable delegation store, ledger overflow) returns
2469
+ * the state unchanged here AND inside the record guard, so the two sides agree
2470
+ * on those paths as well; a divergence that still reaches the guard means the
2471
+ * state genuinely changed between derivation and recording, which fails closed
2472
+ * and is recoverable by re-deriving.
2473
+ */
2474
+ export declare function derivePrReviewPresentationOrder(directory: string, sessionID: string): Promise<'A' | 'B'>;
2475
+ /**
2476
+ * Issue #2906: every currently-composed reviewer item whose verdict flipped
2477
+ * across counterbalanced presentation orders (`orderAgreement: 'disagree'`).
2478
+ * The critic dispatch tool renders these as `order_unstable_item_ids` so the
2479
+ * critic prioritizes them.
2480
+ */
2481
+ export declare function derivePrReviewOrderUnstableItems(directory: string, sessionID: string): Promise<string[]>;
2482
+ /**
2483
+ * Issue #2906: the authoritative per-item order-agreement map for the findings
2484
+ * writer — the same reader shape as `readAuthoritativePrReviewCriticVerdicts`,
2485
+ * so a model-supplied `order_agreement` on a findings row can be cross-checked
2486
+ * against the composed reviewer claims instead of being taken on trust.
2487
+ */
2488
+ export declare function readAuthoritativePrReviewOrderAgreement(directory: string, sessionID: string): Promise<Map<string, 'agree' | 'disagree' | 'single'>>;
2310
2489
  interface ExpectedWorkflowLane {
2311
2490
  laneId: string;
2312
2491
  workflowLane: string;
@@ -2406,6 +2585,17 @@ export interface PrWorkflowGateRecoveryRead {
2406
2585
  * availability one.
2407
2586
  */
2408
2587
  armedShapeUnreadable: boolean;
2588
+ /**
2589
+ * true when the salvage reconstructed ONLY the abort-relevant fields and
2590
+ * every `prReview*` projection field (base dispatches, artifact
2591
+ * boundaries, run id, findings path, settlement digests) was dropped
2592
+ * because the shadow bytes failed schema validation. The status tool uses
2593
+ * this to mark its derived PR_REVIEW sections `unavailable` instead of
2594
+ * reporting healthy-but-empty coverage — an absent field on a salvaged
2595
+ * state proves nothing about the workflow. Present only when true; a
2596
+ * schema-valid shadow (or an ordinary healthy read) keeps full fidelity.
2597
+ */
2598
+ prReviewProjectionDropped?: boolean;
2409
2599
  }
2410
2600
  /**
2411
2601
  * Recovery-only gate-state reader (issue #2242 R4, wedge W-5).
@@ -0,0 +1,96 @@
1
+ /**
2
+ * v2 session client shim — issue #3169 Phase 2 (+ Phase 3 lane sessions).
3
+ *
4
+ * A narrow `OpencodeClient` subset implementing exactly the v1 session surface
5
+ * Epic's dispatch paths use (`session.create/prompt/abort/delete` plus `get`,
6
+ * which verified teardown requires), backed by the v2 host's `ctx.session`
7
+ * domain. Installed as the synthetic v1 PluginInput's `client` field by
8
+ * `setup.ts`, it flows through the shared init core's single client write site
9
+ * into `swarmState.opencodeClient` and every init-path `ctx.client` consumer —
10
+ * the tracking issue's Decision 2 (a client subset instead of v2 branches
11
+ * spread through consumers).
12
+ *
13
+ * Translation contract (per the issue §4 gap table and the Phase 0 live
14
+ * findings on @opencode/cli 2.0.26):
15
+ *
16
+ * - `create({body:{parentID,title}, query:{directory}})` validates placement
17
+ * BEFORE creating anything. Phase 3: a CONFIRMED parent-directory divergence
18
+ * (the worktree-isolation lane shape — a lane worktree directory always
19
+ * differs from the parent's project root) now takes the EAGER path: a REAL
20
+ * parentless host session created immediately in the requested directory
21
+ * (Phase 0 C1: parented children inherit the parent's directory; parentless
22
+ * creates honor the requested one), placement verified post-create (echo,
23
+ * `get` fallback) with a remove-and-fail-closed guard, and the requested
24
+ * `parentID` REMEMBERED plugin-side and overlaid onto `get` results so
25
+ * `prWorkflowSessionResolver`'s first-hop controller resolution
26
+ * (`pr-workflow-session-resolver.ts`) and `lookupParentSessionIDForTaskRoute`
27
+ * stay v1-faithful for parentless lane children (the host-side link is what
28
+ * the v2 host cannot carry here). A real id is returned — the native
29
+ * `subagent` tool resumes it by id (Phase 0 C7). Unverifiable parent
30
+ * placement still fails closed with the Phase 2 typed error (live-verification
31
+ * item), and same-directory/parentless creates keep the deferred placeholder
32
+ * (the real create there must carry prompt-time options — permissions are
33
+ * create-time-only on v2).
34
+ * - `prompt({path:{id}, body:{agent,model?,system?,tools,parts}, signal?})`
35
+ * emulates the v1 BLOCKING call over three arms keyed on the registry:
36
+ * (1) an EAGER record → full treatment on the real session — `switchAgent` +
37
+ * `switchModel`, a sessionID-scoped `context` hook (fence-aware system
38
+ * replacement preserving `<swarm_system_directive` parts, denied-tool
39
+ * deletion from `event.tools`), epoch-scoped error clear, `prompt` →
40
+ * bounded `wait` → `context()`; (2) a deferred/already-prompted PLACEHOLDER
41
+ * → real create carrying agent/model + the read-only denial map as
42
+ * `effect:'deny'` permissions, then the same hook/prompt/wait/context
43
+ * sequence, with the #3186 PRR-002 retire-and-recreate on re-prompts;
44
+ * (3) a foreign real id → the direct path (agent switch only). All three
45
+ * translate into the v1 `{data:{info,parts}}` envelope so
46
+ * `dispatchEphemeralAgent` and `readProviderMessageError` work unchanged.
47
+ * - Provider failures are EVENT-SOURCED on v2 (Phase 0 C4: no error text in
48
+ * `context()`), so the event pump records `session.error` /
49
+ * `session.execution.failed` payloads here (`recordV2SessionErrorFromEnvelope`,
50
+ * called pump-side beside `seedSessionIdentityFromEnvelope`) and the
51
+ * translation surfaces them as the v1 `info.error` shape. A failed outcome
52
+ * without recorded detail yields a bounded `provider.unknown` error
53
+ * instead of a silent empty success.
54
+ * - `abort` maps to `interrupt`, `delete` to `remove` (eager records are
55
+ * pruned after the removal resolves — the id is real, so a later `get`
56
+ * still resolves through to a host that reports the session gone), and
57
+ * `get` maps `{path:{id}}` onto `ctx.session.get({sessionID})` returning
58
+ * `{data: info}` — verified teardown through the shim resolves.
59
+ *
60
+ * Registry (invariant 8): placeholder and eager records share ONE bounded map
61
+ * (cap 64, FIFO). Placeholder residue is intentionally not pruned (keep-for-get);
62
+ * that residue shares the cap, so a live eager record can be evicted after 64
63
+ * later insertions of any kind — a disclosed, bounded degradation (its next
64
+ * prompt takes the direct path and the parentID overlay stops applying), pinned
65
+ * in tests/unit/host/v2/session-client-lane-3169.test.ts.
66
+ *
67
+ * Deferred-work marker: NONE. The unverified live-host behaviors this design
68
+ * rests on are recorded as deferrals in the trace (context-hook firing for
69
+ * plugin-created sessions, permission vocabulary honor, `context()` entry
70
+ * shapes, `wait` on failed prompts, `get(parent).location` availability,
71
+ * parentless subagent resume + parentID overlay — LVD-1..LVD-4) with the owning
72
+ * follow-up on #3169.
73
+ *
74
+ * C6 await convention: every `await` lives inside a `deferredV2Session*`
75
+ * function declaration or `const deferredV2SessionX = async (` binding — the
76
+ * dual-shape-parity scan's function tracker does not recognize object-literal
77
+ * method properties, so the client object's methods never await directly.
78
+ */
79
+ import type { OpencodeClient } from '@opencode-ai/sdk';
80
+ import type { V2EventEnvelope, V2PluginContext, V2SessionPermission } from './types';
81
+ /**
82
+ * Record a `session.error` / `session.execution.failed` envelope's error
83
+ * payload for the shim's result translation. SYNC by contract — the event pump
84
+ * calls it inline in its iteration loop. Accepts the same dual payload dialect
85
+ * `mapV2EventToV1` accepts (live `data`, SDK `properties`).
86
+ */
87
+ export declare function recordV2SessionErrorFromEnvelope(envelope: V2EventEnvelope): void;
88
+ /** Drop all shim-held state (v2 cleanup path; bounded residue documented in the trace). */
89
+ export declare function clearV2SessionClientState(): void;
90
+ /**
91
+ * Map a v1 read-only denial map onto v2 create-time permission entries.
92
+ * Fail-closed shape: only `effect: 'deny'` entries are ever produced.
93
+ */
94
+ export declare function readOnlyToolsToV2Permissions(tools: Readonly<Record<string, false>> | undefined): V2SessionPermission[];
95
+ /** Feature-detect the full surface the shim requires (types.ts host-tolerance contract). */
96
+ export declare function createV2SessionClient(ctx: V2PluginContext): OpencodeClient | undefined;
@@ -14,11 +14,13 @@
14
14
  *
15
15
  * Drift guard: DEFERRED to the #2910 follow-up PR (a check-host-contract v2 digest leg over this corpus, plus the dual-host CI lane); until it lands, type truth rests on this provenance pin (now 2.0.26) and the live-host smoke. See docs/host/v2-hook-inventory.md for the full v1-to-v2 map.
16
16
  *
17
- * Host-tolerance contract for the session/worktree method surface (issue #3169 Phase 1):
18
- * the members below are REQUIRED to mirror the published `SessionDomain`/`WorktreeDomain`,
19
- * but nothing in Phase 1 calls them. Phase 2 call sites MUST feature-detect
20
- * (`typeof ctx.session.create === 'function'`) and degrade — requiredness is type-level
21
- * only and a 2.0.2x host lacking a member must never crash the adapter.
17
+ * Host-tolerance contract for the session/worktree method surface (issue #3169):
18
+ * the members below are REQUIRED to mirror the published `SessionDomain`/`WorktreeDomain`.
19
+ * Since Phase 2 the session-client shim (`src/host/v2/session-client.ts`) is the call
20
+ * site — it feature-detects every member it consumes, including `hook` (`typeof
21
+ * ctx.session.create === 'function'`), and returns `undefined` when any is missing, so
22
+ * requiredness stays type-level only and a 2.0.2x host lacking a member must never crash
23
+ * the adapter.
22
24
  *
23
25
  * Only the surfaces this adapter consumes are typed. Unknown fields are
24
26
  * intentionally left off; the adapter never relies on their absence.