opencode-swarm 6.22.11 → 6.22.13
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/hooks/phase-monitor.d.ts +5 -1
- package/dist/index.js +69 -40
- package/dist/state.d.ts +1 -0
- package/package.json +1 -1
|
@@ -6,11 +6,15 @@
|
|
|
6
6
|
* Wrapped in safeHook — errors must never propagate.
|
|
7
7
|
*/
|
|
8
8
|
import type { PreflightTriggerManager } from '../background/trigger';
|
|
9
|
+
import type { CuratorConfig, CuratorInitResult } from './curator-types';
|
|
10
|
+
/** Injectable curator runner type — allows test injection without module mocking. */
|
|
11
|
+
export type CuratorInitRunner = (directory: string, config: CuratorConfig) => Promise<CuratorInitResult>;
|
|
9
12
|
/**
|
|
10
13
|
* Creates a hook that monitors plan phase transitions and triggers preflight.
|
|
11
14
|
*
|
|
12
15
|
* @param directory - Project directory (where .swarm/ lives)
|
|
13
16
|
* @param preflightManager - The PreflightTriggerManager to call on phase change
|
|
17
|
+
* @param curatorRunner - Optional curator init runner (defaults to runCuratorInit; injectable for tests)
|
|
14
18
|
* @returns A safeHook-wrapped system.transform handler
|
|
15
19
|
*/
|
|
16
|
-
export declare function createPhaseMonitorHook(directory: string, preflightManager: PreflightTriggerManager): (input: unknown, output: unknown) => Promise<void>;
|
|
20
|
+
export declare function createPhaseMonitorHook(directory: string, preflightManager: PreflightTriggerManager, curatorRunner?: CuratorInitRunner): (input: unknown, output: unknown) => Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -48616,7 +48616,9 @@ function createDelegationGateHook(config3) {
|
|
|
48616
48616
|
if (state === "coder_delegated" || state === "pre_check_passed") {
|
|
48617
48617
|
try {
|
|
48618
48618
|
advanceTaskState(session, taskId, "reviewer_run");
|
|
48619
|
-
} catch {
|
|
48619
|
+
} catch (err2) {
|
|
48620
|
+
console.warn(`[delegation-gate] toolAfter: could not advance ${taskId} (${state}) \u2192 reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
48621
|
+
}
|
|
48620
48622
|
}
|
|
48621
48623
|
}
|
|
48622
48624
|
}
|
|
@@ -48625,7 +48627,9 @@ function createDelegationGateHook(config3) {
|
|
|
48625
48627
|
if (state === "reviewer_run") {
|
|
48626
48628
|
try {
|
|
48627
48629
|
advanceTaskState(session, taskId, "tests_run");
|
|
48628
|
-
} catch {
|
|
48630
|
+
} catch (err2) {
|
|
48631
|
+
console.warn(`[delegation-gate] toolAfter: could not advance ${taskId} (${state}) \u2192 tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
48632
|
+
}
|
|
48629
48633
|
}
|
|
48630
48634
|
}
|
|
48631
48635
|
}
|
|
@@ -48640,7 +48644,9 @@ function createDelegationGateHook(config3) {
|
|
|
48640
48644
|
if (state === "coder_delegated" || state === "pre_check_passed") {
|
|
48641
48645
|
try {
|
|
48642
48646
|
advanceTaskState(otherSession, taskId, "reviewer_run");
|
|
48643
|
-
} catch {
|
|
48647
|
+
} catch (err2) {
|
|
48648
|
+
console.warn(`[delegation-gate] toolAfter cross-session: could not advance ${taskId} (${state}) \u2192 reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
48649
|
+
}
|
|
48644
48650
|
}
|
|
48645
48651
|
}
|
|
48646
48652
|
}
|
|
@@ -48649,7 +48655,9 @@ function createDelegationGateHook(config3) {
|
|
|
48649
48655
|
if (state === "reviewer_run") {
|
|
48650
48656
|
try {
|
|
48651
48657
|
advanceTaskState(otherSession, taskId, "tests_run");
|
|
48652
|
-
} catch {
|
|
48658
|
+
} catch (err2) {
|
|
48659
|
+
console.warn(`[delegation-gate] toolAfter cross-session: could not advance ${taskId} (${state}) \u2192 tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
48660
|
+
}
|
|
48653
48661
|
}
|
|
48654
48662
|
}
|
|
48655
48663
|
}
|
|
@@ -48690,7 +48698,9 @@ function createDelegationGateHook(config3) {
|
|
|
48690
48698
|
if (state === "coder_delegated" || state === "pre_check_passed") {
|
|
48691
48699
|
try {
|
|
48692
48700
|
advanceTaskState(session, taskId, "reviewer_run");
|
|
48693
|
-
} catch {
|
|
48701
|
+
} catch (err2) {
|
|
48702
|
+
console.warn(`[delegation-gate] fallback: could not advance ${taskId} (${state}) \u2192 reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
48703
|
+
}
|
|
48694
48704
|
}
|
|
48695
48705
|
}
|
|
48696
48706
|
}
|
|
@@ -48699,7 +48709,9 @@ function createDelegationGateHook(config3) {
|
|
|
48699
48709
|
if (state === "reviewer_run") {
|
|
48700
48710
|
try {
|
|
48701
48711
|
advanceTaskState(session, taskId, "tests_run");
|
|
48702
|
-
} catch {
|
|
48712
|
+
} catch (err2) {
|
|
48713
|
+
console.warn(`[delegation-gate] fallback: could not advance ${taskId} (${state}) \u2192 tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
48714
|
+
}
|
|
48703
48715
|
}
|
|
48704
48716
|
}
|
|
48705
48717
|
}
|
|
@@ -48713,7 +48725,9 @@ function createDelegationGateHook(config3) {
|
|
|
48713
48725
|
if (state === "coder_delegated" || state === "pre_check_passed") {
|
|
48714
48726
|
try {
|
|
48715
48727
|
advanceTaskState(otherSession, taskId, "reviewer_run");
|
|
48716
|
-
} catch {
|
|
48728
|
+
} catch (err2) {
|
|
48729
|
+
console.warn(`[delegation-gate] fallback cross-session: could not advance ${taskId} (${state}) \u2192 reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
48730
|
+
}
|
|
48717
48731
|
}
|
|
48718
48732
|
}
|
|
48719
48733
|
}
|
|
@@ -48728,7 +48742,9 @@ function createDelegationGateHook(config3) {
|
|
|
48728
48742
|
if (state === "reviewer_run") {
|
|
48729
48743
|
try {
|
|
48730
48744
|
advanceTaskState(otherSession, taskId, "tests_run");
|
|
48731
|
-
} catch {
|
|
48745
|
+
} catch (err2) {
|
|
48746
|
+
console.warn(`[delegation-gate] fallback cross-session: could not advance ${taskId} (${state}) \u2192 tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
48747
|
+
}
|
|
48732
48748
|
}
|
|
48733
48749
|
}
|
|
48734
48750
|
}
|
|
@@ -48855,7 +48871,7 @@ ${trimComment}${after}`;
|
|
|
48855
48871
|
let guidance;
|
|
48856
48872
|
if (lastGate?.taskId) {
|
|
48857
48873
|
const gateResult = lastGate.passed ? "PASSED" : "FAILED";
|
|
48858
|
-
const sanitizedGate = lastGate.gate.replace(/</g, "<").replace(/>/g, ">").replace(/\[/g, "(").replace(/\]/g, ")").replace(/[\r\n]/g, " ").slice(0, 64);
|
|
48874
|
+
const sanitizedGate = lastGate.gate.replace(/</g, "<").replace(/>/g, ">").replace(/\[ \]/g, "()").replace(/\[/g, "(").replace(/\]/g, ")").replace(/[\r\n]/g, " ").slice(0, 64);
|
|
48859
48875
|
const sanitizedTaskId = lastGate.taskId.replace(/</g, "<").replace(/>/g, ">").replace(/\[/g, "(").replace(/\]/g, ")").replace(/[\r\n]/g, " ").slice(0, 32);
|
|
48860
48876
|
guidance = `[Last gate: ${sanitizedGate} ${gateResult} for task ${sanitizedTaskId}]
|
|
48861
48877
|
[NEXT] Execute the next gate for the current task.`;
|
|
@@ -48876,27 +48892,35 @@ ${trimComment}${after}`;
|
|
|
48876
48892
|
if (text.length > delegationMaxChars) {
|
|
48877
48893
|
warnings.push(`Delegation exceeds recommended size (${text.length} chars, limit ${delegationMaxChars}). Consider splitting into smaller tasks.`);
|
|
48878
48894
|
}
|
|
48879
|
-
|
|
48880
|
-
|
|
48881
|
-
|
|
48895
|
+
if (isCoderDelegation) {
|
|
48896
|
+
const fileMatches = text.match(/^FILE:/gm);
|
|
48897
|
+
if (fileMatches && fileMatches.length > 1) {
|
|
48898
|
+
warnings.push(`Multiple FILE: directives detected (${fileMatches.length}). Each coder task should target ONE file.`);
|
|
48899
|
+
}
|
|
48882
48900
|
}
|
|
48883
|
-
|
|
48884
|
-
|
|
48885
|
-
|
|
48901
|
+
if (isCoderDelegation) {
|
|
48902
|
+
const taskMatches = text.match(/^TASK:/gm);
|
|
48903
|
+
if (taskMatches && taskMatches.length > 1) {
|
|
48904
|
+
warnings.push(`Multiple TASK: sections detected (${taskMatches.length}). Send ONE task per coder call.`);
|
|
48905
|
+
}
|
|
48886
48906
|
}
|
|
48887
|
-
|
|
48888
|
-
|
|
48889
|
-
|
|
48890
|
-
|
|
48907
|
+
if (isCoderDelegation) {
|
|
48908
|
+
const batchingPattern = /\b(?:and also|then also|additionally|as well as|along with|while you'?re at it)[.,]?\b/gi;
|
|
48909
|
+
const batchingMatches = text.match(batchingPattern);
|
|
48910
|
+
if (batchingMatches && batchingMatches.length > 0) {
|
|
48911
|
+
warnings.push(`Batching language detected (${batchingMatches.join(", ")}). Break compound objectives into separate coder calls.`);
|
|
48912
|
+
}
|
|
48891
48913
|
}
|
|
48892
|
-
|
|
48893
|
-
|
|
48894
|
-
|
|
48895
|
-
|
|
48896
|
-
|
|
48914
|
+
if (isCoderDelegation) {
|
|
48915
|
+
const taskLine = extractTaskLine(text);
|
|
48916
|
+
if (taskLine) {
|
|
48917
|
+
const andPattern = /\s+and\s+(update|add|remove|modify|refactor|implement|create|delete|fix|change|build|deploy|write|test|move|rename|extend|extract|convert|migrate|upgrade|replace)\b/i;
|
|
48918
|
+
if (andPattern.test(taskLine)) {
|
|
48919
|
+
warnings.push('TASK line contains "and" connecting separate actions');
|
|
48920
|
+
}
|
|
48897
48921
|
}
|
|
48898
48922
|
}
|
|
48899
|
-
if (sessionID) {
|
|
48923
|
+
if (isCoderDelegation && sessionID) {
|
|
48900
48924
|
const delegationChain = swarmState.delegationChains.get(sessionID);
|
|
48901
48925
|
if (delegationChain && delegationChain.length >= 2) {
|
|
48902
48926
|
const coderIndices = [];
|
|
@@ -49143,7 +49167,7 @@ function consolidateSystemMessages(messages) {
|
|
|
49143
49167
|
init_schema();
|
|
49144
49168
|
init_manager2();
|
|
49145
49169
|
init_utils2();
|
|
49146
|
-
function createPhaseMonitorHook(directory, preflightManager) {
|
|
49170
|
+
function createPhaseMonitorHook(directory, preflightManager, curatorRunner = runCuratorInit) {
|
|
49147
49171
|
let lastKnownPhase = null;
|
|
49148
49172
|
const handler = async (_input, _output) => {
|
|
49149
49173
|
const plan = await loadPlan(directory);
|
|
@@ -49157,7 +49181,7 @@ function createPhaseMonitorHook(directory, preflightManager) {
|
|
|
49157
49181
|
const { config: config3 } = loadPluginConfigWithMeta2(directory);
|
|
49158
49182
|
const curatorConfig = CuratorConfigSchema.parse(config3.curator ?? {});
|
|
49159
49183
|
if (curatorConfig.enabled && curatorConfig.init_enabled) {
|
|
49160
|
-
await
|
|
49184
|
+
await curatorRunner(directory, curatorConfig);
|
|
49161
49185
|
}
|
|
49162
49186
|
} catch {}
|
|
49163
49187
|
return;
|
|
@@ -54467,6 +54491,11 @@ import * as fs25 from "fs";
|
|
|
54467
54491
|
import * as path37 from "path";
|
|
54468
54492
|
init_utils2();
|
|
54469
54493
|
init_create_tool();
|
|
54494
|
+
function safeWarn(message, error93) {
|
|
54495
|
+
try {
|
|
54496
|
+
console.warn(message, error93);
|
|
54497
|
+
} catch {}
|
|
54498
|
+
}
|
|
54470
54499
|
function collectCrossSessionDispatchedAgents(phaseReferenceTimestamp, callerSessionId) {
|
|
54471
54500
|
const agents = new Set;
|
|
54472
54501
|
const contributorSessionIds = [];
|
|
@@ -54478,11 +54507,6 @@ function collectCrossSessionDispatchedAgents(phaseReferenceTimestamp, callerSess
|
|
|
54478
54507
|
agents.add(agent);
|
|
54479
54508
|
}
|
|
54480
54509
|
}
|
|
54481
|
-
if (callerSession.lastCompletedPhaseAgentsDispatched) {
|
|
54482
|
-
for (const agent of callerSession.lastCompletedPhaseAgentsDispatched) {
|
|
54483
|
-
agents.add(agent);
|
|
54484
|
-
}
|
|
54485
|
-
}
|
|
54486
54510
|
const callerDelegations = swarmState.delegationChains.get(callerSessionId);
|
|
54487
54511
|
if (callerDelegations) {
|
|
54488
54512
|
for (const delegation of callerDelegations) {
|
|
@@ -54507,11 +54531,6 @@ function collectCrossSessionDispatchedAgents(phaseReferenceTimestamp, callerSess
|
|
|
54507
54531
|
agents.add(agent);
|
|
54508
54532
|
}
|
|
54509
54533
|
}
|
|
54510
|
-
if (session.lastCompletedPhaseAgentsDispatched) {
|
|
54511
|
-
for (const agent of session.lastCompletedPhaseAgentsDispatched) {
|
|
54512
|
-
agents.add(agent);
|
|
54513
|
-
}
|
|
54514
|
-
}
|
|
54515
54534
|
const delegations2 = swarmState.delegationChains.get(sessionId);
|
|
54516
54535
|
if (delegations2) {
|
|
54517
54536
|
for (const delegation of delegations2) {
|
|
@@ -54690,7 +54709,7 @@ async function executePhaseComplete(args2, workingDirectory) {
|
|
|
54690
54709
|
};
|
|
54691
54710
|
await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
|
|
54692
54711
|
} catch (error93) {
|
|
54693
|
-
|
|
54712
|
+
safeWarn("[phase_complete] Failed to curate lessons from retrospective:", error93);
|
|
54694
54713
|
}
|
|
54695
54714
|
}
|
|
54696
54715
|
try {
|
|
@@ -54701,7 +54720,7 @@ async function executePhaseComplete(args2, workingDirectory) {
|
|
|
54701
54720
|
await runCriticDriftCheck(dir, phase, curatorResult, curatorConfig);
|
|
54702
54721
|
}
|
|
54703
54722
|
} catch (curatorError) {
|
|
54704
|
-
|
|
54723
|
+
safeWarn("[phase_complete] Curator pipeline error (non-blocking):", curatorError);
|
|
54705
54724
|
}
|
|
54706
54725
|
const effectiveRequired = [...phaseCompleteConfig.required_agents];
|
|
54707
54726
|
if (phaseCompleteConfig.require_docs && !effectiveRequired.includes("docs")) {
|
|
@@ -54723,7 +54742,7 @@ async function executePhaseComplete(args2, workingDirectory) {
|
|
|
54723
54742
|
}
|
|
54724
54743
|
const VALID_TASK_COMPLEXITY = ["trivial", "simple", "moderate", "complex"];
|
|
54725
54744
|
const firstEntry = loadedRetroBundle?.entries?.[0];
|
|
54726
|
-
if (loadedRetroTaskId?.startsWith("retro-") && loadedRetroBundle?.schema_version === "1.0.0" && firstEntry?.task_complexity && VALID_TASK_COMPLEXITY.includes(firstEntry.task_complexity)) {
|
|
54745
|
+
if (loadedRetroTaskId !== primaryRetroTaskId && loadedRetroTaskId?.startsWith("retro-") && loadedRetroBundle?.schema_version === "1.0.0" && firstEntry?.task_complexity && VALID_TASK_COMPLEXITY.includes(firstEntry.task_complexity)) {
|
|
54727
54746
|
warnings.push(`Retrospective data for phase ${phase} may have been automatically migrated to current schema format.`);
|
|
54728
54747
|
}
|
|
54729
54748
|
let success3 = true;
|
|
@@ -60821,14 +60840,24 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
60821
60840
|
if (swarmState.agentSessions.size === 0) {
|
|
60822
60841
|
return { blocked: false, reason: "" };
|
|
60823
60842
|
}
|
|
60843
|
+
let validSessionCount = 0;
|
|
60824
60844
|
for (const [_sessionId, session] of swarmState.agentSessions) {
|
|
60845
|
+
if (!(session.taskWorkflowStates instanceof Map)) {
|
|
60846
|
+
continue;
|
|
60847
|
+
}
|
|
60848
|
+
validSessionCount++;
|
|
60825
60849
|
const state = getTaskState(session, taskId);
|
|
60826
60850
|
if (state === "tests_run" || state === "complete") {
|
|
60827
60851
|
return { blocked: false, reason: "" };
|
|
60828
60852
|
}
|
|
60829
60853
|
}
|
|
60854
|
+
if (validSessionCount === 0) {
|
|
60855
|
+
return { blocked: false, reason: "" };
|
|
60856
|
+
}
|
|
60830
60857
|
const stateEntries = [];
|
|
60831
60858
|
for (const [sessionId, session] of swarmState.agentSessions) {
|
|
60859
|
+
if (!(session.taskWorkflowStates instanceof Map))
|
|
60860
|
+
continue;
|
|
60832
60861
|
const state = getTaskState(session, taskId);
|
|
60833
60862
|
stateEntries.push(`${sessionId}: ${state}`);
|
|
60834
60863
|
}
|
package/dist/state.d.ts
CHANGED
|
@@ -250,6 +250,7 @@ export declare function advanceTaskState(session: AgentSessionState, taskId: str
|
|
|
250
250
|
/**
|
|
251
251
|
* Get the current workflow state for a task.
|
|
252
252
|
* Returns 'idle' if no entry exists.
|
|
253
|
+
* If taskWorkflowStates is missing/invalid, initializes it as a new Map.
|
|
253
254
|
*
|
|
254
255
|
* @param session - The agent session state
|
|
255
256
|
* @param taskId - The task identifier
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "6.22.
|
|
3
|
+
"version": "6.22.13",
|
|
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",
|