opencode-swarm 7.29.1 → 7.29.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +11 -20
- package/dist/index.js +62 -58
- package/dist/telemetry.d.ts +2 -1
- package/dist/tools/test-runner.d.ts +1 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -34,7 +34,7 @@ var package_default;
|
|
|
34
34
|
var init_package = __esm(() => {
|
|
35
35
|
package_default = {
|
|
36
36
|
name: "opencode-swarm",
|
|
37
|
-
version: "7.29.
|
|
37
|
+
version: "7.29.3",
|
|
38
38
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
39
39
|
main: "dist/index.js",
|
|
40
40
|
types: "dist/index.d.ts",
|
|
@@ -505,9 +505,7 @@ function bunSpawn(cmd, options) {
|
|
|
505
505
|
return proc.exitCode;
|
|
506
506
|
},
|
|
507
507
|
kill(signal) {
|
|
508
|
-
|
|
509
|
-
killChild(signal);
|
|
510
|
-
} catch {}
|
|
508
|
+
killChild(signal);
|
|
511
509
|
}
|
|
512
510
|
};
|
|
513
511
|
}
|
|
@@ -46282,7 +46280,7 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
|
|
|
46282
46280
|
const coverage = opts.coverage ?? false;
|
|
46283
46281
|
switch (framework) {
|
|
46284
46282
|
case "bun": {
|
|
46285
|
-
const args = ["bun", "
|
|
46283
|
+
const args = ["bun", "test"];
|
|
46286
46284
|
if (coverage)
|
|
46287
46285
|
args.push("--coverage");
|
|
46288
46286
|
if (scope !== "all" && files.length > 0)
|
|
@@ -48715,7 +48713,7 @@ function getTargetedExecutionUnsupportedReason(framework) {
|
|
|
48715
48713
|
function buildTestCommand2(framework, scope, files, coverage, baseDir) {
|
|
48716
48714
|
switch (framework) {
|
|
48717
48715
|
case "bun": {
|
|
48718
|
-
const args = ["bun", "
|
|
48716
|
+
const args = ["bun", "test"];
|
|
48719
48717
|
if (coverage)
|
|
48720
48718
|
args.push("--coverage");
|
|
48721
48719
|
if (scope !== "all" && files.length > 0) {
|
|
@@ -49252,24 +49250,17 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
|
|
|
49252
49250
|
const proc = bunSpawn(command, {
|
|
49253
49251
|
stdout: "pipe",
|
|
49254
49252
|
stderr: "pipe",
|
|
49255
|
-
|
|
49256
|
-
cwd,
|
|
49257
|
-
killProcessTree: true
|
|
49258
|
-
});
|
|
49259
|
-
let timeoutHandle;
|
|
49260
|
-
const timeoutPromise = new Promise((resolve14) => {
|
|
49261
|
-
timeoutHandle = setTimeout(() => {
|
|
49262
|
-
proc.kill();
|
|
49263
|
-
resolve14(-1);
|
|
49264
|
-
}, timeout_ms);
|
|
49253
|
+
cwd
|
|
49265
49254
|
});
|
|
49255
|
+
const timeoutPromise = new Promise((resolve14) => setTimeout(() => {
|
|
49256
|
+
proc.kill();
|
|
49257
|
+
resolve14(-1);
|
|
49258
|
+
}, timeout_ms));
|
|
49266
49259
|
const [exitCode, stdoutResult, stderrResult] = await Promise.all([
|
|
49267
49260
|
Promise.race([proc.exited, timeoutPromise]),
|
|
49268
49261
|
readBoundedStream(proc.stdout, MAX_OUTPUT_BYTES3),
|
|
49269
49262
|
readBoundedStream(proc.stderr, MAX_OUTPUT_BYTES3)
|
|
49270
49263
|
]);
|
|
49271
|
-
if (timeoutHandle !== undefined)
|
|
49272
|
-
clearTimeout(timeoutHandle);
|
|
49273
49264
|
const duration_ms = Date.now() - startTime;
|
|
49274
49265
|
let output = stdoutResult.text;
|
|
49275
49266
|
if (stderrResult.text) {
|
|
@@ -49572,6 +49563,7 @@ var init_test_runner = __esm(() => {
|
|
|
49572
49563
|
files: exports_external.array(exports_external.string()).optional().describe('Specific files to test. For "convention", pass source files or direct test files. For "graph" and "impact", pass source files only.'),
|
|
49573
49564
|
coverage: exports_external.boolean().optional().describe("Enable coverage reporting if supported"),
|
|
49574
49565
|
timeout_ms: exports_external.number().optional().describe("Timeout in milliseconds (default 60000, max 300000)"),
|
|
49566
|
+
allow_full_suite: exports_external.boolean().optional().describe('Explicit opt-in for scope "all". Required because full-suite output can destabilize SSE streaming.'),
|
|
49575
49567
|
working_directory: exports_external.string().optional().describe("Explicit project root directory. When provided, tests run relative to this path instead of the plugin context directory. Use this when CWD differs from the actual project root.")
|
|
49576
49568
|
},
|
|
49577
49569
|
async execute(args, directory) {
|
|
@@ -49645,8 +49637,7 @@ var init_test_runner = __esm(() => {
|
|
|
49645
49637
|
}
|
|
49646
49638
|
const scope = args.scope || "all";
|
|
49647
49639
|
if (scope === "all") {
|
|
49648
|
-
|
|
49649
|
-
if (!fullSuiteAllowed) {
|
|
49640
|
+
if (!process.env.SWARM_ALLOW_FULL_SUITE) {
|
|
49650
49641
|
const errorResult = {
|
|
49651
49642
|
success: false,
|
|
49652
49643
|
framework: "none",
|
package/dist/index.js
CHANGED
|
@@ -48,7 +48,7 @@ var package_default;
|
|
|
48
48
|
var init_package = __esm(() => {
|
|
49
49
|
package_default = {
|
|
50
50
|
name: "opencode-swarm",
|
|
51
|
-
version: "7.29.
|
|
51
|
+
version: "7.29.3",
|
|
52
52
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
53
53
|
main: "dist/index.js",
|
|
54
54
|
types: "dist/index.d.ts",
|
|
@@ -16715,9 +16715,7 @@ function bunSpawn(cmd, options) {
|
|
|
16715
16715
|
return proc.exitCode;
|
|
16716
16716
|
},
|
|
16717
16717
|
kill(signal) {
|
|
16718
|
-
|
|
16719
|
-
killChild(signal);
|
|
16720
|
-
} catch {}
|
|
16718
|
+
killChild(signal);
|
|
16721
16719
|
}
|
|
16722
16720
|
};
|
|
16723
16721
|
}
|
|
@@ -16969,6 +16967,13 @@ var init_telemetry = __esm(() => {
|
|
|
16969
16967
|
gatePassed(sessionId, gate, taskId) {
|
|
16970
16968
|
_internals4.emit("gate_passed", { sessionId, gate, taskId });
|
|
16971
16969
|
},
|
|
16970
|
+
gateParseError(taskId, error49) {
|
|
16971
|
+
_internals4.emit("gate_parse_error", {
|
|
16972
|
+
taskId,
|
|
16973
|
+
errorName: error49.name,
|
|
16974
|
+
errorMessage: error49.message.slice(0, 200)
|
|
16975
|
+
});
|
|
16976
|
+
},
|
|
16972
16977
|
gateFailed(sessionId, gate, taskId, reason) {
|
|
16973
16978
|
_internals4.emit("gate_failed", { sessionId, gate, taskId, reason });
|
|
16974
16979
|
},
|
|
@@ -38741,12 +38746,15 @@ function getEvidencePath(directory, taskId) {
|
|
|
38741
38746
|
assertValidTaskId(taskId);
|
|
38742
38747
|
return path12.join(getEvidenceDir(directory), `${taskId}.json`);
|
|
38743
38748
|
}
|
|
38744
|
-
function readExisting(evidencePath) {
|
|
38749
|
+
function readExisting(evidencePath, taskId) {
|
|
38745
38750
|
try {
|
|
38746
38751
|
const raw = readFileSync5(evidencePath, "utf-8");
|
|
38747
38752
|
return TaskEvidenceSchema.parse(JSON.parse(raw));
|
|
38748
|
-
} catch {
|
|
38749
|
-
|
|
38753
|
+
} catch (error49) {
|
|
38754
|
+
if (error49.code === "ENOENT")
|
|
38755
|
+
return null;
|
|
38756
|
+
telemetry.gateParseError(taskId, error49);
|
|
38757
|
+
throw error49;
|
|
38750
38758
|
}
|
|
38751
38759
|
}
|
|
38752
38760
|
async function atomicWrite2(targetPath, content) {
|
|
@@ -38767,7 +38775,13 @@ async function recordGateEvidence(directory, taskId, gate, sessionId, turbo) {
|
|
|
38767
38775
|
const lockRelPath = path12.join("evidence", `${taskId}.json`);
|
|
38768
38776
|
await withEvidenceLock(directory, lockRelPath, gate, taskId, async () => {
|
|
38769
38777
|
const evidencePath = getEvidencePath(directory, taskId);
|
|
38770
|
-
|
|
38778
|
+
let existing = null;
|
|
38779
|
+
try {
|
|
38780
|
+
existing = readExisting(evidencePath, taskId);
|
|
38781
|
+
} catch (error49) {
|
|
38782
|
+
telemetry.gateParseError(taskId, error49);
|
|
38783
|
+
throw error49;
|
|
38784
|
+
}
|
|
38771
38785
|
const requiredGates = existing ? expandRequiredGates(existing.required_gates, gate) : deriveRequiredGates(gate);
|
|
38772
38786
|
const updated = {
|
|
38773
38787
|
taskId,
|
|
@@ -38793,7 +38807,13 @@ async function recordAgentDispatch(directory, taskId, agentType, turbo) {
|
|
|
38793
38807
|
const lockRelPath = path12.join("evidence", `${taskId}.json`);
|
|
38794
38808
|
await withEvidenceLock(directory, lockRelPath, agentType, taskId, async () => {
|
|
38795
38809
|
const evidencePath = getEvidencePath(directory, taskId);
|
|
38796
|
-
|
|
38810
|
+
let existing = null;
|
|
38811
|
+
try {
|
|
38812
|
+
existing = readExisting(evidencePath, taskId);
|
|
38813
|
+
} catch (error49) {
|
|
38814
|
+
telemetry.gateParseError(taskId, error49);
|
|
38815
|
+
throw error49;
|
|
38816
|
+
}
|
|
38797
38817
|
const requiredGates = existing ? expandRequiredGates(existing.required_gates, agentType) : deriveRequiredGates(agentType);
|
|
38798
38818
|
const updated = {
|
|
38799
38819
|
taskId,
|
|
@@ -38807,7 +38827,7 @@ async function recordAgentDispatch(directory, taskId, agentType, turbo) {
|
|
|
38807
38827
|
async function readTaskEvidence(directory, taskId) {
|
|
38808
38828
|
try {
|
|
38809
38829
|
assertValidTaskId(taskId);
|
|
38810
|
-
return readExisting(getEvidencePath(directory, taskId));
|
|
38830
|
+
return readExisting(getEvidencePath(directory, taskId), taskId);
|
|
38811
38831
|
} catch {
|
|
38812
38832
|
return null;
|
|
38813
38833
|
}
|
|
@@ -67375,7 +67395,7 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
|
|
|
67375
67395
|
const coverage = opts.coverage ?? false;
|
|
67376
67396
|
switch (framework) {
|
|
67377
67397
|
case "bun": {
|
|
67378
|
-
const args2 = ["bun", "
|
|
67398
|
+
const args2 = ["bun", "test"];
|
|
67379
67399
|
if (coverage)
|
|
67380
67400
|
args2.push("--coverage");
|
|
67381
67401
|
if (scope !== "all" && files.length > 0)
|
|
@@ -69808,7 +69828,7 @@ function getTargetedExecutionUnsupportedReason(framework) {
|
|
|
69808
69828
|
function buildTestCommand2(framework, scope, files, coverage, baseDir) {
|
|
69809
69829
|
switch (framework) {
|
|
69810
69830
|
case "bun": {
|
|
69811
|
-
const args2 = ["bun", "
|
|
69831
|
+
const args2 = ["bun", "test"];
|
|
69812
69832
|
if (coverage)
|
|
69813
69833
|
args2.push("--coverage");
|
|
69814
69834
|
if (scope !== "all" && files.length > 0) {
|
|
@@ -70345,24 +70365,17 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
|
|
|
70345
70365
|
const proc = bunSpawn(command, {
|
|
70346
70366
|
stdout: "pipe",
|
|
70347
70367
|
stderr: "pipe",
|
|
70348
|
-
|
|
70349
|
-
cwd,
|
|
70350
|
-
killProcessTree: true
|
|
70351
|
-
});
|
|
70352
|
-
let timeoutHandle;
|
|
70353
|
-
const timeoutPromise = new Promise((resolve16) => {
|
|
70354
|
-
timeoutHandle = setTimeout(() => {
|
|
70355
|
-
proc.kill();
|
|
70356
|
-
resolve16(-1);
|
|
70357
|
-
}, timeout_ms);
|
|
70368
|
+
cwd
|
|
70358
70369
|
});
|
|
70370
|
+
const timeoutPromise = new Promise((resolve16) => setTimeout(() => {
|
|
70371
|
+
proc.kill();
|
|
70372
|
+
resolve16(-1);
|
|
70373
|
+
}, timeout_ms));
|
|
70359
70374
|
const [exitCode, stdoutResult, stderrResult] = await Promise.all([
|
|
70360
70375
|
Promise.race([proc.exited, timeoutPromise]),
|
|
70361
70376
|
readBoundedStream(proc.stdout, MAX_OUTPUT_BYTES3),
|
|
70362
70377
|
readBoundedStream(proc.stderr, MAX_OUTPUT_BYTES3)
|
|
70363
70378
|
]);
|
|
70364
|
-
if (timeoutHandle !== undefined)
|
|
70365
|
-
clearTimeout(timeoutHandle);
|
|
70366
70379
|
const duration_ms = Date.now() - startTime;
|
|
70367
70380
|
let output = stdoutResult.text;
|
|
70368
70381
|
if (stderrResult.text) {
|
|
@@ -70665,6 +70678,7 @@ var init_test_runner = __esm(() => {
|
|
|
70665
70678
|
files: exports_external.array(exports_external.string()).optional().describe('Specific files to test. For "convention", pass source files or direct test files. For "graph" and "impact", pass source files only.'),
|
|
70666
70679
|
coverage: exports_external.boolean().optional().describe("Enable coverage reporting if supported"),
|
|
70667
70680
|
timeout_ms: exports_external.number().optional().describe("Timeout in milliseconds (default 60000, max 300000)"),
|
|
70681
|
+
allow_full_suite: exports_external.boolean().optional().describe('Explicit opt-in for scope "all". Required because full-suite output can destabilize SSE streaming.'),
|
|
70668
70682
|
working_directory: exports_external.string().optional().describe("Explicit project root directory. When provided, tests run relative to this path instead of the plugin context directory. Use this when CWD differs from the actual project root.")
|
|
70669
70683
|
},
|
|
70670
70684
|
async execute(args2, directory) {
|
|
@@ -70738,8 +70752,7 @@ var init_test_runner = __esm(() => {
|
|
|
70738
70752
|
}
|
|
70739
70753
|
const scope = args2.scope || "all";
|
|
70740
70754
|
if (scope === "all") {
|
|
70741
|
-
|
|
70742
|
-
if (!fullSuiteAllowed) {
|
|
70755
|
+
if (!process.env.SWARM_ALLOW_FULL_SUITE) {
|
|
70743
70756
|
const errorResult = {
|
|
70744
70757
|
success: false,
|
|
70745
70758
|
framework: "none",
|
|
@@ -75931,8 +75944,6 @@ SECURITY_KEYWORDS: password, secret, token, credential, auth, login, encryption,
|
|
|
75931
75944
|
{{AGENT_PREFIX}}test_engineer - Test generation AND execution (writes tests, runs them, reports PASS/FAIL)
|
|
75932
75945
|
{{AGENT_PREFIX}}critic - Plan review gate (reviews plan BEFORE implementation)
|
|
75933
75946
|
{{AGENT_PREFIX}}critic_sounding_board - Pre-escalation pushback (honest engineer review before user contact)
|
|
75934
|
-
{{AGENT_PREFIX}}skill_improver - Low-frequency skill / knowledge / prompt improvement adviser
|
|
75935
|
-
{{AGENT_PREFIX}}spec_writer - .swarm/spec.md authoring via spec_write
|
|
75936
75947
|
{{AGENT_PREFIX}}docs - Documentation updates (README, API docs, guides — NOT .swarm/ files)
|
|
75937
75948
|
{{AGENT_PREFIX}}designer - UI/UX design specs (scaffold generation for UI components — runs BEFORE coder on UI tasks)
|
|
75938
75949
|
|
|
@@ -75983,20 +75994,30 @@ For every applicable directive in the block:
|
|
|
75983
75994
|
|
|
75984
75995
|
You may also call the \`knowledge_ack\` tool to record an outcome explicitly when chat-text markers would be ambiguous (e.g. inside structured tool args).
|
|
75985
75996
|
|
|
75986
|
-
## SKILL IMPROVER
|
|
75997
|
+
## SKILL IMPROVER (low-frequency, expensive-model adviser)
|
|
75987
75998
|
|
|
75988
|
-
\`
|
|
75989
|
-
|
|
75990
|
-
|
|
75999
|
+
The \`skill_improver\` agent and the \`skill_improve\` tool exist for rare, deep
|
|
76000
|
+
review of accumulated knowledge / skills / spec / architect prompt. They are
|
|
76001
|
+
quota-bounded (default 10 calls/day) and disabled by default. Suggest running
|
|
76002
|
+
\`skill_improve\` only after one of:
|
|
76003
|
+
- repeated reviewer rejections in a row,
|
|
76004
|
+
- many \`KNOWLEDGE_IGNORED\` outcomes for the same cluster,
|
|
76005
|
+
- stale skills (no updates while their target area changed),
|
|
76006
|
+
- a fresh spec mismatch with shipped behaviour.
|
|
75991
76007
|
|
|
75992
76008
|
When \`skill_improver.require_user_approval\` is true (default), ASK the user
|
|
75993
76009
|
before running. Default outputs are proposals only — they never modify source.
|
|
75994
76010
|
|
|
75995
76011
|
## SPEC WRITER
|
|
75996
76012
|
|
|
75997
|
-
For substantial spec authoring
|
|
75998
|
-
|
|
75999
|
-
|
|
76013
|
+
For substantial spec authoring or revision, prefer delegating to the
|
|
76014
|
+
\`spec_writer\` agent (independent model from architect). It writes only via
|
|
76015
|
+
the safe \`spec_write\` tool. Use it when:
|
|
76016
|
+
- the user requests a new spec or major spec revision,
|
|
76017
|
+
- requirements decomposition is non-trivial,
|
|
76018
|
+
- you would otherwise inline-author \`.swarm/spec.md\` yourself.
|
|
76019
|
+
|
|
76020
|
+
Continue handling small touch-ups (typos, cross-references) inline.
|
|
76000
76021
|
|
|
76001
76022
|
### ANTI-RATIONALIZATION
|
|
76002
76023
|
- ✗ "The coder already knows these conventions" → Skills contain project-specific rules the model cannot know from training. Always pass.
|
|
@@ -76177,12 +76198,11 @@ MODE: BRAINSTORM runs seven phases in strict order. Do not skip phases. Do not c
|
|
|
76177
76198
|
- Exit with a design outline the user can skim in under two minutes.
|
|
76178
76199
|
|
|
76179
76200
|
**Phase 5: SPEC WRITE + SELF-REVIEW (architect + reviewer).**
|
|
76180
|
-
-
|
|
76181
|
-
- The spec must follow the same SPEC CONTENT RULES that MODE: SPECIFY uses: WHAT/WHY only, no tech stack, no implementation details, FR-### / SC-### numbering, Given/When/Then scenarios, \`[NEEDS CLARIFICATION]\` markers (max 3).
|
|
76201
|
+
- Generate \`.swarm/spec.md\` following the same SPEC CONTENT RULES that MODE: SPECIFY uses: WHAT/WHY only, no tech stack, no implementation details, FR-### / SC-### numbering, Given/When/Then scenarios, \`[NEEDS CLARIFICATION]\` markers (max 3).
|
|
76182
76202
|
- Cross-reference design sections by name where relevant context helps (but keep HOW out of the spec).
|
|
76183
76203
|
- Delegate to \`{{AGENT_PREFIX}}reviewer\` for an independent review of the draft spec. Reviewer must flag: requirements that encode HOW, untestable requirements, missing edge cases, silent assumptions.
|
|
76184
76204
|
- Apply reviewer feedback. If reviewer rejects, iterate once and re-review. After two rounds, surface remaining disagreements to the user.
|
|
76185
|
-
-
|
|
76205
|
+
- Write the final spec to \`.swarm/spec.md\`.
|
|
76186
76206
|
- Exit when reviewer signs off (or user explicitly accepts remaining disagreements).
|
|
76187
76207
|
|
|
76188
76208
|
**Phase 6: QA GATE SELECTION (architect, dialogue only).**
|
|
@@ -76254,7 +76274,7 @@ Activates when: user asks to "specify", "define requirements", "write a spec", o
|
|
|
76254
76274
|
1b. Run CODEBASE REALITY CHECK for any codebase references mentioned by the user or implied by the feature. Skip if work is purely greenfield (no existing codebase to check). Report discrepancies before proceeding to explorer.
|
|
76255
76275
|
2. Delegate to \`{{AGENT_PREFIX}}explorer\` to scan the codebase for relevant context (existing patterns, related code, affected areas).
|
|
76256
76276
|
3. Delegate to \`{{AGENT_PREFIX}}sme\` for domain research on the feature area to surface known constraints, best practices, and integration concerns.
|
|
76257
|
-
4.
|
|
76277
|
+
4. Generate \`.swarm/spec.md\` capturing:
|
|
76258
76278
|
- First line must be: \`# Specification: <feature-name>\`
|
|
76259
76279
|
- Feature description: WHAT users need and WHY — never HOW to implement
|
|
76260
76280
|
- User scenarios with acceptance criteria (Given/When/Then format)
|
|
@@ -76263,7 +76283,7 @@ Activates when: user asks to "specify", "define requirements", "write a spec", o
|
|
|
76263
76283
|
- Key entities if data is involved (no schema or field definitions — entity names only)
|
|
76264
76284
|
- Edge cases and known failure modes
|
|
76265
76285
|
- \`[NEEDS CLARIFICATION]\` markers (max 3) for items where uncertainty could change scope, security, or core behavior; prefer informed defaults over asking
|
|
76266
|
-
5.
|
|
76286
|
+
5. Write the spec to \`.swarm/spec.md\`.
|
|
76267
76287
|
5b. **QA GATE SELECTION (dialogue only).**
|
|
76268
76288
|
{{QA_GATE_DIALOGUE_SPECIFY}}
|
|
76269
76289
|
|
|
@@ -79466,24 +79486,8 @@ function createSwarmAgents(swarmId, swarmConfig, isDefault, pluginConfig, projec
|
|
|
79466
79486
|
const swarmIdentity = isDefault ? "default" : swarmId;
|
|
79467
79487
|
const agentPrefix = prefix;
|
|
79468
79488
|
architect.config.prompt = architect.config.prompt?.replace(/\{\{SWARM_ID\}\}/g, swarmIdentity).replace(/\{\{AGENT_PREFIX\}\}/g, agentPrefix).replace(/\{\{QA_RETRY_LIMIT\}\}/g, String(qaRetryLimit)).replace(/\{\{PROJECT_LANGUAGE\}\}/g, projectContext.PROJECT_LANGUAGE).replace(/\{\{PROJECT_FRAMEWORK\}\}/g, projectContext.PROJECT_FRAMEWORK).replace(/\{\{BUILD_CMD\}\}/g, projectContext.BUILD_CMD).replace(/\{\{TEST_CMD\}\}/g, projectContext.TEST_CMD).replace(/\{\{LINT_CMD\}\}/g, projectContext.LINT_CMD).replace(/\{\{ENTRY_POINTS\}\}/g, projectContext.ENTRY_POINTS).replace(/\{\{CODER_CONSTRAINTS\}\}/g, projectContext.CODER_CONSTRAINTS).replace(/\{\{TEST_CONSTRAINTS\}\}/g, projectContext.TEST_CONSTRAINTS).replace(/\{\{REVIEWER_CHECKLIST\}\}/g, projectContext.REVIEWER_CHECKLIST).replace(/\{\{PROJECT_CONTEXT_SECONDARY_LANGUAGES\}\}/g, projectContext.PROJECT_CONTEXT_SECONDARY_LANGUAGES);
|
|
79469
|
-
const skillImproverEnabled = !isAgentDisabled("skill_improver", swarmAgents, swarmPrefix);
|
|
79470
|
-
const specWriterEnabled = !isAgentDisabled("spec_writer", swarmAgents, swarmPrefix);
|
|
79471
|
-
if (!skillImproverEnabled) {
|
|
79472
|
-
architect.config.prompt = architect.config.prompt?.replace(`, ${agentPrefix}skill_improver`, "").replace(`
|
|
79473
|
-
${agentPrefix}skill_improver - Low-frequency skill / knowledge / prompt improvement adviser`, "").replace(/\n## SKILL IMPROVER[\s\S]*?(?=\n\n## SPEC WRITER)/, "");
|
|
79474
|
-
}
|
|
79475
|
-
if (!specWriterEnabled) {
|
|
79476
|
-
const escapedAgentPrefix = agentPrefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
79477
|
-
architect.config.prompt = architect.config.prompt?.replace(`, ${agentPrefix}spec_writer`, "").replace(`
|
|
79478
|
-
${agentPrefix}spec_writer - .swarm/spec.md authoring via spec_write`, "").replace(/\n## SPEC WRITER[\s\S]*?(?=\n\n### ANTI-RATIONALIZATION)/, "").replace(new RegExp(`- Delegate substantial spec drafting to \`${escapedAgentPrefix}spec_writer\`[^\\n]*\\n`, "g"), "- spec_writer is disabled. Ask the user to enable the spec_writer agent before creating or revising `.swarm/spec.md`.\n").replace(new RegExp(`4\\. Delegate substantial spec drafting to \`${escapedAgentPrefix}spec_writer\`[^\\n]*`), "4. spec_writer is disabled. Ask the user to enable the spec_writer agent before creating or revising `.swarm/spec.md`.").replace(new RegExp(`5\\. Require \`${escapedAgentPrefix}spec_writer\` to write the spec via \`spec_write\`, then read back and lint \`\\.swarm/spec\\.md\`\\.`), "5. Do not continue SPECIFY until spec_writer is available.").replace(new RegExp(`- Read back and lint the final spec after \`${escapedAgentPrefix}spec_writer\` writes it\\.`), "- Do not continue BRAINSTORM spec writing until spec_writer is available.");
|
|
79479
|
-
}
|
|
79480
79489
|
if (!isDefault) {
|
|
79481
79490
|
architect.description = `[${swarmName}] ${architect.description}`;
|
|
79482
|
-
const optionalAgentLines = [
|
|
79483
|
-
skillImproverEnabled ? `- @${swarmId}_skill_improver (not @skill_improver)` : undefined,
|
|
79484
|
-
specWriterEnabled ? `- @${swarmId}_spec_writer (not @spec_writer)` : undefined
|
|
79485
|
-
].filter((line) => Boolean(line)).join(`
|
|
79486
|
-
`);
|
|
79487
79491
|
const swarmHeader = `## ⚠️ YOU ARE THE ${swarmName.toUpperCase()} SWARM ARCHITECT
|
|
79488
79492
|
|
|
79489
79493
|
Your swarm ID is "${swarmId}". ALL your agents have the "${swarmId}_" prefix:
|
|
@@ -79491,8 +79495,8 @@ Your swarm ID is "${swarmId}". ALL your agents have the "${swarmId}_" prefix:
|
|
|
79491
79495
|
- @${swarmId}_coder (not @coder)
|
|
79492
79496
|
- @${swarmId}_sme (not @sme)
|
|
79493
79497
|
- @${swarmId}_reviewer (not @reviewer)
|
|
79494
|
-
|
|
79495
|
-
|
|
79498
|
+
- @${swarmId}_spec_writer (not @spec_writer)
|
|
79499
|
+
- etc.
|
|
79496
79500
|
|
|
79497
79501
|
CRITICAL: Agents without the "${swarmId}_" prefix DO NOT EXIST or belong to a DIFFERENT swarm.
|
|
79498
79502
|
If you call @coder instead of @${swarmId}_coder, the call will FAIL or go to the wrong swarm.
|
package/dist/telemetry.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type TelemetryEvent = 'session_started' | 'session_ended' | 'agent_activated' | 'delegation_begin' | 'delegation_end' | 'task_state_changed' | 'gate_passed' | 'gate_failed' | 'phase_changed' | 'budget_updated' | 'model_fallback' | 'hard_limit_hit' | 'revision_limit_hit' | 'loop_detected' | 'scope_violation' | 'qa_skip_violation' | 'heartbeat' | 'turbo_mode_changed' | 'auto_oversight_escalation' | 'environment_detected' | 'evidence_lock_acquired' | 'evidence_lock_contended' | 'evidence_lock_stale_recovered' | 'plan_ledger_cas_retry' | 'plan_md_write_failed' | 'prm_pattern_detected' | 'prm_course_correction_injected' | 'prm_escalation_triggered' | 'prm_hard_stop';
|
|
1
|
+
export type TelemetryEvent = 'session_started' | 'session_ended' | 'agent_activated' | 'delegation_begin' | 'delegation_end' | 'task_state_changed' | 'gate_passed' | 'gate_failed' | 'gate_parse_error' | 'phase_changed' | 'budget_updated' | 'model_fallback' | 'hard_limit_hit' | 'revision_limit_hit' | 'loop_detected' | 'scope_violation' | 'qa_skip_violation' | 'heartbeat' | 'turbo_mode_changed' | 'auto_oversight_escalation' | 'environment_detected' | 'evidence_lock_acquired' | 'evidence_lock_contended' | 'evidence_lock_stale_recovered' | 'plan_ledger_cas_retry' | 'plan_md_write_failed' | 'prm_pattern_detected' | 'prm_course_correction_injected' | 'prm_escalation_triggered' | 'prm_hard_stop';
|
|
2
2
|
export type TelemetryListener = (event: TelemetryEvent, data: Record<string, unknown>) => void;
|
|
3
3
|
/** @internal - For testing only */
|
|
4
4
|
export declare function resetTelemetryForTesting(): void;
|
|
@@ -39,6 +39,7 @@ export declare const telemetry: {
|
|
|
39
39
|
delegationEnd(sessionId: string, agentName: string, taskId: string, result: string): void;
|
|
40
40
|
taskStateChanged(sessionId: string, taskId: string, newState: string, oldState?: string): void;
|
|
41
41
|
gatePassed(sessionId: string, gate: string, taskId: string): void;
|
|
42
|
+
gateParseError(taskId: string, error: Error): void;
|
|
42
43
|
gateFailed(sessionId: string, gate: string, taskId: string, reason: string): void;
|
|
43
44
|
phaseChanged(sessionId: string, oldPhase: number, newPhase: number): void;
|
|
44
45
|
budgetUpdated(sessionId: string, budgetPct: number, agentName: string): void;
|
|
@@ -23,6 +23,7 @@ export interface TestRunnerArgs {
|
|
|
23
23
|
files?: string[];
|
|
24
24
|
coverage?: boolean;
|
|
25
25
|
timeout_ms?: number;
|
|
26
|
+
allow_full_suite?: boolean;
|
|
26
27
|
}
|
|
27
28
|
export type RegressionOutcome = 'pass' | 'skip' | 'regression' | 'scope_exceeded' | 'error';
|
|
28
29
|
export interface TestTotals {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.29.
|
|
3
|
+
"version": "7.29.3",
|
|
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",
|