opencode-swarm 7.95.0 → 7.97.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.
- package/.opencode/skills/codebase-review-swarm/references/review-protocol-v8.2.md +1 -1
- package/.opencode/skills/council/SKILL.md +4 -2
- package/.opencode/skills/deep-dive/SKILL.md +3 -1
- package/.opencode/skills/deep-research/SKILL.md +13 -7
- package/.opencode/skills/execute/SKILL.md +2 -2
- package/.opencode/skills/pre-phase-briefing/SKILL.md +21 -5
- package/.opencode/skills/swarm-pr-feedback/SKILL.md +19 -7
- package/.opencode/skills/swarm-pr-review/SKILL.md +3 -1
- package/dist/cli/{config-doctor-n5w1jexx.js → config-doctor-h1xrvq83.js} +2 -2
- package/dist/cli/{evidence-summary-service-mr9sns2d.js → evidence-summary-service-g4x5e3e3.js} +1 -1
- package/dist/cli/{guardrail-explain-1ad236sh.js → guardrail-explain-t6svvtmn.js} +6 -6
- package/dist/cli/{guardrail-log-0v924awy.js → guardrail-log-9yyeccv5.js} +3 -3
- package/dist/cli/{index-y1z6yaq4.js → index-4c5jpmn9.js} +3 -3
- package/dist/cli/{index-0xkf7xn2.js → index-a9ghr5cx.js} +2 -2
- package/dist/cli/{index-c7xgx041.js → index-b223mczb.js} +1 -1
- package/dist/cli/{index-7d38zerp.js → index-byb9tgay.js} +7 -7
- package/dist/cli/{index-5zwr6xz4.js → index-rdc6nvmw.js} +1 -1
- package/dist/cli/{index-wz5ex5q7.js → index-sgdr2e4n.js} +17 -13
- package/dist/cli/{index-w015kchv.js → index-tqbb2jx6.js} +2 -2
- package/dist/cli/{index-tht37da9.js → index-xx3sv77e.js} +1 -1
- package/dist/cli/index.js +5 -5
- package/dist/cli/{schema-qz5mgmz3.js → schema-a8fneygm.js} +1 -1
- package/dist/index.js +139 -73
- package/dist/plan/checkpoint.d.ts +16 -2
- package/dist/tools/dispatch-lanes.d.ts +18 -0
- package/package.json +1 -1
|
@@ -128,7 +128,7 @@ Before writing under `.swarm/`, verify `.swarm/` is ignored or locally excluded.
|
|
|
128
128
|
1. Run 0A alone.
|
|
129
129
|
2. After 0A, run 0B and 0C through `dispatch_lanes_async` only if the repository is large enough to benefit. While those lanes run, the Architect continues deterministic inventory work that does not depend on their results.
|
|
130
130
|
3. After 0B, run 0D and 0E through `dispatch_lanes_async` only if 0E can leave `linked_claims` blank for Architect linking in 0J. Otherwise run 0D before 0E.
|
|
131
|
-
4. Preferred async batch order: batch 1 = 0F and 0G; batch 2 = 0H and 0I. Never exceed two Phase 0 agents.
|
|
131
|
+
4. Preferred async batch order: batch 1 = 0F and 0G; batch 2 = 0H and 0I. Never exceed two Phase 0 agents — Phase 0 inventory units (0A→0J) form a largely sequential dependency chain, so concurrency is intentionally capped at 2 to respect that ordering rather than scaled toward the 8-lane dispatch limit.
|
|
132
132
|
5. Run 0F after 0E when possible.
|
|
133
133
|
6. Run 0G after 0B and 0C.
|
|
134
134
|
7. Run 0H and 0I after 0B and 0C.
|
|
@@ -114,8 +114,10 @@ Do NOT share other agents' responses at this stage.
|
|
|
114
114
|
(synthesis outline, citation normalization, disagreement categories). Only
|
|
115
115
|
use `wait: true` if lanes are still pending and no more independent work
|
|
116
116
|
remains. All three lanes must be settled before proceeding to synthesis.
|
|
117
|
-
If `dispatch_lanes_async` is unavailable, use blocking
|
|
118
|
-
and record that async advisory lanes were unavailable
|
|
117
|
+
If `dispatch_lanes_async` is unavailable, use blocking `dispatch_lanes`
|
|
118
|
+
and record that async advisory lanes were unavailable; do not substitute
|
|
119
|
+
per-agent Task calls for this fallback unless lane tools are unavailable and
|
|
120
|
+
you explicitly verify equivalent agent type, prompt, scope, and isolation. The
|
|
119
121
|
`round1Responses` array will contain entries with `memberId` of
|
|
120
122
|
`council_generalist`, `council_skeptic`, and `council_domain_expert` and
|
|
121
123
|
`role` of `generalist`, `skeptic`, and `domain_expert` respectively. If
|
|
@@ -18,7 +18,7 @@ Read-only deep audit of a specified codebase scope using parallel explorer waves
|
|
|
18
18
|
Parse the MODE: DEEP_DIVE header to extract:
|
|
19
19
|
- `scope`: the codebase area to audit (e.g., "auth", "payment flow", "src/hooks/")
|
|
20
20
|
- `profile`: one of standard | security | ux | architecture | full (default: standard)
|
|
21
|
-
- `max_explorers`: integer 1..8 (default: 6, or 8 for full profile)
|
|
21
|
+
- `max_explorers`: integer 1..8 — upper bound on explorer waves (default: 6, or 8 for full profile). This is a CAP, not a fixed count: scale the actual wave size to the resolved scope surface — a trivial scope needs 1–2 explorers, a typical scope 3–5, a large multi-module scope up to the cap — never fix the count in advance.
|
|
22
22
|
- `output`: markdown | json (default: markdown)
|
|
23
23
|
- `update_main`: boolean (default: true) — whether to fetch/ff-only main before starting
|
|
24
24
|
- `allow_dirty`: boolean (default: false) — whether to proceed with uncommitted changes
|
|
@@ -52,6 +52,8 @@ Dispatch explorer waves with `dispatch_lanes_async` when available. Each wave co
|
|
|
52
52
|
- ~3500 total lines across all files in a mission
|
|
53
53
|
- Group files by import proximity (files that import each other go in the same mission)
|
|
54
54
|
|
|
55
|
+
**Partition is the contract:** missions own non-overlapping file sets — no file appears in two missions — and the union of all missions must cover every file in the Step 2 scope map. Any scope-map file not assigned to a mission is an explicit coverage gap, not an optional skip.
|
|
56
|
+
|
|
55
57
|
**Profile-based lane selection — each profile activates specific lanes:**
|
|
56
58
|
|
|
57
59
|
| Lane | Template | standard | security | ux | architecture | full |
|
|
@@ -118,13 +118,19 @@ include:
|
|
|
118
118
|
- `OUTPUT`: claims with evidence refs, contradictions noted, confidence (0–1)
|
|
119
119
|
- `SKILLS: none`
|
|
120
120
|
|
|
121
|
-
The sme synthesizes only from the provided evidence — it does not fetch.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
121
|
+
The sme synthesizes only from the provided evidence — it does not fetch. While
|
|
122
|
+
synthesis lanes run, poll with `collect_lane_results` without `wait` (or
|
|
123
|
+
`wait: false`) to process completed worker responses as they settle while
|
|
124
|
+
continuing independent architect work between polls. Before Step 5, call
|
|
125
|
+
`collect_lane_results` with `wait: true` for every open synthesis batch only if
|
|
126
|
+
lanes are still pending and no independent work remains. Do not advance to Step 5
|
|
127
|
+
until every synthesis lane is settled. Collect all completed worker responses into
|
|
128
|
+
a candidate findings set, each finding tagged with its subtopic, evidence refs,
|
|
129
|
+
and the worker's confidence. Treat missing, stale, cancelled, or failed lanes as
|
|
130
|
+
explicit coverage gaps. If `dispatch_lanes_async` is unavailable, use blocking
|
|
131
|
+
`dispatch_lanes` and record that async advisory lanes were unavailable; do not
|
|
132
|
+
substitute per-agent Task calls for this fallback unless lane tools are unavailable
|
|
133
|
+
and you explicitly verify equivalent agent type, prompt, scope, and isolation.
|
|
128
134
|
|
|
129
135
|
## Step 5 — Dual-Reviewer Claim Verification
|
|
130
136
|
|
|
@@ -204,9 +204,9 @@ This step supplements (not replaces) the existing regression-sweep and test-drif
|
|
|
204
204
|
|
|
205
205
|
## Dispatch-lanes empty-output fallback
|
|
206
206
|
|
|
207
|
-
|
|
207
|
+
This fallback applies only to a settled, blocking `dispatch_lanes` result with empty output (0 chars, `output_digest` matching SHA-256 of empty string `e3b0c442...b855`). It does **not** apply to `dispatch_lanes_async` rows that are still pending/running, an early `collect_lane_results` poll, or an async result whose full text is available through `retrieve_lane_output`.
|
|
208
208
|
|
|
209
|
-
**
|
|
209
|
+
For read-only advisory lanes, do **not** jump straight to Task. First re-collect async lanes with `collect_lane_results` (`wait: true` when no independent work remains) and inspect any `output_ref` with `retrieve_lane_output`. If a settled blocking `dispatch_lanes` lane is genuinely empty, prefer retrying the same agent through `dispatch_lanes_async` when promptAsync is available. Use the **Task tool** (`Task(subagent_type=..., prompt=...)`) only as a last-resort equivalent dispatch mechanism after the lane tools are unavailable or have produced a confirmed empty settled result; record the same agent, same prompt, same scope, and which dispatch mechanism succeeded.
|
|
210
210
|
|
|
211
211
|
If the Task tool also returns empty, **then** escalate to substitute review (4-member council without the broken agent) or surface to the user. Never fabricate or substitute a verdict for the missing agent.
|
|
212
212
|
|
|
@@ -42,15 +42,31 @@ This briefing is a HARD REQUIREMENT for ALL phases. Skipping it is a process vio
|
|
|
42
42
|
|
|
43
43
|
### CODEBASE REALITY CHECK (Required Before Speccing or Planning)
|
|
44
44
|
|
|
45
|
-
Before any spec generation, plan creation, or plan ingestion begins, the Architect must
|
|
45
|
+
Before any spec generation, plan creation, or plan ingestion begins, the Architect must verify the codebase reality of every item the work references. This runs as **asynchronous, fanned-out Explorer lanes by default**, joined behind a hard settlement gate — never as a single blocking explorer call, and never as fire-and-forget.
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
**1. Enumerate and partition the references (before dispatch).**
|
|
48
|
+
List every referenced item — file, module, function, API, config surface, and behavioral assumption — named or implied by the spec, the user request, or the plan. Partition them into **non-overlapping** lane assignments. The partition is the contract: no two lanes may share a reference (this prevents duplicated work), and the **union of all lanes must cover every referenced item** (this prevents gaps). Under-specified lane boundaries are the dominant fan-out failure mode — be explicit about what each lane owns.
|
|
49
|
+
|
|
50
|
+
**2. Scale the number of lanes to the size of the referenced surface.**
|
|
51
|
+
- Trivial surface (a single file/function, one logical area) → **1 lane**.
|
|
52
|
+
- Typical phase spanning a few areas → **2–4 lanes**.
|
|
53
|
+
- Large surface (many modules/hooks/config surfaces) → **more lanes, up to the dispatch cap of 8 lanes per batch**.
|
|
54
|
+
|
|
55
|
+
Do not fix the lane count in advance and do not over-spawn: extra lanes on a small surface waste tokens without improving coverage, while too few on a large surface leave gaps. Split by codebase area by default; when the surface is a single dense area, split by check-type instead — one lane for *existence & current state*, one for *assumption correctness & prior-work*.
|
|
56
|
+
|
|
57
|
+
**3. Dispatch asynchronously, then keep working.**
|
|
58
|
+
Dispatch the lanes with `dispatch_lanes_async`, record the returned `batch_id`, and continue **non-dependent** Architect work while they run — digest the retrospective and `user_directives`, review the spec/plan text for internal consistency, check governance/QA-gate config and the obligation ledger, and prepare the plan skeleton / task decomposition. This is dispatch-and-keep-busy, not fire-and-forget. Poll with `collect_lane_results` (wait omitted or false) to process settled lanes incrementally, or join with `wait: true` once independent work is exhausted.
|
|
59
|
+
|
|
60
|
+
Each lane must be given: its objective, its named (disjoint) reference subset, the fixed REALITY-CHECK output format below, and clear boundaries. Lanes are read-only — they cannot `declare_scope` or mutate the worktree.
|
|
61
|
+
|
|
62
|
+
**4. For each referenced item, the lane must determine:**
|
|
48
63
|
- Does this file/module/function already exist?
|
|
49
64
|
- If it exists, what is its current state? Does it already implement any part of what the plan or spec describes?
|
|
50
65
|
- Is the plan's or user's assumption about the current state accurate? Flag any discrepancy between what is expected and what actually exists.
|
|
51
66
|
- Has any portion of this work already been applied (partially or fully) in a prior session or commit?
|
|
52
67
|
|
|
53
|
-
|
|
68
|
+
**5. Hard settlement gate (join before any downstream work).**
|
|
69
|
+
The Architect synthesizes the lane outputs into a single CODEBASE REALITY REPORT. The report must list every referenced item with one of:
|
|
54
70
|
NOT STARTED | PARTIALLY DONE | ALREADY COMPLETE | ASSUMPTION INCORRECT
|
|
55
71
|
|
|
56
72
|
Format:
|
|
@@ -59,11 +75,11 @@ Format:
|
|
|
59
75
|
✗ src/services/status-service.ts — ASSUMPTION INCORRECT: compactionCount is no longer hardcoded (fixed in v6.29.1)
|
|
60
76
|
✓ src/config/evidence-schema.ts — confirmed phase_number min(1)
|
|
61
77
|
|
|
62
|
-
No implementation
|
|
78
|
+
No spec finalization, plan generation, plan ingestion, `declare_scope`, or implementation-agent dispatch (coder, reviewer, test-engineer) may begin until ALL lanes in the batch are settled (`collect_lane_results` reports `all_settled`) AND this report is finalized. A lane that is missing, failed, or timed out is an explicit coverage gap, not a pass: mark the affected references BLOCKED or SKIPPED_WITH_REASON and resolve them before proceeding — never silently continue. Async dispatch changes *when* the Architect waits, never *whether* the gate holds.
|
|
63
79
|
|
|
64
80
|
This check fires automatically in:
|
|
65
81
|
- MODE: SPECIFY — before explorer dispatch for context (step 2)
|
|
66
82
|
- MODE: PLAN — before plan generation or validation
|
|
67
83
|
- EXTERNAL PLAN IMPORT PATH — before parsing the provided plan
|
|
68
84
|
|
|
69
|
-
GREENFIELD EXEMPTION: If the work is purely greenfield (new project, no existing codebase references), skip this check.
|
|
85
|
+
GREENFIELD EXEMPTION: If the work is purely greenfield (new project, no existing codebase references), skip this check. A trivial single-area surface stays a single lane rather than being force-fanned.
|
|
@@ -198,15 +198,27 @@ If a source is unavailable, retry with alternative access paths. If unavailable
|
|
|
198
198
|
After the complete feedback ledger exists and before editing, use
|
|
199
199
|
`dispatch_lanes_async` when available for independent read-only verification lanes:
|
|
200
200
|
comment classification, CI/log root-cause inspection, test impact mapping,
|
|
201
|
-
release/docs claim checks, and stale-branch/conflict analysis.
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
201
|
+
release/docs claim checks, and stale-branch/conflict analysis. Partition the
|
|
202
|
+
ledger so each `FB-###` item is owned by exactly one verification lane and the
|
|
203
|
+
union of lanes covers the entire ledger — no feedback item may be left
|
|
204
|
+
unassigned to a lane; state each lane's owned `FB-###` range in its prompt. Scale
|
|
205
|
+
the lane count to the ledger size: a 1–3 item round may use a single combined
|
|
206
|
+
lane, while a large multi-round intake may warrant one lane per category above.
|
|
207
|
+
Cap each `dispatch_lanes_async` batch at 8 lanes (`MAX_LANES`); if the ledger
|
|
208
|
+
needs more than 8 verification lanes, dispatch in sequential batches and settle
|
|
209
|
+
each batch's COVERAGE GATE before the next — do not over-spawn lanes for a
|
|
210
|
+
trivial round. Record each returned `batch_id`, then continue only ledger-safe
|
|
211
|
+
architect work: normalize feedback IDs, gather deterministic PR metadata, prepare
|
|
212
|
+
reproduction commands, and plan likely fix groups. Do not edit, close items, or
|
|
213
|
+
mark feedback resolved from running lanes.
|
|
206
214
|
|
|
207
215
|
Before the Verification step can mark any item `RESOLVED`, `DISPROVED`,
|
|
208
|
-
`PRE_EXISTING`, `NEEDS_MORE_EVIDENCE`, or `NEEDS_USER_DECISION`,
|
|
209
|
-
|
|
216
|
+
`PRE_EXISTING`, `NEEDS_MORE_EVIDENCE`, or `NEEDS_USER_DECISION`, every open
|
|
217
|
+
verification batch must be fully settled. Poll with `collect_lane_results` (wait
|
|
218
|
+
omitted or `false`) to process settled lanes incrementally — clustering confirmed
|
|
219
|
+
items and pre-reading files for settled findings while ledger-safe work remains —
|
|
220
|
+
then issue a final `collect_lane_results` with `wait: true` per batch once
|
|
221
|
+
independent work is exhausted, to confirm every lane is settled.
|
|
210
222
|
Missing, stale, cancelled, or failed lanes are coverage gaps that must be closed
|
|
211
223
|
before marking any item RESOLVED/DISPROVED/PRE_EXISTING. Apply the COVERAGE GATE:
|
|
212
224
|
retry failed lanes (max 2), deploy a verified equivalent alternative (same agent
|
|
@@ -517,7 +517,7 @@ Before Phase 4 or synthesis, all base lanes must be settled. `dispatch_lanes_asy
|
|
|
517
517
|
|
|
518
518
|
For ANY lane that failed (either mode):
|
|
519
519
|
1. **Retry** (max 2 attempts) with materially different parameters — different session, different prompt decomposition, or blocking `dispatch_lanes`.
|
|
520
|
-
2. If retries fail, **deploy an equivalent alternative** and **verify equivalence**: same agent type, same prompt, same scope, same isolation. State the equivalence verification explicitly.
|
|
520
|
+
2. If retries fail, **deploy an equivalent alternative** and **verify equivalence**: same agent type, same prompt, same scope, same isolation. State the equivalence verification explicitly. Task is not an early-poll or empty-partial-output fallback; use it only as a last-resort equivalent dispatch mechanism after `dispatch_lanes_async` is unavailable or a settled lane result is confirmed failed/empty, and after blocking `dispatch_lanes` is unavailable or inappropriate. Use `retrieve_lane_output` to inspect the full artifact before declaring equivalence or failure.
|
|
521
521
|
3. If no equivalent alternative can be verified, **report to the user as INCOMPLETE**. Present partial findings from successful lanes alongside the INCOMPLETE verdict. The user decides whether to accept reduced coverage. The architect NEVER makes that call.
|
|
522
522
|
|
|
523
523
|
### Candidate extraction via parser
|
|
@@ -558,6 +558,8 @@ in the same batch unless intentionally replacing that exact lane before dispatch
|
|
|
558
558
|
|
|
559
559
|
Explorers optimize for recall. Over-reporting is expected. Explorers produce candidates only.
|
|
560
560
|
|
|
561
|
+
The six lanes are a fixed **check-type** partition (correctness / security / deps / docs / tests / performance), not an area partition: the count is intentionally constant — every PR needs all six review dimensions — and the lanes deliberately overlap by file, each receiving the same diff via `common_prompt` and viewing it through a different lens. This is the deliberate exception to surface-scaled fan-out: the base wave is a fixed six by design, never collapsed or expanded with the size of the change. Coverage is guaranteed by the six dimensions each reading the whole diff, not by partitioning files across lanes — so the disjoint-partition rule that governs area-split fan-outs does not apply to these check-type lanes.
|
|
562
|
+
|
|
561
563
|
| Lane | Focus | Required checks |
|
|
562
564
|
|---|---|---|
|
|
563
565
|
| Lane 1: Correctness and edge cases | Logic errors, null/undefined handling, incorrect operators, async ordering, races, off-by-one, error paths | input domain, nullability, async/await, loop termination, exception behavior, backward compatibility |
|
|
@@ -12,8 +12,8 @@ import {
|
|
|
12
12
|
shouldRunOnStartup,
|
|
13
13
|
writeBackupArtifact,
|
|
14
14
|
writeDoctorArtifact
|
|
15
|
-
} from "./index-
|
|
16
|
-
import"./index-
|
|
15
|
+
} from "./index-xx3sv77e.js";
|
|
16
|
+
import"./index-tqbb2jx6.js";
|
|
17
17
|
import"./index-5e4e2hvv.js";
|
|
18
18
|
import"./index-p0arc26j.js";
|
|
19
19
|
import"./index-zgwm4ryv.js";
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
handleGuardrailExplain
|
|
4
|
-
} from "./index-
|
|
5
|
-
import"./index-
|
|
6
|
-
import"./index-
|
|
4
|
+
} from "./index-a9ghr5cx.js";
|
|
5
|
+
import"./index-sgdr2e4n.js";
|
|
6
|
+
import"./index-b223mczb.js";
|
|
7
7
|
import"./index-2a6ppa65.js";
|
|
8
8
|
import"./index-fjxjb66n.js";
|
|
9
9
|
import"./index-hb10a2g8.js";
|
|
10
|
-
import"./index-
|
|
11
|
-
import"./index-
|
|
12
|
-
import"./index-
|
|
10
|
+
import"./index-xx3sv77e.js";
|
|
11
|
+
import"./index-tqbb2jx6.js";
|
|
12
|
+
import"./index-4c5jpmn9.js";
|
|
13
13
|
import"./index-adz3nk9b.js";
|
|
14
14
|
import"./index-v4fcn4tr.js";
|
|
15
15
|
import"./index-mh1ej70w.js";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
handleGuardrailLog
|
|
4
|
-
} from "./index-
|
|
5
|
-
import"./index-
|
|
6
|
-
import"./index-
|
|
4
|
+
} from "./index-rdc6nvmw.js";
|
|
5
|
+
import"./index-b223mczb.js";
|
|
6
|
+
import"./index-tqbb2jx6.js";
|
|
7
7
|
import"./index-5e4e2hvv.js";
|
|
8
8
|
import"./index-p0arc26j.js";
|
|
9
9
|
import"./index-zgwm4ryv.js";
|
|
@@ -2236,7 +2236,7 @@ async function loadPlan(directory) {
|
|
|
2236
2236
|
await rebuildPlan(directory, rebuilt, {
|
|
2237
2237
|
reason: "ledger_hash_mismatch_recovery"
|
|
2238
2238
|
});
|
|
2239
|
-
warn("[loadPlan] Rebuilt plan from ledger. Checkpoint available at .swarm/SWARM_PLAN.md if it exists.");
|
|
2239
|
+
warn("[loadPlan] Rebuilt plan from ledger. Checkpoint available at .swarm/plan-export/SWARM_PLAN.md if it exists.");
|
|
2240
2240
|
return rebuilt;
|
|
2241
2241
|
}
|
|
2242
2242
|
} catch (replayError) {
|
|
@@ -2259,7 +2259,7 @@ async function loadPlan(directory) {
|
|
|
2259
2259
|
return approved.plan;
|
|
2260
2260
|
}
|
|
2261
2261
|
} catch {}
|
|
2262
|
-
warn(`[loadPlan] Ledger replay failed during hash-mismatch rebuild: ${replayError instanceof Error ? replayError.message : String(replayError)}. Returning stale plan.json. To recover: check .swarm/SWARM_PLAN.md for a checkpoint, or run /swarm reset-session.`);
|
|
2262
|
+
warn(`[loadPlan] Ledger replay failed during hash-mismatch rebuild: ${replayError instanceof Error ? replayError.message : String(replayError)}. Returning stale plan.json. To recover: check .swarm/plan-export/SWARM_PLAN.md for a checkpoint, or run /swarm reset-session.`);
|
|
2263
2263
|
}
|
|
2264
2264
|
}
|
|
2265
2265
|
}
|
|
@@ -2306,7 +2306,7 @@ async function loadPlan(directory) {
|
|
|
2306
2306
|
return validated;
|
|
2307
2307
|
}
|
|
2308
2308
|
} catch (error2) {
|
|
2309
|
-
warn(`[loadPlan] plan.json validation failed: ${error2 instanceof Error ? error2.message : String(error2)}. Attempting rebuild from ledger. If rebuild fails, check .swarm/SWARM_PLAN.md for a checkpoint.`);
|
|
2309
|
+
warn(`[loadPlan] plan.json validation failed: ${error2 instanceof Error ? error2.message : String(error2)}. Attempting rebuild from ledger. If rebuild fails, check .swarm/plan-export/SWARM_PLAN.md for a checkpoint.`);
|
|
2310
2310
|
let rawPlanId = null;
|
|
2311
2311
|
try {
|
|
2312
2312
|
const rawParsed = JSON.parse(planJsonContent);
|
|
@@ -12,14 +12,14 @@ import {
|
|
|
12
12
|
detectPosixWrites,
|
|
13
13
|
detectWindowsWrites,
|
|
14
14
|
resolveWriteTargets
|
|
15
|
-
} from "./index-
|
|
15
|
+
} from "./index-sgdr2e4n.js";
|
|
16
16
|
import {
|
|
17
17
|
checkFileAuthority,
|
|
18
18
|
classifyFile,
|
|
19
19
|
isInDeclaredScope,
|
|
20
20
|
redactPath,
|
|
21
21
|
redactShellCommand
|
|
22
|
-
} from "./index-
|
|
22
|
+
} from "./index-b223mczb.js";
|
|
23
23
|
|
|
24
24
|
// src/services/guardrail-explain-service.ts
|
|
25
25
|
import path from "path";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
handleGuardrailExplain
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-a9ghr5cx.js";
|
|
5
5
|
import {
|
|
6
6
|
handleGuardrailLog
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-rdc6nvmw.js";
|
|
8
8
|
import {
|
|
9
9
|
COMMAND_REGISTRY,
|
|
10
10
|
SWARM_COMMAND_TOOL_ALLOWLIST,
|
|
@@ -78,18 +78,18 @@ import {
|
|
|
78
78
|
handleWriteRetroCommand,
|
|
79
79
|
normalizeSwarmCommandInput,
|
|
80
80
|
resolveCommand
|
|
81
|
-
} from "./index-
|
|
82
|
-
import"./index-
|
|
81
|
+
} from "./index-sgdr2e4n.js";
|
|
82
|
+
import"./index-b223mczb.js";
|
|
83
83
|
import"./index-2a6ppa65.js";
|
|
84
84
|
import"./index-fjxjb66n.js";
|
|
85
85
|
import"./index-hb10a2g8.js";
|
|
86
|
-
import"./index-
|
|
86
|
+
import"./index-xx3sv77e.js";
|
|
87
87
|
import {
|
|
88
88
|
AGENT_TOOL_MAP,
|
|
89
89
|
ORCHESTRATOR_NAME,
|
|
90
90
|
stripKnownSwarmPrefix
|
|
91
|
-
} from "./index-
|
|
92
|
-
import"./index-
|
|
91
|
+
} from "./index-tqbb2jx6.js";
|
|
92
|
+
import"./index-4c5jpmn9.js";
|
|
93
93
|
import"./index-adz3nk9b.js";
|
|
94
94
|
import"./index-v4fcn4tr.js";
|
|
95
95
|
import"./index-mh1ej70w.js";
|
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
readDoctorArtifact,
|
|
58
58
|
removeStraySwarmDir,
|
|
59
59
|
runConfigDoctor
|
|
60
|
-
} from "./index-
|
|
60
|
+
} from "./index-xx3sv77e.js";
|
|
61
61
|
import {
|
|
62
62
|
AGENT_TOOL_MAP,
|
|
63
63
|
ALL_SUBAGENT_NAMES,
|
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
TOOL_NAME_SET,
|
|
71
71
|
resolveExternalSkillsConfig,
|
|
72
72
|
stripKnownSwarmPrefix
|
|
73
|
-
} from "./index-
|
|
73
|
+
} from "./index-tqbb2jx6.js";
|
|
74
74
|
import {
|
|
75
75
|
MAX_TRANSIENT_RETRIES,
|
|
76
76
|
PlanSchema,
|
|
@@ -114,7 +114,7 @@ import {
|
|
|
114
114
|
transientBackoff,
|
|
115
115
|
validateProjectRoot,
|
|
116
116
|
writeProjectedSpecSync
|
|
117
|
-
} from "./index-
|
|
117
|
+
} from "./index-4c5jpmn9.js";
|
|
118
118
|
import {
|
|
119
119
|
_internals as _internals2,
|
|
120
120
|
_internals1 as _internals3,
|
|
@@ -909,7 +909,7 @@ var init_executor = __esm(() => {
|
|
|
909
909
|
// package.json
|
|
910
910
|
var package_default = {
|
|
911
911
|
name: "opencode-swarm",
|
|
912
|
-
version: "7.
|
|
912
|
+
version: "7.97.0",
|
|
913
913
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
914
914
|
main: "dist/index.js",
|
|
915
915
|
types: "dist/index.d.ts",
|
|
@@ -13070,7 +13070,7 @@ async function runFinalizeStage(ctx) {
|
|
|
13070
13070
|
}
|
|
13071
13071
|
}
|
|
13072
13072
|
try {
|
|
13073
|
-
const { CuratorConfigSchema: CCS } = await import("./schema-
|
|
13073
|
+
const { CuratorConfigSchema: CCS } = await import("./schema-a8fneygm.js");
|
|
13074
13074
|
const { config: pmLoadedConfig } = _internals20.loadPluginConfigWithMeta(ctx.directory);
|
|
13075
13075
|
const curatorCfg = CCS.parse(pmLoadedConfig.curator ?? {});
|
|
13076
13076
|
if (curatorCfg.enabled && curatorCfg.postmortem_enabled) {
|
|
@@ -13351,6 +13351,8 @@ async function runCleanStage(ctx) {
|
|
|
13351
13351
|
}
|
|
13352
13352
|
let swarmPlanFilesRemoved = 0;
|
|
13353
13353
|
const candidates = [
|
|
13354
|
+
path25.join(ctx.directory, ".swarm", "plan-export", "SWARM_PLAN.json"),
|
|
13355
|
+
path25.join(ctx.directory, ".swarm", "plan-export", "SWARM_PLAN.md"),
|
|
13354
13356
|
path25.join(ctx.directory, ".swarm", "SWARM_PLAN.json"),
|
|
13355
13357
|
path25.join(ctx.directory, ".swarm", "SWARM_PLAN.md"),
|
|
13356
13358
|
path25.join(ctx.directory, "SWARM_PLAN.json"),
|
|
@@ -13630,7 +13632,7 @@ This project was already finalized in a previous /swarm close run. The plan has
|
|
|
13630
13632
|
`- Removed ${cleanResult.configBackupsRemoved} stale config backup file(s)`
|
|
13631
13633
|
] : [],
|
|
13632
13634
|
...cleanResult.swarmPlanFilesRemoved > 0 ? [
|
|
13633
|
-
`- Removed ${cleanResult.swarmPlanFilesRemoved} SWARM_PLAN checkpoint artifact(s)`
|
|
13635
|
+
`- Removed ${cleanResult.swarmPlanFilesRemoved} SWARM_PLAN checkpoint artifact(s) from .swarm/plan-export/ and legacy locations`
|
|
13634
13636
|
] : [],
|
|
13635
13637
|
...ctx.planExists && !ctx.planAlreadyDone ? ["- Set non-completed phases/tasks to closed status"] : [],
|
|
13636
13638
|
...ctx.curationSucceeded && ctx.allLessons.length > 0 ? [`- Committed ${ctx.allLessons.length} lesson(s) to knowledge store`] : [],
|
|
@@ -16791,7 +16793,7 @@ async function handleDoctorCommand(directory, args) {
|
|
|
16791
16793
|
const result = runConfigDoctor(config, directory);
|
|
16792
16794
|
let output;
|
|
16793
16795
|
if (enableAutoFix && result.hasAutoFixableIssues) {
|
|
16794
|
-
const { runConfigDoctorWithFixes } = await import("./config-doctor-
|
|
16796
|
+
const { runConfigDoctorWithFixes } = await import("./config-doctor-h1xrvq83.js");
|
|
16795
16797
|
const fixResult = await runConfigDoctorWithFixes(directory, config, true);
|
|
16796
16798
|
output = formatDoctorMarkdown(fixResult.result);
|
|
16797
16799
|
} else {
|
|
@@ -17604,7 +17606,7 @@ async function handleEvidenceCommand(directory, args) {
|
|
|
17604
17606
|
return formatTaskEvidenceMarkdown(evidenceData);
|
|
17605
17607
|
}
|
|
17606
17608
|
async function handleEvidenceSummaryCommand(directory) {
|
|
17607
|
-
const { buildEvidenceSummary } = await import("./evidence-summary-service-
|
|
17609
|
+
const { buildEvidenceSummary } = await import("./evidence-summary-service-g4x5e3e3.js");
|
|
17608
17610
|
const artifact = await buildEvidenceSummary(directory);
|
|
17609
17611
|
if (!artifact) {
|
|
17610
17612
|
return "No plan found. Run `/swarm plan` to check plan status.";
|
|
@@ -29819,7 +29821,7 @@ async function handleResetCommand(directory, args) {
|
|
|
29819
29821
|
return [
|
|
29820
29822
|
"## Swarm Reset",
|
|
29821
29823
|
"",
|
|
29822
|
-
"\u26A0\uFE0F This will delete all swarm state from .swarm/ (plan, context, checkpoints, SWARM_PLAN artifacts)",
|
|
29824
|
+
"\u26A0\uFE0F This will delete all swarm state from .swarm/ (plan, context, checkpoints, SWARM_PLAN artifacts including .swarm/plan-export/)",
|
|
29823
29825
|
"",
|
|
29824
29826
|
"**Tip**: Run `/swarm export` first to backup your state.",
|
|
29825
29827
|
"",
|
|
@@ -29833,6 +29835,8 @@ async function handleResetCommand(directory, args) {
|
|
|
29833
29835
|
"context.md",
|
|
29834
29836
|
"SWARM_PLAN.md",
|
|
29835
29837
|
"SWARM_PLAN.json",
|
|
29838
|
+
"plan-export/SWARM_PLAN.md",
|
|
29839
|
+
"plan-export/SWARM_PLAN.json",
|
|
29836
29840
|
"checkpoints.json",
|
|
29837
29841
|
"events.jsonl"
|
|
29838
29842
|
];
|
|
@@ -31853,7 +31857,7 @@ function buildDetailedHelp(commandName, entry) {
|
|
|
31853
31857
|
async function handleHelpCommand(ctx) {
|
|
31854
31858
|
const targetCommand = ctx.args.join(" ");
|
|
31855
31859
|
if (!targetCommand) {
|
|
31856
|
-
const { buildHelpText } = await import("./index-
|
|
31860
|
+
const { buildHelpText } = await import("./index-byb9tgay.js");
|
|
31857
31861
|
return buildHelpText();
|
|
31858
31862
|
}
|
|
31859
31863
|
const tokens = targetCommand.split(/\s+/);
|
|
@@ -31862,7 +31866,7 @@ async function handleHelpCommand(ctx) {
|
|
|
31862
31866
|
return _internals45.buildDetailedHelp(resolved.key, resolved.entry);
|
|
31863
31867
|
}
|
|
31864
31868
|
const similar = _internals45.findSimilarCommands(targetCommand);
|
|
31865
|
-
const { buildHelpText: fullHelp } = await import("./index-
|
|
31869
|
+
const { buildHelpText: fullHelp } = await import("./index-byb9tgay.js");
|
|
31866
31870
|
if (similar.length > 0) {
|
|
31867
31871
|
return `Command '/swarm ${targetCommand}' not found.
|
|
31868
31872
|
|
|
@@ -31995,7 +31999,7 @@ var COMMAND_REGISTRY = {
|
|
|
31995
31999
|
},
|
|
31996
32000
|
"guardrail explain": {
|
|
31997
32001
|
handler: async (ctx) => {
|
|
31998
|
-
const { handleGuardrailExplain } = await import("./guardrail-explain-
|
|
32002
|
+
const { handleGuardrailExplain } = await import("./guardrail-explain-t6svvtmn.js");
|
|
31999
32003
|
return handleGuardrailExplain(ctx.directory, ctx.args);
|
|
32000
32004
|
},
|
|
32001
32005
|
description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
|
|
@@ -32005,7 +32009,7 @@ var COMMAND_REGISTRY = {
|
|
|
32005
32009
|
},
|
|
32006
32010
|
"guardrail-log": {
|
|
32007
32011
|
handler: async (ctx) => {
|
|
32008
|
-
const { handleGuardrailLog } = await import("./guardrail-log-
|
|
32012
|
+
const { handleGuardrailLog } = await import("./guardrail-log-9yyeccv5.js");
|
|
32009
32013
|
return handleGuardrailLog(ctx.directory, ctx.args);
|
|
32010
32014
|
},
|
|
32011
32015
|
description: "Read the guardrail decision log (use --blocks-only for blocks)",
|
|
@@ -552,11 +552,11 @@ var TOOL_METADATA = {
|
|
|
552
552
|
agents: ["architect"]
|
|
553
553
|
},
|
|
554
554
|
dispatch_lanes_async: {
|
|
555
|
-
description: "launch read-only advisory lanes non-blockingly and return a batch id immediately so you can keep working; poll incrementally with collect_lane_results (wait omitted or false) while doing independent investigation, or join with wait: true when you need all results",
|
|
555
|
+
description: "launch read-only advisory lanes non-blockingly and return a batch id plus lane session handles immediately so you can keep working; launch_timeout_ms is only a promptAsync acceptance budget, not a lane runtime timeout; poll incrementally with collect_lane_results (wait omitted or false) while doing independent investigation, or join with wait: true when you need all results",
|
|
556
556
|
agents: ["architect"]
|
|
557
557
|
},
|
|
558
558
|
collect_lane_results: {
|
|
559
|
-
description: "collect or poll results for a dispatch_lanes_async batch; supports both non-blocking polling (wait omitted or false) and blocking join (wait: true).
|
|
559
|
+
description: "collect or poll results for a dispatch_lanes_async batch; supports both non-blocking polling (wait omitted or false) and blocking join (wait: true). Non-blocking polls include pending lane identities by default and process settled lanes incrementally while continuing independent work; busy/retry lanes are not timed out just because they run for a long time. Does not advance workflow gates.",
|
|
560
560
|
agents: ["architect"]
|
|
561
561
|
},
|
|
562
562
|
summarize_work: {
|
package/dist/cli/index.js
CHANGED
|
@@ -7,16 +7,16 @@ import {
|
|
|
7
7
|
getPluginLockFilePaths,
|
|
8
8
|
package_default,
|
|
9
9
|
resolveCommand
|
|
10
|
-
} from "./index-
|
|
11
|
-
import"./index-
|
|
10
|
+
} from "./index-sgdr2e4n.js";
|
|
11
|
+
import"./index-b223mczb.js";
|
|
12
12
|
import"./index-2a6ppa65.js";
|
|
13
13
|
import"./index-fjxjb66n.js";
|
|
14
14
|
import"./index-hb10a2g8.js";
|
|
15
|
-
import"./index-
|
|
15
|
+
import"./index-xx3sv77e.js";
|
|
16
16
|
import {
|
|
17
17
|
DEFAULT_AGENT_CONFIGS
|
|
18
|
-
} from "./index-
|
|
19
|
-
import"./index-
|
|
18
|
+
} from "./index-tqbb2jx6.js";
|
|
19
|
+
import"./index-4c5jpmn9.js";
|
|
20
20
|
import"./index-adz3nk9b.js";
|
|
21
21
|
import"./index-v4fcn4tr.js";
|
|
22
22
|
import"./index-mh1ej70w.js";
|
package/dist/index.js
CHANGED
|
@@ -69,7 +69,7 @@ var package_default;
|
|
|
69
69
|
var init_package = __esm(() => {
|
|
70
70
|
package_default = {
|
|
71
71
|
name: "opencode-swarm",
|
|
72
|
-
version: "7.
|
|
72
|
+
version: "7.97.0",
|
|
73
73
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
74
74
|
main: "dist/index.js",
|
|
75
75
|
types: "dist/index.d.ts",
|
|
@@ -729,11 +729,11 @@ var init_tool_metadata = __esm(() => {
|
|
|
729
729
|
agents: ["architect"]
|
|
730
730
|
},
|
|
731
731
|
dispatch_lanes_async: {
|
|
732
|
-
description: "launch read-only advisory lanes non-blockingly and return a batch id immediately so you can keep working; poll incrementally with collect_lane_results (wait omitted or false) while doing independent investigation, or join with wait: true when you need all results",
|
|
732
|
+
description: "launch read-only advisory lanes non-blockingly and return a batch id plus lane session handles immediately so you can keep working; launch_timeout_ms is only a promptAsync acceptance budget, not a lane runtime timeout; poll incrementally with collect_lane_results (wait omitted or false) while doing independent investigation, or join with wait: true when you need all results",
|
|
733
733
|
agents: ["architect"]
|
|
734
734
|
},
|
|
735
735
|
collect_lane_results: {
|
|
736
|
-
description: "collect or poll results for a dispatch_lanes_async batch; supports both non-blocking polling (wait omitted or false) and blocking join (wait: true).
|
|
736
|
+
description: "collect or poll results for a dispatch_lanes_async batch; supports both non-blocking polling (wait omitted or false) and blocking join (wait: true). Non-blocking polls include pending lane identities by default and process settled lanes incrementally while continuing independent work; busy/retry lanes are not timed out just because they run for a long time. Does not advance workflow gates.",
|
|
737
737
|
agents: ["architect"]
|
|
738
738
|
},
|
|
739
739
|
summarize_work: {
|
|
@@ -20500,7 +20500,7 @@ async function loadPlan(directory) {
|
|
|
20500
20500
|
await rebuildPlan(directory, rebuilt, {
|
|
20501
20501
|
reason: "ledger_hash_mismatch_recovery"
|
|
20502
20502
|
});
|
|
20503
|
-
warn("[loadPlan] Rebuilt plan from ledger. Checkpoint available at .swarm/SWARM_PLAN.md if it exists.");
|
|
20503
|
+
warn("[loadPlan] Rebuilt plan from ledger. Checkpoint available at .swarm/plan-export/SWARM_PLAN.md if it exists.");
|
|
20504
20504
|
return rebuilt;
|
|
20505
20505
|
}
|
|
20506
20506
|
} catch (replayError) {
|
|
@@ -20523,7 +20523,7 @@ async function loadPlan(directory) {
|
|
|
20523
20523
|
return approved.plan;
|
|
20524
20524
|
}
|
|
20525
20525
|
} catch {}
|
|
20526
|
-
warn(`[loadPlan] Ledger replay failed during hash-mismatch rebuild: ${replayError instanceof Error ? replayError.message : String(replayError)}. Returning stale plan.json. To recover: check .swarm/SWARM_PLAN.md for a checkpoint, or run /swarm reset-session.`);
|
|
20526
|
+
warn(`[loadPlan] Ledger replay failed during hash-mismatch rebuild: ${replayError instanceof Error ? replayError.message : String(replayError)}. Returning stale plan.json. To recover: check .swarm/plan-export/SWARM_PLAN.md for a checkpoint, or run /swarm reset-session.`);
|
|
20527
20527
|
}
|
|
20528
20528
|
}
|
|
20529
20529
|
}
|
|
@@ -20570,7 +20570,7 @@ async function loadPlan(directory) {
|
|
|
20570
20570
|
return validated;
|
|
20571
20571
|
}
|
|
20572
20572
|
} catch (error49) {
|
|
20573
|
-
warn(`[loadPlan] plan.json validation failed: ${error49 instanceof Error ? error49.message : String(error49)}. Attempting rebuild from ledger. If rebuild fails, check .swarm/SWARM_PLAN.md for a checkpoint.`);
|
|
20573
|
+
warn(`[loadPlan] plan.json validation failed: ${error49 instanceof Error ? error49.message : String(error49)}. Attempting rebuild from ledger. If rebuild fails, check .swarm/plan-export/SWARM_PLAN.md for a checkpoint.`);
|
|
20574
20574
|
let rawPlanId = null;
|
|
20575
20575
|
try {
|
|
20576
20576
|
const rawParsed = JSON.parse(planJsonContent);
|
|
@@ -73548,6 +73548,8 @@ async function runCleanStage(ctx) {
|
|
|
73548
73548
|
}
|
|
73549
73549
|
let swarmPlanFilesRemoved = 0;
|
|
73550
73550
|
const candidates = [
|
|
73551
|
+
path60.join(ctx.directory, ".swarm", "plan-export", "SWARM_PLAN.json"),
|
|
73552
|
+
path60.join(ctx.directory, ".swarm", "plan-export", "SWARM_PLAN.md"),
|
|
73551
73553
|
path60.join(ctx.directory, ".swarm", "SWARM_PLAN.json"),
|
|
73552
73554
|
path60.join(ctx.directory, ".swarm", "SWARM_PLAN.md"),
|
|
73553
73555
|
path60.join(ctx.directory, "SWARM_PLAN.json"),
|
|
@@ -73827,7 +73829,7 @@ This project was already finalized in a previous /swarm close run. The plan has
|
|
|
73827
73829
|
`- Removed ${cleanResult.configBackupsRemoved} stale config backup file(s)`
|
|
73828
73830
|
] : [],
|
|
73829
73831
|
...cleanResult.swarmPlanFilesRemoved > 0 ? [
|
|
73830
|
-
`- Removed ${cleanResult.swarmPlanFilesRemoved} SWARM_PLAN checkpoint artifact(s)`
|
|
73832
|
+
`- Removed ${cleanResult.swarmPlanFilesRemoved} SWARM_PLAN checkpoint artifact(s) from .swarm/plan-export/ and legacy locations`
|
|
73831
73833
|
] : [],
|
|
73832
73834
|
...ctx.planExists && !ctx.planAlreadyDone ? ["- Set non-completed phases/tasks to closed status"] : [],
|
|
73833
73835
|
...ctx.curationSucceeded && ctx.allLessons.length > 0 ? [`- Committed ${ctx.allLessons.length} lesson(s) to knowledge store`] : [],
|
|
@@ -96336,7 +96338,7 @@ async function handleResetCommand(directory, args2) {
|
|
|
96336
96338
|
return [
|
|
96337
96339
|
"## Swarm Reset",
|
|
96338
96340
|
"",
|
|
96339
|
-
"⚠️ This will delete all swarm state from .swarm/ (plan, context, checkpoints, SWARM_PLAN artifacts)",
|
|
96341
|
+
"⚠️ This will delete all swarm state from .swarm/ (plan, context, checkpoints, SWARM_PLAN artifacts including .swarm/plan-export/)",
|
|
96340
96342
|
"",
|
|
96341
96343
|
"**Tip**: Run `/swarm export` first to backup your state.",
|
|
96342
96344
|
"",
|
|
@@ -96350,6 +96352,8 @@ async function handleResetCommand(directory, args2) {
|
|
|
96350
96352
|
"context.md",
|
|
96351
96353
|
"SWARM_PLAN.md",
|
|
96352
96354
|
"SWARM_PLAN.json",
|
|
96355
|
+
"plan-export/SWARM_PLAN.md",
|
|
96356
|
+
"plan-export/SWARM_PLAN.json",
|
|
96353
96357
|
"checkpoints.json",
|
|
96354
96358
|
"events.jsonl"
|
|
96355
96359
|
];
|
|
@@ -101929,7 +101933,7 @@ If a tool modifies a file, it is a CODER tool. Delegate.
|
|
|
101929
101933
|
2. ONE agent per message. Send, STOP, wait for response.
|
|
101930
101934
|
Exception: Stage B reviewer/test_engineer gate agents for the SAME completed coder task may be dispatched together before waiting when both gates are required. This exception NEVER applies to coder delegations. Preserve ONE task per coder call.
|
|
101931
101935
|
Separate parallel-mode exception (distinct from the Stage B exception above, and the ONLY case where more than one coder may be dispatched before waiting): when an active \`[PARALLEL EXECUTION PROFILE]\` directive is present in your context (parallelization_enabled=true), you MAY dispatch multiple {{AGENT_PREFIX}}coder agents in a single message — up to the stated max_concurrent_tasks — but ONLY for distinct, dependency-ready tasks whose declared file scopes do NOT overlap. Each coder still requires its own \`declare_scope\` call and carries exactly ONE task (Rule 3 still holds: never batch multiple objectives into one coder). Parallel coders each run in an isolated git worktree, so their writes never collide and are merged back automatically. If no \`[PARALLEL EXECUTION PROFILE]\` directive is present, dispatch coders one at a time.
|
|
101932
|
-
Read-only advisory-lane exception (NON-BLOCKING; distinct from both exceptions above): the "Send, STOP, wait" rule governs MUTATION delegations (coder, and the test_engineer/reviewer Stage B completion gates). It does NOT govern read-only advisory exploration/review lanes. When you dispatch read-only advisory lanes — \`{{AGENT_PREFIX}}explorer\`, \`{{AGENT_PREFIX}}sme\`, \`{{AGENT_PREFIX}}researcher\`, the council members (\`council_generalist\`/\`council_skeptic\`/\`council_domain_expert\`), or an advisory \`{{AGENT_PREFIX}}critic\` lane — use the NON-BLOCKING path so you keep working while they run. Dispatch PROMPTLY: emit the \`dispatch_lanes_async\` call EARLY with compact lane prompts — do not accumulate long planning prose or build oversized inline prompts first, or the tool call can be truncated out of your message and the lanes never launch (a real failure mode on smaller models). The lane mechanism is a SINGLE \`dispatch_lanes_async\` call carrying all lane specs — NOT a per-agent Task/run-in-background pattern. Call \`dispatch_lanes_async\` with all lane specs in one call, record the returned \`batch_id\`, then IMMEDIATELY continue non-dependent architect work (refine the plan/obligation ledger, inspect metadata, prepare the synthesis/reviewer structure, run deterministic read-only tools). Do NOT sit idle waiting on running lanes, and do NOT synthesize findings from still-running lanes. Join later by calling \`collect_lane_results\` with \`wait: true\` as the explicit barrier immediately before you synthesize. Use blocking \`dispatch_lanes\` only when \`dispatch_lanes_async\`/promptAsync is unavailable. Keep each lane prompt compact: send large shared context (PR diff, ledger, scope) ONCE via the \`common_prompt\` field, or have lanes read it from a file by absolute path, instead of inlining the same blob into every lane prompt — inlining large context into many lanes is what produces malformed or truncated tool-call JSON and forces clumsy file workarounds. This non-blocking exception applies ONLY to read-only advisory lanes; it NEVER applies to coder delegations, to the test_engineer/reviewer Stage B completion gates, or to the critic PLAN-review gate, which all still follow "Send, STOP, wait" (or the Stage B parallel-dispatch exception above).
|
|
101936
|
+
Read-only advisory-lane exception (NON-BLOCKING; distinct from both exceptions above): the "Send, STOP, wait" rule governs MUTATION delegations (coder, and the test_engineer/reviewer Stage B completion gates). It does NOT govern read-only advisory exploration/review lanes. When you dispatch read-only advisory lanes — \`{{AGENT_PREFIX}}explorer\`, \`{{AGENT_PREFIX}}sme\`, \`{{AGENT_PREFIX}}researcher\`, the council members (\`council_generalist\`/\`council_skeptic\`/\`council_domain_expert\`), or an advisory \`{{AGENT_PREFIX}}critic\` lane — use the NON-BLOCKING path so you keep working while they run. Dispatch PROMPTLY: emit the \`dispatch_lanes_async\` call EARLY with compact lane prompts — do not accumulate long planning prose or build oversized inline prompts first, or the tool call can be truncated out of your message and the lanes never launch (a real failure mode on smaller models). The lane mechanism is a SINGLE \`dispatch_lanes_async\` call carrying all lane specs — NOT a per-agent Task/run-in-background pattern. Call \`dispatch_lanes_async\` with all lane specs in one call, record the returned \`batch_id\`, then IMMEDIATELY continue non-dependent architect work (refine the plan/obligation ledger, inspect metadata, prepare the synthesis/reviewer structure, run deterministic read-only tools). Poll incrementally with \`collect_lane_results\` without \`wait\` (or with \`wait: false\`) to harvest lanes as they settle; process completed lane output immediately while other lanes remain pending/running, then continue independent work between polls. Do NOT sit idle waiting on running lanes, and do NOT synthesize findings from still-running lanes. Join later by calling \`collect_lane_results\` with \`wait: true\` as the explicit barrier immediately before you synthesize. Use blocking \`dispatch_lanes\` only when \`dispatch_lanes_async\`/promptAsync is unavailable. Keep each lane prompt compact: send large shared context (PR diff, ledger, scope) ONCE via the \`common_prompt\` field, or have lanes read it from a file by absolute path, instead of inlining the same blob into every lane prompt — inlining large context into many lanes is what produces malformed or truncated tool-call JSON and forces clumsy file workarounds. This non-blocking exception applies ONLY to read-only advisory lanes; it NEVER applies to coder delegations, to the test_engineer/reviewer Stage B completion gates, or to the critic PLAN-review gate, which all still follow "Send, STOP, wait" (or the Stage B parallel-dispatch exception above).
|
|
101933
101937
|
3. ONE task per {{AGENT_PREFIX}}coder call. Never batch.
|
|
101934
101938
|
3a. PRE-DELEGATION SCOPE CALL (required): BEFORE every {{AGENT_PREFIX}}coder delegation, you MUST call \`declare_scope\` with { taskId, files } listing the exact file(s) this task will modify (including generated/lockfile paths). No \`declare_scope\` call → no coder delegation. See Rule 1a.
|
|
101935
101939
|
3b. PRE-DELEGATION SCOPE CALL (test_engineer): BEFORE any {{AGENT_PREFIX}}test_engineer delegation that will CREATE or MODIFY test files, you MUST call \`declare_scope\` with { taskId, files } listing the exact test file path(s) to write. Omitting this call leaves the write scope undeclared and will block the write. See Rule 1a.
|
|
@@ -102289,7 +102293,7 @@ Available Tools: {{AVAILABLE_TOOLS}}
|
|
|
102289
102293
|
|
|
102290
102294
|
## DELEGATION FORMAT
|
|
102291
102295
|
|
|
102292
|
-
|
|
102296
|
+
Mutation delegations are performed by calling the **Task** tool. Read-only advisory lanes are the explicit exception: dispatch them with \`dispatch_lanes_async\` plus incremental \`collect_lane_results\` polls (no \`wait\` / \`wait: false\`) before a final \`wait: true\` join, or blocking \`dispatch_lanes\` only when async is unavailable. Never turn advisory lanes into a per-agent Task/run-in-background pattern. Writing delegation text into the chat does nothing — the agent will not receive it. Every mutation delegation below is the content you pass to the Task tool, not text you output to the conversation.
|
|
102293
102297
|
|
|
102294
102298
|
All delegations MUST follow the receiving agent's INPUT FORMAT exactly. Do NOT invent fields, omit required fields, or force one agent's schema onto another. Every delegation MUST begin with the agent name, include \`TASK:\`, and include \`SKILLS:\` when that agent prompt supports skills.
|
|
102295
102299
|
Do NOT add conversational preamble before the agent prefix. Begin directly with the agent name.
|
|
@@ -102533,7 +102537,7 @@ Purpose: Read the previous retrospective and produce a codebase reality report b
|
|
|
102533
102537
|
ACTION: Load skill file:.opencode/skills/pre-phase-briefing/SKILL.md immediately. Follow the protocol defined there.
|
|
102534
102538
|
|
|
102535
102539
|
HARD CONSTRAINTS:
|
|
102536
|
-
- Complete the codebase reality report before
|
|
102540
|
+
- Complete the codebase reality report before spec finalization, plan generation, plan ingestion, declare_scope, or starting/resuming phase implementation. Dispatching the reality-check lanes asynchronously is allowed and preferred; settling all lanes before any of that downstream work is not optional.
|
|
102537
102541
|
|
|
102538
102542
|
### MODE: COUNCIL
|
|
102539
102543
|
Activates when the user invokes /swarm council or requests a council-style decision review.
|
|
@@ -107428,6 +107432,7 @@ async function scanDocIndex(directory) {
|
|
|
107428
107432
|
const resolvedDirectory = await realpath4(directory).catch(() => directory);
|
|
107429
107433
|
const discoveredFiles = [];
|
|
107430
107434
|
let rootReadable = false;
|
|
107435
|
+
let truncated = false;
|
|
107431
107436
|
const walkDir2 = async (dir) => {
|
|
107432
107437
|
let entries;
|
|
107433
107438
|
try {
|
|
@@ -107438,8 +107443,10 @@ async function scanDocIndex(directory) {
|
|
|
107438
107443
|
return;
|
|
107439
107444
|
}
|
|
107440
107445
|
for (const entry of entries) {
|
|
107441
|
-
if (discoveredFiles.length >= MAX_INDEXED_FILES)
|
|
107446
|
+
if (discoveredFiles.length >= MAX_INDEXED_FILES) {
|
|
107447
|
+
truncated = true;
|
|
107442
107448
|
return;
|
|
107449
|
+
}
|
|
107443
107450
|
const isDir = entry.isDirectory();
|
|
107444
107451
|
let isFile = entry.isFile();
|
|
107445
107452
|
if (entry.isSymbolicLink()) {
|
|
@@ -107511,7 +107518,6 @@ async function scanDocIndex(directory) {
|
|
|
107511
107518
|
};
|
|
107512
107519
|
}
|
|
107513
107520
|
discoveredFiles.sort((a, b) => a.path.toLowerCase().localeCompare(b.path.toLowerCase()));
|
|
107514
|
-
let truncated = false;
|
|
107515
107521
|
if (discoveredFiles.length > MAX_INDEXED_FILES) {
|
|
107516
107522
|
discoveredFiles.splice(MAX_INDEXED_FILES);
|
|
107517
107523
|
truncated = true;
|
|
@@ -131427,6 +131433,7 @@ var COMMON_PROMPT_SEPARATOR = `
|
|
|
131427
131433
|
|
|
131428
131434
|
`;
|
|
131429
131435
|
var DEFAULT_TIMEOUT_MS3 = 300000;
|
|
131436
|
+
var DEFAULT_ASYNC_LAUNCH_TIMEOUT_MS = 30000;
|
|
131430
131437
|
var MAX_TIMEOUT_MS2 = 1800000;
|
|
131431
131438
|
var MAX_LANE_OUTPUT_CHARS = 20000;
|
|
131432
131439
|
var ASYNC_MESSAGE_FETCH_LIMIT = 50;
|
|
@@ -131502,9 +131509,10 @@ var DispatchLanesArgsSchema = exports_external.object({
|
|
|
131502
131509
|
lanes: exports_external.array(LaneSchema).min(1).max(MAX_LANES).describe("Read-only lane specs to dispatch concurrently"),
|
|
131503
131510
|
common_prompt: exports_external.string().min(1).regex(/\S/, "common_prompt must contain non-whitespace content").max(MAX_PROMPT_CHARS - COMMON_PROMPT_SEPARATOR.length - 1).optional().describe("Optional shared context prepended to every lane prompt. Send large shared context (PR diff, obligation ledger, scope) ONCE here instead of inlining the same blob into each lane prompt; this keeps the tool-call payload small and avoids malformed/truncated tool-call JSON. Combined common_prompt + per-lane prompt must not exceed the per-lane character limit."),
|
|
131504
131511
|
max_concurrent: exports_external.number().int().min(1).max(MAX_LANES).optional().describe("Maximum lanes in flight at once; defaults to lane count"),
|
|
131505
|
-
timeout_ms: exports_external.number().int().min(10).max(MAX_TIMEOUT_MS2).optional().describe("Per-lane session create
|
|
131512
|
+
timeout_ms: exports_external.number().int().min(10).max(MAX_TIMEOUT_MS2).optional().describe("Per-lane timeout in milliseconds. For blocking dispatch this covers session create and prompt execution; for async dispatch this covers launch only, never lane runtime.")
|
|
131506
131513
|
});
|
|
131507
131514
|
var DispatchLanesAsyncArgsSchema = DispatchLanesArgsSchema.extend({
|
|
131515
|
+
launch_timeout_ms: exports_external.number().int().min(10).max(MAX_TIMEOUT_MS2).optional().describe("Async launch acceptance timeout in milliseconds. This only bounds session creation and promptAsync acceptance; it is never a lane runtime timeout. Deprecated alias: timeout_ms."),
|
|
131508
131516
|
batch_id: exports_external.string().min(1).max(MAX_BATCH_ID_CHARS).regex(/^[A-Za-z0-9][A-Za-z0-9_.:-]*$/).optional().describe("Stable async batch id for later collection; generated when omitted"),
|
|
131509
131517
|
mode: exports_external.string().min(1).max(80).optional().describe("Advisory workflow mode, such as deep-dive or swarm-pr-review"),
|
|
131510
131518
|
pr_head_sha: exports_external.string().min(1).max(80).optional(),
|
|
@@ -131514,7 +131522,7 @@ var CollectLaneResultsArgsSchema = exports_external.object({
|
|
|
131514
131522
|
batch_id: exports_external.string().min(1).max(MAX_BATCH_ID_CHARS),
|
|
131515
131523
|
wait: exports_external.boolean().optional().describe("Poll until all lanes settle or timeout"),
|
|
131516
131524
|
timeout_ms: exports_external.number().int().min(0).max(MAX_COLLECT_TIMEOUT_MS).optional().describe("Total wait budget when wait=true"),
|
|
131517
|
-
include_pending: exports_external.boolean().optional().describe("Include pending/running lanes in
|
|
131525
|
+
include_pending: exports_external.boolean().optional().describe("Include pending/running lanes in lane_results. Defaults to true for non-blocking polls and false for wait=true joins."),
|
|
131518
131526
|
cancel_pending: exports_external.boolean().optional().describe("Abort and mark pending/running lanes cancelled")
|
|
131519
131527
|
});
|
|
131520
131528
|
var _internals94 = {
|
|
@@ -131614,7 +131622,7 @@ async function executeDispatchLanesAsync(args2, directory, context = {}) {
|
|
|
131614
131622
|
});
|
|
131615
131623
|
}
|
|
131616
131624
|
const maxConcurrent = Math.min(parsed.data.max_concurrent ?? lanes.length, lanes.length, MAX_LANES);
|
|
131617
|
-
const
|
|
131625
|
+
const launchTimeoutMs = parsed.data.launch_timeout_ms ?? parsed.data.timeout_ms ?? DEFAULT_ASYNC_LAUNCH_TIMEOUT_MS;
|
|
131618
131626
|
const dispatcher = _internals94.createParallelDispatcher({
|
|
131619
131627
|
enabled: true,
|
|
131620
131628
|
maxConcurrentTasks: maxConcurrent,
|
|
@@ -131627,7 +131635,7 @@ async function executeDispatchLanesAsync(args2, directory, context = {}) {
|
|
|
131627
131635
|
dispatcher,
|
|
131628
131636
|
lane,
|
|
131629
131637
|
directory,
|
|
131630
|
-
timeoutMs,
|
|
131638
|
+
timeoutMs: launchTimeoutMs,
|
|
131631
131639
|
context,
|
|
131632
131640
|
batchId,
|
|
131633
131641
|
mode: parsed.data.mode,
|
|
@@ -131645,7 +131653,8 @@ async function executeDispatchLanesAsync(args2, directory, context = {}) {
|
|
|
131645
131653
|
failed: failed.length,
|
|
131646
131654
|
rejected: rejected.length,
|
|
131647
131655
|
max_concurrent: maxConcurrent,
|
|
131648
|
-
|
|
131656
|
+
launch_timeout_ms: launchTimeoutMs,
|
|
131657
|
+
timeout_ms: launchTimeoutMs,
|
|
131649
131658
|
lane_results: laneResults
|
|
131650
131659
|
};
|
|
131651
131660
|
} finally {
|
|
@@ -131673,7 +131682,6 @@ async function executeCollectLaneResults(args2, directory, context = {}) {
|
|
|
131673
131682
|
const timeoutMs = parsed.data.timeout_ms ?? DEFAULT_COLLECT_TIMEOUT_MS;
|
|
131674
131683
|
const deadline = _internals94.now() + timeoutMs;
|
|
131675
131684
|
const batchFilter = context.sessionID !== undefined ? { parentSessionId: context.sessionID } : undefined;
|
|
131676
|
-
await sweepStaleDelegations(directory, DEFAULT_ASYNC_STALE_TIMEOUT_MS);
|
|
131677
131685
|
let records = findByBatchId(directory, parsed.data.batch_id, batchFilter);
|
|
131678
131686
|
if (records.length === 0) {
|
|
131679
131687
|
return collectFailureResult({
|
|
@@ -131686,7 +131694,7 @@ async function executeCollectLaneResults(args2, directory, context = {}) {
|
|
|
131686
131694
|
let pollIntervalMs = COLLECT_POLL_INTERVAL_MS;
|
|
131687
131695
|
while (keepPolling) {
|
|
131688
131696
|
await collectOnce(session, directory, records, parsed.data.cancel_pending === true);
|
|
131689
|
-
await
|
|
131697
|
+
await sweepStaleAsyncLaneRecords(session, directory, records, DEFAULT_ASYNC_STALE_TIMEOUT_MS);
|
|
131690
131698
|
records = findByBatchId(directory, parsed.data.batch_id, batchFilter);
|
|
131691
131699
|
if (allSettled(records) || parsed.data.wait !== true) {
|
|
131692
131700
|
keepPolling = false;
|
|
@@ -131699,7 +131707,7 @@ async function executeCollectLaneResults(args2, directory, context = {}) {
|
|
|
131699
131707
|
await _internals94.sleep(Math.min(pollIntervalMs, Math.max(0, deadline - _internals94.now())));
|
|
131700
131708
|
pollIntervalMs = nextCollectPollInterval(pollIntervalMs);
|
|
131701
131709
|
}
|
|
131702
|
-
return buildCollectResult(parsed.data.batch_id, records, parsed.data.include_pending
|
|
131710
|
+
return buildCollectResult(parsed.data.batch_id, records, parsed.data.include_pending ?? parsed.data.wait !== true);
|
|
131703
131711
|
}
|
|
131704
131712
|
async function launchAsyncLane(args2) {
|
|
131705
131713
|
const validation2 = validateLaneAgent(args2.lane.agent, args2.context);
|
|
@@ -131773,54 +131781,17 @@ async function launchAsyncLane(args2) {
|
|
|
131773
131781
|
scope: args2.scope ?? null
|
|
131774
131782
|
},
|
|
131775
131783
|
generation: 1
|
|
131776
|
-
}
|
|
131784
|
+
});
|
|
131777
131785
|
if (!pendingRecord) {
|
|
131778
131786
|
cleanupAsyncLaunchSession(args2.session, sessionId);
|
|
131779
131787
|
return failedLane(args2.lane, role, startedAt, "Failed to record async lane in background delegation ledger", decision.slot.slotId, decision.slot.runId);
|
|
131780
131788
|
}
|
|
131781
|
-
|
|
131782
|
-
|
|
131783
|
-
|
|
131784
|
-
|
|
131785
|
-
|
|
131786
|
-
|
|
131787
|
-
body: {
|
|
131788
|
-
agent: args2.lane.agent,
|
|
131789
|
-
tools: buildReadOnlyTools(),
|
|
131790
|
-
parts: [{ type: "text", text: args2.lane.prompt }]
|
|
131791
|
-
},
|
|
131792
|
-
signal: promptController.signal
|
|
131793
|
-
}), args2.timeoutMs, `Lane "${args2.lane.id}" session.promptAsync timed out after ${args2.timeoutMs}ms`, promptController);
|
|
131794
|
-
} catch (error93) {
|
|
131795
|
-
const message = formatError3(error93);
|
|
131796
|
-
await appendDelegationTransition(args2.directory, sessionId, {
|
|
131797
|
-
status: "error",
|
|
131798
|
-
result: {
|
|
131799
|
-
error: message,
|
|
131800
|
-
chars: message.length,
|
|
131801
|
-
truncated: false,
|
|
131802
|
-
digest: digestText2(message)
|
|
131803
|
-
}
|
|
131804
|
-
});
|
|
131805
|
-
cleanupAsyncLaunchSession(args2.session, sessionId);
|
|
131806
|
-
return failedLane(args2.lane, role, startedAt, message, decision.slot.slotId, decision.slot.runId);
|
|
131807
|
-
}
|
|
131808
|
-
if (promptResult.error) {
|
|
131809
|
-
const error93 = `session.promptAsync failed: ${formatError3(promptResult.error)}`;
|
|
131810
|
-
await appendDelegationTransition(args2.directory, sessionId, {
|
|
131811
|
-
status: "error",
|
|
131812
|
-
result: {
|
|
131813
|
-
error: error93,
|
|
131814
|
-
chars: error93.length,
|
|
131815
|
-
truncated: false,
|
|
131816
|
-
digest: digestText2(error93)
|
|
131817
|
-
}
|
|
131818
|
-
});
|
|
131819
|
-
cleanupAsyncLaunchSession(args2.session, sessionId);
|
|
131820
|
-
return failedLane(args2.lane, role, startedAt, error93, decision.slot.slotId, decision.slot.runId);
|
|
131821
|
-
}
|
|
131822
|
-
await appendDelegationTransition(args2.directory, sessionId, {
|
|
131823
|
-
status: "running"
|
|
131789
|
+
scheduleAsyncLanePrompt({
|
|
131790
|
+
session: args2.session,
|
|
131791
|
+
directory: args2.directory,
|
|
131792
|
+
sessionId,
|
|
131793
|
+
lane: args2.lane,
|
|
131794
|
+
timeoutMs: args2.timeoutMs
|
|
131824
131795
|
});
|
|
131825
131796
|
return {
|
|
131826
131797
|
id: args2.lane.id,
|
|
@@ -131854,6 +131825,9 @@ async function collectOnce(session, directory, records, cancelPending) {
|
|
|
131854
131825
|
});
|
|
131855
131826
|
continue;
|
|
131856
131827
|
}
|
|
131828
|
+
const readyForCollection = await isLaneReadyForCollection(session, directory, record3.subagentSessionId);
|
|
131829
|
+
if (!readyForCollection)
|
|
131830
|
+
continue;
|
|
131857
131831
|
let messages;
|
|
131858
131832
|
try {
|
|
131859
131833
|
messages = await session.messages({
|
|
@@ -131899,6 +131873,82 @@ async function collectOnce(session, directory, records, cancelPending) {
|
|
|
131899
131873
|
});
|
|
131900
131874
|
}
|
|
131901
131875
|
}
|
|
131876
|
+
function scheduleAsyncLanePrompt(args2) {
|
|
131877
|
+
queueMicrotask(() => {
|
|
131878
|
+
startAsyncLanePrompt(args2).catch(async (error93) => {
|
|
131879
|
+
const message = formatError3(error93);
|
|
131880
|
+
await appendAsyncLaneLaunchError(args2.directory, args2.session, args2.sessionId, message);
|
|
131881
|
+
});
|
|
131882
|
+
});
|
|
131883
|
+
}
|
|
131884
|
+
async function startAsyncLanePrompt(args2) {
|
|
131885
|
+
const promptController = new AbortController;
|
|
131886
|
+
let promptResult;
|
|
131887
|
+
try {
|
|
131888
|
+
promptResult = await withTimeout2(args2.session.promptAsync({
|
|
131889
|
+
path: { id: args2.sessionId },
|
|
131890
|
+
query: { directory: args2.directory },
|
|
131891
|
+
body: {
|
|
131892
|
+
agent: args2.lane.agent,
|
|
131893
|
+
tools: buildReadOnlyTools(),
|
|
131894
|
+
parts: [{ type: "text", text: args2.lane.prompt }]
|
|
131895
|
+
},
|
|
131896
|
+
signal: promptController.signal
|
|
131897
|
+
}), args2.timeoutMs, `Lane "${args2.lane.id}" session.promptAsync launch timed out after ${args2.timeoutMs}ms`, promptController);
|
|
131898
|
+
} catch (error93) {
|
|
131899
|
+
await appendAsyncLaneLaunchError(args2.directory, args2.session, args2.sessionId, formatError3(error93));
|
|
131900
|
+
return;
|
|
131901
|
+
}
|
|
131902
|
+
if (promptResult.error) {
|
|
131903
|
+
await appendAsyncLaneLaunchError(args2.directory, args2.session, args2.sessionId, `session.promptAsync launch failed: ${formatError3(promptResult.error)}`);
|
|
131904
|
+
return;
|
|
131905
|
+
}
|
|
131906
|
+
await appendDelegationTransition(args2.directory, args2.sessionId, {
|
|
131907
|
+
status: "running"
|
|
131908
|
+
});
|
|
131909
|
+
}
|
|
131910
|
+
async function appendAsyncLaneLaunchError(directory, session, sessionId, message) {
|
|
131911
|
+
await appendDelegationTransition(directory, sessionId, {
|
|
131912
|
+
status: "error",
|
|
131913
|
+
result: {
|
|
131914
|
+
error: message,
|
|
131915
|
+
chars: message.length,
|
|
131916
|
+
truncated: false,
|
|
131917
|
+
digest: digestText2(message)
|
|
131918
|
+
}
|
|
131919
|
+
});
|
|
131920
|
+
cleanupAsyncLaunchSession(session, sessionId);
|
|
131921
|
+
}
|
|
131922
|
+
async function isLaneReadyForCollection(session, directory, sessionId) {
|
|
131923
|
+
if (typeof session.status !== "function")
|
|
131924
|
+
return true;
|
|
131925
|
+
try {
|
|
131926
|
+
const status = await session.status({ query: { directory } });
|
|
131927
|
+
if (status.error || !status.data)
|
|
131928
|
+
return false;
|
|
131929
|
+
const current = status.data[sessionId];
|
|
131930
|
+
return current === undefined || current.type === "idle";
|
|
131931
|
+
} catch {
|
|
131932
|
+
return false;
|
|
131933
|
+
}
|
|
131934
|
+
}
|
|
131935
|
+
async function sweepStaleAsyncLaneRecords(session, directory, records, staleTimeoutMs) {
|
|
131936
|
+
if (staleTimeoutMs <= 0)
|
|
131937
|
+
return;
|
|
131938
|
+
const now = _internals94.now();
|
|
131939
|
+
for (const record3 of records) {
|
|
131940
|
+
if (record3.status !== "pending" && record3.status !== "running" && record3.status !== "ingestion_error")
|
|
131941
|
+
continue;
|
|
131942
|
+
if (now - record3.updatedAt <= staleTimeoutMs)
|
|
131943
|
+
continue;
|
|
131944
|
+
const readyForCollection = await isLaneReadyForCollection(session, directory, record3.subagentSessionId);
|
|
131945
|
+
if (!readyForCollection)
|
|
131946
|
+
continue;
|
|
131947
|
+
await appendDelegationTransition(directory, record3.correlationId, {
|
|
131948
|
+
status: "stale"
|
|
131949
|
+
});
|
|
131950
|
+
}
|
|
131951
|
+
}
|
|
131902
131952
|
function extractAssistantTranscript(messages) {
|
|
131903
131953
|
const assistantTexts = [];
|
|
131904
131954
|
for (const message of messages) {
|
|
@@ -132207,6 +132257,7 @@ function asyncFailureResult(args2) {
|
|
|
132207
132257
|
failed: 0,
|
|
132208
132258
|
rejected: 0,
|
|
132209
132259
|
max_concurrent: 0,
|
|
132260
|
+
launch_timeout_ms: 0,
|
|
132210
132261
|
timeout_ms: 0,
|
|
132211
132262
|
lane_results: [],
|
|
132212
132263
|
errors: args2.errors
|
|
@@ -132360,11 +132411,12 @@ var dispatch_lanes = createSwarmTool({
|
|
|
132360
132411
|
}
|
|
132361
132412
|
});
|
|
132362
132413
|
var dispatch_lanes_async = createSwarmTool({
|
|
132363
|
-
description: "Launch multiple read-only advisory lanes with OpenCode promptAsync and return IMMEDIATELY with a batch id (non-blocking). After launching, keep working on non-dependent investigation while lanes run — poll incrementally with collect_lane_results (wait omitted or false) to process settled lanes as they complete, or use wait: true only at workflow boundaries where all results are needed. Keep each lane prompt compact: send large shared context once via common_prompt (or have lanes read it from a file by absolute path) instead of inlining it into every lane prompt, which can produce oversized or malformed tool-call JSON.",
|
|
132414
|
+
description: "Launch multiple read-only advisory lanes with OpenCode promptAsync and return IMMEDIATELY with a batch id and lane session handles (non-blocking). launch_timeout_ms only bounds session creation and promptAsync acceptance; it is NOT a lane runtime timeout. After launching, keep working on non-dependent investigation while lanes run — poll incrementally with collect_lane_results (wait omitted or false) to process settled lanes as they complete, or use wait: true only at workflow boundaries where all results are needed. Keep each lane prompt compact: send large shared context once via common_prompt (or have lanes read it from a file by absolute path) instead of inlining it into every lane prompt, which can produce oversized or malformed tool-call JSON.",
|
|
132364
132415
|
args: {
|
|
132365
132416
|
lanes: DispatchLanesAsyncArgsSchema.shape.lanes,
|
|
132366
132417
|
common_prompt: DispatchLanesAsyncArgsSchema.shape.common_prompt,
|
|
132367
132418
|
max_concurrent: DispatchLanesAsyncArgsSchema.shape.max_concurrent,
|
|
132419
|
+
launch_timeout_ms: DispatchLanesAsyncArgsSchema.shape.launch_timeout_ms,
|
|
132368
132420
|
timeout_ms: DispatchLanesAsyncArgsSchema.shape.timeout_ms,
|
|
132369
132421
|
batch_id: DispatchLanesAsyncArgsSchema.shape.batch_id,
|
|
132370
132422
|
mode: DispatchLanesAsyncArgsSchema.shape.mode,
|
|
@@ -132380,7 +132432,7 @@ var dispatch_lanes_async = createSwarmTool({
|
|
|
132380
132432
|
}
|
|
132381
132433
|
});
|
|
132382
132434
|
var collect_lane_results = createSwarmTool({
|
|
132383
|
-
description: "Collect or poll results for a dispatch_lanes_async batch. Supports two modes: (1) non-blocking poll (wait omitted or false) — performs one collection pass and returns current lane status and any settled results so you can process completed lanes while continuing independent work; (2) blocking join (wait: true) — polls until all lanes settle or
|
|
132435
|
+
description: "Collect or poll results for a dispatch_lanes_async batch. Supports two modes: (1) non-blocking poll (wait omitted or false) — performs one collection pass and returns current lane status, including pending lane identities by default, and any settled results so you can process completed lanes while continuing independent work; (2) blocking join (wait: true) — polls until all lanes settle or the collection wait budget expires. Busy/retry lanes do not become stale solely because they run for a long time. Does not advance workflow gates.",
|
|
132384
132436
|
args: {
|
|
132385
132437
|
batch_id: CollectLaneResultsArgsSchema.shape.batch_id,
|
|
132386
132438
|
wait: CollectLaneResultsArgsSchema.shape.wait,
|
|
@@ -141306,18 +141358,32 @@ init_ledger();
|
|
|
141306
141358
|
init_manager();
|
|
141307
141359
|
import * as fs115 from "node:fs";
|
|
141308
141360
|
import * as path187 from "node:path";
|
|
141361
|
+
var _fsInternals = {
|
|
141362
|
+
mkdirSync: (...args2) => fs115.mkdirSync(...args2),
|
|
141363
|
+
writeFileSync: (path188, data, encoding) => fs115.writeFileSync(path188, data, encoding ?? "utf8"),
|
|
141364
|
+
readFileSync: (path188, encoding) => fs115.readFileSync(path188, encoding ?? "utf8"),
|
|
141365
|
+
existsSync: (path188) => fs115.existsSync(path188)
|
|
141366
|
+
};
|
|
141309
141367
|
async function writeCheckpoint(directory) {
|
|
141310
141368
|
try {
|
|
141311
141369
|
const plan = await loadPlan(directory);
|
|
141312
141370
|
if (!plan)
|
|
141313
141371
|
return;
|
|
141314
|
-
const
|
|
141315
|
-
|
|
141316
|
-
const jsonPath = path187.join(
|
|
141317
|
-
const mdPath = path187.join(
|
|
141318
|
-
|
|
141372
|
+
const exportDir = path187.join(directory, ".swarm", "plan-export");
|
|
141373
|
+
_fsInternals.mkdirSync(exportDir, { recursive: true });
|
|
141374
|
+
const jsonPath = path187.join(exportDir, "SWARM_PLAN.json");
|
|
141375
|
+
const mdPath = path187.join(exportDir, "SWARM_PLAN.md");
|
|
141376
|
+
_fsInternals.writeFileSync(jsonPath, JSON.stringify(plan, null, 2));
|
|
141319
141377
|
const md = derivePlanMarkdown(plan);
|
|
141320
|
-
|
|
141378
|
+
const header = `<!--
|
|
141379
|
+
AUTO-GENERATED EXPORT/CHECKPOINT SNAPSHOT — DO NOT EDIT
|
|
141380
|
+
This file is NOT the live plan. It is a derived export artifact.
|
|
141381
|
+
- .swarm/plan-ledger.jsonl is the authoritative source of plan state.
|
|
141382
|
+
- .swarm/plan.json and .swarm/plan.md are derived projections.
|
|
141383
|
+
Regenerated on: save_plan and phase_complete.
|
|
141384
|
+
-->
|
|
141385
|
+
`;
|
|
141386
|
+
_fsInternals.writeFileSync(mdPath, header + md);
|
|
141321
141387
|
} catch (error93) {
|
|
141322
141388
|
console.warn(`[checkpoint] Failed to write SWARM_PLAN checkpoint: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
141323
141389
|
}
|
|
@@ -1,6 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkpoint artifact writer.
|
|
3
|
+
* Writes SWARM_PLAN.md and SWARM_PLAN.json inside .swarm/plan-export/.
|
|
4
|
+
* Export-only — not a live runtime source of truth.
|
|
5
|
+
* Called on: save_plan, phase completion, /swarm close.
|
|
6
|
+
* NOT called on every task update.
|
|
7
|
+
*/
|
|
8
|
+
import * as fs from 'node:fs';
|
|
9
|
+
export declare const _fsInternals: {
|
|
10
|
+
mkdirSync: (path: fs.PathLike, options?: fs.MakeDirectoryOptions | fs.Mode | null | undefined) => string | undefined;
|
|
11
|
+
writeFileSync: (path: string, data: string, encoding?: BufferEncoding) => void;
|
|
12
|
+
readFileSync: (path: string, encoding?: BufferEncoding) => string;
|
|
13
|
+
existsSync: (path: string) => boolean;
|
|
14
|
+
};
|
|
1
15
|
import { type Plan } from '../config/plan-schema';
|
|
2
16
|
/**
|
|
3
|
-
* Write SWARM_PLAN.json and SWARM_PLAN.md inside the .swarm/ directory under the project root.
|
|
17
|
+
* Write SWARM_PLAN.json and SWARM_PLAN.md inside the .swarm/plan-export/ directory under the project root.
|
|
4
18
|
* Non-blocking: logs a warning on failure but never throws.
|
|
5
19
|
* @param directory - The working directory (project root)
|
|
6
20
|
*/
|
|
@@ -14,7 +28,7 @@ export interface ImportCheckpointResult {
|
|
|
14
28
|
error?: string;
|
|
15
29
|
}
|
|
16
30
|
/**
|
|
17
|
-
* Import a checkpoint from .swarm/SWARM_PLAN.json (with backward-compat fallback to project root).
|
|
31
|
+
* Import a checkpoint from .swarm/plan-export/SWARM_PLAN.json (with backward-compat fallback to .swarm/ and project root).
|
|
18
32
|
* Validates the checkpoint against PlanSchema, persists it as the live plan
|
|
19
33
|
* via savePlan, and appends a 'plan_rebuilt' ledger event.
|
|
20
34
|
*
|
|
@@ -26,6 +26,7 @@ declare const DispatchLanesAsyncArgsSchema: z.ZodObject<{
|
|
|
26
26
|
common_prompt: z.ZodOptional<z.ZodString>;
|
|
27
27
|
max_concurrent: z.ZodOptional<z.ZodNumber>;
|
|
28
28
|
timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
29
|
+
launch_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
29
30
|
batch_id: z.ZodOptional<z.ZodString>;
|
|
30
31
|
mode: z.ZodOptional<z.ZodString>;
|
|
31
32
|
pr_head_sha: z.ZodOptional<z.ZodString>;
|
|
@@ -88,6 +89,8 @@ export interface DispatchLanesAsyncResult {
|
|
|
88
89
|
failed: number;
|
|
89
90
|
rejected: number;
|
|
90
91
|
max_concurrent: number;
|
|
92
|
+
launch_timeout_ms: number;
|
|
93
|
+
/** Deprecated alias for launch_timeout_ms; retained for existing callers. */
|
|
91
94
|
timeout_ms: number;
|
|
92
95
|
lane_results: DispatchLaneResult[];
|
|
93
96
|
errors?: string[];
|
|
@@ -181,6 +184,16 @@ export interface SessionOps {
|
|
|
181
184
|
}> | null;
|
|
182
185
|
error?: unknown;
|
|
183
186
|
}>;
|
|
187
|
+
status?: (args: {
|
|
188
|
+
query?: {
|
|
189
|
+
directory?: string;
|
|
190
|
+
};
|
|
191
|
+
}) => Promise<{
|
|
192
|
+
data?: Record<string, {
|
|
193
|
+
type?: string;
|
|
194
|
+
}> | null;
|
|
195
|
+
error?: unknown;
|
|
196
|
+
}>;
|
|
184
197
|
abort?: (args: {
|
|
185
198
|
path: {
|
|
186
199
|
id: string;
|
|
@@ -225,11 +238,16 @@ export declare const _test_exports: {
|
|
|
225
238
|
common_prompt: z.ZodOptional<z.ZodString>;
|
|
226
239
|
max_concurrent: z.ZodOptional<z.ZodNumber>;
|
|
227
240
|
timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
241
|
+
launch_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
228
242
|
batch_id: z.ZodOptional<z.ZodString>;
|
|
229
243
|
mode: z.ZodOptional<z.ZodString>;
|
|
230
244
|
pr_head_sha: z.ZodOptional<z.ZodString>;
|
|
231
245
|
scope: z.ZodOptional<z.ZodString>;
|
|
232
246
|
}, z.core.$strip>;
|
|
247
|
+
DEFAULT_TIMEOUT_MS: number;
|
|
248
|
+
DEFAULT_ASYNC_LAUNCH_TIMEOUT_MS: number;
|
|
249
|
+
DEFAULT_ASYNC_STALE_TIMEOUT_MS: number;
|
|
250
|
+
DEFAULT_COLLECT_TIMEOUT_MS: number;
|
|
233
251
|
};
|
|
234
252
|
type ReadOnlyToolPermissions = Record<string, false> & {
|
|
235
253
|
write: false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.97.0",
|
|
4
4
|
"description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|