opencode-swarm 7.3.0 → 7.3.2
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 +3 -1
- package/dist/hooks/agent-activity.d.ts +5 -3
- package/dist/hooks/agent-activity.test.d.ts +1 -0
- package/dist/index.js +904 -697
- package/dist/state.d.ts +8 -2
- package/dist/state.telemetry.test.d.ts +1 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/submit-phase-council-verdicts.d.ts +39 -0
- package/dist/tools/tool-names.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -33,7 +33,7 @@ var package_default;
|
|
|
33
33
|
var init_package = __esm(() => {
|
|
34
34
|
package_default = {
|
|
35
35
|
name: "opencode-swarm",
|
|
36
|
-
version: "7.3.
|
|
36
|
+
version: "7.3.2",
|
|
37
37
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
38
38
|
main: "dist/index.js",
|
|
39
39
|
types: "dist/index.d.ts",
|
|
@@ -125,6 +125,7 @@ var init_tool_names = __esm(() => {
|
|
|
125
125
|
"check_gate_status",
|
|
126
126
|
"completion_verify",
|
|
127
127
|
"submit_council_verdicts",
|
|
128
|
+
"submit_phase_council_verdicts",
|
|
128
129
|
"declare_council_criteria",
|
|
129
130
|
"sbom_generate",
|
|
130
131
|
"checkpoint",
|
|
@@ -272,6 +273,7 @@ var init_constants = __esm(() => {
|
|
|
272
273
|
"completion_verify",
|
|
273
274
|
"complexity_hotspots",
|
|
274
275
|
"submit_council_verdicts",
|
|
276
|
+
"submit_phase_council_verdicts",
|
|
275
277
|
"declare_council_criteria",
|
|
276
278
|
"detect_domains",
|
|
277
279
|
"evidence_check",
|
|
@@ -531,6 +533,7 @@ var init_constants = __esm(() => {
|
|
|
531
533
|
check_gate_status: "check the gate status of a specific task",
|
|
532
534
|
completion_verify: "verify completed tasks have required evidence",
|
|
533
535
|
submit_council_verdicts: "submit pre-collected council member verdicts for synthesis (architect MUST dispatch critic/reviewer/sme/test_engineer/explorer as Agent tasks first; this tool synthesizes only, it does not contact members)",
|
|
536
|
+
submit_phase_council_verdicts: "submit pre-collected phase-level council member verdicts for holistic phase synthesis (architect MUST dispatch all 5 council members with phase-scoped context first; this tool synthesizes only, it does not contact members)",
|
|
534
537
|
declare_council_criteria: "pre-declare acceptance criteria for a task before the coder starts work; criteria are read back during council evaluation",
|
|
535
538
|
detect_domains: "detect which SME domains are relevant for a given text",
|
|
536
539
|
extract_code_blocks: "extract code blocks from text content and save them to files",
|
|
@@ -25579,7 +25582,7 @@ function createDelegationGateHook(config2, directory) {
|
|
|
25579
25582
|
});
|
|
25580
25583
|
if (councilActive && result.overallVerdict === "APPROVE" && result.allCriteriaMet === true && (result.requiredFixesCount ?? 0) === 0) {
|
|
25581
25584
|
try {
|
|
25582
|
-
await advanceTaskStateAndPersist(session, taskId, "complete", directory, config2.council);
|
|
25585
|
+
await advanceTaskStateAndPersist(session, taskId, "complete", directory, { telemetrySessionId: input.sessionID }, config2.council);
|
|
25583
25586
|
} catch (err2) {
|
|
25584
25587
|
warn(`[delegation-gate] toolAfter submit_council_verdicts: could not advance ${taskId} → complete: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25585
25588
|
}
|
|
@@ -25603,122 +25606,128 @@ function createDelegationGateHook(config2, directory) {
|
|
|
25603
25606
|
hasReviewer = true;
|
|
25604
25607
|
if (targetAgent === "test_engineer")
|
|
25605
25608
|
hasTestEngineer = true;
|
|
25606
|
-
|
|
25607
|
-
|
|
25608
|
-
if (
|
|
25609
|
-
|
|
25610
|
-
|
|
25611
|
-
|
|
25612
|
-
|
|
25613
|
-
|
|
25614
|
-
|
|
25615
|
-
|
|
25616
|
-
|
|
25617
|
-
|
|
25618
|
-
|
|
25619
|
-
|
|
25620
|
-
|
|
25621
|
-
|
|
25622
|
-
|
|
25623
|
-
|
|
25624
|
-
}
|
|
25625
|
-
advanceTaskState(session, taskId, "tests_run");
|
|
25626
|
-
} catch (err2) {
|
|
25627
|
-
warn(`[delegation-gate] toolAfter stage-b-parallel: could not advance ${taskId} (${eligibleState}) → tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25609
|
+
const stageBParallelEnabled = config2.parallelization?.stageB?.parallel?.enabled === true;
|
|
25610
|
+
if (stageBParallelEnabled) {
|
|
25611
|
+
if ((targetAgent === "reviewer" || targetAgent === "test_engineer") && session.taskWorkflowStates) {
|
|
25612
|
+
const stageBEligibleStates = [
|
|
25613
|
+
"coder_delegated",
|
|
25614
|
+
"pre_check_passed",
|
|
25615
|
+
"reviewer_run"
|
|
25616
|
+
];
|
|
25617
|
+
for (const [taskId, state] of session.taskWorkflowStates) {
|
|
25618
|
+
if (!stageBEligibleStates.includes(state))
|
|
25619
|
+
continue;
|
|
25620
|
+
const eligibleState = state;
|
|
25621
|
+
recordStageBCompletion(session, taskId, targetAgent);
|
|
25622
|
+
if (hasBothStageBCompletions(session, taskId)) {
|
|
25623
|
+
try {
|
|
25624
|
+
if (eligibleState === "coder_delegated" || eligibleState === "pre_check_passed") {
|
|
25625
|
+
advanceTaskState(session, taskId, "reviewer_run", {
|
|
25626
|
+
telemetrySessionId: input.sessionID
|
|
25627
|
+
});
|
|
25628
25628
|
}
|
|
25629
|
+
advanceTaskState(session, taskId, "tests_run", {
|
|
25630
|
+
telemetrySessionId: input.sessionID
|
|
25631
|
+
});
|
|
25632
|
+
} catch (err2) {
|
|
25633
|
+
warn(`[delegation-gate] toolAfter stage-b-parallel: could not advance ${taskId} (${eligibleState}) → tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25629
25634
|
}
|
|
25630
25635
|
}
|
|
25631
|
-
|
|
25632
|
-
|
|
25633
|
-
|
|
25634
|
-
|
|
25635
|
-
|
|
25636
|
-
|
|
25637
|
-
|
|
25638
|
-
|
|
25639
|
-
|
|
25640
|
-
|
|
25641
|
-
|
|
25642
|
-
|
|
25643
|
-
|
|
25644
|
-
|
|
25645
|
-
|
|
25646
|
-
|
|
25647
|
-
|
|
25648
|
-
|
|
25649
|
-
|
|
25650
|
-
|
|
25651
|
-
}
|
|
25652
|
-
advanceTaskState(otherSession, seedTaskId, "tests_run");
|
|
25653
|
-
} catch (err2) {
|
|
25654
|
-
warn(`[delegation-gate] toolAfter cross-session stage-b-parallel: could not advance ${seedTaskId} (${seedEligibleState}) → tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25636
|
+
}
|
|
25637
|
+
const seedTaskId = getSeedTaskId(session);
|
|
25638
|
+
if (seedTaskId) {
|
|
25639
|
+
for (const [, otherSession] of swarmState.agentSessions) {
|
|
25640
|
+
if (otherSession === session)
|
|
25641
|
+
continue;
|
|
25642
|
+
if (!otherSession.taskWorkflowStates)
|
|
25643
|
+
continue;
|
|
25644
|
+
if (!otherSession.taskWorkflowStates.has(seedTaskId)) {
|
|
25645
|
+
otherSession.taskWorkflowStates.set(seedTaskId, "coder_delegated");
|
|
25646
|
+
}
|
|
25647
|
+
const seedState = otherSession.taskWorkflowStates.get(seedTaskId);
|
|
25648
|
+
if (!seedState || !stageBEligibleStates.includes(seedState)) {
|
|
25649
|
+
continue;
|
|
25650
|
+
}
|
|
25651
|
+
const seedEligibleState = seedState;
|
|
25652
|
+
recordStageBCompletion(otherSession, seedTaskId, targetAgent);
|
|
25653
|
+
if (hasBothStageBCompletions(otherSession, seedTaskId)) {
|
|
25654
|
+
try {
|
|
25655
|
+
if (seedEligibleState === "coder_delegated" || seedEligibleState === "pre_check_passed") {
|
|
25656
|
+
advanceTaskState(otherSession, seedTaskId, "reviewer_run", { emitTelemetry: false });
|
|
25655
25657
|
}
|
|
25658
|
+
advanceTaskState(otherSession, seedTaskId, "tests_run", {
|
|
25659
|
+
emitTelemetry: false
|
|
25660
|
+
});
|
|
25661
|
+
} catch (err2) {
|
|
25662
|
+
warn(`[delegation-gate] toolAfter cross-session stage-b-parallel: could not advance ${seedTaskId} (${seedEligibleState}) → tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25656
25663
|
}
|
|
25657
25664
|
}
|
|
25658
25665
|
}
|
|
25659
25666
|
}
|
|
25660
|
-
}
|
|
25661
|
-
|
|
25662
|
-
|
|
25663
|
-
|
|
25664
|
-
|
|
25665
|
-
|
|
25666
|
-
|
|
25667
|
-
|
|
25668
|
-
}
|
|
25667
|
+
}
|
|
25668
|
+
} else {
|
|
25669
|
+
if (targetAgent === "reviewer" && session.taskWorkflowStates) {
|
|
25670
|
+
for (const [taskId, state] of session.taskWorkflowStates) {
|
|
25671
|
+
if (state === "coder_delegated" || state === "pre_check_passed") {
|
|
25672
|
+
try {
|
|
25673
|
+
advanceTaskState(session, taskId, "reviewer_run", {
|
|
25674
|
+
telemetrySessionId: input.sessionID
|
|
25675
|
+
});
|
|
25676
|
+
} catch (err2) {
|
|
25677
|
+
warn(`[delegation-gate] toolAfter: could not advance ${taskId} (${state}) → reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25669
25678
|
}
|
|
25670
25679
|
}
|
|
25671
25680
|
}
|
|
25672
|
-
|
|
25673
|
-
|
|
25674
|
-
|
|
25675
|
-
|
|
25676
|
-
|
|
25677
|
-
|
|
25678
|
-
|
|
25679
|
-
}
|
|
25681
|
+
}
|
|
25682
|
+
if (targetAgent === "test_engineer" && session.taskWorkflowStates) {
|
|
25683
|
+
for (const [taskId, state] of session.taskWorkflowStates) {
|
|
25684
|
+
if (state === "reviewer_run") {
|
|
25685
|
+
try {
|
|
25686
|
+
advanceTaskState(session, taskId, "tests_run", {
|
|
25687
|
+
telemetrySessionId: input.sessionID
|
|
25688
|
+
});
|
|
25689
|
+
} catch (err2) {
|
|
25690
|
+
warn(`[delegation-gate] toolAfter: could not advance ${taskId} (${state}) → tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25680
25691
|
}
|
|
25681
25692
|
}
|
|
25682
25693
|
}
|
|
25683
|
-
|
|
25684
|
-
|
|
25685
|
-
|
|
25686
|
-
|
|
25687
|
-
|
|
25688
|
-
|
|
25689
|
-
|
|
25690
|
-
|
|
25691
|
-
|
|
25692
|
-
|
|
25693
|
-
|
|
25694
|
-
|
|
25695
|
-
|
|
25696
|
-
|
|
25697
|
-
|
|
25698
|
-
|
|
25699
|
-
|
|
25700
|
-
|
|
25701
|
-
|
|
25702
|
-
|
|
25703
|
-
}
|
|
25694
|
+
}
|
|
25695
|
+
if (targetAgent === "reviewer" || targetAgent === "test_engineer") {
|
|
25696
|
+
for (const [, otherSession] of swarmState.agentSessions) {
|
|
25697
|
+
if (otherSession === session)
|
|
25698
|
+
continue;
|
|
25699
|
+
if (!otherSession.taskWorkflowStates)
|
|
25700
|
+
continue;
|
|
25701
|
+
if (targetAgent === "reviewer") {
|
|
25702
|
+
const seedTaskId = getSeedTaskId(session);
|
|
25703
|
+
if (seedTaskId && !otherSession.taskWorkflowStates.has(seedTaskId)) {
|
|
25704
|
+
otherSession.taskWorkflowStates.set(seedTaskId, "coder_delegated");
|
|
25705
|
+
}
|
|
25706
|
+
for (const [taskId, state] of otherSession.taskWorkflowStates) {
|
|
25707
|
+
if (state === "coder_delegated" || state === "pre_check_passed") {
|
|
25708
|
+
try {
|
|
25709
|
+
advanceTaskState(otherSession, taskId, "reviewer_run", {
|
|
25710
|
+
emitTelemetry: false
|
|
25711
|
+
});
|
|
25712
|
+
} catch (err2) {
|
|
25713
|
+
warn(`[delegation-gate] toolAfter cross-session: could not advance ${taskId} (${state}) → reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25704
25714
|
}
|
|
25705
25715
|
}
|
|
25706
25716
|
}
|
|
25707
|
-
|
|
25708
|
-
|
|
25709
|
-
|
|
25710
|
-
|
|
25711
|
-
|
|
25712
|
-
|
|
25713
|
-
|
|
25714
|
-
|
|
25715
|
-
|
|
25716
|
-
|
|
25717
|
-
|
|
25718
|
-
|
|
25719
|
-
|
|
25720
|
-
|
|
25721
|
-
}
|
|
25717
|
+
}
|
|
25718
|
+
if (targetAgent === "test_engineer") {
|
|
25719
|
+
const seedTaskId = getSeedTaskId(session);
|
|
25720
|
+
if (seedTaskId && !otherSession.taskWorkflowStates.has(seedTaskId)) {
|
|
25721
|
+
otherSession.taskWorkflowStates.set(seedTaskId, "reviewer_run");
|
|
25722
|
+
}
|
|
25723
|
+
for (const [taskId, state] of otherSession.taskWorkflowStates) {
|
|
25724
|
+
if (state === "reviewer_run") {
|
|
25725
|
+
try {
|
|
25726
|
+
advanceTaskState(otherSession, taskId, "tests_run", {
|
|
25727
|
+
emitTelemetry: false
|
|
25728
|
+
});
|
|
25729
|
+
} catch (err2) {
|
|
25730
|
+
warn(`[delegation-gate] toolAfter cross-session: could not advance ${taskId} (${state}) → tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25722
25731
|
}
|
|
25723
25732
|
}
|
|
25724
25733
|
}
|
|
@@ -25778,71 +25787,73 @@ function createDelegationGateHook(config2, directory) {
|
|
|
25778
25787
|
if (target === "test_engineer")
|
|
25779
25788
|
hasTestEngineer = true;
|
|
25780
25789
|
}
|
|
25781
|
-
if (
|
|
25782
|
-
|
|
25783
|
-
|
|
25784
|
-
|
|
25790
|
+
if (lastCoderIndex !== -1 && hasReviewer && hasTestEngineer) {
|
|
25791
|
+
session.qaSkipCount = 0;
|
|
25792
|
+
session.qaSkipTaskIds = [];
|
|
25793
|
+
}
|
|
25794
|
+
if (lastCoderIndex !== -1 && hasReviewer && session.taskWorkflowStates) {
|
|
25795
|
+
for (const [taskId, state] of session.taskWorkflowStates) {
|
|
25796
|
+
if (state === "coder_delegated" || state === "pre_check_passed") {
|
|
25797
|
+
try {
|
|
25798
|
+
advanceTaskState(session, taskId, "reviewer_run");
|
|
25799
|
+
} catch (err2) {
|
|
25800
|
+
warn(`[delegation-gate] fallback: could not advance ${taskId} (${state}) → reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25801
|
+
}
|
|
25802
|
+
}
|
|
25785
25803
|
}
|
|
25786
|
-
|
|
25787
|
-
|
|
25788
|
-
|
|
25789
|
-
|
|
25790
|
-
|
|
25791
|
-
|
|
25792
|
-
|
|
25793
|
-
}
|
|
25804
|
+
}
|
|
25805
|
+
if (lastCoderIndex !== -1 && hasReviewer && hasTestEngineer && session.taskWorkflowStates) {
|
|
25806
|
+
for (const [taskId, state] of session.taskWorkflowStates) {
|
|
25807
|
+
if (state === "reviewer_run") {
|
|
25808
|
+
try {
|
|
25809
|
+
advanceTaskState(session, taskId, "tests_run");
|
|
25810
|
+
} catch (err2) {
|
|
25811
|
+
warn(`[delegation-gate] fallback: could not advance ${taskId} (${state}) → tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25794
25812
|
}
|
|
25795
25813
|
}
|
|
25796
25814
|
}
|
|
25797
|
-
|
|
25798
|
-
|
|
25799
|
-
|
|
25815
|
+
}
|
|
25816
|
+
if (lastCoderIndex !== -1 && hasReviewer) {
|
|
25817
|
+
for (const [, otherSession] of swarmState.agentSessions) {
|
|
25818
|
+
if (otherSession === session)
|
|
25819
|
+
continue;
|
|
25820
|
+
if (!otherSession.taskWorkflowStates)
|
|
25821
|
+
continue;
|
|
25822
|
+
const seedTaskId = getSeedTaskId(session);
|
|
25823
|
+
if (seedTaskId && !otherSession.taskWorkflowStates.has(seedTaskId)) {
|
|
25824
|
+
otherSession.taskWorkflowStates.set(seedTaskId, "coder_delegated");
|
|
25825
|
+
}
|
|
25826
|
+
for (const [taskId, state] of otherSession.taskWorkflowStates) {
|
|
25827
|
+
if (state === "coder_delegated" || state === "pre_check_passed") {
|
|
25800
25828
|
try {
|
|
25801
|
-
advanceTaskState(
|
|
25829
|
+
advanceTaskState(otherSession, taskId, "reviewer_run", {
|
|
25830
|
+
emitTelemetry: false
|
|
25831
|
+
});
|
|
25802
25832
|
} catch (err2) {
|
|
25803
|
-
warn(`[delegation-gate] fallback: could not advance ${taskId} (${state}) →
|
|
25833
|
+
warn(`[delegation-gate] fallback cross-session: could not advance ${taskId} (${state}) → reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25804
25834
|
}
|
|
25805
25835
|
}
|
|
25806
25836
|
}
|
|
25807
25837
|
}
|
|
25808
|
-
|
|
25809
|
-
|
|
25810
|
-
|
|
25811
|
-
|
|
25812
|
-
|
|
25813
|
-
|
|
25814
|
-
|
|
25815
|
-
|
|
25816
|
-
|
|
25817
|
-
|
|
25818
|
-
for (const [taskId, state] of otherSession.taskWorkflowStates) {
|
|
25819
|
-
if (state === "coder_delegated" || state === "pre_check_passed") {
|
|
25820
|
-
try {
|
|
25821
|
-
advanceTaskState(otherSession, taskId, "reviewer_run");
|
|
25822
|
-
} catch (err2) {
|
|
25823
|
-
warn(`[delegation-gate] fallback cross-session: could not advance ${taskId} (${state}) → reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25824
|
-
}
|
|
25825
|
-
}
|
|
25826
|
-
}
|
|
25838
|
+
}
|
|
25839
|
+
if (lastCoderIndex !== -1 && hasReviewer && hasTestEngineer) {
|
|
25840
|
+
for (const [, otherSession] of swarmState.agentSessions) {
|
|
25841
|
+
if (otherSession === session)
|
|
25842
|
+
continue;
|
|
25843
|
+
if (!otherSession.taskWorkflowStates)
|
|
25844
|
+
continue;
|
|
25845
|
+
const seedTaskId = getSeedTaskId(session);
|
|
25846
|
+
if (seedTaskId && !otherSession.taskWorkflowStates.has(seedTaskId)) {
|
|
25847
|
+
otherSession.taskWorkflowStates.set(seedTaskId, "reviewer_run");
|
|
25827
25848
|
}
|
|
25828
|
-
|
|
25829
|
-
|
|
25830
|
-
|
|
25831
|
-
|
|
25832
|
-
|
|
25833
|
-
|
|
25834
|
-
|
|
25835
|
-
|
|
25836
|
-
if (seedTaskId && !otherSession.taskWorkflowStates.has(seedTaskId)) {
|
|
25837
|
-
otherSession.taskWorkflowStates.set(seedTaskId, "reviewer_run");
|
|
25838
|
-
}
|
|
25839
|
-
for (const [taskId, state] of otherSession.taskWorkflowStates) {
|
|
25840
|
-
if (state === "reviewer_run") {
|
|
25841
|
-
try {
|
|
25842
|
-
advanceTaskState(otherSession, taskId, "tests_run");
|
|
25843
|
-
} catch (err2) {
|
|
25844
|
-
warn(`[delegation-gate] fallback cross-session: could not advance ${taskId} (${state}) → tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25845
|
-
}
|
|
25849
|
+
for (const [taskId, state] of otherSession.taskWorkflowStates) {
|
|
25850
|
+
if (state === "reviewer_run") {
|
|
25851
|
+
try {
|
|
25852
|
+
advanceTaskState(otherSession, taskId, "tests_run", {
|
|
25853
|
+
emitTelemetry: false
|
|
25854
|
+
});
|
|
25855
|
+
} catch (err2) {
|
|
25856
|
+
warn(`[delegation-gate] fallback cross-session: could not advance ${taskId} (${state}) → tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25846
25857
|
}
|
|
25847
25858
|
}
|
|
25848
25859
|
}
|
|
@@ -25966,7 +25977,7 @@ ${trimComment}${after}`;
|
|
|
25966
25977
|
pendingCoderScopeByTaskId.delete(currentTaskId);
|
|
25967
25978
|
}
|
|
25968
25979
|
try {
|
|
25969
|
-
await advanceTaskStateAndPersist(session, currentTaskId, "coder_delegated", directory);
|
|
25980
|
+
await advanceTaskStateAndPersist(session, currentTaskId, "coder_delegated", directory, { telemetrySessionId: sessionID });
|
|
25970
25981
|
} catch (err2) {
|
|
25971
25982
|
warn(`[delegation-gate] state machine warn: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25972
25983
|
}
|
|
@@ -26492,7 +26503,7 @@ function isValidTaskId2(taskId) {
|
|
|
26492
26503
|
const trimmed = taskId.trim();
|
|
26493
26504
|
return trimmed.length > 0;
|
|
26494
26505
|
}
|
|
26495
|
-
function advanceTaskState(session, taskId, newState, councilConfig) {
|
|
26506
|
+
function advanceTaskState(session, taskId, newState, options, councilConfig) {
|
|
26496
26507
|
if (!isValidTaskId2(taskId)) {
|
|
26497
26508
|
return;
|
|
26498
26509
|
}
|
|
@@ -26523,10 +26534,12 @@ function advanceTaskState(session, taskId, newState, councilConfig) {
|
|
|
26523
26534
|
}
|
|
26524
26535
|
}
|
|
26525
26536
|
session.taskWorkflowStates.set(taskId, newState);
|
|
26526
|
-
|
|
26537
|
+
if (options?.emitTelemetry !== false) {
|
|
26538
|
+
telemetry.taskStateChanged(options?.telemetrySessionId ?? session.agentName, taskId, newState, current);
|
|
26539
|
+
}
|
|
26527
26540
|
}
|
|
26528
|
-
async function advanceTaskStateAndPersist(session, taskId, newState, directory, councilConfig) {
|
|
26529
|
-
advanceTaskState(session, taskId, newState, councilConfig);
|
|
26541
|
+
async function advanceTaskStateAndPersist(session, taskId, newState, directory, options, councilConfig) {
|
|
26542
|
+
advanceTaskState(session, taskId, newState, options, councilConfig);
|
|
26530
26543
|
if (newState !== "coder_delegated" && newState !== "complete") {
|
|
26531
26544
|
return;
|
|
26532
26545
|
}
|
|
@@ -56133,106 +56146,101 @@ ${validation.warnings.join(`
|
|
|
56133
56146
|
function buildCouncilWorkflow(council) {
|
|
56134
56147
|
if (council?.enabled !== true)
|
|
56135
56148
|
return "";
|
|
56136
|
-
return `## COUNCIL WORKFLOW (
|
|
56149
|
+
return `## COUNCIL WORKFLOW (submit_phase_council_verdicts)
|
|
56137
56150
|
|
|
56138
|
-
CRITICAL: \`
|
|
56151
|
+
CRITICAL: \`submit_phase_council_verdicts\` does NOT run council members.
|
|
56139
56152
|
It synthesizes verdicts that you must collect BEFORE calling it.
|
|
56140
56153
|
|
|
56141
|
-
When \`council.enabled\` is true
|
|
56142
|
-
|
|
56143
|
-
(reviewer + test_engineer
|
|
56144
|
-
|
|
56154
|
+
When \`council.enabled\` is true and \`council_mode\` is enabled in the QA gate
|
|
56155
|
+
profile, a phase-level council review is required before calling \`phase_complete\`.
|
|
56156
|
+
Stage B (reviewer + test_engineer) ALWAYS runs per-task as normal.
|
|
56157
|
+
Stage B always runs per-task — council is an ADDITIONAL verification layer at PHASE LEVEL, never a replacement for Stage B.
|
|
56145
56158
|
|
|
56146
|
-
###
|
|
56147
|
-
|
|
56148
|
-
|
|
56149
|
-
|
|
56150
|
-
|
|
56151
|
-
|
|
56159
|
+
### WHEN TO RUN COUNCIL
|
|
56160
|
+
After ALL tasks in the current phase have been marked \`completed\` and their
|
|
56161
|
+
Stage B gates have passed, and BEFORE calling \`phase_complete\`, convene the
|
|
56162
|
+
phase council for a Phase Dossier Assembly — a holistic review of cross-cutting concerns,
|
|
56163
|
+
behavioral cohesion, and the full body of work completed in the phase.
|
|
56164
|
+
|
|
56165
|
+
## PHASE COUNCIL
|
|
56152
56166
|
|
|
56153
56167
|
### MANDATORY SEQUENCE — never skip or reorder
|
|
56154
56168
|
|
|
56155
|
-
#### STEP 1 — DISPATCH all council members
|
|
56156
|
-
|
|
56157
|
-
|
|
56158
|
-
|
|
56159
|
-
|
|
56160
|
-
- \`
|
|
56161
|
-
- \`
|
|
56162
|
-
- \`
|
|
56163
|
-
|
|
56164
|
-
|
|
56165
|
-
|
|
56166
|
-
|
|
56167
|
-
|
|
56168
|
-
Wait for ALL dispatched agents to return their verdict objects.
|
|
56169
|
+
#### STEP 1 — DISPATCH all 5 council members in parallel (phase-scoped)
|
|
56170
|
+
In a SINGLE message, dispatch \`critic\`, \`reviewer\`, \`sme\`, \`test_engineer\`,
|
|
56171
|
+
and \`explorer\` as parallel Agent tasks. Each member receives phase-scoped context:
|
|
56172
|
+
- \`critic\` — full diff for the phase + all task specs + approved-plan baseline (via \`get_approved_plan\`) + spec-intent drift analysis
|
|
56173
|
+
- \`reviewer\` — phase-wide semantic diff summary + blast radius across all changed files
|
|
56174
|
+
- \`sme\` — phase domain context + knowledge base entries relevant to the phase
|
|
56175
|
+
- \`test_engineer\` — all changed test files for the phase + coverage delta + known mutation gaps
|
|
56176
|
+
- \`explorer\` — full phase diff + original task intents + prior slop findings across all tasks
|
|
56177
|
+
(hunts for lazy implementations, hallucinated APIs, cargo-cult patterns,
|
|
56178
|
+
spec drift, lazy abstractions introduced anywhere in the phase)
|
|
56179
|
+
|
|
56180
|
+
Wait for ALL dispatched agents to return their verdict objects before proceeding.
|
|
56169
56181
|
|
|
56170
56182
|
#### STEP 2 — COLLECT verdicts
|
|
56171
56183
|
Read each agent's response and extract their \`CouncilMemberVerdict\` object.
|
|
56172
|
-
Each member must return
|
|
56184
|
+
Each member must return: \`agent\`, \`verdict\` (APPROVE|CONCERNS|REJECT),
|
|
56173
56185
|
\`confidence\` (0.0–1.0), \`findings[]\`, \`criteriaAssessed[]\`, \`criteriaUnmet[]\`,
|
|
56174
56186
|
\`durationMs\`.
|
|
56175
56187
|
|
|
56176
56188
|
Do NOT fabricate, infer, or substitute a verdict. If an agent did not return
|
|
56177
|
-
a valid verdict, re-dispatch that agent.
|
|
56189
|
+
a valid verdict object, re-dispatch that agent.
|
|
56178
56190
|
|
|
56179
|
-
#### STEP 3 — CALL
|
|
56180
|
-
ONLY after collecting real verdicts from
|
|
56181
|
-
\`
|
|
56182
|
-
|
|
56191
|
+
#### STEP 3 — CALL submit_phase_council_verdicts
|
|
56192
|
+
ONLY after collecting real verdicts from all dispatched agents, call
|
|
56193
|
+
\`submit_phase_council_verdicts\` with:
|
|
56194
|
+
- \`phaseNumber\`: the phase number just completed (integer, e.g. \`1\`)
|
|
56195
|
+
- \`swarmId\`: the swarm identifier (e.g. \`"mega"\`)
|
|
56196
|
+
- \`phaseSummary\`: a 2–4 sentence plain-language summary of what the phase accomplished
|
|
56197
|
+
- \`verdicts\`: the array of collected \`CouncilMemberVerdict\` objects
|
|
56198
|
+
- \`roundNumber\`: 1-indexed (default 1 on first council call for this phase)
|
|
56199
|
+
|
|
56200
|
+
This writes \`.swarm/evidence/{phase}/phase-council.json\`, which Gate 5 in
|
|
56201
|
+
\`phase_complete\` will read and validate.
|
|
56183
56202
|
|
|
56184
56203
|
#### STEP 4 — READ the response
|
|
56185
|
-
Inspect \`membersAbsent
|
|
56186
|
-
|
|
56187
|
-
|
|
56188
|
-
|
|
56189
|
-
|
|
56190
|
-
|
|
56191
|
-
|
|
56192
|
-
|
|
56193
|
-
|
|
56194
|
-
|
|
56195
|
-
|
|
56196
|
-
|
|
56197
|
-
|
|
56198
|
-
|
|
56199
|
-
- **
|
|
56200
|
-
|
|
56201
|
-
|
|
56202
|
-
|
|
56203
|
-
|
|
56204
|
-
|
|
56205
|
-
|
|
56206
|
-
|
|
56207
|
-
-
|
|
56208
|
-
with the BLOCKING flag. The coder must resolve all
|
|
56209
|
-
\`requiredFixes\` before re-submitting. Maximum
|
|
56210
|
-
\`council.maxRounds\` rounds (default 3). If
|
|
56211
|
-
\`roundNumber >= maxRounds\` and verdict is still REJECT,
|
|
56212
|
-
surface \`unifiedFeedbackMd\` to the user and HALT — do NOT
|
|
56213
|
-
auto-advance.
|
|
56214
|
-
|
|
56215
|
-
### ANTI-PATTERNS — any of these are council bypass violations
|
|
56216
|
-
- ✗ Calling \`submit_council_verdicts\` without first dispatching council members.
|
|
56217
|
-
- ✗ Passing a verdict you inferred or fabricated rather than received from a dispatched agent.
|
|
56204
|
+
Inspect \`membersAbsent\`. If non-empty, dispatch the missing members and re-collect.
|
|
56205
|
+
Inspect \`overallVerdict\`.
|
|
56206
|
+
|
|
56207
|
+
If \`success: false\` and \`reason: 'insufficient_quorum'\`:
|
|
56208
|
+
dispatch the absent members and re-call \`submit_phase_council_verdicts\`.
|
|
56209
|
+
|
|
56210
|
+
#### STEP 5 — ACT on the verdict, then call phase_complete
|
|
56211
|
+
- **APPROVE**: Call \`phase_complete\`. Gate 5 will pass.
|
|
56212
|
+
If \`advisoryFindingsCount > 0\`, deliver \`unifiedFeedbackMd\` as a single
|
|
56213
|
+
non-blocking advisory note to the team before proceeding.
|
|
56214
|
+
- **CONCERNS**: Evaluate severity. Minor concerns → call \`phase_complete\` and
|
|
56215
|
+
surface \`unifiedFeedbackMd\` as a non-blocking note. Significant concerns →
|
|
56216
|
+
send \`unifiedFeedbackMd\` to the coder as ONE coherent document for resolution
|
|
56217
|
+
before calling \`phase_complete\`. Increment \`roundNumber\` on re-council.
|
|
56218
|
+
- **REJECT**: Block advancement. Send \`unifiedFeedbackMd\` to the coder
|
|
56219
|
+
with the BLOCKING flag. The coder must resolve all \`requiredFixes\` before
|
|
56220
|
+
the phase council is re-convened. Maximum \`council.maxRounds\` rounds (default 3).
|
|
56221
|
+
If \`roundNumber >= maxRounds\` and verdict is still REJECT, surface
|
|
56222
|
+
\`unifiedFeedbackMd\` to the user and HALT — do NOT auto-advance.
|
|
56223
|
+
|
|
56224
|
+
### ANTI-PATTERNS — phase council bypass violations
|
|
56225
|
+
- ✗ Calling \`submit_phase_council_verdicts\` without first dispatching all 5 members.
|
|
56226
|
+
- ✗ Passing verdicts inferred or fabricated rather than received from dispatched agents.
|
|
56218
56227
|
- ✗ Claiming "Council APPROVED" when \`membersAbsent\` is non-empty.
|
|
56219
|
-
- ✗
|
|
56220
|
-
- ✗
|
|
56228
|
+
- ✗ Omitting per-task review gates (reviewer + test_engineer) because council mode is on — these gates are mandatory regardless.
|
|
56229
|
+
- ✗ Calling \`phase_complete\` before council evidence has been written (Gate 5 will block you).
|
|
56230
|
+
- ✗ Treating a prior phase's council verdict as valid for a new phase.
|
|
56231
|
+
- ✗ Incrementing \`roundNumber\` without re-dispatching members for the new round.
|
|
56221
56232
|
|
|
56222
56233
|
### ROUND 2 DELIBERATION
|
|
56223
|
-
If round 1 produces REJECT or CONCERNS, dispatch only the
|
|
56224
|
-
for round 2 focused on the specific
|
|
56225
|
-
NEW agent responses —
|
|
56226
|
-
\`roundNumber\`.
|
|
56234
|
+
If round 1 produces REJECT or CONCERNS requiring re-work, dispatch only the
|
|
56235
|
+
dissenting members for round 2 focused on the specific areas they flagged.
|
|
56236
|
+
Round 2 must produce NEW agent responses — never reuse round 1 verdicts.
|
|
56227
56237
|
|
|
56228
56238
|
### Retry protocol
|
|
56229
|
-
On re-submission after REJECT
|
|
56230
|
-
|
|
56231
|
-
|
|
56232
|
-
|
|
56233
|
-
|
|
56234
|
-
sending it to the coder — the coder never sees contradictory instructions
|
|
56235
|
-
from different members.`;
|
|
56239
|
+
On re-submission after REJECT/CONCERNS: council members receive (a) the previous
|
|
56240
|
+
synthesis findings plus (b) the diff of what changed since the last round.
|
|
56241
|
+
Members verify prior findings are resolved without re-reviewing unchanged code.
|
|
56242
|
+
The architect resolves any \`unresolvedConflicts\` in \`unifiedFeedbackMd\` BEFORE
|
|
56243
|
+
sending it to the coder — the coder never sees contradictory instructions.`;
|
|
56236
56244
|
}
|
|
56237
56245
|
function buildYourToolsList(council) {
|
|
56238
56246
|
const tools = AGENT_TOOL_MAP.architect ?? [];
|
|
@@ -56240,7 +56248,7 @@ function buildYourToolsList(council) {
|
|
|
56240
56248
|
const qaCouncilEnabled = council?.enabled === true;
|
|
56241
56249
|
const generalCouncilEnabled = council?.general?.enabled === true;
|
|
56242
56250
|
const filtered = sorted.filter((t) => {
|
|
56243
|
-
if (!qaCouncilEnabled && (t === "submit_council_verdicts" || t === "declare_council_criteria")) {
|
|
56251
|
+
if (!qaCouncilEnabled && (t === "submit_council_verdicts" || t === "declare_council_criteria" || t === "submit_phase_council_verdicts")) {
|
|
56244
56252
|
return false;
|
|
56245
56253
|
}
|
|
56246
56254
|
if (!generalCouncilEnabled && t === "convene_general_council") {
|
|
@@ -56274,7 +56282,7 @@ function buildAvailableToolsList(council) {
|
|
|
56274
56282
|
const qaCouncilEnabled = council?.enabled === true;
|
|
56275
56283
|
const generalCouncilEnabled = council?.general?.enabled === true;
|
|
56276
56284
|
const filtered = sorted.filter((t) => {
|
|
56277
|
-
if (!qaCouncilEnabled && (t === "submit_council_verdicts" || t === "declare_council_criteria")) {
|
|
56285
|
+
if (!qaCouncilEnabled && (t === "submit_council_verdicts" || t === "declare_council_criteria" || t === "submit_phase_council_verdicts")) {
|
|
56278
56286
|
return false;
|
|
56279
56287
|
}
|
|
56280
56288
|
if (!generalCouncilEnabled && t === "convene_general_council") {
|
|
@@ -56660,7 +56668,7 @@ TIER 3 — CRITICAL
|
|
|
56660
56668
|
Pipeline: Full Stage A. Stage B = {{AGENT_PREFIX}}reviewer×2 + {{AGENT_PREFIX}}test_engineer×2.
|
|
56661
56669
|
Rationale: Security paths need adversarial review.
|
|
56662
56670
|
|
|
56663
|
-
|
|
56671
|
+
Council mode is additive — Stage B always runs per-task in both modes. The council runs holistically at phase end via \`submit_phase_council_verdicts\` before calling \`phase_complete\`. Council is supplemental; Stage B is mandatory in all modes.
|
|
56664
56672
|
|
|
56665
56673
|
CLASSIFICATION RULES:
|
|
56666
56674
|
- Multi-tier → use HIGHEST tier.
|
|
@@ -56687,7 +56695,7 @@ Stage B runs by default for TIER 1-3 classifications. Stage A passing does not s
|
|
|
56687
56695
|
Stage B is where logic errors, security flaws, edge cases, and behavioral bugs are caught.
|
|
56688
56696
|
You MUST delegate to each Stage B agent and wait for their response.
|
|
56689
56697
|
|
|
56690
|
-
|
|
56698
|
+
Stage B (reviewer + test_engineer) **always runs per-task** regardless of council mode — it is never replaced, never omitted, never deferred. When \`council_mode\` is enabled in the QA gate profile, a **phase-level** council review is additionally required before calling \`phase_complete\`: dispatch all 5 council members, collect their verdicts, call \`submit_phase_council_verdicts\`, then call \`phase_complete\` (Gate 5 validates the resulting \`phase-council.json\` evidence). Stage A (\`pre_check_batch\`) still runs as the pre-review gate for each task.
|
|
56691
56699
|
|
|
56692
56700
|
A task is complete ONLY when BOTH stages pass.
|
|
56693
56701
|
|
|
@@ -64980,7 +64988,7 @@ var init_curator_drift = __esm(() => {
|
|
|
64980
64988
|
// src/index.ts
|
|
64981
64989
|
init_package();
|
|
64982
64990
|
init_agents2();
|
|
64983
|
-
import * as
|
|
64991
|
+
import * as path110 from "node:path";
|
|
64984
64992
|
|
|
64985
64993
|
// src/background/index.ts
|
|
64986
64994
|
init_event_bus();
|
|
@@ -65364,8 +65372,9 @@ function createAgentActivityHooks(config3, directory) {
|
|
|
65364
65372
|
return;
|
|
65365
65373
|
swarmState.activeToolCalls.delete(input.callID);
|
|
65366
65374
|
const duration5 = Date.now() - entry.startTime;
|
|
65367
|
-
const
|
|
65368
|
-
const
|
|
65375
|
+
const explicitSuccess = typeof output.success === "boolean" ? output.success : undefined;
|
|
65376
|
+
const explicitFailure = explicitSuccess === false || !!output.error;
|
|
65377
|
+
const success3 = explicitFailure ? false : true;
|
|
65369
65378
|
const key = entry.tool;
|
|
65370
65379
|
const existing = swarmState.toolAggregates.get(key) ?? {
|
|
65371
65380
|
tool: key,
|
|
@@ -76460,6 +76469,10 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
76460
76469
|
}
|
|
76461
76470
|
}
|
|
76462
76471
|
|
|
76472
|
+
// src/council/council-service.ts
|
|
76473
|
+
import fs59 from "node:fs";
|
|
76474
|
+
import path77 from "node:path";
|
|
76475
|
+
|
|
76463
76476
|
// src/council/types.ts
|
|
76464
76477
|
var COUNCIL_DEFAULTS = {
|
|
76465
76478
|
enabled: false,
|
|
@@ -76584,6 +76597,143 @@ function buildUnifiedFeedback(taskId, verdict, vetoedBy, requiredFixes, advisory
|
|
|
76584
76597
|
return lines.join(`
|
|
76585
76598
|
`);
|
|
76586
76599
|
}
|
|
76600
|
+
function synthesizePhaseCouncilAdvisory(phaseNumber, phaseSummary, verdicts, roundNumber, config3 = {}, workingDir) {
|
|
76601
|
+
const cfg = { ...COUNCIL_DEFAULTS, ...config3 };
|
|
76602
|
+
const timestamp = new Date().toISOString();
|
|
76603
|
+
const scope = "phase";
|
|
76604
|
+
const quorumSize = new Set(verdicts.map((v) => v.agent)).size;
|
|
76605
|
+
const rejectingMembers = verdicts.filter((v) => v.verdict === "REJECT").map((v) => v.agent);
|
|
76606
|
+
let overallVerdict;
|
|
76607
|
+
if (cfg.vetoPriority && rejectingMembers.length > 0) {
|
|
76608
|
+
overallVerdict = "REJECT";
|
|
76609
|
+
} else if (verdicts.some((v) => v.verdict === "CONCERNS") || !cfg.vetoPriority && rejectingMembers.length > 0) {
|
|
76610
|
+
overallVerdict = "CONCERNS";
|
|
76611
|
+
} else {
|
|
76612
|
+
overallVerdict = "APPROVE";
|
|
76613
|
+
}
|
|
76614
|
+
const unresolvedConflicts = detectConflicts(verdicts);
|
|
76615
|
+
const rejectingSet = new Set(rejectingMembers);
|
|
76616
|
+
const vetoFindings = verdicts.filter((v) => rejectingSet.has(v.agent)).flatMap((v) => v.findings);
|
|
76617
|
+
const requiredFixes = vetoFindings.filter((f) => f.severity === "HIGH" || f.severity === "MEDIUM");
|
|
76618
|
+
const advisoryFindings = [
|
|
76619
|
+
...vetoFindings.filter((f) => f.severity === "LOW"),
|
|
76620
|
+
...verdicts.filter((v) => !rejectingSet.has(v.agent)).flatMap((v) => v.findings)
|
|
76621
|
+
];
|
|
76622
|
+
const advisoryNotes = [];
|
|
76623
|
+
if (advisoryFindings.length > 0) {
|
|
76624
|
+
advisoryNotes.push(`Phase ${phaseNumber} council found ${advisoryFindings.length} advisory finding(s). Review before proceeding to next phase.`);
|
|
76625
|
+
}
|
|
76626
|
+
if (verdicts.length < 3) {
|
|
76627
|
+
advisoryNotes.push(`Phase council quorum is ${verdicts.length} members — consider convening additional members for broader review coverage.`);
|
|
76628
|
+
}
|
|
76629
|
+
const allUnmetIds = new Set(verdicts.flatMap((v) => v.criteriaUnmet));
|
|
76630
|
+
const allCriteriaMet = allUnmetIds.size === 0 && verdicts.length > 0;
|
|
76631
|
+
const unifiedFeedbackMd = buildPhaseCouncilFeedback(phaseNumber, phaseSummary, overallVerdict, rejectingMembers, requiredFixes, advisoryFindings, unresolvedConflicts, roundNumber, cfg.maxRounds);
|
|
76632
|
+
const evidencePath = `.swarm/evidence/${phaseNumber}/phase-council.json`;
|
|
76633
|
+
const baseDir = workingDir ?? process.cwd();
|
|
76634
|
+
const evidenceDir = path77.join(baseDir, ".swarm", "evidence", String(phaseNumber));
|
|
76635
|
+
fs59.mkdirSync(evidenceDir, { recursive: true });
|
|
76636
|
+
const evidenceFile = path77.join(evidenceDir, "phase-council.json");
|
|
76637
|
+
const evidenceBundle = {
|
|
76638
|
+
entries: [
|
|
76639
|
+
{
|
|
76640
|
+
type: "phase-council",
|
|
76641
|
+
phase_number: phaseNumber,
|
|
76642
|
+
scope: "phase",
|
|
76643
|
+
timestamp,
|
|
76644
|
+
verdict: overallVerdict,
|
|
76645
|
+
quorumSize,
|
|
76646
|
+
phaseSummary,
|
|
76647
|
+
requiredFixes: requiredFixes.map((f) => ({
|
|
76648
|
+
severity: f.severity,
|
|
76649
|
+
category: f.category,
|
|
76650
|
+
location: f.location,
|
|
76651
|
+
detail: f.detail,
|
|
76652
|
+
evidence: f.evidence
|
|
76653
|
+
})),
|
|
76654
|
+
advisoryNotes,
|
|
76655
|
+
advisoryFindings: advisoryFindings.map((f) => ({
|
|
76656
|
+
severity: f.severity,
|
|
76657
|
+
category: f.category,
|
|
76658
|
+
location: f.location,
|
|
76659
|
+
detail: f.detail,
|
|
76660
|
+
evidence: f.evidence
|
|
76661
|
+
})),
|
|
76662
|
+
roundNumber,
|
|
76663
|
+
allCriteriaMet
|
|
76664
|
+
}
|
|
76665
|
+
]
|
|
76666
|
+
};
|
|
76667
|
+
try {
|
|
76668
|
+
const tempFile = `${evidenceFile}.tmp-${Date.now()}`;
|
|
76669
|
+
fs59.writeFileSync(tempFile, JSON.stringify(evidenceBundle, null, 2), "utf-8");
|
|
76670
|
+
fs59.renameSync(tempFile, evidenceFile);
|
|
76671
|
+
} catch (writeErr) {
|
|
76672
|
+
console.warn(`[phase-council] Failed to write phase-council evidence to ${evidenceFile}: ${writeErr instanceof Error ? writeErr.message : String(writeErr)}`);
|
|
76673
|
+
}
|
|
76674
|
+
return {
|
|
76675
|
+
phaseNumber,
|
|
76676
|
+
scope,
|
|
76677
|
+
timestamp,
|
|
76678
|
+
overallVerdict,
|
|
76679
|
+
vetoedBy: rejectingMembers.length > 0 ? rejectingMembers : null,
|
|
76680
|
+
memberVerdicts: verdicts,
|
|
76681
|
+
unresolvedConflicts,
|
|
76682
|
+
requiredFixes,
|
|
76683
|
+
advisoryFindings,
|
|
76684
|
+
advisoryNotes,
|
|
76685
|
+
unifiedFeedbackMd,
|
|
76686
|
+
roundNumber,
|
|
76687
|
+
allCriteriaMet,
|
|
76688
|
+
quorumSize,
|
|
76689
|
+
evidencePath,
|
|
76690
|
+
phaseSummary
|
|
76691
|
+
};
|
|
76692
|
+
}
|
|
76693
|
+
function buildPhaseCouncilFeedback(phaseNumber, phaseSummary, verdict, vetoedBy, requiredFixes, advisoryFindings, conflicts, roundNumber, maxRounds) {
|
|
76694
|
+
const lines = [
|
|
76695
|
+
`## Phase Council Review — Round ${roundNumber}/${maxRounds}`,
|
|
76696
|
+
`**Phase:** ${phaseNumber} **Overall verdict:** ${verdict}`,
|
|
76697
|
+
""
|
|
76698
|
+
];
|
|
76699
|
+
if (phaseSummary) {
|
|
76700
|
+
lines.push(`**Phase Summary:** ${phaseSummary}`);
|
|
76701
|
+
lines.push("");
|
|
76702
|
+
}
|
|
76703
|
+
if (vetoedBy.length > 0) {
|
|
76704
|
+
lines.push(`> ⛔ **BLOCKED** by: ${vetoedBy.join(", ")}`);
|
|
76705
|
+
lines.push("");
|
|
76706
|
+
}
|
|
76707
|
+
if (requiredFixes.length > 0) {
|
|
76708
|
+
lines.push("### Required Fixes (must resolve before re-submission)");
|
|
76709
|
+
for (const f of requiredFixes) {
|
|
76710
|
+
lines.push(`- **[${f.severity}]** \`${f.location}\` — ${f.detail}`, ` _Evidence:_ ${f.evidence}`);
|
|
76711
|
+
}
|
|
76712
|
+
lines.push("");
|
|
76713
|
+
}
|
|
76714
|
+
if (conflicts.length > 0) {
|
|
76715
|
+
lines.push("### Conflicts to Resolve");
|
|
76716
|
+
lines.push("_The following reviewers gave contradictory instructions. Architect must resolve before sending to coder._");
|
|
76717
|
+
for (const c of conflicts) {
|
|
76718
|
+
lines.push(`- ${c}`);
|
|
76719
|
+
}
|
|
76720
|
+
lines.push("");
|
|
76721
|
+
}
|
|
76722
|
+
if (advisoryFindings.length > 0) {
|
|
76723
|
+
lines.push("### Advisory Findings (non-blocking)");
|
|
76724
|
+
for (const f of advisoryFindings) {
|
|
76725
|
+
lines.push(`- **[${f.severity}]** \`${f.location}\` — ${f.detail}`);
|
|
76726
|
+
}
|
|
76727
|
+
lines.push("");
|
|
76728
|
+
}
|
|
76729
|
+
if (verdict === "APPROVE") {
|
|
76730
|
+
lines.push("> ✅ **Phase council approved.** Phase may proceed to completion.");
|
|
76731
|
+
} else if (roundNumber >= maxRounds) {
|
|
76732
|
+
lines.push(`> ⚠️ **Max rounds (${maxRounds}) reached.** Escalate to user — do not auto-advance.`);
|
|
76733
|
+
}
|
|
76734
|
+
return lines.join(`
|
|
76735
|
+
`);
|
|
76736
|
+
}
|
|
76587
76737
|
|
|
76588
76738
|
// src/council/criteria-store.ts
|
|
76589
76739
|
import { existsSync as existsSync39, mkdirSync as mkdirSync20, readFileSync as readFileSync37, writeFileSync as writeFileSync13 } from "node:fs";
|
|
@@ -76752,8 +76902,8 @@ var submit_council_verdicts = createSwarmTool({
|
|
|
76752
76902
|
// src/tools/convene-general-council.ts
|
|
76753
76903
|
init_zod();
|
|
76754
76904
|
init_loader();
|
|
76755
|
-
import * as
|
|
76756
|
-
import * as
|
|
76905
|
+
import * as fs60 from "node:fs";
|
|
76906
|
+
import * as path78 from "node:path";
|
|
76757
76907
|
|
|
76758
76908
|
// src/council/general-council-advisory.ts
|
|
76759
76909
|
var ADVISORY_HEADER = "[general_council] (advisory; not blocking)";
|
|
@@ -77181,13 +77331,13 @@ var convene_general_council = createSwarmTool({
|
|
|
77181
77331
|
const round1 = input.round1Responses;
|
|
77182
77332
|
const round2 = input.round2Responses ?? [];
|
|
77183
77333
|
const result = synthesizeGeneralCouncil(input.question, input.mode, round1, round2);
|
|
77184
|
-
const evidenceDir =
|
|
77334
|
+
const evidenceDir = path78.join(workingDir, ".swarm", "council", "general");
|
|
77185
77335
|
const safeTimestamp = result.timestamp.replace(/[:.]/g, "-");
|
|
77186
77336
|
const evidenceFile = `${safeTimestamp}-${input.mode}.json`;
|
|
77187
|
-
const evidencePath =
|
|
77337
|
+
const evidencePath = path78.join(evidenceDir, evidenceFile);
|
|
77188
77338
|
try {
|
|
77189
|
-
await
|
|
77190
|
-
await
|
|
77339
|
+
await fs60.promises.mkdir(evidenceDir, { recursive: true });
|
|
77340
|
+
await fs60.promises.writeFile(evidencePath, JSON.stringify(result, null, 2));
|
|
77191
77341
|
} catch (err2) {
|
|
77192
77342
|
const message = err2 instanceof Error ? err2.message : String(err2);
|
|
77193
77343
|
console.warn(`[convene_general_council] Failed to write evidence to ${evidencePath}: ${message}`);
|
|
@@ -77418,8 +77568,8 @@ init_scope_persistence();
|
|
|
77418
77568
|
init_state();
|
|
77419
77569
|
init_task_id();
|
|
77420
77570
|
init_create_tool();
|
|
77421
|
-
import * as
|
|
77422
|
-
import * as
|
|
77571
|
+
import * as fs61 from "node:fs";
|
|
77572
|
+
import * as path79 from "node:path";
|
|
77423
77573
|
function validateTaskIdFormat2(taskId) {
|
|
77424
77574
|
return validateTaskIdFormat(taskId);
|
|
77425
77575
|
}
|
|
@@ -77493,8 +77643,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
77493
77643
|
};
|
|
77494
77644
|
}
|
|
77495
77645
|
}
|
|
77496
|
-
normalizedDir =
|
|
77497
|
-
const pathParts = normalizedDir.split(
|
|
77646
|
+
normalizedDir = path79.normalize(args2.working_directory);
|
|
77647
|
+
const pathParts = normalizedDir.split(path79.sep);
|
|
77498
77648
|
if (pathParts.includes("..")) {
|
|
77499
77649
|
return {
|
|
77500
77650
|
success: false,
|
|
@@ -77504,11 +77654,11 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
77504
77654
|
]
|
|
77505
77655
|
};
|
|
77506
77656
|
}
|
|
77507
|
-
const resolvedDir =
|
|
77657
|
+
const resolvedDir = path79.resolve(normalizedDir);
|
|
77508
77658
|
try {
|
|
77509
|
-
const realPath =
|
|
77510
|
-
const planPath2 =
|
|
77511
|
-
if (!
|
|
77659
|
+
const realPath = fs61.realpathSync(resolvedDir);
|
|
77660
|
+
const planPath2 = path79.join(realPath, ".swarm", "plan.json");
|
|
77661
|
+
if (!fs61.existsSync(planPath2)) {
|
|
77512
77662
|
return {
|
|
77513
77663
|
success: false,
|
|
77514
77664
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -77531,8 +77681,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
77531
77681
|
console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
|
|
77532
77682
|
}
|
|
77533
77683
|
const directory = normalizedDir || fallbackDir;
|
|
77534
|
-
const planPath =
|
|
77535
|
-
if (!
|
|
77684
|
+
const planPath = path79.resolve(directory, ".swarm", "plan.json");
|
|
77685
|
+
if (!fs61.existsSync(planPath)) {
|
|
77536
77686
|
return {
|
|
77537
77687
|
success: false,
|
|
77538
77688
|
message: "No plan found",
|
|
@@ -77541,7 +77691,7 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
77541
77691
|
}
|
|
77542
77692
|
let planContent;
|
|
77543
77693
|
try {
|
|
77544
|
-
planContent = JSON.parse(
|
|
77694
|
+
planContent = JSON.parse(fs61.readFileSync(planPath, "utf-8"));
|
|
77545
77695
|
} catch {
|
|
77546
77696
|
return {
|
|
77547
77697
|
success: false,
|
|
@@ -77571,8 +77721,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
77571
77721
|
const normalizeErrors = [];
|
|
77572
77722
|
const dir = normalizedDir || fallbackDir || process.cwd();
|
|
77573
77723
|
const mergedFiles = rawMergedFiles.map((file3) => {
|
|
77574
|
-
if (
|
|
77575
|
-
const relativePath =
|
|
77724
|
+
if (path79.isAbsolute(file3)) {
|
|
77725
|
+
const relativePath = path79.relative(dir, file3).replace(/\\/g, "/");
|
|
77576
77726
|
if (relativePath.startsWith("..")) {
|
|
77577
77727
|
normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
|
|
77578
77728
|
return file3;
|
|
@@ -77632,8 +77782,8 @@ var declare_scope = createSwarmTool({
|
|
|
77632
77782
|
// src/tools/diff.ts
|
|
77633
77783
|
init_zod();
|
|
77634
77784
|
import * as child_process7 from "node:child_process";
|
|
77635
|
-
import * as
|
|
77636
|
-
import * as
|
|
77785
|
+
import * as fs62 from "node:fs";
|
|
77786
|
+
import * as path80 from "node:path";
|
|
77637
77787
|
init_create_tool();
|
|
77638
77788
|
var MAX_DIFF_LINES = 500;
|
|
77639
77789
|
var DIFF_TIMEOUT_MS = 30000;
|
|
@@ -77662,20 +77812,20 @@ function validateBase(base) {
|
|
|
77662
77812
|
function validatePaths(paths) {
|
|
77663
77813
|
if (!paths)
|
|
77664
77814
|
return null;
|
|
77665
|
-
for (const
|
|
77666
|
-
if (!
|
|
77815
|
+
for (const path81 of paths) {
|
|
77816
|
+
if (!path81 || path81.length === 0) {
|
|
77667
77817
|
return "empty path not allowed";
|
|
77668
77818
|
}
|
|
77669
|
-
if (
|
|
77819
|
+
if (path81.length > MAX_PATH_LENGTH) {
|
|
77670
77820
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
77671
77821
|
}
|
|
77672
|
-
if (SHELL_METACHARACTERS2.test(
|
|
77822
|
+
if (SHELL_METACHARACTERS2.test(path81)) {
|
|
77673
77823
|
return "path contains shell metacharacters";
|
|
77674
77824
|
}
|
|
77675
|
-
if (
|
|
77825
|
+
if (path81.startsWith("-")) {
|
|
77676
77826
|
return 'path cannot start with "-" (option-like arguments not allowed)';
|
|
77677
77827
|
}
|
|
77678
|
-
if (CONTROL_CHAR_PATTERN2.test(
|
|
77828
|
+
if (CONTROL_CHAR_PATTERN2.test(path81)) {
|
|
77679
77829
|
return "path contains control characters";
|
|
77680
77830
|
}
|
|
77681
77831
|
}
|
|
@@ -77781,8 +77931,8 @@ var diff = createSwarmTool({
|
|
|
77781
77931
|
if (parts2.length >= 3) {
|
|
77782
77932
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
77783
77933
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
77784
|
-
const
|
|
77785
|
-
files.push({ path:
|
|
77934
|
+
const path81 = parts2[2];
|
|
77935
|
+
files.push({ path: path81, additions, deletions });
|
|
77786
77936
|
}
|
|
77787
77937
|
}
|
|
77788
77938
|
const contractChanges = [];
|
|
@@ -77822,7 +77972,7 @@ var diff = createSwarmTool({
|
|
|
77822
77972
|
} else if (base === "unstaged") {
|
|
77823
77973
|
const oldRef = `:${file3.path}`;
|
|
77824
77974
|
oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
|
|
77825
|
-
newContent =
|
|
77975
|
+
newContent = fs62.readFileSync(path80.join(directory, file3.path), "utf-8");
|
|
77826
77976
|
} else {
|
|
77827
77977
|
const oldRef = `${base}:${file3.path}`;
|
|
77828
77978
|
oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
|
|
@@ -77896,8 +78046,8 @@ var diff = createSwarmTool({
|
|
|
77896
78046
|
// src/tools/diff-summary.ts
|
|
77897
78047
|
init_zod();
|
|
77898
78048
|
import * as child_process8 from "node:child_process";
|
|
77899
|
-
import * as
|
|
77900
|
-
import * as
|
|
78049
|
+
import * as fs63 from "node:fs";
|
|
78050
|
+
import * as path81 from "node:path";
|
|
77901
78051
|
init_create_tool();
|
|
77902
78052
|
var diff_summary = createSwarmTool({
|
|
77903
78053
|
description: "Generate a filtered semantic diff summary from AST analysis. Returns SemanticDiffSummary with optional filtering by classification or riskLevel.",
|
|
@@ -77945,7 +78095,7 @@ var diff_summary = createSwarmTool({
|
|
|
77945
78095
|
}
|
|
77946
78096
|
try {
|
|
77947
78097
|
let oldContent;
|
|
77948
|
-
const newContent =
|
|
78098
|
+
const newContent = fs63.readFileSync(path81.join(workingDir, filePath), "utf-8");
|
|
77949
78099
|
if (fileExistsInHead) {
|
|
77950
78100
|
oldContent = child_process8.execFileSync("git", ["show", `HEAD:${filePath}`], {
|
|
77951
78101
|
encoding: "utf-8",
|
|
@@ -78173,8 +78323,8 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
78173
78323
|
init_zod();
|
|
78174
78324
|
init_create_tool();
|
|
78175
78325
|
init_path_security();
|
|
78176
|
-
import * as
|
|
78177
|
-
import * as
|
|
78326
|
+
import * as fs64 from "node:fs";
|
|
78327
|
+
import * as path82 from "node:path";
|
|
78178
78328
|
var MAX_FILE_SIZE_BYTES6 = 1024 * 1024;
|
|
78179
78329
|
var MAX_EVIDENCE_FILES = 1000;
|
|
78180
78330
|
var EVIDENCE_DIR3 = ".swarm/evidence";
|
|
@@ -78201,9 +78351,9 @@ function validateRequiredTypes(input) {
|
|
|
78201
78351
|
return null;
|
|
78202
78352
|
}
|
|
78203
78353
|
function isPathWithinSwarm2(filePath, cwd) {
|
|
78204
|
-
const normalizedCwd =
|
|
78205
|
-
const swarmPath =
|
|
78206
|
-
const normalizedPath =
|
|
78354
|
+
const normalizedCwd = path82.resolve(cwd);
|
|
78355
|
+
const swarmPath = path82.join(normalizedCwd, ".swarm");
|
|
78356
|
+
const normalizedPath = path82.resolve(filePath);
|
|
78207
78357
|
return normalizedPath.startsWith(swarmPath);
|
|
78208
78358
|
}
|
|
78209
78359
|
function parseCompletedTasks(planContent) {
|
|
@@ -78219,12 +78369,12 @@ function parseCompletedTasks(planContent) {
|
|
|
78219
78369
|
}
|
|
78220
78370
|
function readEvidenceFiles(evidenceDir, _cwd) {
|
|
78221
78371
|
const evidence = [];
|
|
78222
|
-
if (!
|
|
78372
|
+
if (!fs64.existsSync(evidenceDir) || !fs64.statSync(evidenceDir).isDirectory()) {
|
|
78223
78373
|
return evidence;
|
|
78224
78374
|
}
|
|
78225
78375
|
let files;
|
|
78226
78376
|
try {
|
|
78227
|
-
files =
|
|
78377
|
+
files = fs64.readdirSync(evidenceDir);
|
|
78228
78378
|
} catch {
|
|
78229
78379
|
return evidence;
|
|
78230
78380
|
}
|
|
@@ -78233,14 +78383,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
78233
78383
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
78234
78384
|
continue;
|
|
78235
78385
|
}
|
|
78236
|
-
const filePath =
|
|
78386
|
+
const filePath = path82.join(evidenceDir, filename);
|
|
78237
78387
|
try {
|
|
78238
|
-
const resolvedPath =
|
|
78239
|
-
const evidenceDirResolved =
|
|
78388
|
+
const resolvedPath = path82.resolve(filePath);
|
|
78389
|
+
const evidenceDirResolved = path82.resolve(evidenceDir);
|
|
78240
78390
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
78241
78391
|
continue;
|
|
78242
78392
|
}
|
|
78243
|
-
const stat6 =
|
|
78393
|
+
const stat6 = fs64.lstatSync(filePath);
|
|
78244
78394
|
if (!stat6.isFile()) {
|
|
78245
78395
|
continue;
|
|
78246
78396
|
}
|
|
@@ -78249,7 +78399,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
78249
78399
|
}
|
|
78250
78400
|
let fileStat;
|
|
78251
78401
|
try {
|
|
78252
|
-
fileStat =
|
|
78402
|
+
fileStat = fs64.statSync(filePath);
|
|
78253
78403
|
if (fileStat.size > MAX_FILE_SIZE_BYTES6) {
|
|
78254
78404
|
continue;
|
|
78255
78405
|
}
|
|
@@ -78258,7 +78408,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
78258
78408
|
}
|
|
78259
78409
|
let content;
|
|
78260
78410
|
try {
|
|
78261
|
-
content =
|
|
78411
|
+
content = fs64.readFileSync(filePath, "utf-8");
|
|
78262
78412
|
} catch {
|
|
78263
78413
|
continue;
|
|
78264
78414
|
}
|
|
@@ -78354,7 +78504,7 @@ var evidence_check = createSwarmTool({
|
|
|
78354
78504
|
return JSON.stringify(errorResult, null, 2);
|
|
78355
78505
|
}
|
|
78356
78506
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
|
|
78357
|
-
const planPath =
|
|
78507
|
+
const planPath = path82.join(cwd, PLAN_FILE);
|
|
78358
78508
|
if (!isPathWithinSwarm2(planPath, cwd)) {
|
|
78359
78509
|
const errorResult = {
|
|
78360
78510
|
error: "plan file path validation failed",
|
|
@@ -78368,7 +78518,7 @@ var evidence_check = createSwarmTool({
|
|
|
78368
78518
|
}
|
|
78369
78519
|
let planContent;
|
|
78370
78520
|
try {
|
|
78371
|
-
planContent =
|
|
78521
|
+
planContent = fs64.readFileSync(planPath, "utf-8");
|
|
78372
78522
|
} catch {
|
|
78373
78523
|
const result2 = {
|
|
78374
78524
|
message: "No completed tasks found in plan.",
|
|
@@ -78386,7 +78536,7 @@ var evidence_check = createSwarmTool({
|
|
|
78386
78536
|
};
|
|
78387
78537
|
return JSON.stringify(result2, null, 2);
|
|
78388
78538
|
}
|
|
78389
|
-
const evidenceDir =
|
|
78539
|
+
const evidenceDir = path82.join(cwd, EVIDENCE_DIR3);
|
|
78390
78540
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
78391
78541
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
78392
78542
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -78403,8 +78553,8 @@ var evidence_check = createSwarmTool({
|
|
|
78403
78553
|
// src/tools/file-extractor.ts
|
|
78404
78554
|
init_zod();
|
|
78405
78555
|
init_create_tool();
|
|
78406
|
-
import * as
|
|
78407
|
-
import * as
|
|
78556
|
+
import * as fs65 from "node:fs";
|
|
78557
|
+
import * as path83 from "node:path";
|
|
78408
78558
|
var EXT_MAP = {
|
|
78409
78559
|
python: ".py",
|
|
78410
78560
|
py: ".py",
|
|
@@ -78466,8 +78616,8 @@ var extract_code_blocks = createSwarmTool({
|
|
|
78466
78616
|
execute: async (args2, directory) => {
|
|
78467
78617
|
const { content, output_dir, prefix } = args2;
|
|
78468
78618
|
const targetDir = output_dir || directory;
|
|
78469
|
-
if (!
|
|
78470
|
-
|
|
78619
|
+
if (!fs65.existsSync(targetDir)) {
|
|
78620
|
+
fs65.mkdirSync(targetDir, { recursive: true });
|
|
78471
78621
|
}
|
|
78472
78622
|
if (!content) {
|
|
78473
78623
|
return "Error: content is required";
|
|
@@ -78485,16 +78635,16 @@ var extract_code_blocks = createSwarmTool({
|
|
|
78485
78635
|
if (prefix) {
|
|
78486
78636
|
filename = `${prefix}_${filename}`;
|
|
78487
78637
|
}
|
|
78488
|
-
let filepath =
|
|
78489
|
-
const base =
|
|
78490
|
-
const ext =
|
|
78638
|
+
let filepath = path83.join(targetDir, filename);
|
|
78639
|
+
const base = path83.basename(filepath, path83.extname(filepath));
|
|
78640
|
+
const ext = path83.extname(filepath);
|
|
78491
78641
|
let counter = 1;
|
|
78492
|
-
while (
|
|
78493
|
-
filepath =
|
|
78642
|
+
while (fs65.existsSync(filepath)) {
|
|
78643
|
+
filepath = path83.join(targetDir, `${base}_${counter}${ext}`);
|
|
78494
78644
|
counter++;
|
|
78495
78645
|
}
|
|
78496
78646
|
try {
|
|
78497
|
-
|
|
78647
|
+
fs65.writeFileSync(filepath, code.trim(), "utf-8");
|
|
78498
78648
|
savedFiles.push(filepath);
|
|
78499
78649
|
} catch (error93) {
|
|
78500
78650
|
errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
@@ -78753,8 +78903,8 @@ var gitingest = createSwarmTool({
|
|
|
78753
78903
|
init_zod();
|
|
78754
78904
|
init_create_tool();
|
|
78755
78905
|
init_path_security();
|
|
78756
|
-
import * as
|
|
78757
|
-
import * as
|
|
78906
|
+
import * as fs66 from "node:fs";
|
|
78907
|
+
import * as path84 from "node:path";
|
|
78758
78908
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
78759
78909
|
var MAX_SYMBOL_LENGTH = 256;
|
|
78760
78910
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
@@ -78802,7 +78952,7 @@ function validateSymbolInput(symbol3) {
|
|
|
78802
78952
|
return null;
|
|
78803
78953
|
}
|
|
78804
78954
|
function isBinaryFile2(filePath, buffer) {
|
|
78805
|
-
const ext =
|
|
78955
|
+
const ext = path84.extname(filePath).toLowerCase();
|
|
78806
78956
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
78807
78957
|
return false;
|
|
78808
78958
|
}
|
|
@@ -78826,15 +78976,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
78826
78976
|
const imports = [];
|
|
78827
78977
|
let _resolvedTarget;
|
|
78828
78978
|
try {
|
|
78829
|
-
_resolvedTarget =
|
|
78979
|
+
_resolvedTarget = path84.resolve(targetFile);
|
|
78830
78980
|
} catch {
|
|
78831
78981
|
_resolvedTarget = targetFile;
|
|
78832
78982
|
}
|
|
78833
|
-
const targetBasename =
|
|
78983
|
+
const targetBasename = path84.basename(targetFile, path84.extname(targetFile));
|
|
78834
78984
|
const targetWithExt = targetFile;
|
|
78835
78985
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
78836
|
-
const normalizedTargetWithExt =
|
|
78837
|
-
const normalizedTargetWithoutExt =
|
|
78986
|
+
const normalizedTargetWithExt = path84.normalize(targetWithExt).replace(/\\/g, "/");
|
|
78987
|
+
const normalizedTargetWithoutExt = path84.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
78838
78988
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
78839
78989
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
78840
78990
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -78857,9 +79007,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
78857
79007
|
}
|
|
78858
79008
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
78859
79009
|
let isMatch = false;
|
|
78860
|
-
const _targetDir =
|
|
78861
|
-
const targetExt =
|
|
78862
|
-
const targetBasenameNoExt =
|
|
79010
|
+
const _targetDir = path84.dirname(targetFile);
|
|
79011
|
+
const targetExt = path84.extname(targetFile);
|
|
79012
|
+
const targetBasenameNoExt = path84.basename(targetFile, targetExt);
|
|
78863
79013
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
78864
79014
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
78865
79015
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -78916,7 +79066,7 @@ var SKIP_DIRECTORIES4 = new Set([
|
|
|
78916
79066
|
function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
|
|
78917
79067
|
let entries;
|
|
78918
79068
|
try {
|
|
78919
|
-
entries =
|
|
79069
|
+
entries = fs66.readdirSync(dir);
|
|
78920
79070
|
} catch (e) {
|
|
78921
79071
|
stats.fileErrors.push({
|
|
78922
79072
|
path: dir,
|
|
@@ -78927,13 +79077,13 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
78927
79077
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
78928
79078
|
for (const entry of entries) {
|
|
78929
79079
|
if (SKIP_DIRECTORIES4.has(entry)) {
|
|
78930
|
-
stats.skippedDirs.push(
|
|
79080
|
+
stats.skippedDirs.push(path84.join(dir, entry));
|
|
78931
79081
|
continue;
|
|
78932
79082
|
}
|
|
78933
|
-
const fullPath =
|
|
79083
|
+
const fullPath = path84.join(dir, entry);
|
|
78934
79084
|
let stat6;
|
|
78935
79085
|
try {
|
|
78936
|
-
stat6 =
|
|
79086
|
+
stat6 = fs66.statSync(fullPath);
|
|
78937
79087
|
} catch (e) {
|
|
78938
79088
|
stats.fileErrors.push({
|
|
78939
79089
|
path: fullPath,
|
|
@@ -78944,7 +79094,7 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
78944
79094
|
if (stat6.isDirectory()) {
|
|
78945
79095
|
findSourceFiles2(fullPath, files, stats);
|
|
78946
79096
|
} else if (stat6.isFile()) {
|
|
78947
|
-
const ext =
|
|
79097
|
+
const ext = path84.extname(fullPath).toLowerCase();
|
|
78948
79098
|
if (SUPPORTED_EXTENSIONS3.includes(ext)) {
|
|
78949
79099
|
files.push(fullPath);
|
|
78950
79100
|
}
|
|
@@ -79001,8 +79151,8 @@ var imports = createSwarmTool({
|
|
|
79001
79151
|
return JSON.stringify(errorResult, null, 2);
|
|
79002
79152
|
}
|
|
79003
79153
|
try {
|
|
79004
|
-
const targetFile =
|
|
79005
|
-
if (!
|
|
79154
|
+
const targetFile = path84.resolve(file3);
|
|
79155
|
+
if (!fs66.existsSync(targetFile)) {
|
|
79006
79156
|
const errorResult = {
|
|
79007
79157
|
error: `target file not found: ${file3}`,
|
|
79008
79158
|
target: file3,
|
|
@@ -79012,7 +79162,7 @@ var imports = createSwarmTool({
|
|
|
79012
79162
|
};
|
|
79013
79163
|
return JSON.stringify(errorResult, null, 2);
|
|
79014
79164
|
}
|
|
79015
|
-
const targetStat =
|
|
79165
|
+
const targetStat = fs66.statSync(targetFile);
|
|
79016
79166
|
if (!targetStat.isFile()) {
|
|
79017
79167
|
const errorResult = {
|
|
79018
79168
|
error: "target must be a file, not a directory",
|
|
@@ -79023,7 +79173,7 @@ var imports = createSwarmTool({
|
|
|
79023
79173
|
};
|
|
79024
79174
|
return JSON.stringify(errorResult, null, 2);
|
|
79025
79175
|
}
|
|
79026
|
-
const baseDir =
|
|
79176
|
+
const baseDir = path84.dirname(targetFile);
|
|
79027
79177
|
const scanStats = {
|
|
79028
79178
|
skippedDirs: [],
|
|
79029
79179
|
skippedFiles: 0,
|
|
@@ -79038,12 +79188,12 @@ var imports = createSwarmTool({
|
|
|
79038
79188
|
if (consumers.length >= MAX_CONSUMERS)
|
|
79039
79189
|
break;
|
|
79040
79190
|
try {
|
|
79041
|
-
const stat6 =
|
|
79191
|
+
const stat6 = fs66.statSync(filePath);
|
|
79042
79192
|
if (stat6.size > MAX_FILE_SIZE_BYTES7) {
|
|
79043
79193
|
skippedFileCount++;
|
|
79044
79194
|
continue;
|
|
79045
79195
|
}
|
|
79046
|
-
const buffer =
|
|
79196
|
+
const buffer = fs66.readFileSync(filePath);
|
|
79047
79197
|
if (isBinaryFile2(filePath, buffer)) {
|
|
79048
79198
|
skippedFileCount++;
|
|
79049
79199
|
continue;
|
|
@@ -79568,8 +79718,8 @@ init_schema();
|
|
|
79568
79718
|
init_qa_gate_profile();
|
|
79569
79719
|
init_manager2();
|
|
79570
79720
|
init_curator();
|
|
79571
|
-
import * as
|
|
79572
|
-
import * as
|
|
79721
|
+
import * as fs68 from "node:fs";
|
|
79722
|
+
import * as path86 from "node:path";
|
|
79573
79723
|
init_knowledge_curator();
|
|
79574
79724
|
init_knowledge_reader();
|
|
79575
79725
|
init_knowledge_store();
|
|
@@ -79581,20 +79731,20 @@ init_file_locks();
|
|
|
79581
79731
|
init_plan_schema();
|
|
79582
79732
|
init_ledger();
|
|
79583
79733
|
init_manager();
|
|
79584
|
-
import * as
|
|
79585
|
-
import * as
|
|
79734
|
+
import * as fs67 from "node:fs";
|
|
79735
|
+
import * as path85 from "node:path";
|
|
79586
79736
|
async function writeCheckpoint(directory) {
|
|
79587
79737
|
try {
|
|
79588
79738
|
const plan = await loadPlan(directory);
|
|
79589
79739
|
if (!plan)
|
|
79590
79740
|
return;
|
|
79591
|
-
const swarmDir =
|
|
79592
|
-
|
|
79593
|
-
const jsonPath =
|
|
79594
|
-
const mdPath =
|
|
79595
|
-
|
|
79741
|
+
const swarmDir = path85.join(directory, ".swarm");
|
|
79742
|
+
fs67.mkdirSync(swarmDir, { recursive: true });
|
|
79743
|
+
const jsonPath = path85.join(swarmDir, "SWARM_PLAN.json");
|
|
79744
|
+
const mdPath = path85.join(swarmDir, "SWARM_PLAN.md");
|
|
79745
|
+
fs67.writeFileSync(jsonPath, JSON.stringify(plan, null, 2), "utf8");
|
|
79596
79746
|
const md = derivePlanMarkdown(plan);
|
|
79597
|
-
|
|
79747
|
+
fs67.writeFileSync(mdPath, md, "utf8");
|
|
79598
79748
|
} catch (error93) {
|
|
79599
79749
|
console.warn(`[checkpoint] Failed to write SWARM_PLAN checkpoint: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
79600
79750
|
}
|
|
@@ -79826,8 +79976,8 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
79826
79976
|
let driftCheckEnabled = true;
|
|
79827
79977
|
let driftHasSpecMd = false;
|
|
79828
79978
|
try {
|
|
79829
|
-
const specMdPath =
|
|
79830
|
-
driftHasSpecMd =
|
|
79979
|
+
const specMdPath = path86.join(dir, ".swarm", "spec.md");
|
|
79980
|
+
driftHasSpecMd = fs68.existsSync(specMdPath);
|
|
79831
79981
|
const gatePlan = await loadPlan(dir);
|
|
79832
79982
|
if (gatePlan) {
|
|
79833
79983
|
const gatePlanId = `${gatePlan.swarm}-${gatePlan.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
|
|
@@ -79848,9 +79998,9 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
79848
79998
|
} else {
|
|
79849
79999
|
let phaseType;
|
|
79850
80000
|
try {
|
|
79851
|
-
const planPath =
|
|
79852
|
-
if (
|
|
79853
|
-
const planRaw =
|
|
80001
|
+
const planPath = path86.join(dir, ".swarm", "plan.json");
|
|
80002
|
+
if (fs68.existsSync(planPath)) {
|
|
80003
|
+
const planRaw = fs68.readFileSync(planPath, "utf-8");
|
|
79854
80004
|
const plan = JSON.parse(planRaw);
|
|
79855
80005
|
const targetPhase = plan.phases?.find((p) => p.id === phase);
|
|
79856
80006
|
phaseType = targetPhase?.type;
|
|
@@ -79861,11 +80011,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
79861
80011
|
warnings.push(`Phase ${phase} is annotated as 'non-code'. Drift verification was skipped per phase type annotation.`);
|
|
79862
80012
|
} else {
|
|
79863
80013
|
try {
|
|
79864
|
-
const driftEvidencePath =
|
|
80014
|
+
const driftEvidencePath = path86.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
|
|
79865
80015
|
let driftVerdictFound = false;
|
|
79866
80016
|
let driftVerdictApproved = false;
|
|
79867
80017
|
try {
|
|
79868
|
-
const driftEvidenceContent =
|
|
80018
|
+
const driftEvidenceContent = fs68.readFileSync(driftEvidencePath, "utf-8");
|
|
79869
80019
|
const driftEvidence = JSON.parse(driftEvidenceContent);
|
|
79870
80020
|
const entries = driftEvidence.entries ?? [];
|
|
79871
80021
|
for (const entry of entries) {
|
|
@@ -79899,9 +80049,9 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
79899
80049
|
let incompleteTaskCount = 0;
|
|
79900
80050
|
let planParseable = false;
|
|
79901
80051
|
try {
|
|
79902
|
-
const planPath =
|
|
79903
|
-
if (
|
|
79904
|
-
const planRaw =
|
|
80052
|
+
const planPath = path86.join(dir, ".swarm", "plan.json");
|
|
80053
|
+
if (fs68.existsSync(planPath)) {
|
|
80054
|
+
const planRaw = fs68.readFileSync(planPath, "utf-8");
|
|
79905
80055
|
const plan = JSON.parse(planRaw);
|
|
79906
80056
|
planParseable = true;
|
|
79907
80057
|
const planPhase = plan.phases?.find((p) => p.id === phase);
|
|
@@ -79966,11 +80116,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
79966
80116
|
const overrides = session2?.qaGateSessionOverrides ?? {};
|
|
79967
80117
|
const effective = getEffectiveGates(profile, overrides);
|
|
79968
80118
|
if (effective.hallucination_guard === true) {
|
|
79969
|
-
const hgPath =
|
|
80119
|
+
const hgPath = path86.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
|
|
79970
80120
|
let hgVerdictFound = false;
|
|
79971
80121
|
let hgVerdictApproved = false;
|
|
79972
80122
|
try {
|
|
79973
|
-
const hgContent =
|
|
80123
|
+
const hgContent = fs68.readFileSync(hgPath, "utf-8");
|
|
79974
80124
|
const hgBundle = JSON.parse(hgContent);
|
|
79975
80125
|
for (const entry of hgBundle.entries ?? []) {
|
|
79976
80126
|
if (typeof entry.type === "string" && entry.type.includes("hallucination") && typeof entry.verdict === "string") {
|
|
@@ -80038,11 +80188,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
80038
80188
|
const overrides = session2?.qaGateSessionOverrides ?? {};
|
|
80039
80189
|
const effective = getEffectiveGates(profile, overrides);
|
|
80040
80190
|
if (effective.mutation_test === true) {
|
|
80041
|
-
const mgPath =
|
|
80191
|
+
const mgPath = path86.join(dir, ".swarm", "evidence", String(phase), "mutation-gate.json");
|
|
80042
80192
|
let mgVerdictFound = false;
|
|
80043
80193
|
let mgVerdict;
|
|
80044
80194
|
try {
|
|
80045
|
-
const mgContent =
|
|
80195
|
+
const mgContent = fs68.readFileSync(mgPath, "utf-8");
|
|
80046
80196
|
const mgBundle = JSON.parse(mgContent);
|
|
80047
80197
|
for (const entry of mgBundle.entries ?? []) {
|
|
80048
80198
|
if (typeof entry.type === "string" && entry.type === "mutation-gate" && typeof entry.verdict === "string") {
|
|
@@ -80112,14 +80262,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
80112
80262
|
const effective = getEffectiveGates(profile, overrides);
|
|
80113
80263
|
if (effective.council_mode === true) {
|
|
80114
80264
|
councilModeEnabled = true;
|
|
80115
|
-
const pcPath =
|
|
80265
|
+
const pcPath = path86.join(dir, ".swarm", "evidence", String(phase), "phase-council.json");
|
|
80116
80266
|
let pcVerdictFound = false;
|
|
80117
80267
|
let _pcVerdict;
|
|
80118
80268
|
let pcQuorumSize;
|
|
80119
80269
|
let pcTimestamp;
|
|
80120
80270
|
let pcPhaseNumber;
|
|
80121
80271
|
try {
|
|
80122
|
-
const pcContent =
|
|
80272
|
+
const pcContent = fs68.readFileSync(pcPath, "utf-8");
|
|
80123
80273
|
const pcBundle = JSON.parse(pcContent);
|
|
80124
80274
|
for (const entry of pcBundle.entries ?? []) {
|
|
80125
80275
|
if (typeof entry.type === "string" && entry.type === "phase-council" && typeof entry.verdict === "string") {
|
|
@@ -80228,11 +80378,11 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
80228
80378
|
status: "blocked",
|
|
80229
80379
|
reason: "PHASE_COUNCIL_REQUIRED",
|
|
80230
80380
|
phase_council_required: true,
|
|
80231
|
-
message: `Phase ${phase} cannot be completed: council_mode is enabled and phase council evidence not found at .swarm/evidence/${phase}/phase-council.json. Convene a phase-level council (dispatch 5 members, collect verdicts, call
|
|
80381
|
+
message: `Phase ${phase} cannot be completed: council_mode is enabled and phase council evidence not found at .swarm/evidence/${phase}/phase-council.json. Convene a phase-level council (dispatch 5 members, collect verdicts, call submit_phase_council_verdicts) before completing the phase.`,
|
|
80232
80382
|
agentsDispatched,
|
|
80233
80383
|
agentsMissing: [],
|
|
80234
80384
|
warnings: [
|
|
80235
|
-
`Phase council required — convene 5 council members (critic, reviewer, sme, test_engineer, explorer) for holistic phase review. Call
|
|
80385
|
+
`Phase council required — convene 5 council members (critic, reviewer, sme, test_engineer, explorer) for holistic phase review. Call submit_phase_council_verdicts to synthesize verdicts and write phase-council.json evidence.`
|
|
80236
80386
|
]
|
|
80237
80387
|
}, null, 2);
|
|
80238
80388
|
}
|
|
@@ -80314,7 +80464,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
80314
80464
|
}
|
|
80315
80465
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
80316
80466
|
try {
|
|
80317
|
-
const projectName =
|
|
80467
|
+
const projectName = path86.basename(dir);
|
|
80318
80468
|
const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
|
|
80319
80469
|
if (curationResult) {
|
|
80320
80470
|
const sessionState = swarmState.agentSessions.get(sessionID);
|
|
@@ -80394,7 +80544,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
80394
80544
|
let phaseRequiredAgents;
|
|
80395
80545
|
try {
|
|
80396
80546
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
80397
|
-
const planRaw =
|
|
80547
|
+
const planRaw = fs68.readFileSync(planPath, "utf-8");
|
|
80398
80548
|
const plan = JSON.parse(planRaw);
|
|
80399
80549
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
80400
80550
|
phaseRequiredAgents = phaseObj?.required_agents;
|
|
@@ -80409,7 +80559,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
80409
80559
|
if (agentsMissing.length > 0) {
|
|
80410
80560
|
try {
|
|
80411
80561
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
80412
|
-
const planRaw =
|
|
80562
|
+
const planRaw = fs68.readFileSync(planPath, "utf-8");
|
|
80413
80563
|
const plan = JSON.parse(planRaw);
|
|
80414
80564
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
80415
80565
|
if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
|
|
@@ -80449,7 +80599,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
80449
80599
|
if (phaseCompleteConfig.regression_sweep?.enforce) {
|
|
80450
80600
|
try {
|
|
80451
80601
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
80452
|
-
const planRaw =
|
|
80602
|
+
const planRaw = fs68.readFileSync(planPath, "utf-8");
|
|
80453
80603
|
const plan = JSON.parse(planRaw);
|
|
80454
80604
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
80455
80605
|
if (targetPhase) {
|
|
@@ -80503,7 +80653,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
80503
80653
|
}
|
|
80504
80654
|
try {
|
|
80505
80655
|
const eventsPath = validateSwarmPath(dir, "events.jsonl");
|
|
80506
|
-
|
|
80656
|
+
fs68.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
80507
80657
|
`, "utf-8");
|
|
80508
80658
|
} catch (writeError) {
|
|
80509
80659
|
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -80578,12 +80728,12 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
80578
80728
|
warnings.push(`Warning: failed to update plan.json phase status`);
|
|
80579
80729
|
try {
|
|
80580
80730
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
80581
|
-
const planRaw =
|
|
80731
|
+
const planRaw = fs68.readFileSync(planPath, "utf-8");
|
|
80582
80732
|
const plan2 = JSON.parse(planRaw);
|
|
80583
80733
|
const phaseObj = plan2.phases.find((p) => p.id === phase);
|
|
80584
80734
|
if (phaseObj) {
|
|
80585
80735
|
phaseObj.status = "complete";
|
|
80586
|
-
|
|
80736
|
+
fs68.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
|
|
80587
80737
|
}
|
|
80588
80738
|
} catch {}
|
|
80589
80739
|
} else if (plan) {
|
|
@@ -80620,12 +80770,12 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
80620
80770
|
warnings.push(`Warning: failed to update plan.json phase status`);
|
|
80621
80771
|
try {
|
|
80622
80772
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
80623
|
-
const planRaw =
|
|
80773
|
+
const planRaw = fs68.readFileSync(planPath, "utf-8");
|
|
80624
80774
|
const plan = JSON.parse(planRaw);
|
|
80625
80775
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
80626
80776
|
if (phaseObj) {
|
|
80627
80777
|
phaseObj.status = "complete";
|
|
80628
|
-
|
|
80778
|
+
fs68.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
|
|
80629
80779
|
}
|
|
80630
80780
|
} catch {}
|
|
80631
80781
|
}
|
|
@@ -80683,8 +80833,8 @@ init_discovery();
|
|
|
80683
80833
|
init_utils();
|
|
80684
80834
|
init_bun_compat();
|
|
80685
80835
|
init_create_tool();
|
|
80686
|
-
import * as
|
|
80687
|
-
import * as
|
|
80836
|
+
import * as fs69 from "node:fs";
|
|
80837
|
+
import * as path87 from "node:path";
|
|
80688
80838
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
80689
80839
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
80690
80840
|
function isValidEcosystem(value) {
|
|
@@ -80712,31 +80862,31 @@ function validateArgs3(args2) {
|
|
|
80712
80862
|
function detectEcosystems(directory) {
|
|
80713
80863
|
const ecosystems = [];
|
|
80714
80864
|
const cwd = directory;
|
|
80715
|
-
if (
|
|
80865
|
+
if (fs69.existsSync(path87.join(cwd, "package.json"))) {
|
|
80716
80866
|
ecosystems.push("npm");
|
|
80717
80867
|
}
|
|
80718
|
-
if (
|
|
80868
|
+
if (fs69.existsSync(path87.join(cwd, "pyproject.toml")) || fs69.existsSync(path87.join(cwd, "requirements.txt"))) {
|
|
80719
80869
|
ecosystems.push("pip");
|
|
80720
80870
|
}
|
|
80721
|
-
if (
|
|
80871
|
+
if (fs69.existsSync(path87.join(cwd, "Cargo.toml"))) {
|
|
80722
80872
|
ecosystems.push("cargo");
|
|
80723
80873
|
}
|
|
80724
|
-
if (
|
|
80874
|
+
if (fs69.existsSync(path87.join(cwd, "go.mod"))) {
|
|
80725
80875
|
ecosystems.push("go");
|
|
80726
80876
|
}
|
|
80727
80877
|
try {
|
|
80728
|
-
const files =
|
|
80878
|
+
const files = fs69.readdirSync(cwd);
|
|
80729
80879
|
if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
80730
80880
|
ecosystems.push("dotnet");
|
|
80731
80881
|
}
|
|
80732
80882
|
} catch {}
|
|
80733
|
-
if (
|
|
80883
|
+
if (fs69.existsSync(path87.join(cwd, "Gemfile")) || fs69.existsSync(path87.join(cwd, "Gemfile.lock"))) {
|
|
80734
80884
|
ecosystems.push("ruby");
|
|
80735
80885
|
}
|
|
80736
|
-
if (
|
|
80886
|
+
if (fs69.existsSync(path87.join(cwd, "pubspec.yaml"))) {
|
|
80737
80887
|
ecosystems.push("dart");
|
|
80738
80888
|
}
|
|
80739
|
-
if (
|
|
80889
|
+
if (fs69.existsSync(path87.join(cwd, "composer.lock"))) {
|
|
80740
80890
|
ecosystems.push("composer");
|
|
80741
80891
|
}
|
|
80742
80892
|
return ecosystems;
|
|
@@ -81871,8 +82021,8 @@ var pkg_audit = createSwarmTool({
|
|
|
81871
82021
|
// src/tools/placeholder-scan.ts
|
|
81872
82022
|
init_zod();
|
|
81873
82023
|
init_manager2();
|
|
81874
|
-
import * as
|
|
81875
|
-
import * as
|
|
82024
|
+
import * as fs70 from "node:fs";
|
|
82025
|
+
import * as path88 from "node:path";
|
|
81876
82026
|
init_utils();
|
|
81877
82027
|
init_create_tool();
|
|
81878
82028
|
var MAX_FILE_SIZE = 1024 * 1024;
|
|
@@ -81995,7 +82145,7 @@ function isScaffoldFile(filePath) {
|
|
|
81995
82145
|
if (SCAFFOLD_PATH_PATTERNS.some((pattern) => pattern.test(normalizedPath))) {
|
|
81996
82146
|
return true;
|
|
81997
82147
|
}
|
|
81998
|
-
const filename =
|
|
82148
|
+
const filename = path88.basename(filePath);
|
|
81999
82149
|
if (SCAFFOLD_FILENAME_PATTERNS.some((pattern) => pattern.test(filename))) {
|
|
82000
82150
|
return true;
|
|
82001
82151
|
}
|
|
@@ -82012,7 +82162,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
|
|
|
82012
82162
|
if (regex.test(normalizedPath)) {
|
|
82013
82163
|
return true;
|
|
82014
82164
|
}
|
|
82015
|
-
const filename =
|
|
82165
|
+
const filename = path88.basename(filePath);
|
|
82016
82166
|
const filenameRegex = new RegExp(`^${regexPattern}$`, "i");
|
|
82017
82167
|
if (filenameRegex.test(filename)) {
|
|
82018
82168
|
return true;
|
|
@@ -82021,7 +82171,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
|
|
|
82021
82171
|
return false;
|
|
82022
82172
|
}
|
|
82023
82173
|
function isParserSupported(filePath) {
|
|
82024
|
-
const ext =
|
|
82174
|
+
const ext = path88.extname(filePath).toLowerCase();
|
|
82025
82175
|
return SUPPORTED_PARSER_EXTENSIONS.has(ext);
|
|
82026
82176
|
}
|
|
82027
82177
|
function isPlanFile(filePath) {
|
|
@@ -82268,28 +82418,28 @@ async function placeholderScan(input, directory) {
|
|
|
82268
82418
|
let filesScanned = 0;
|
|
82269
82419
|
const filesWithFindings = new Set;
|
|
82270
82420
|
for (const filePath of changed_files) {
|
|
82271
|
-
const fullPath =
|
|
82272
|
-
const resolvedDirectory =
|
|
82273
|
-
if (!fullPath.startsWith(resolvedDirectory +
|
|
82421
|
+
const fullPath = path88.isAbsolute(filePath) ? filePath : path88.resolve(directory, filePath);
|
|
82422
|
+
const resolvedDirectory = path88.resolve(directory);
|
|
82423
|
+
if (!fullPath.startsWith(resolvedDirectory + path88.sep) && fullPath !== resolvedDirectory) {
|
|
82274
82424
|
continue;
|
|
82275
82425
|
}
|
|
82276
|
-
if (!
|
|
82426
|
+
if (!fs70.existsSync(fullPath)) {
|
|
82277
82427
|
continue;
|
|
82278
82428
|
}
|
|
82279
82429
|
if (isAllowedByGlobs(filePath, allow_globs)) {
|
|
82280
82430
|
continue;
|
|
82281
82431
|
}
|
|
82282
|
-
const relativeFilePath =
|
|
82432
|
+
const relativeFilePath = path88.relative(directory, fullPath).replace(/\\/g, "/");
|
|
82283
82433
|
if (FILE_ALLOWLIST.some((allowed) => relativeFilePath.endsWith(allowed))) {
|
|
82284
82434
|
continue;
|
|
82285
82435
|
}
|
|
82286
82436
|
let content;
|
|
82287
82437
|
try {
|
|
82288
|
-
const stat6 =
|
|
82438
|
+
const stat6 = fs70.statSync(fullPath);
|
|
82289
82439
|
if (stat6.size > MAX_FILE_SIZE) {
|
|
82290
82440
|
continue;
|
|
82291
82441
|
}
|
|
82292
|
-
content =
|
|
82442
|
+
content = fs70.readFileSync(fullPath, "utf-8");
|
|
82293
82443
|
} catch {
|
|
82294
82444
|
continue;
|
|
82295
82445
|
}
|
|
@@ -82350,8 +82500,8 @@ var placeholder_scan = createSwarmTool({
|
|
|
82350
82500
|
}
|
|
82351
82501
|
});
|
|
82352
82502
|
// src/tools/pre-check-batch.ts
|
|
82353
|
-
import * as
|
|
82354
|
-
import * as
|
|
82503
|
+
import * as fs73 from "node:fs";
|
|
82504
|
+
import * as path91 from "node:path";
|
|
82355
82505
|
init_zod();
|
|
82356
82506
|
init_manager2();
|
|
82357
82507
|
init_utils();
|
|
@@ -82488,8 +82638,8 @@ var quality_budget = createSwarmTool({
|
|
|
82488
82638
|
init_zod();
|
|
82489
82639
|
init_manager2();
|
|
82490
82640
|
init_detector();
|
|
82491
|
-
import * as
|
|
82492
|
-
import * as
|
|
82641
|
+
import * as fs72 from "node:fs";
|
|
82642
|
+
import * as path90 from "node:path";
|
|
82493
82643
|
import { extname as extname18 } from "node:path";
|
|
82494
82644
|
|
|
82495
82645
|
// src/sast/rules/c.ts
|
|
@@ -83382,25 +83532,25 @@ init_create_tool();
|
|
|
83382
83532
|
// src/tools/sast-baseline.ts
|
|
83383
83533
|
init_utils2();
|
|
83384
83534
|
import * as crypto8 from "node:crypto";
|
|
83385
|
-
import * as
|
|
83386
|
-
import * as
|
|
83535
|
+
import * as fs71 from "node:fs";
|
|
83536
|
+
import * as path89 from "node:path";
|
|
83387
83537
|
var BASELINE_SCHEMA_VERSION = "1.0.0";
|
|
83388
83538
|
var MAX_BASELINE_FINDINGS = 2000;
|
|
83389
83539
|
var MAX_BASELINE_BYTES = 2 * 1048576;
|
|
83390
83540
|
var LOCK_RETRY_DELAYS_MS = [50, 100, 200, 400, 800];
|
|
83391
83541
|
function normalizeFindingPath(directory, file3) {
|
|
83392
|
-
const resolved =
|
|
83393
|
-
const rel =
|
|
83542
|
+
const resolved = path89.isAbsolute(file3) ? file3 : path89.resolve(directory, file3);
|
|
83543
|
+
const rel = path89.relative(path89.resolve(directory), resolved);
|
|
83394
83544
|
return rel.replace(/\\/g, "/");
|
|
83395
83545
|
}
|
|
83396
83546
|
function baselineRelPath(phase) {
|
|
83397
|
-
return
|
|
83547
|
+
return path89.join("evidence", String(phase), "sast-baseline.json");
|
|
83398
83548
|
}
|
|
83399
83549
|
function tempRelPath(phase) {
|
|
83400
|
-
return
|
|
83550
|
+
return path89.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
|
|
83401
83551
|
}
|
|
83402
83552
|
function lockRelPath(phase) {
|
|
83403
|
-
return
|
|
83553
|
+
return path89.join("evidence", String(phase), "sast-baseline.json.lock");
|
|
83404
83554
|
}
|
|
83405
83555
|
function getLine(lines, idx) {
|
|
83406
83556
|
if (idx < 0 || idx >= lines.length)
|
|
@@ -83417,7 +83567,7 @@ function fingerprintFinding(finding, directory, occurrenceIndex) {
|
|
|
83417
83567
|
}
|
|
83418
83568
|
const lineNum = finding.location.line;
|
|
83419
83569
|
try {
|
|
83420
|
-
const content =
|
|
83570
|
+
const content = fs71.readFileSync(finding.location.file, "utf-8");
|
|
83421
83571
|
const lines = content.split(`
|
|
83422
83572
|
`);
|
|
83423
83573
|
const idx = lineNum - 1;
|
|
@@ -83448,7 +83598,7 @@ function assignOccurrenceIndices(findings, directory) {
|
|
|
83448
83598
|
try {
|
|
83449
83599
|
if (relFile.startsWith(".."))
|
|
83450
83600
|
throw new Error("escapes workspace");
|
|
83451
|
-
const content =
|
|
83601
|
+
const content = fs71.readFileSync(finding.location.file, "utf-8");
|
|
83452
83602
|
const lines = content.split(`
|
|
83453
83603
|
`);
|
|
83454
83604
|
const idx = lineNum - 1;
|
|
@@ -83477,11 +83627,11 @@ function assignOccurrenceIndices(findings, directory) {
|
|
|
83477
83627
|
async function acquireLock(lockPath) {
|
|
83478
83628
|
for (let attempt = 0;attempt <= LOCK_RETRY_DELAYS_MS.length; attempt++) {
|
|
83479
83629
|
try {
|
|
83480
|
-
const fd =
|
|
83481
|
-
|
|
83630
|
+
const fd = fs71.openSync(lockPath, "wx");
|
|
83631
|
+
fs71.closeSync(fd);
|
|
83482
83632
|
return () => {
|
|
83483
83633
|
try {
|
|
83484
|
-
|
|
83634
|
+
fs71.unlinkSync(lockPath);
|
|
83485
83635
|
} catch {}
|
|
83486
83636
|
};
|
|
83487
83637
|
} catch {
|
|
@@ -83521,13 +83671,13 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
83521
83671
|
message: e instanceof Error ? e.message : "Path validation failed"
|
|
83522
83672
|
};
|
|
83523
83673
|
}
|
|
83524
|
-
|
|
83525
|
-
|
|
83674
|
+
fs71.mkdirSync(path89.dirname(baselinePath), { recursive: true });
|
|
83675
|
+
fs71.mkdirSync(path89.dirname(tempPath), { recursive: true });
|
|
83526
83676
|
const releaseLock = await acquireLock(lockPath);
|
|
83527
83677
|
try {
|
|
83528
83678
|
let existing = null;
|
|
83529
83679
|
try {
|
|
83530
|
-
const raw =
|
|
83680
|
+
const raw = fs71.readFileSync(baselinePath, "utf-8");
|
|
83531
83681
|
const parsed = JSON.parse(raw);
|
|
83532
83682
|
if (parsed.schema_version === BASELINE_SCHEMA_VERSION) {
|
|
83533
83683
|
existing = parsed;
|
|
@@ -83587,8 +83737,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
83587
83737
|
message: `Baseline would exceed size cap (${json4.length} bytes > ${MAX_BASELINE_BYTES})`
|
|
83588
83738
|
};
|
|
83589
83739
|
}
|
|
83590
|
-
|
|
83591
|
-
|
|
83740
|
+
fs71.writeFileSync(tempPath, json4, "utf-8");
|
|
83741
|
+
fs71.renameSync(tempPath, baselinePath);
|
|
83592
83742
|
return {
|
|
83593
83743
|
status: "merged",
|
|
83594
83744
|
path: baselinePath,
|
|
@@ -83619,8 +83769,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
83619
83769
|
message: `Baseline would exceed size cap (${json3.length} bytes > ${MAX_BASELINE_BYTES})`
|
|
83620
83770
|
};
|
|
83621
83771
|
}
|
|
83622
|
-
|
|
83623
|
-
|
|
83772
|
+
fs71.writeFileSync(tempPath, json3, "utf-8");
|
|
83773
|
+
fs71.renameSync(tempPath, baselinePath);
|
|
83624
83774
|
return {
|
|
83625
83775
|
status: "written",
|
|
83626
83776
|
path: baselinePath,
|
|
@@ -83645,7 +83795,7 @@ function loadBaseline(directory, phase) {
|
|
|
83645
83795
|
};
|
|
83646
83796
|
}
|
|
83647
83797
|
try {
|
|
83648
|
-
const raw =
|
|
83798
|
+
const raw = fs71.readFileSync(baselinePath, "utf-8");
|
|
83649
83799
|
const parsed = JSON.parse(raw);
|
|
83650
83800
|
if (parsed.schema_version !== BASELINE_SCHEMA_VERSION) {
|
|
83651
83801
|
return {
|
|
@@ -83687,17 +83837,17 @@ var SEVERITY_ORDER = {
|
|
|
83687
83837
|
};
|
|
83688
83838
|
function shouldSkipFile(filePath) {
|
|
83689
83839
|
try {
|
|
83690
|
-
const stats =
|
|
83840
|
+
const stats = fs72.statSync(filePath);
|
|
83691
83841
|
if (stats.size > MAX_FILE_SIZE_BYTES8) {
|
|
83692
83842
|
return { skip: true, reason: "file too large" };
|
|
83693
83843
|
}
|
|
83694
83844
|
if (stats.size === 0) {
|
|
83695
83845
|
return { skip: true, reason: "empty file" };
|
|
83696
83846
|
}
|
|
83697
|
-
const fd =
|
|
83847
|
+
const fd = fs72.openSync(filePath, "r");
|
|
83698
83848
|
const buffer = Buffer.alloc(8192);
|
|
83699
|
-
const bytesRead =
|
|
83700
|
-
|
|
83849
|
+
const bytesRead = fs72.readSync(fd, buffer, 0, 8192, 0);
|
|
83850
|
+
fs72.closeSync(fd);
|
|
83701
83851
|
if (bytesRead > 0) {
|
|
83702
83852
|
let nullCount = 0;
|
|
83703
83853
|
for (let i2 = 0;i2 < bytesRead; i2++) {
|
|
@@ -83736,7 +83886,7 @@ function countBySeverity(findings) {
|
|
|
83736
83886
|
}
|
|
83737
83887
|
function scanFileWithTierA(filePath, language) {
|
|
83738
83888
|
try {
|
|
83739
|
-
const content =
|
|
83889
|
+
const content = fs72.readFileSync(filePath, "utf-8");
|
|
83740
83890
|
const findings = executeRulesSync(filePath, content, language);
|
|
83741
83891
|
return findings.map((f) => ({
|
|
83742
83892
|
rule_id: f.rule_id,
|
|
@@ -83789,13 +83939,13 @@ async function sastScan(input, directory, config3) {
|
|
|
83789
83939
|
_filesSkipped++;
|
|
83790
83940
|
continue;
|
|
83791
83941
|
}
|
|
83792
|
-
const resolvedPath =
|
|
83793
|
-
const resolvedDirectory =
|
|
83794
|
-
if (!resolvedPath.startsWith(resolvedDirectory +
|
|
83942
|
+
const resolvedPath = path90.isAbsolute(filePath) ? filePath : path90.resolve(directory, filePath);
|
|
83943
|
+
const resolvedDirectory = path90.resolve(directory);
|
|
83944
|
+
if (!resolvedPath.startsWith(resolvedDirectory + path90.sep) && resolvedPath !== resolvedDirectory) {
|
|
83795
83945
|
_filesSkipped++;
|
|
83796
83946
|
continue;
|
|
83797
83947
|
}
|
|
83798
|
-
if (!
|
|
83948
|
+
if (!fs72.existsSync(resolvedPath)) {
|
|
83799
83949
|
_filesSkipped++;
|
|
83800
83950
|
continue;
|
|
83801
83951
|
}
|
|
@@ -84102,18 +84252,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
84102
84252
|
let resolved;
|
|
84103
84253
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
84104
84254
|
if (isWinAbs) {
|
|
84105
|
-
resolved =
|
|
84106
|
-
} else if (
|
|
84107
|
-
resolved =
|
|
84255
|
+
resolved = path91.win32.resolve(inputPath);
|
|
84256
|
+
} else if (path91.isAbsolute(inputPath)) {
|
|
84257
|
+
resolved = path91.resolve(inputPath);
|
|
84108
84258
|
} else {
|
|
84109
|
-
resolved =
|
|
84259
|
+
resolved = path91.resolve(baseDir, inputPath);
|
|
84110
84260
|
}
|
|
84111
|
-
const workspaceResolved =
|
|
84261
|
+
const workspaceResolved = path91.resolve(workspaceDir);
|
|
84112
84262
|
let relative20;
|
|
84113
84263
|
if (isWinAbs) {
|
|
84114
|
-
relative20 =
|
|
84264
|
+
relative20 = path91.win32.relative(workspaceResolved, resolved);
|
|
84115
84265
|
} else {
|
|
84116
|
-
relative20 =
|
|
84266
|
+
relative20 = path91.relative(workspaceResolved, resolved);
|
|
84117
84267
|
}
|
|
84118
84268
|
if (relative20.startsWith("..")) {
|
|
84119
84269
|
return "path traversal detected";
|
|
@@ -84178,7 +84328,7 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
84178
84328
|
if (typeof file3 !== "string") {
|
|
84179
84329
|
continue;
|
|
84180
84330
|
}
|
|
84181
|
-
const resolvedPath =
|
|
84331
|
+
const resolvedPath = path91.resolve(file3);
|
|
84182
84332
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
84183
84333
|
if (validationError) {
|
|
84184
84334
|
continue;
|
|
@@ -84335,7 +84485,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
84335
84485
|
skippedFiles++;
|
|
84336
84486
|
continue;
|
|
84337
84487
|
}
|
|
84338
|
-
const resolvedPath =
|
|
84488
|
+
const resolvedPath = path91.resolve(file3);
|
|
84339
84489
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
84340
84490
|
if (validationError) {
|
|
84341
84491
|
skippedFiles++;
|
|
@@ -84353,14 +84503,14 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
84353
84503
|
};
|
|
84354
84504
|
}
|
|
84355
84505
|
for (const file3 of validatedFiles) {
|
|
84356
|
-
const ext =
|
|
84506
|
+
const ext = path91.extname(file3).toLowerCase();
|
|
84357
84507
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
84358
84508
|
skippedFiles++;
|
|
84359
84509
|
continue;
|
|
84360
84510
|
}
|
|
84361
84511
|
let stat6;
|
|
84362
84512
|
try {
|
|
84363
|
-
stat6 =
|
|
84513
|
+
stat6 = fs73.statSync(file3);
|
|
84364
84514
|
} catch {
|
|
84365
84515
|
skippedFiles++;
|
|
84366
84516
|
continue;
|
|
@@ -84371,7 +84521,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
84371
84521
|
}
|
|
84372
84522
|
let content;
|
|
84373
84523
|
try {
|
|
84374
|
-
const buffer =
|
|
84524
|
+
const buffer = fs73.readFileSync(file3);
|
|
84375
84525
|
if (buffer.includes(0)) {
|
|
84376
84526
|
skippedFiles++;
|
|
84377
84527
|
continue;
|
|
@@ -84572,7 +84722,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
|
|
|
84572
84722
|
const preexistingFindings = [];
|
|
84573
84723
|
for (const finding of findings) {
|
|
84574
84724
|
const filePath = finding.location.file;
|
|
84575
|
-
const normalised =
|
|
84725
|
+
const normalised = path91.relative(directory, filePath).replace(/\\/g, "/");
|
|
84576
84726
|
const changedLines = changedLineRanges.get(normalised);
|
|
84577
84727
|
if (changedLines?.has(finding.location.line)) {
|
|
84578
84728
|
newFindings.push(finding);
|
|
@@ -84623,7 +84773,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
|
|
|
84623
84773
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
84624
84774
|
continue;
|
|
84625
84775
|
}
|
|
84626
|
-
changedFiles.push(
|
|
84776
|
+
changedFiles.push(path91.resolve(directory, file3));
|
|
84627
84777
|
}
|
|
84628
84778
|
if (changedFiles.length === 0) {
|
|
84629
84779
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -84824,7 +84974,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
84824
84974
|
};
|
|
84825
84975
|
return JSON.stringify(errorResult, null, 2);
|
|
84826
84976
|
}
|
|
84827
|
-
const resolvedDirectory =
|
|
84977
|
+
const resolvedDirectory = path91.resolve(typedArgs.directory);
|
|
84828
84978
|
const workspaceAnchor = resolvedDirectory;
|
|
84829
84979
|
const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
|
|
84830
84980
|
if (dirError) {
|
|
@@ -84865,7 +85015,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
84865
85015
|
});
|
|
84866
85016
|
// src/tools/repo-map.ts
|
|
84867
85017
|
init_zod();
|
|
84868
|
-
import * as
|
|
85018
|
+
import * as path92 from "node:path";
|
|
84869
85019
|
init_path_security();
|
|
84870
85020
|
init_create_tool();
|
|
84871
85021
|
var VALID_ACTIONS = [
|
|
@@ -84890,7 +85040,7 @@ function validateFile(p) {
|
|
|
84890
85040
|
return "file contains control characters";
|
|
84891
85041
|
if (containsPathTraversal(p))
|
|
84892
85042
|
return "file contains path traversal";
|
|
84893
|
-
if (
|
|
85043
|
+
if (path92.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
|
|
84894
85044
|
return "file must be a workspace-relative path, not absolute";
|
|
84895
85045
|
}
|
|
84896
85046
|
return null;
|
|
@@ -84913,8 +85063,8 @@ function ok(action, payload) {
|
|
|
84913
85063
|
}
|
|
84914
85064
|
function toRelativeGraphPath(input, workspaceRoot) {
|
|
84915
85065
|
const normalized = input.replace(/\\/g, "/");
|
|
84916
|
-
if (
|
|
84917
|
-
const rel =
|
|
85066
|
+
if (path92.isAbsolute(normalized)) {
|
|
85067
|
+
const rel = path92.relative(workspaceRoot, normalized).replace(/\\/g, "/");
|
|
84918
85068
|
return normalizeGraphPath2(rel);
|
|
84919
85069
|
}
|
|
84920
85070
|
return normalizeGraphPath2(normalized);
|
|
@@ -85058,8 +85208,8 @@ var repo_map = createSwarmTool({
|
|
|
85058
85208
|
// src/tools/req-coverage.ts
|
|
85059
85209
|
init_zod();
|
|
85060
85210
|
init_create_tool();
|
|
85061
|
-
import * as
|
|
85062
|
-
import * as
|
|
85211
|
+
import * as fs74 from "node:fs";
|
|
85212
|
+
import * as path93 from "node:path";
|
|
85063
85213
|
var SPEC_FILE = ".swarm/spec.md";
|
|
85064
85214
|
var EVIDENCE_DIR4 = ".swarm/evidence";
|
|
85065
85215
|
var OBLIGATION_KEYWORDS = ["MUST", "SHOULD", "SHALL"];
|
|
@@ -85118,19 +85268,19 @@ function extractObligationAndText(id, lineText) {
|
|
|
85118
85268
|
var PHASE_TASK_ID_REGEX = /^\d+\.\d+(\.\d+)*$/;
|
|
85119
85269
|
function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
85120
85270
|
const touchedFiles = new Set;
|
|
85121
|
-
if (!
|
|
85271
|
+
if (!fs74.existsSync(evidenceDir) || !fs74.statSync(evidenceDir).isDirectory()) {
|
|
85122
85272
|
return [];
|
|
85123
85273
|
}
|
|
85124
85274
|
let entries;
|
|
85125
85275
|
try {
|
|
85126
|
-
entries =
|
|
85276
|
+
entries = fs74.readdirSync(evidenceDir);
|
|
85127
85277
|
} catch {
|
|
85128
85278
|
return [];
|
|
85129
85279
|
}
|
|
85130
85280
|
for (const entry of entries) {
|
|
85131
|
-
const entryPath =
|
|
85281
|
+
const entryPath = path93.join(evidenceDir, entry);
|
|
85132
85282
|
try {
|
|
85133
|
-
const stat6 =
|
|
85283
|
+
const stat6 = fs74.statSync(entryPath);
|
|
85134
85284
|
if (!stat6.isDirectory()) {
|
|
85135
85285
|
continue;
|
|
85136
85286
|
}
|
|
@@ -85144,14 +85294,14 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
85144
85294
|
if (entryPhase !== String(phase)) {
|
|
85145
85295
|
continue;
|
|
85146
85296
|
}
|
|
85147
|
-
const evidenceFilePath =
|
|
85297
|
+
const evidenceFilePath = path93.join(entryPath, "evidence.json");
|
|
85148
85298
|
try {
|
|
85149
|
-
const resolvedPath =
|
|
85150
|
-
const evidenceDirResolved =
|
|
85151
|
-
if (!resolvedPath.startsWith(evidenceDirResolved +
|
|
85299
|
+
const resolvedPath = path93.resolve(evidenceFilePath);
|
|
85300
|
+
const evidenceDirResolved = path93.resolve(evidenceDir);
|
|
85301
|
+
if (!resolvedPath.startsWith(evidenceDirResolved + path93.sep)) {
|
|
85152
85302
|
continue;
|
|
85153
85303
|
}
|
|
85154
|
-
const stat6 =
|
|
85304
|
+
const stat6 = fs74.lstatSync(evidenceFilePath);
|
|
85155
85305
|
if (!stat6.isFile()) {
|
|
85156
85306
|
continue;
|
|
85157
85307
|
}
|
|
@@ -85163,7 +85313,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
85163
85313
|
}
|
|
85164
85314
|
let content;
|
|
85165
85315
|
try {
|
|
85166
|
-
content =
|
|
85316
|
+
content = fs74.readFileSync(evidenceFilePath, "utf-8");
|
|
85167
85317
|
} catch {
|
|
85168
85318
|
continue;
|
|
85169
85319
|
}
|
|
@@ -85182,7 +85332,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
85182
85332
|
if (Array.isArray(diffEntry.files_changed)) {
|
|
85183
85333
|
for (const file3 of diffEntry.files_changed) {
|
|
85184
85334
|
if (typeof file3 === "string") {
|
|
85185
|
-
touchedFiles.add(
|
|
85335
|
+
touchedFiles.add(path93.resolve(cwd, file3));
|
|
85186
85336
|
}
|
|
85187
85337
|
}
|
|
85188
85338
|
}
|
|
@@ -85195,12 +85345,12 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
85195
85345
|
}
|
|
85196
85346
|
function searchFileForKeywords(filePath, keywords, cwd) {
|
|
85197
85347
|
try {
|
|
85198
|
-
const resolvedPath =
|
|
85199
|
-
const cwdResolved =
|
|
85348
|
+
const resolvedPath = path93.resolve(filePath);
|
|
85349
|
+
const cwdResolved = path93.resolve(cwd);
|
|
85200
85350
|
if (!resolvedPath.startsWith(cwdResolved)) {
|
|
85201
85351
|
return false;
|
|
85202
85352
|
}
|
|
85203
|
-
const content =
|
|
85353
|
+
const content = fs74.readFileSync(resolvedPath, "utf-8");
|
|
85204
85354
|
for (const keyword of keywords) {
|
|
85205
85355
|
const regex = new RegExp(`\\b${keyword}\\b`, "i");
|
|
85206
85356
|
if (regex.test(content)) {
|
|
@@ -85330,10 +85480,10 @@ var req_coverage = createSwarmTool({
|
|
|
85330
85480
|
}, null, 2);
|
|
85331
85481
|
}
|
|
85332
85482
|
const cwd = inputDirectory || directory;
|
|
85333
|
-
const specPath =
|
|
85483
|
+
const specPath = path93.join(cwd, SPEC_FILE);
|
|
85334
85484
|
let specContent;
|
|
85335
85485
|
try {
|
|
85336
|
-
specContent =
|
|
85486
|
+
specContent = fs74.readFileSync(specPath, "utf-8");
|
|
85337
85487
|
} catch (readError) {
|
|
85338
85488
|
return JSON.stringify({
|
|
85339
85489
|
success: false,
|
|
@@ -85357,7 +85507,7 @@ var req_coverage = createSwarmTool({
|
|
|
85357
85507
|
message: "No FR requirements found in spec.md"
|
|
85358
85508
|
}, null, 2);
|
|
85359
85509
|
}
|
|
85360
|
-
const evidenceDir =
|
|
85510
|
+
const evidenceDir = path93.join(cwd, EVIDENCE_DIR4);
|
|
85361
85511
|
const touchedFiles = readTouchedFiles(evidenceDir, phase, cwd);
|
|
85362
85512
|
const analyzedRequirements = [];
|
|
85363
85513
|
let coveredCount = 0;
|
|
@@ -85383,12 +85533,12 @@ var req_coverage = createSwarmTool({
|
|
|
85383
85533
|
requirements: analyzedRequirements
|
|
85384
85534
|
};
|
|
85385
85535
|
const reportFilename = `req-coverage-phase-${phase}.json`;
|
|
85386
|
-
const reportPath =
|
|
85536
|
+
const reportPath = path93.join(evidenceDir, reportFilename);
|
|
85387
85537
|
try {
|
|
85388
|
-
if (!
|
|
85389
|
-
|
|
85538
|
+
if (!fs74.existsSync(evidenceDir)) {
|
|
85539
|
+
fs74.mkdirSync(evidenceDir, { recursive: true });
|
|
85390
85540
|
}
|
|
85391
|
-
|
|
85541
|
+
fs74.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8");
|
|
85392
85542
|
} catch (writeError) {
|
|
85393
85543
|
console.warn(`Failed to write coverage report: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
85394
85544
|
}
|
|
@@ -85470,8 +85620,8 @@ init_plan_schema();
|
|
|
85470
85620
|
init_qa_gate_profile();
|
|
85471
85621
|
init_file_locks();
|
|
85472
85622
|
import * as crypto9 from "node:crypto";
|
|
85473
|
-
import * as
|
|
85474
|
-
import * as
|
|
85623
|
+
import * as fs75 from "node:fs";
|
|
85624
|
+
import * as path94 from "node:path";
|
|
85475
85625
|
init_ledger();
|
|
85476
85626
|
init_manager();
|
|
85477
85627
|
init_state();
|
|
@@ -85549,17 +85699,17 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
85549
85699
|
};
|
|
85550
85700
|
}
|
|
85551
85701
|
if (args2.working_directory && fallbackDir) {
|
|
85552
|
-
const resolvedTarget =
|
|
85553
|
-
const resolvedRoot =
|
|
85702
|
+
const resolvedTarget = path94.resolve(args2.working_directory);
|
|
85703
|
+
const resolvedRoot = path94.resolve(fallbackDir);
|
|
85554
85704
|
let fallbackExists = false;
|
|
85555
85705
|
try {
|
|
85556
|
-
|
|
85706
|
+
fs75.accessSync(resolvedRoot, fs75.constants.F_OK);
|
|
85557
85707
|
fallbackExists = true;
|
|
85558
85708
|
} catch {
|
|
85559
85709
|
fallbackExists = false;
|
|
85560
85710
|
}
|
|
85561
85711
|
if (fallbackExists) {
|
|
85562
|
-
const isSubdirectory = resolvedTarget.startsWith(resolvedRoot +
|
|
85712
|
+
const isSubdirectory = resolvedTarget.startsWith(resolvedRoot + path94.sep);
|
|
85563
85713
|
if (isSubdirectory) {
|
|
85564
85714
|
return {
|
|
85565
85715
|
success: false,
|
|
@@ -85575,11 +85725,11 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
85575
85725
|
let specMtime;
|
|
85576
85726
|
let specHash;
|
|
85577
85727
|
if (process.env.SWARM_SKIP_SPEC_GATE !== "1") {
|
|
85578
|
-
const specPath =
|
|
85728
|
+
const specPath = path94.join(targetWorkspace, ".swarm", "spec.md");
|
|
85579
85729
|
try {
|
|
85580
|
-
const stat6 = await
|
|
85730
|
+
const stat6 = await fs75.promises.stat(specPath);
|
|
85581
85731
|
specMtime = stat6.mtime.toISOString();
|
|
85582
|
-
const content = await
|
|
85732
|
+
const content = await fs75.promises.readFile(specPath, "utf8");
|
|
85583
85733
|
specHash = crypto9.createHash("sha256").update(content).digest("hex");
|
|
85584
85734
|
} catch {
|
|
85585
85735
|
return {
|
|
@@ -85591,10 +85741,10 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
85591
85741
|
}
|
|
85592
85742
|
}
|
|
85593
85743
|
if (process.env.SWARM_SKIP_GATE_SELECTION !== "1") {
|
|
85594
|
-
const contextPath =
|
|
85744
|
+
const contextPath = path94.join(targetWorkspace, ".swarm", "context.md");
|
|
85595
85745
|
let contextContent = "";
|
|
85596
85746
|
try {
|
|
85597
|
-
contextContent = await
|
|
85747
|
+
contextContent = await fs75.promises.readFile(contextPath, "utf8");
|
|
85598
85748
|
} catch {}
|
|
85599
85749
|
const hasPendingSection = contextContent.includes("## Pending QA Gate Selection");
|
|
85600
85750
|
if (!hasPendingSection) {
|
|
@@ -85741,14 +85891,14 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
85741
85891
|
}
|
|
85742
85892
|
await writeCheckpoint(dir).catch(() => {});
|
|
85743
85893
|
try {
|
|
85744
|
-
const markerPath =
|
|
85894
|
+
const markerPath = path94.join(dir, ".swarm", ".plan-write-marker");
|
|
85745
85895
|
const marker = JSON.stringify({
|
|
85746
85896
|
source: "save_plan",
|
|
85747
85897
|
timestamp: new Date().toISOString(),
|
|
85748
85898
|
phases_count: plan.phases.length,
|
|
85749
85899
|
tasks_count: tasksCount
|
|
85750
85900
|
});
|
|
85751
|
-
await
|
|
85901
|
+
await fs75.promises.writeFile(markerPath, marker, "utf8");
|
|
85752
85902
|
} catch {}
|
|
85753
85903
|
const warnings = [];
|
|
85754
85904
|
let criticReviewFound = false;
|
|
@@ -85764,7 +85914,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
85764
85914
|
return {
|
|
85765
85915
|
success: true,
|
|
85766
85916
|
message: "Plan saved successfully",
|
|
85767
|
-
plan_path:
|
|
85917
|
+
plan_path: path94.join(dir, ".swarm", "plan.json"),
|
|
85768
85918
|
phases_count: plan.phases.length,
|
|
85769
85919
|
tasks_count: tasksCount,
|
|
85770
85920
|
...resolvedProfile !== undefined ? { execution_profile: resolvedProfile } : {},
|
|
@@ -85816,8 +85966,8 @@ var save_plan = createSwarmTool({
|
|
|
85816
85966
|
// src/tools/sbom-generate.ts
|
|
85817
85967
|
init_zod();
|
|
85818
85968
|
init_manager2();
|
|
85819
|
-
import * as
|
|
85820
|
-
import * as
|
|
85969
|
+
import * as fs76 from "node:fs";
|
|
85970
|
+
import * as path95 from "node:path";
|
|
85821
85971
|
|
|
85822
85972
|
// src/sbom/detectors/index.ts
|
|
85823
85973
|
init_utils();
|
|
@@ -86665,9 +86815,9 @@ function findManifestFiles(rootDir) {
|
|
|
86665
86815
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
86666
86816
|
function searchDir(dir) {
|
|
86667
86817
|
try {
|
|
86668
|
-
const entries =
|
|
86818
|
+
const entries = fs76.readdirSync(dir, { withFileTypes: true });
|
|
86669
86819
|
for (const entry of entries) {
|
|
86670
|
-
const fullPath =
|
|
86820
|
+
const fullPath = path95.join(dir, entry.name);
|
|
86671
86821
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
86672
86822
|
continue;
|
|
86673
86823
|
}
|
|
@@ -86676,7 +86826,7 @@ function findManifestFiles(rootDir) {
|
|
|
86676
86826
|
} else if (entry.isFile()) {
|
|
86677
86827
|
for (const pattern of patterns) {
|
|
86678
86828
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
86679
|
-
manifestFiles.push(
|
|
86829
|
+
manifestFiles.push(path95.relative(rootDir, fullPath));
|
|
86680
86830
|
break;
|
|
86681
86831
|
}
|
|
86682
86832
|
}
|
|
@@ -86692,13 +86842,13 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
86692
86842
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
86693
86843
|
for (const dir of directories) {
|
|
86694
86844
|
try {
|
|
86695
|
-
const entries =
|
|
86845
|
+
const entries = fs76.readdirSync(dir, { withFileTypes: true });
|
|
86696
86846
|
for (const entry of entries) {
|
|
86697
|
-
const fullPath =
|
|
86847
|
+
const fullPath = path95.join(dir, entry.name);
|
|
86698
86848
|
if (entry.isFile()) {
|
|
86699
86849
|
for (const pattern of patterns) {
|
|
86700
86850
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
86701
|
-
found.push(
|
|
86851
|
+
found.push(path95.relative(workingDir, fullPath));
|
|
86702
86852
|
break;
|
|
86703
86853
|
}
|
|
86704
86854
|
}
|
|
@@ -86711,11 +86861,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
86711
86861
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
86712
86862
|
const dirs = new Set;
|
|
86713
86863
|
for (const file3 of changedFiles) {
|
|
86714
|
-
let currentDir =
|
|
86864
|
+
let currentDir = path95.dirname(file3);
|
|
86715
86865
|
while (true) {
|
|
86716
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
86717
|
-
dirs.add(
|
|
86718
|
-
const parent =
|
|
86866
|
+
if (currentDir && currentDir !== "." && currentDir !== path95.sep) {
|
|
86867
|
+
dirs.add(path95.join(workingDir, currentDir));
|
|
86868
|
+
const parent = path95.dirname(currentDir);
|
|
86719
86869
|
if (parent === currentDir)
|
|
86720
86870
|
break;
|
|
86721
86871
|
currentDir = parent;
|
|
@@ -86729,7 +86879,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
86729
86879
|
}
|
|
86730
86880
|
function ensureOutputDir(outputDir) {
|
|
86731
86881
|
try {
|
|
86732
|
-
|
|
86882
|
+
fs76.mkdirSync(outputDir, { recursive: true });
|
|
86733
86883
|
} catch (error93) {
|
|
86734
86884
|
if (!error93 || error93.code !== "EEXIST") {
|
|
86735
86885
|
throw error93;
|
|
@@ -86799,7 +86949,7 @@ var sbom_generate = createSwarmTool({
|
|
|
86799
86949
|
const changedFiles = obj.changed_files;
|
|
86800
86950
|
const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
|
|
86801
86951
|
const workingDir = directory;
|
|
86802
|
-
const outputDir =
|
|
86952
|
+
const outputDir = path95.isAbsolute(relativeOutputDir) ? relativeOutputDir : path95.join(workingDir, relativeOutputDir);
|
|
86803
86953
|
let manifestFiles = [];
|
|
86804
86954
|
if (scope === "all") {
|
|
86805
86955
|
manifestFiles = findManifestFiles(workingDir);
|
|
@@ -86822,11 +86972,11 @@ var sbom_generate = createSwarmTool({
|
|
|
86822
86972
|
const processedFiles = [];
|
|
86823
86973
|
for (const manifestFile of manifestFiles) {
|
|
86824
86974
|
try {
|
|
86825
|
-
const fullPath =
|
|
86826
|
-
if (!
|
|
86975
|
+
const fullPath = path95.isAbsolute(manifestFile) ? manifestFile : path95.join(workingDir, manifestFile);
|
|
86976
|
+
if (!fs76.existsSync(fullPath)) {
|
|
86827
86977
|
continue;
|
|
86828
86978
|
}
|
|
86829
|
-
const content =
|
|
86979
|
+
const content = fs76.readFileSync(fullPath, "utf-8");
|
|
86830
86980
|
const components = detectComponents(manifestFile, content);
|
|
86831
86981
|
processedFiles.push(manifestFile);
|
|
86832
86982
|
if (components.length > 0) {
|
|
@@ -86839,8 +86989,8 @@ var sbom_generate = createSwarmTool({
|
|
|
86839
86989
|
const bom = generateCycloneDX(allComponents);
|
|
86840
86990
|
const bomJson = serializeCycloneDX(bom);
|
|
86841
86991
|
const filename = generateSbomFilename();
|
|
86842
|
-
const outputPath =
|
|
86843
|
-
|
|
86992
|
+
const outputPath = path95.join(outputDir, filename);
|
|
86993
|
+
fs76.writeFileSync(outputPath, bomJson, "utf-8");
|
|
86844
86994
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
86845
86995
|
try {
|
|
86846
86996
|
const timestamp = new Date().toISOString();
|
|
@@ -86882,8 +87032,8 @@ var sbom_generate = createSwarmTool({
|
|
|
86882
87032
|
// src/tools/schema-drift.ts
|
|
86883
87033
|
init_zod();
|
|
86884
87034
|
init_create_tool();
|
|
86885
|
-
import * as
|
|
86886
|
-
import * as
|
|
87035
|
+
import * as fs77 from "node:fs";
|
|
87036
|
+
import * as path96 from "node:path";
|
|
86887
87037
|
var SPEC_CANDIDATES = [
|
|
86888
87038
|
"openapi.json",
|
|
86889
87039
|
"openapi.yaml",
|
|
@@ -86915,28 +87065,28 @@ function normalizePath3(p) {
|
|
|
86915
87065
|
}
|
|
86916
87066
|
function discoverSpecFile(cwd, specFileArg) {
|
|
86917
87067
|
if (specFileArg) {
|
|
86918
|
-
const resolvedPath =
|
|
86919
|
-
const normalizedCwd = cwd.endsWith(
|
|
87068
|
+
const resolvedPath = path96.resolve(cwd, specFileArg);
|
|
87069
|
+
const normalizedCwd = cwd.endsWith(path96.sep) ? cwd : cwd + path96.sep;
|
|
86920
87070
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
86921
87071
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
86922
87072
|
}
|
|
86923
|
-
const ext =
|
|
87073
|
+
const ext = path96.extname(resolvedPath).toLowerCase();
|
|
86924
87074
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
86925
87075
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
86926
87076
|
}
|
|
86927
|
-
const stats =
|
|
87077
|
+
const stats = fs77.statSync(resolvedPath);
|
|
86928
87078
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
86929
87079
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
86930
87080
|
}
|
|
86931
|
-
if (!
|
|
87081
|
+
if (!fs77.existsSync(resolvedPath)) {
|
|
86932
87082
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
86933
87083
|
}
|
|
86934
87084
|
return resolvedPath;
|
|
86935
87085
|
}
|
|
86936
87086
|
for (const candidate of SPEC_CANDIDATES) {
|
|
86937
|
-
const candidatePath =
|
|
86938
|
-
if (
|
|
86939
|
-
const stats =
|
|
87087
|
+
const candidatePath = path96.resolve(cwd, candidate);
|
|
87088
|
+
if (fs77.existsSync(candidatePath)) {
|
|
87089
|
+
const stats = fs77.statSync(candidatePath);
|
|
86940
87090
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
86941
87091
|
return candidatePath;
|
|
86942
87092
|
}
|
|
@@ -86945,8 +87095,8 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
86945
87095
|
return null;
|
|
86946
87096
|
}
|
|
86947
87097
|
function parseSpec(specFile) {
|
|
86948
|
-
const content =
|
|
86949
|
-
const ext =
|
|
87098
|
+
const content = fs77.readFileSync(specFile, "utf-8");
|
|
87099
|
+
const ext = path96.extname(specFile).toLowerCase();
|
|
86950
87100
|
if (ext === ".json") {
|
|
86951
87101
|
return parseJsonSpec(content);
|
|
86952
87102
|
}
|
|
@@ -87017,12 +87167,12 @@ function extractRoutes(cwd) {
|
|
|
87017
87167
|
function walkDir(dir) {
|
|
87018
87168
|
let entries;
|
|
87019
87169
|
try {
|
|
87020
|
-
entries =
|
|
87170
|
+
entries = fs77.readdirSync(dir, { withFileTypes: true });
|
|
87021
87171
|
} catch {
|
|
87022
87172
|
return;
|
|
87023
87173
|
}
|
|
87024
87174
|
for (const entry of entries) {
|
|
87025
|
-
const fullPath =
|
|
87175
|
+
const fullPath = path96.join(dir, entry.name);
|
|
87026
87176
|
if (entry.isSymbolicLink()) {
|
|
87027
87177
|
continue;
|
|
87028
87178
|
}
|
|
@@ -87032,7 +87182,7 @@ function extractRoutes(cwd) {
|
|
|
87032
87182
|
}
|
|
87033
87183
|
walkDir(fullPath);
|
|
87034
87184
|
} else if (entry.isFile()) {
|
|
87035
|
-
const ext =
|
|
87185
|
+
const ext = path96.extname(entry.name).toLowerCase();
|
|
87036
87186
|
const baseName = entry.name.toLowerCase();
|
|
87037
87187
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
87038
87188
|
continue;
|
|
@@ -87050,7 +87200,7 @@ function extractRoutes(cwd) {
|
|
|
87050
87200
|
}
|
|
87051
87201
|
function extractRoutesFromFile(filePath) {
|
|
87052
87202
|
const routes = [];
|
|
87053
|
-
const content =
|
|
87203
|
+
const content = fs77.readFileSync(filePath, "utf-8");
|
|
87054
87204
|
const lines = content.split(/\r?\n/);
|
|
87055
87205
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
87056
87206
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -87199,8 +87349,8 @@ init_zod();
|
|
|
87199
87349
|
init_bun_compat();
|
|
87200
87350
|
init_path_security();
|
|
87201
87351
|
init_create_tool();
|
|
87202
|
-
import * as
|
|
87203
|
-
import * as
|
|
87352
|
+
import * as fs78 from "node:fs";
|
|
87353
|
+
import * as path97 from "node:path";
|
|
87204
87354
|
var DEFAULT_MAX_RESULTS = 100;
|
|
87205
87355
|
var DEFAULT_MAX_LINES = 200;
|
|
87206
87356
|
var REGEX_TIMEOUT_MS = 5000;
|
|
@@ -87236,11 +87386,11 @@ function containsWindowsAttacks3(str) {
|
|
|
87236
87386
|
}
|
|
87237
87387
|
function isPathInWorkspace3(filePath, workspace) {
|
|
87238
87388
|
try {
|
|
87239
|
-
const resolvedPath =
|
|
87240
|
-
const realWorkspace =
|
|
87241
|
-
const realResolvedPath =
|
|
87242
|
-
const relativePath =
|
|
87243
|
-
if (relativePath.startsWith("..") ||
|
|
87389
|
+
const resolvedPath = path97.resolve(workspace, filePath);
|
|
87390
|
+
const realWorkspace = fs78.realpathSync(workspace);
|
|
87391
|
+
const realResolvedPath = fs78.realpathSync(resolvedPath);
|
|
87392
|
+
const relativePath = path97.relative(realWorkspace, realResolvedPath);
|
|
87393
|
+
if (relativePath.startsWith("..") || path97.isAbsolute(relativePath)) {
|
|
87244
87394
|
return false;
|
|
87245
87395
|
}
|
|
87246
87396
|
return true;
|
|
@@ -87253,12 +87403,12 @@ function validatePathForRead2(filePath, workspace) {
|
|
|
87253
87403
|
}
|
|
87254
87404
|
function findRgInEnvPath() {
|
|
87255
87405
|
const searchPath = process.env.PATH ?? "";
|
|
87256
|
-
for (const dir of searchPath.split(
|
|
87406
|
+
for (const dir of searchPath.split(path97.delimiter)) {
|
|
87257
87407
|
if (!dir)
|
|
87258
87408
|
continue;
|
|
87259
87409
|
const isWindows = process.platform === "win32";
|
|
87260
|
-
const candidate =
|
|
87261
|
-
if (
|
|
87410
|
+
const candidate = path97.join(dir, isWindows ? "rg.exe" : "rg");
|
|
87411
|
+
if (fs78.existsSync(candidate))
|
|
87262
87412
|
return candidate;
|
|
87263
87413
|
}
|
|
87264
87414
|
return null;
|
|
@@ -87385,10 +87535,10 @@ function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
|
|
|
87385
87535
|
return files;
|
|
87386
87536
|
}
|
|
87387
87537
|
try {
|
|
87388
|
-
const entries =
|
|
87538
|
+
const entries = fs78.readdirSync(dir, { withFileTypes: true });
|
|
87389
87539
|
for (const entry of entries) {
|
|
87390
|
-
const fullPath =
|
|
87391
|
-
const relativePath =
|
|
87540
|
+
const fullPath = path97.join(dir, entry.name);
|
|
87541
|
+
const relativePath = path97.relative(workspace, fullPath);
|
|
87392
87542
|
if (!validatePathForRead2(fullPath, workspace)) {
|
|
87393
87543
|
continue;
|
|
87394
87544
|
}
|
|
@@ -87429,13 +87579,13 @@ async function fallbackSearch(opts) {
|
|
|
87429
87579
|
const matches = [];
|
|
87430
87580
|
let total = 0;
|
|
87431
87581
|
for (const file3 of files) {
|
|
87432
|
-
const fullPath =
|
|
87582
|
+
const fullPath = path97.join(opts.workspace, file3);
|
|
87433
87583
|
if (!validatePathForRead2(fullPath, opts.workspace)) {
|
|
87434
87584
|
continue;
|
|
87435
87585
|
}
|
|
87436
87586
|
let stats;
|
|
87437
87587
|
try {
|
|
87438
|
-
stats =
|
|
87588
|
+
stats = fs78.statSync(fullPath);
|
|
87439
87589
|
if (stats.size > MAX_FILE_SIZE_BYTES10) {
|
|
87440
87590
|
continue;
|
|
87441
87591
|
}
|
|
@@ -87444,7 +87594,7 @@ async function fallbackSearch(opts) {
|
|
|
87444
87594
|
}
|
|
87445
87595
|
let content;
|
|
87446
87596
|
try {
|
|
87447
|
-
content =
|
|
87597
|
+
content = fs78.readFileSync(fullPath, "utf-8");
|
|
87448
87598
|
} catch {
|
|
87449
87599
|
continue;
|
|
87450
87600
|
}
|
|
@@ -87556,7 +87706,7 @@ var search = createSwarmTool({
|
|
|
87556
87706
|
message: "Exclude pattern contains invalid Windows-specific sequence"
|
|
87557
87707
|
}, null, 2);
|
|
87558
87708
|
}
|
|
87559
|
-
if (!
|
|
87709
|
+
if (!fs78.existsSync(directory)) {
|
|
87560
87710
|
return JSON.stringify({
|
|
87561
87711
|
error: true,
|
|
87562
87712
|
type: "unknown",
|
|
@@ -87681,12 +87831,136 @@ var set_qa_gates = createSwarmTool({
|
|
|
87681
87831
|
return JSON.stringify(await executeSetQaGates(typedArgs, directory), null, 2);
|
|
87682
87832
|
}
|
|
87683
87833
|
});
|
|
87834
|
+
// src/tools/submit-phase-council-verdicts.ts
|
|
87835
|
+
init_zod();
|
|
87836
|
+
init_loader();
|
|
87837
|
+
init_create_tool();
|
|
87838
|
+
init_resolve_working_directory();
|
|
87839
|
+
var VerdictSchema2 = exports_external.object({
|
|
87840
|
+
agent: exports_external.enum(["critic", "reviewer", "sme", "test_engineer", "explorer"]),
|
|
87841
|
+
verdict: exports_external.enum(["APPROVE", "CONCERNS", "REJECT"]),
|
|
87842
|
+
confidence: exports_external.number().min(0).max(1),
|
|
87843
|
+
findings: exports_external.array(exports_external.object({
|
|
87844
|
+
severity: exports_external.enum(["HIGH", "MEDIUM", "LOW"]),
|
|
87845
|
+
category: exports_external.string().min(1),
|
|
87846
|
+
location: exports_external.string(),
|
|
87847
|
+
detail: exports_external.string(),
|
|
87848
|
+
evidence: exports_external.string()
|
|
87849
|
+
})),
|
|
87850
|
+
criteriaAssessed: exports_external.array(exports_external.string()),
|
|
87851
|
+
criteriaUnmet: exports_external.array(exports_external.string()),
|
|
87852
|
+
durationMs: exports_external.number().nonnegative()
|
|
87853
|
+
});
|
|
87854
|
+
var ArgsSchema4 = exports_external.object({
|
|
87855
|
+
phaseNumber: exports_external.number().int().min(1),
|
|
87856
|
+
swarmId: exports_external.string().min(1),
|
|
87857
|
+
phaseSummary: exports_external.string().min(1),
|
|
87858
|
+
roundNumber: exports_external.number().int().min(1).max(10).optional(),
|
|
87859
|
+
verdicts: exports_external.array(VerdictSchema2).min(1).max(5),
|
|
87860
|
+
working_directory: exports_external.string().optional()
|
|
87861
|
+
});
|
|
87862
|
+
var submit_phase_council_verdicts = createSwarmTool({
|
|
87863
|
+
description: "Submit pre-collected council member verdicts for PHASE-LEVEL synthesis. " + "PREREQUISITE — you MUST dispatch each council member (critic, reviewer, sme, " + "test_engineer, explorer) as separate Agent tasks with PHASE-SCOPED context and " + "collect their verdict responses BEFORE calling this tool. This tool performs " + "synthesis only — it does NOT dispatch, invoke, or contact council members. " + "Writes .swarm/evidence/{phase}/phase-council.json which is required by " + "phase_complete Gate 5 when council_mode is enabled. " + "Architect-only. Config-gated via council.enabled.",
|
|
87864
|
+
args: {
|
|
87865
|
+
phaseNumber: exports_external.number().int().min(1).describe("Phase number being reviewed (e.g. 1, 2, 3)"),
|
|
87866
|
+
swarmId: exports_external.string().min(1).describe('Swarm identifier, e.g. "mega"'),
|
|
87867
|
+
phaseSummary: exports_external.string().min(1).describe("2–4 sentence summary of what the phase accomplished"),
|
|
87868
|
+
roundNumber: exports_external.number().int().min(1).max(10).optional().describe("1-indexed round number. Defaults to 1."),
|
|
87869
|
+
verdicts: exports_external.array(exports_external.object({
|
|
87870
|
+
agent: exports_external.enum([
|
|
87871
|
+
"critic",
|
|
87872
|
+
"reviewer",
|
|
87873
|
+
"sme",
|
|
87874
|
+
"test_engineer",
|
|
87875
|
+
"explorer"
|
|
87876
|
+
]),
|
|
87877
|
+
verdict: exports_external.enum(["APPROVE", "CONCERNS", "REJECT"]),
|
|
87878
|
+
confidence: exports_external.number().min(0).max(1),
|
|
87879
|
+
findings: exports_external.array(exports_external.object({
|
|
87880
|
+
severity: exports_external.enum(["HIGH", "MEDIUM", "LOW"]),
|
|
87881
|
+
category: exports_external.string().min(1),
|
|
87882
|
+
location: exports_external.string(),
|
|
87883
|
+
detail: exports_external.string(),
|
|
87884
|
+
evidence: exports_external.string()
|
|
87885
|
+
})),
|
|
87886
|
+
criteriaAssessed: exports_external.array(exports_external.string()),
|
|
87887
|
+
criteriaUnmet: exports_external.array(exports_external.string()),
|
|
87888
|
+
durationMs: exports_external.number()
|
|
87889
|
+
})).min(1).max(5).describe("Collected CouncilMemberVerdict objects from all dispatched council members"),
|
|
87890
|
+
working_directory: exports_external.string().optional().describe("Working directory where the plan is located")
|
|
87891
|
+
},
|
|
87892
|
+
async execute(args2, directory) {
|
|
87893
|
+
const parsed = ArgsSchema4.safeParse(args2);
|
|
87894
|
+
if (!parsed.success) {
|
|
87895
|
+
return JSON.stringify({
|
|
87896
|
+
success: false,
|
|
87897
|
+
reason: "invalid arguments",
|
|
87898
|
+
errors: parsed.error.issues.map((i2) => ({
|
|
87899
|
+
path: i2.path.join("."),
|
|
87900
|
+
message: i2.message
|
|
87901
|
+
}))
|
|
87902
|
+
}, null, 2);
|
|
87903
|
+
}
|
|
87904
|
+
const input = parsed.data;
|
|
87905
|
+
const dirResult = resolveWorkingDirectory(input.working_directory, directory);
|
|
87906
|
+
if (!dirResult.success) {
|
|
87907
|
+
return JSON.stringify({ success: false, reason: dirResult.message }, null, 2);
|
|
87908
|
+
}
|
|
87909
|
+
const workingDir = dirResult.directory;
|
|
87910
|
+
const config3 = loadPluginConfig(workingDir);
|
|
87911
|
+
if (!config3.council?.enabled) {
|
|
87912
|
+
return JSON.stringify({
|
|
87913
|
+
success: false,
|
|
87914
|
+
reason: "council feature is disabled — set council.enabled: true in .opencode/opencode-swarm.json to enable"
|
|
87915
|
+
}, null, 2);
|
|
87916
|
+
}
|
|
87917
|
+
const effectiveMinimum = config3.council?.requireAllMembers ? 5 : config3.council?.minimumMembers ?? 3;
|
|
87918
|
+
const ALL_MEMBERS = [
|
|
87919
|
+
"critic",
|
|
87920
|
+
"reviewer",
|
|
87921
|
+
"sme",
|
|
87922
|
+
"test_engineer",
|
|
87923
|
+
"explorer"
|
|
87924
|
+
];
|
|
87925
|
+
const distinctMembers = new Set(input.verdicts.map((v) => v.agent));
|
|
87926
|
+
const membersVoted = [...distinctMembers];
|
|
87927
|
+
const membersAbsent = ALL_MEMBERS.filter((m) => !distinctMembers.has(m));
|
|
87928
|
+
if (membersVoted.length < effectiveMinimum) {
|
|
87929
|
+
return JSON.stringify({
|
|
87930
|
+
success: false,
|
|
87931
|
+
reason: "insufficient_quorum",
|
|
87932
|
+
message: `Phase council quorum not met: ${membersVoted.length} of ${effectiveMinimum} required members provided verdicts. ` + `Members voted: [${membersVoted.join(", ")}]. ` + `Members absent: [${membersAbsent.join(", ")}]. ` + `Dispatch the absent council members with phase-scoped context and collect their verdicts before calling submit_phase_council_verdicts.`,
|
|
87933
|
+
membersVoted,
|
|
87934
|
+
membersAbsent,
|
|
87935
|
+
quorumRequired: effectiveMinimum
|
|
87936
|
+
}, null, 2);
|
|
87937
|
+
}
|
|
87938
|
+
const synthesis = synthesizePhaseCouncilAdvisory(input.phaseNumber, input.phaseSummary, input.verdicts, input.roundNumber ?? 1, config3.council, workingDir);
|
|
87939
|
+
return JSON.stringify({
|
|
87940
|
+
success: true,
|
|
87941
|
+
overallVerdict: synthesis.overallVerdict,
|
|
87942
|
+
vetoedBy: synthesis.vetoedBy,
|
|
87943
|
+
roundNumber: synthesis.roundNumber,
|
|
87944
|
+
allCriteriaMet: synthesis.allCriteriaMet,
|
|
87945
|
+
requiredFixesCount: synthesis.requiredFixes?.length ?? 0,
|
|
87946
|
+
advisoryFindingsCount: synthesis.advisoryFindings?.length ?? 0,
|
|
87947
|
+
unresolvedConflictsCount: synthesis.unresolvedConflicts?.length ?? 0,
|
|
87948
|
+
advisoryNotes: synthesis.advisoryNotes ?? [],
|
|
87949
|
+
membersVoted,
|
|
87950
|
+
membersAbsent,
|
|
87951
|
+
quorumSize: membersVoted.length,
|
|
87952
|
+
quorumMet: true,
|
|
87953
|
+
evidencePath: synthesis.evidencePath,
|
|
87954
|
+
unifiedFeedbackMd: synthesis.unifiedFeedbackMd
|
|
87955
|
+
}, null, 2);
|
|
87956
|
+
}
|
|
87957
|
+
});
|
|
87684
87958
|
// src/tools/suggest-patch.ts
|
|
87685
87959
|
init_zod();
|
|
87686
87960
|
init_path_security();
|
|
87687
87961
|
init_create_tool();
|
|
87688
|
-
import * as
|
|
87689
|
-
import * as
|
|
87962
|
+
import * as fs79 from "node:fs";
|
|
87963
|
+
import * as path98 from "node:path";
|
|
87690
87964
|
var WINDOWS_RESERVED_NAMES4 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
87691
87965
|
function containsWindowsAttacks4(str) {
|
|
87692
87966
|
if (/:[^\\/]/.test(str))
|
|
@@ -87700,14 +87974,14 @@ function containsWindowsAttacks4(str) {
|
|
|
87700
87974
|
}
|
|
87701
87975
|
function isPathInWorkspace4(filePath, workspace) {
|
|
87702
87976
|
try {
|
|
87703
|
-
const resolvedPath =
|
|
87704
|
-
if (!
|
|
87977
|
+
const resolvedPath = path98.resolve(workspace, filePath);
|
|
87978
|
+
if (!fs79.existsSync(resolvedPath)) {
|
|
87705
87979
|
return true;
|
|
87706
87980
|
}
|
|
87707
|
-
const realWorkspace =
|
|
87708
|
-
const realResolvedPath =
|
|
87709
|
-
const relativePath =
|
|
87710
|
-
if (relativePath.startsWith("..") ||
|
|
87981
|
+
const realWorkspace = fs79.realpathSync(workspace);
|
|
87982
|
+
const realResolvedPath = fs79.realpathSync(resolvedPath);
|
|
87983
|
+
const relativePath = path98.relative(realWorkspace, realResolvedPath);
|
|
87984
|
+
if (relativePath.startsWith("..") || path98.isAbsolute(relativePath)) {
|
|
87711
87985
|
return false;
|
|
87712
87986
|
}
|
|
87713
87987
|
return true;
|
|
@@ -87879,7 +88153,7 @@ var suggestPatch = createSwarmTool({
|
|
|
87879
88153
|
message: "changes cannot be empty"
|
|
87880
88154
|
}, null, 2);
|
|
87881
88155
|
}
|
|
87882
|
-
if (!
|
|
88156
|
+
if (!fs79.existsSync(directory)) {
|
|
87883
88157
|
return JSON.stringify({
|
|
87884
88158
|
success: false,
|
|
87885
88159
|
error: true,
|
|
@@ -87915,8 +88189,8 @@ var suggestPatch = createSwarmTool({
|
|
|
87915
88189
|
});
|
|
87916
88190
|
continue;
|
|
87917
88191
|
}
|
|
87918
|
-
const fullPath =
|
|
87919
|
-
if (!
|
|
88192
|
+
const fullPath = path98.resolve(directory, change.file);
|
|
88193
|
+
if (!fs79.existsSync(fullPath)) {
|
|
87920
88194
|
errors5.push({
|
|
87921
88195
|
success: false,
|
|
87922
88196
|
error: true,
|
|
@@ -87930,7 +88204,7 @@ var suggestPatch = createSwarmTool({
|
|
|
87930
88204
|
}
|
|
87931
88205
|
let content;
|
|
87932
88206
|
try {
|
|
87933
|
-
content =
|
|
88207
|
+
content = fs79.readFileSync(fullPath, "utf-8");
|
|
87934
88208
|
} catch (err3) {
|
|
87935
88209
|
errors5.push({
|
|
87936
88210
|
success: false,
|
|
@@ -88177,8 +88451,8 @@ var generate_mutants = createSwarmTool({
|
|
|
88177
88451
|
// src/tools/lint-spec.ts
|
|
88178
88452
|
init_spec_schema();
|
|
88179
88453
|
init_create_tool();
|
|
88180
|
-
import * as
|
|
88181
|
-
import * as
|
|
88454
|
+
import * as fs80 from "node:fs";
|
|
88455
|
+
import * as path99 from "node:path";
|
|
88182
88456
|
var SPEC_FILE_NAME = "spec.md";
|
|
88183
88457
|
var SWARM_DIR2 = ".swarm";
|
|
88184
88458
|
var OBLIGATION_KEYWORDS2 = ["MUST", "SHALL", "SHOULD", "MAY"];
|
|
@@ -88231,8 +88505,8 @@ var lint_spec = createSwarmTool({
|
|
|
88231
88505
|
async execute(_args, directory) {
|
|
88232
88506
|
const errors5 = [];
|
|
88233
88507
|
const warnings = [];
|
|
88234
|
-
const specPath =
|
|
88235
|
-
if (!
|
|
88508
|
+
const specPath = path99.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
|
|
88509
|
+
if (!fs80.existsSync(specPath)) {
|
|
88236
88510
|
const result2 = {
|
|
88237
88511
|
valid: false,
|
|
88238
88512
|
specMtime: null,
|
|
@@ -88251,12 +88525,12 @@ var lint_spec = createSwarmTool({
|
|
|
88251
88525
|
}
|
|
88252
88526
|
let specMtime = null;
|
|
88253
88527
|
try {
|
|
88254
|
-
const stats =
|
|
88528
|
+
const stats = fs80.statSync(specPath);
|
|
88255
88529
|
specMtime = stats.mtime.toISOString();
|
|
88256
88530
|
} catch {}
|
|
88257
88531
|
let content;
|
|
88258
88532
|
try {
|
|
88259
|
-
content =
|
|
88533
|
+
content = fs80.readFileSync(specPath, "utf-8");
|
|
88260
88534
|
} catch (e) {
|
|
88261
88535
|
const result2 = {
|
|
88262
88536
|
valid: false,
|
|
@@ -88301,13 +88575,13 @@ var lint_spec = createSwarmTool({
|
|
|
88301
88575
|
});
|
|
88302
88576
|
// src/tools/mutation-test.ts
|
|
88303
88577
|
init_zod();
|
|
88304
|
-
import * as
|
|
88305
|
-
import * as
|
|
88578
|
+
import * as fs81 from "node:fs";
|
|
88579
|
+
import * as path101 from "node:path";
|
|
88306
88580
|
|
|
88307
88581
|
// src/mutation/engine.ts
|
|
88308
88582
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
88309
88583
|
import { unlinkSync as unlinkSync13, writeFileSync as writeFileSync20 } from "node:fs";
|
|
88310
|
-
import * as
|
|
88584
|
+
import * as path100 from "node:path";
|
|
88311
88585
|
|
|
88312
88586
|
// src/mutation/equivalence.ts
|
|
88313
88587
|
function isStaticallyEquivalent(originalCode, mutatedCode) {
|
|
@@ -88442,7 +88716,7 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
|
|
|
88442
88716
|
let patchFile;
|
|
88443
88717
|
try {
|
|
88444
88718
|
const safeId2 = patch.id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
88445
|
-
patchFile =
|
|
88719
|
+
patchFile = path100.join(workingDir, `.mutation_patch_${safeId2}.diff`);
|
|
88446
88720
|
try {
|
|
88447
88721
|
writeFileSync20(patchFile, patch.patch);
|
|
88448
88722
|
} catch (writeErr) {
|
|
@@ -88836,8 +89110,8 @@ var mutation_test = createSwarmTool({
|
|
|
88836
89110
|
];
|
|
88837
89111
|
for (const filePath of uniquePaths) {
|
|
88838
89112
|
try {
|
|
88839
|
-
const resolvedPath =
|
|
88840
|
-
sourceFiles.set(filePath,
|
|
89113
|
+
const resolvedPath = path101.resolve(cwd, filePath);
|
|
89114
|
+
sourceFiles.set(filePath, fs81.readFileSync(resolvedPath, "utf-8"));
|
|
88841
89115
|
} catch {}
|
|
88842
89116
|
}
|
|
88843
89117
|
const report = await executeMutationSuite(typedArgs.patches, typedArgs.test_command, typedArgs.files, cwd, undefined, undefined, sourceFiles.size > 0 ? sourceFiles : undefined);
|
|
@@ -88855,8 +89129,8 @@ var mutation_test = createSwarmTool({
|
|
|
88855
89129
|
init_zod();
|
|
88856
89130
|
init_manager2();
|
|
88857
89131
|
init_detector();
|
|
88858
|
-
import * as
|
|
88859
|
-
import * as
|
|
89132
|
+
import * as fs82 from "node:fs";
|
|
89133
|
+
import * as path102 from "node:path";
|
|
88860
89134
|
init_create_tool();
|
|
88861
89135
|
var MAX_FILE_SIZE2 = 2 * 1024 * 1024;
|
|
88862
89136
|
var BINARY_CHECK_BYTES = 8192;
|
|
@@ -88922,7 +89196,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
88922
89196
|
if (languages?.length) {
|
|
88923
89197
|
const lowerLangs = languages.map((l) => l.toLowerCase());
|
|
88924
89198
|
filesToCheck = filesToCheck.filter((file3) => {
|
|
88925
|
-
const ext =
|
|
89199
|
+
const ext = path102.extname(file3.path).toLowerCase();
|
|
88926
89200
|
const langDef = getLanguageForExtension(ext);
|
|
88927
89201
|
const fileProfile = getProfileForFile(file3.path);
|
|
88928
89202
|
const langId = fileProfile?.id || langDef?.id;
|
|
@@ -88935,7 +89209,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
88935
89209
|
let skippedCount = 0;
|
|
88936
89210
|
for (const fileInfo of filesToCheck) {
|
|
88937
89211
|
const { path: filePath } = fileInfo;
|
|
88938
|
-
const fullPath =
|
|
89212
|
+
const fullPath = path102.isAbsolute(filePath) ? filePath : path102.join(directory, filePath);
|
|
88939
89213
|
const result = {
|
|
88940
89214
|
path: filePath,
|
|
88941
89215
|
language: "",
|
|
@@ -88965,7 +89239,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
88965
89239
|
}
|
|
88966
89240
|
let content;
|
|
88967
89241
|
try {
|
|
88968
|
-
content =
|
|
89242
|
+
content = fs82.readFileSync(fullPath, "utf8");
|
|
88969
89243
|
} catch {
|
|
88970
89244
|
result.skipped_reason = "file_read_error";
|
|
88971
89245
|
skippedCount++;
|
|
@@ -88984,7 +89258,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
88984
89258
|
results.push(result);
|
|
88985
89259
|
continue;
|
|
88986
89260
|
}
|
|
88987
|
-
const ext =
|
|
89261
|
+
const ext = path102.extname(filePath).toLowerCase();
|
|
88988
89262
|
const langDef = getLanguageForExtension(ext);
|
|
88989
89263
|
result.language = profile?.id || langDef?.id || "unknown";
|
|
88990
89264
|
const errors5 = extractSyntaxErrors(parser, content);
|
|
@@ -89076,8 +89350,8 @@ init_zod();
|
|
|
89076
89350
|
init_utils();
|
|
89077
89351
|
init_create_tool();
|
|
89078
89352
|
init_path_security();
|
|
89079
|
-
import * as
|
|
89080
|
-
import * as
|
|
89353
|
+
import * as fs83 from "node:fs";
|
|
89354
|
+
import * as path103 from "node:path";
|
|
89081
89355
|
var MAX_TEXT_LENGTH = 200;
|
|
89082
89356
|
var MAX_FILE_SIZE_BYTES11 = 1024 * 1024;
|
|
89083
89357
|
var SUPPORTED_EXTENSIONS4 = new Set([
|
|
@@ -89143,9 +89417,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
89143
89417
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
89144
89418
|
}
|
|
89145
89419
|
try {
|
|
89146
|
-
const resolvedPath =
|
|
89147
|
-
const normalizedCwd =
|
|
89148
|
-
const normalizedResolved =
|
|
89420
|
+
const resolvedPath = path103.resolve(paths);
|
|
89421
|
+
const normalizedCwd = path103.resolve(cwd);
|
|
89422
|
+
const normalizedResolved = path103.resolve(resolvedPath);
|
|
89149
89423
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
89150
89424
|
return {
|
|
89151
89425
|
error: "paths must be within the current working directory",
|
|
@@ -89161,13 +89435,13 @@ function validatePathsInput(paths, cwd) {
|
|
|
89161
89435
|
}
|
|
89162
89436
|
}
|
|
89163
89437
|
function isSupportedExtension(filePath) {
|
|
89164
|
-
const ext =
|
|
89438
|
+
const ext = path103.extname(filePath).toLowerCase();
|
|
89165
89439
|
return SUPPORTED_EXTENSIONS4.has(ext);
|
|
89166
89440
|
}
|
|
89167
89441
|
function findSourceFiles3(dir, files = []) {
|
|
89168
89442
|
let entries;
|
|
89169
89443
|
try {
|
|
89170
|
-
entries =
|
|
89444
|
+
entries = fs83.readdirSync(dir);
|
|
89171
89445
|
} catch {
|
|
89172
89446
|
return files;
|
|
89173
89447
|
}
|
|
@@ -89176,10 +89450,10 @@ function findSourceFiles3(dir, files = []) {
|
|
|
89176
89450
|
if (SKIP_DIRECTORIES5.has(entry)) {
|
|
89177
89451
|
continue;
|
|
89178
89452
|
}
|
|
89179
|
-
const fullPath =
|
|
89453
|
+
const fullPath = path103.join(dir, entry);
|
|
89180
89454
|
let stat6;
|
|
89181
89455
|
try {
|
|
89182
|
-
stat6 =
|
|
89456
|
+
stat6 = fs83.statSync(fullPath);
|
|
89183
89457
|
} catch {
|
|
89184
89458
|
continue;
|
|
89185
89459
|
}
|
|
@@ -89272,7 +89546,7 @@ var todo_extract = createSwarmTool({
|
|
|
89272
89546
|
return JSON.stringify(errorResult, null, 2);
|
|
89273
89547
|
}
|
|
89274
89548
|
const scanPath = resolvedPath;
|
|
89275
|
-
if (!
|
|
89549
|
+
if (!fs83.existsSync(scanPath)) {
|
|
89276
89550
|
const errorResult = {
|
|
89277
89551
|
error: `path not found: ${pathsInput}`,
|
|
89278
89552
|
total: 0,
|
|
@@ -89282,13 +89556,13 @@ var todo_extract = createSwarmTool({
|
|
|
89282
89556
|
return JSON.stringify(errorResult, null, 2);
|
|
89283
89557
|
}
|
|
89284
89558
|
const filesToScan = [];
|
|
89285
|
-
const stat6 =
|
|
89559
|
+
const stat6 = fs83.statSync(scanPath);
|
|
89286
89560
|
if (stat6.isFile()) {
|
|
89287
89561
|
if (isSupportedExtension(scanPath)) {
|
|
89288
89562
|
filesToScan.push(scanPath);
|
|
89289
89563
|
} else {
|
|
89290
89564
|
const errorResult = {
|
|
89291
|
-
error: `unsupported file extension: ${
|
|
89565
|
+
error: `unsupported file extension: ${path103.extname(scanPath)}`,
|
|
89292
89566
|
total: 0,
|
|
89293
89567
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
89294
89568
|
entries: []
|
|
@@ -89301,11 +89575,11 @@ var todo_extract = createSwarmTool({
|
|
|
89301
89575
|
const allEntries = [];
|
|
89302
89576
|
for (const filePath of filesToScan) {
|
|
89303
89577
|
try {
|
|
89304
|
-
const fileStat =
|
|
89578
|
+
const fileStat = fs83.statSync(filePath);
|
|
89305
89579
|
if (fileStat.size > MAX_FILE_SIZE_BYTES11) {
|
|
89306
89580
|
continue;
|
|
89307
89581
|
}
|
|
89308
|
-
const content =
|
|
89582
|
+
const content = fs83.readFileSync(filePath, "utf-8");
|
|
89309
89583
|
const entries = parseTodoComments(content, filePath, tagsSet);
|
|
89310
89584
|
allEntries.push(...entries);
|
|
89311
89585
|
} catch {}
|
|
@@ -89336,19 +89610,19 @@ init_loader();
|
|
|
89336
89610
|
init_schema();
|
|
89337
89611
|
init_qa_gate_profile();
|
|
89338
89612
|
init_gate_evidence();
|
|
89339
|
-
import * as
|
|
89340
|
-
import * as
|
|
89613
|
+
import * as fs85 from "node:fs";
|
|
89614
|
+
import * as path105 from "node:path";
|
|
89341
89615
|
|
|
89342
89616
|
// src/hooks/diff-scope.ts
|
|
89343
89617
|
init_bun_compat();
|
|
89344
|
-
import * as
|
|
89345
|
-
import * as
|
|
89618
|
+
import * as fs84 from "node:fs";
|
|
89619
|
+
import * as path104 from "node:path";
|
|
89346
89620
|
function getDeclaredScope(taskId, directory) {
|
|
89347
89621
|
try {
|
|
89348
|
-
const planPath =
|
|
89349
|
-
if (!
|
|
89622
|
+
const planPath = path104.join(directory, ".swarm", "plan.json");
|
|
89623
|
+
if (!fs84.existsSync(planPath))
|
|
89350
89624
|
return null;
|
|
89351
|
-
const raw =
|
|
89625
|
+
const raw = fs84.readFileSync(planPath, "utf-8");
|
|
89352
89626
|
const plan = JSON.parse(raw);
|
|
89353
89627
|
for (const phase of plan.phases ?? []) {
|
|
89354
89628
|
for (const task of phase.tasks ?? []) {
|
|
@@ -89464,7 +89738,7 @@ var TIER_3_PATTERNS = [
|
|
|
89464
89738
|
];
|
|
89465
89739
|
function matchesTier3Pattern(files) {
|
|
89466
89740
|
for (const file3 of files) {
|
|
89467
|
-
const fileName =
|
|
89741
|
+
const fileName = path105.basename(file3);
|
|
89468
89742
|
for (const pattern of TIER_3_PATTERNS) {
|
|
89469
89743
|
if (pattern.test(fileName)) {
|
|
89470
89744
|
return true;
|
|
@@ -89478,8 +89752,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
89478
89752
|
if (hasActiveTurboMode()) {
|
|
89479
89753
|
const resolvedDir2 = workingDirectory;
|
|
89480
89754
|
try {
|
|
89481
|
-
const planPath =
|
|
89482
|
-
const planRaw =
|
|
89755
|
+
const planPath = path105.join(resolvedDir2, ".swarm", "plan.json");
|
|
89756
|
+
const planRaw = fs85.readFileSync(planPath, "utf-8");
|
|
89483
89757
|
const plan = JSON.parse(planRaw);
|
|
89484
89758
|
for (const planPhase of plan.phases ?? []) {
|
|
89485
89759
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -89548,8 +89822,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
89548
89822
|
}
|
|
89549
89823
|
try {
|
|
89550
89824
|
const resolvedDir2 = workingDirectory;
|
|
89551
|
-
const planPath =
|
|
89552
|
-
const planRaw =
|
|
89825
|
+
const planPath = path105.join(resolvedDir2, ".swarm", "plan.json");
|
|
89826
|
+
const planRaw = fs85.readFileSync(planPath, "utf-8");
|
|
89553
89827
|
const plan = JSON.parse(planRaw);
|
|
89554
89828
|
for (const planPhase of plan.phases ?? []) {
|
|
89555
89829
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -89692,65 +89966,6 @@ function recoverTaskStateFromDelegations(taskId) {
|
|
|
89692
89966
|
}
|
|
89693
89967
|
}
|
|
89694
89968
|
}
|
|
89695
|
-
function checkCouncilGate(workingDirectory, taskId) {
|
|
89696
|
-
let councilEnabled = false;
|
|
89697
|
-
let effectiveMinimum = 3;
|
|
89698
|
-
try {
|
|
89699
|
-
const config3 = loadPluginConfig(workingDirectory);
|
|
89700
|
-
councilEnabled = config3.council?.enabled === true;
|
|
89701
|
-
effectiveMinimum = config3.council?.requireAllMembers ? 5 : config3.council?.minimumMembers ?? 3;
|
|
89702
|
-
} catch {
|
|
89703
|
-
return { blocked: false, reason: "" };
|
|
89704
|
-
}
|
|
89705
|
-
if (!councilEnabled) {
|
|
89706
|
-
return { blocked: false, reason: "" };
|
|
89707
|
-
}
|
|
89708
|
-
try {
|
|
89709
|
-
const planPath = path104.join(workingDirectory, ".swarm", "plan.json");
|
|
89710
|
-
const planRaw = fs84.readFileSync(planPath, "utf-8");
|
|
89711
|
-
const planObj = JSON.parse(planRaw);
|
|
89712
|
-
if (planObj.swarm && planObj.title) {
|
|
89713
|
-
const planId = `${planObj.swarm}-${planObj.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
|
|
89714
|
-
const profile = getProfile(workingDirectory, planId);
|
|
89715
|
-
if (!profile || !profile.gates.council_mode) {
|
|
89716
|
-
return { blocked: false, reason: "" };
|
|
89717
|
-
}
|
|
89718
|
-
}
|
|
89719
|
-
} catch {
|
|
89720
|
-
return { blocked: false, reason: "" };
|
|
89721
|
-
}
|
|
89722
|
-
let evidence;
|
|
89723
|
-
try {
|
|
89724
|
-
evidence = readTaskEvidenceRaw(workingDirectory, taskId);
|
|
89725
|
-
} catch {
|
|
89726
|
-
return {
|
|
89727
|
-
blocked: true,
|
|
89728
|
-
reason: "council gate required but not yet run — architect must call submit_council_verdicts before advancing this task"
|
|
89729
|
-
};
|
|
89730
|
-
}
|
|
89731
|
-
const councilGate = evidence?.gates?.council;
|
|
89732
|
-
if (!councilGate) {
|
|
89733
|
-
return {
|
|
89734
|
-
blocked: true,
|
|
89735
|
-
reason: "council gate required but not yet run — architect must call submit_council_verdicts before advancing this task"
|
|
89736
|
-
};
|
|
89737
|
-
}
|
|
89738
|
-
if (councilGate.verdict === "REJECT") {
|
|
89739
|
-
return {
|
|
89740
|
-
blocked: true,
|
|
89741
|
-
reason: "council gate blocked advancement — resolve requiredFixes and re-run submit_council_verdicts"
|
|
89742
|
-
};
|
|
89743
|
-
}
|
|
89744
|
-
const rawQuorumSize = councilGate.quorumSize;
|
|
89745
|
-
const quorumSize = typeof rawQuorumSize === "number" && Number.isFinite(rawQuorumSize) && rawQuorumSize >= 1 ? rawQuorumSize : 1;
|
|
89746
|
-
if (quorumSize < effectiveMinimum) {
|
|
89747
|
-
return {
|
|
89748
|
-
blocked: true,
|
|
89749
|
-
reason: `council gate blocked advancement — recorded verdict has insufficient quorum (${quorumSize} of ${effectiveMinimum} required members). Re-run submit_council_verdicts with the missing council members.`
|
|
89750
|
-
};
|
|
89751
|
-
}
|
|
89752
|
-
return { blocked: false, reason: "" };
|
|
89753
|
-
}
|
|
89754
89969
|
async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
89755
89970
|
const statusError = validateStatus(args2.status);
|
|
89756
89971
|
if (statusError) {
|
|
@@ -89797,8 +90012,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
89797
90012
|
};
|
|
89798
90013
|
}
|
|
89799
90014
|
}
|
|
89800
|
-
normalizedDir =
|
|
89801
|
-
const pathParts = normalizedDir.split(
|
|
90015
|
+
normalizedDir = path105.normalize(args2.working_directory);
|
|
90016
|
+
const pathParts = normalizedDir.split(path105.sep);
|
|
89802
90017
|
if (pathParts.includes("..")) {
|
|
89803
90018
|
return {
|
|
89804
90019
|
success: false,
|
|
@@ -89808,11 +90023,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
89808
90023
|
]
|
|
89809
90024
|
};
|
|
89810
90025
|
}
|
|
89811
|
-
const resolvedDir =
|
|
90026
|
+
const resolvedDir = path105.resolve(normalizedDir);
|
|
89812
90027
|
try {
|
|
89813
|
-
const realPath =
|
|
89814
|
-
const planPath =
|
|
89815
|
-
if (!
|
|
90028
|
+
const realPath = fs85.realpathSync(resolvedDir);
|
|
90029
|
+
const planPath = path105.join(realPath, ".swarm", "plan.json");
|
|
90030
|
+
if (!fs85.existsSync(planPath)) {
|
|
89816
90031
|
return {
|
|
89817
90032
|
success: false,
|
|
89818
90033
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -89843,22 +90058,22 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
89843
90058
|
}
|
|
89844
90059
|
if (args2.status === "in_progress") {
|
|
89845
90060
|
try {
|
|
89846
|
-
const evidencePath =
|
|
89847
|
-
|
|
89848
|
-
const fd =
|
|
90061
|
+
const evidencePath = path105.join(directory, ".swarm", "evidence", `${args2.task_id}.json`);
|
|
90062
|
+
fs85.mkdirSync(path105.dirname(evidencePath), { recursive: true });
|
|
90063
|
+
const fd = fs85.openSync(evidencePath, "wx");
|
|
89849
90064
|
let writeOk = false;
|
|
89850
90065
|
try {
|
|
89851
|
-
|
|
90066
|
+
fs85.writeSync(fd, JSON.stringify({
|
|
89852
90067
|
taskId: args2.task_id,
|
|
89853
90068
|
required_gates: ["reviewer", "test_engineer"],
|
|
89854
90069
|
gates: {}
|
|
89855
90070
|
}, null, 2));
|
|
89856
90071
|
writeOk = true;
|
|
89857
90072
|
} finally {
|
|
89858
|
-
|
|
90073
|
+
fs85.closeSync(fd);
|
|
89859
90074
|
if (!writeOk) {
|
|
89860
90075
|
try {
|
|
89861
|
-
|
|
90076
|
+
fs85.unlinkSync(evidencePath);
|
|
89862
90077
|
} catch {}
|
|
89863
90078
|
}
|
|
89864
90079
|
}
|
|
@@ -89868,8 +90083,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
89868
90083
|
recoverTaskStateFromDelegations(args2.task_id);
|
|
89869
90084
|
let phaseRequiresReviewer = true;
|
|
89870
90085
|
try {
|
|
89871
|
-
const planPath =
|
|
89872
|
-
const planRaw =
|
|
90086
|
+
const planPath = path105.join(directory, ".swarm", "plan.json");
|
|
90087
|
+
const planRaw = fs85.readFileSync(planPath, "utf-8");
|
|
89873
90088
|
const plan = JSON.parse(planRaw);
|
|
89874
90089
|
const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
|
|
89875
90090
|
if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
|
|
@@ -89886,14 +90101,6 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
89886
90101
|
};
|
|
89887
90102
|
}
|
|
89888
90103
|
}
|
|
89889
|
-
const councilCheck = checkCouncilGate(directory, args2.task_id);
|
|
89890
|
-
if (councilCheck.blocked) {
|
|
89891
|
-
return {
|
|
89892
|
-
success: false,
|
|
89893
|
-
message: councilCheck.reason,
|
|
89894
|
-
errors: [councilCheck.reason]
|
|
89895
|
-
};
|
|
89896
|
-
}
|
|
89897
90104
|
}
|
|
89898
90105
|
const lockTaskId = `update-task-status-${args2.task_id}-${Date.now()}`;
|
|
89899
90106
|
const planFilePath = "plan.json";
|
|
@@ -90103,7 +90310,7 @@ function createWebSearchProvider(config3) {
|
|
|
90103
90310
|
init_create_tool();
|
|
90104
90311
|
init_resolve_working_directory();
|
|
90105
90312
|
var MAX_RESULTS_HARD_CAP = 10;
|
|
90106
|
-
var
|
|
90313
|
+
var ArgsSchema5 = exports_external.object({
|
|
90107
90314
|
query: exports_external.string().min(1).max(500),
|
|
90108
90315
|
max_results: exports_external.number().int().min(1).max(20).optional(),
|
|
90109
90316
|
working_directory: exports_external.string().optional()
|
|
@@ -90116,7 +90323,7 @@ var web_search = createSwarmTool({
|
|
|
90116
90323
|
working_directory: exports_external.string().optional().describe("Project root for config resolution. Optional.")
|
|
90117
90324
|
},
|
|
90118
90325
|
execute: async (args2, directory) => {
|
|
90119
|
-
const parsed =
|
|
90326
|
+
const parsed = ArgsSchema5.safeParse(args2);
|
|
90120
90327
|
if (!parsed.success) {
|
|
90121
90328
|
const fail = {
|
|
90122
90329
|
success: false,
|
|
@@ -90187,8 +90394,8 @@ init_utils2();
|
|
|
90187
90394
|
init_ledger();
|
|
90188
90395
|
init_manager();
|
|
90189
90396
|
init_create_tool();
|
|
90190
|
-
import
|
|
90191
|
-
import
|
|
90397
|
+
import fs86 from "node:fs";
|
|
90398
|
+
import path106 from "node:path";
|
|
90192
90399
|
function derivePlanId5(plan) {
|
|
90193
90400
|
return `${plan.swarm}-${plan.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
|
|
90194
90401
|
}
|
|
@@ -90239,7 +90446,7 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
90239
90446
|
entries: [evidenceEntry]
|
|
90240
90447
|
};
|
|
90241
90448
|
const filename = "drift-verifier.json";
|
|
90242
|
-
const relativePath =
|
|
90449
|
+
const relativePath = path106.join("evidence", String(phase), filename);
|
|
90243
90450
|
let validatedPath;
|
|
90244
90451
|
try {
|
|
90245
90452
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -90250,12 +90457,12 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
90250
90457
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
90251
90458
|
}, null, 2);
|
|
90252
90459
|
}
|
|
90253
|
-
const evidenceDir =
|
|
90460
|
+
const evidenceDir = path106.dirname(validatedPath);
|
|
90254
90461
|
try {
|
|
90255
|
-
await
|
|
90256
|
-
const tempPath =
|
|
90257
|
-
await
|
|
90258
|
-
await
|
|
90462
|
+
await fs86.promises.mkdir(evidenceDir, { recursive: true });
|
|
90463
|
+
const tempPath = path106.join(evidenceDir, `.${filename}.tmp`);
|
|
90464
|
+
await fs86.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
90465
|
+
await fs86.promises.rename(tempPath, validatedPath);
|
|
90259
90466
|
let snapshotInfo;
|
|
90260
90467
|
let snapshotError;
|
|
90261
90468
|
let qaProfileLocked;
|
|
@@ -90349,8 +90556,8 @@ var write_drift_evidence = createSwarmTool({
|
|
|
90349
90556
|
init_zod();
|
|
90350
90557
|
init_utils2();
|
|
90351
90558
|
init_create_tool();
|
|
90352
|
-
import
|
|
90353
|
-
import
|
|
90559
|
+
import fs87 from "node:fs";
|
|
90560
|
+
import path107 from "node:path";
|
|
90354
90561
|
function normalizeVerdict2(verdict) {
|
|
90355
90562
|
switch (verdict) {
|
|
90356
90563
|
case "APPROVED":
|
|
@@ -90398,7 +90605,7 @@ async function executeWriteHallucinationEvidence(args2, directory) {
|
|
|
90398
90605
|
entries: [evidenceEntry]
|
|
90399
90606
|
};
|
|
90400
90607
|
const filename = "hallucination-guard.json";
|
|
90401
|
-
const relativePath =
|
|
90608
|
+
const relativePath = path107.join("evidence", String(phase), filename);
|
|
90402
90609
|
let validatedPath;
|
|
90403
90610
|
try {
|
|
90404
90611
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -90409,12 +90616,12 @@ async function executeWriteHallucinationEvidence(args2, directory) {
|
|
|
90409
90616
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
90410
90617
|
}, null, 2);
|
|
90411
90618
|
}
|
|
90412
|
-
const evidenceDir =
|
|
90619
|
+
const evidenceDir = path107.dirname(validatedPath);
|
|
90413
90620
|
try {
|
|
90414
|
-
await
|
|
90415
|
-
const tempPath =
|
|
90416
|
-
await
|
|
90417
|
-
await
|
|
90621
|
+
await fs87.promises.mkdir(evidenceDir, { recursive: true });
|
|
90622
|
+
const tempPath = path107.join(evidenceDir, `.${filename}.tmp`);
|
|
90623
|
+
await fs87.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
90624
|
+
await fs87.promises.rename(tempPath, validatedPath);
|
|
90418
90625
|
return JSON.stringify({
|
|
90419
90626
|
success: true,
|
|
90420
90627
|
phase,
|
|
@@ -90460,8 +90667,8 @@ var write_hallucination_evidence = createSwarmTool({
|
|
|
90460
90667
|
init_zod();
|
|
90461
90668
|
init_utils2();
|
|
90462
90669
|
init_create_tool();
|
|
90463
|
-
import
|
|
90464
|
-
import
|
|
90670
|
+
import fs88 from "node:fs";
|
|
90671
|
+
import path108 from "node:path";
|
|
90465
90672
|
function normalizeVerdict3(verdict) {
|
|
90466
90673
|
switch (verdict) {
|
|
90467
90674
|
case "PASS":
|
|
@@ -90535,7 +90742,7 @@ async function executeWriteMutationEvidence(args2, directory) {
|
|
|
90535
90742
|
entries: [evidenceEntry]
|
|
90536
90743
|
};
|
|
90537
90744
|
const filename = "mutation-gate.json";
|
|
90538
|
-
const relativePath =
|
|
90745
|
+
const relativePath = path108.join("evidence", String(phase), filename);
|
|
90539
90746
|
let validatedPath;
|
|
90540
90747
|
try {
|
|
90541
90748
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -90546,12 +90753,12 @@ async function executeWriteMutationEvidence(args2, directory) {
|
|
|
90546
90753
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
90547
90754
|
}, null, 2);
|
|
90548
90755
|
}
|
|
90549
|
-
const evidenceDir =
|
|
90756
|
+
const evidenceDir = path108.dirname(validatedPath);
|
|
90550
90757
|
try {
|
|
90551
|
-
await
|
|
90552
|
-
const tempPath =
|
|
90553
|
-
await
|
|
90554
|
-
await
|
|
90758
|
+
await fs88.promises.mkdir(evidenceDir, { recursive: true });
|
|
90759
|
+
const tempPath = path108.join(evidenceDir, `.${filename}.tmp`);
|
|
90760
|
+
await fs88.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
90761
|
+
await fs88.promises.rename(tempPath, validatedPath);
|
|
90555
90762
|
return JSON.stringify({
|
|
90556
90763
|
success: true,
|
|
90557
90764
|
phase,
|
|
@@ -90605,20 +90812,20 @@ init_write_retro();
|
|
|
90605
90812
|
init_utils();
|
|
90606
90813
|
|
|
90607
90814
|
// src/utils/gitignore-warning.ts
|
|
90608
|
-
import * as
|
|
90609
|
-
import * as
|
|
90815
|
+
import * as fs89 from "node:fs";
|
|
90816
|
+
import * as path109 from "node:path";
|
|
90610
90817
|
var _gitignoreWarningEmitted = false;
|
|
90611
90818
|
function findGitRoot(startDir) {
|
|
90612
90819
|
let current = startDir;
|
|
90613
90820
|
while (true) {
|
|
90614
90821
|
try {
|
|
90615
|
-
const gitPath =
|
|
90616
|
-
const stat6 =
|
|
90822
|
+
const gitPath = path109.join(current, ".git");
|
|
90823
|
+
const stat6 = fs89.statSync(gitPath);
|
|
90617
90824
|
if (stat6.isDirectory()) {
|
|
90618
90825
|
return current;
|
|
90619
90826
|
}
|
|
90620
90827
|
} catch {}
|
|
90621
|
-
const parent =
|
|
90828
|
+
const parent = path109.dirname(current);
|
|
90622
90829
|
if (parent === current) {
|
|
90623
90830
|
return null;
|
|
90624
90831
|
}
|
|
@@ -90638,7 +90845,7 @@ function fileCoversSwarm(content) {
|
|
|
90638
90845
|
}
|
|
90639
90846
|
function readFileSafe(filePath) {
|
|
90640
90847
|
try {
|
|
90641
|
-
return
|
|
90848
|
+
return fs89.readFileSync(filePath, "utf8");
|
|
90642
90849
|
} catch {
|
|
90643
90850
|
return null;
|
|
90644
90851
|
}
|
|
@@ -90650,12 +90857,12 @@ function warnIfSwarmNotGitignored(directory, quiet = false) {
|
|
|
90650
90857
|
const gitRoot = findGitRoot(directory);
|
|
90651
90858
|
if (!gitRoot)
|
|
90652
90859
|
return;
|
|
90653
|
-
const gitignoreContent = readFileSafe(
|
|
90860
|
+
const gitignoreContent = readFileSafe(path109.join(gitRoot, ".gitignore"));
|
|
90654
90861
|
if (gitignoreContent !== null && fileCoversSwarm(gitignoreContent)) {
|
|
90655
90862
|
_gitignoreWarningEmitted = true;
|
|
90656
90863
|
return;
|
|
90657
90864
|
}
|
|
90658
|
-
const excludeContent = readFileSafe(
|
|
90865
|
+
const excludeContent = readFileSafe(path109.join(gitRoot, ".git", "info", "exclude"));
|
|
90659
90866
|
if (excludeContent !== null && fileCoversSwarm(excludeContent)) {
|
|
90660
90867
|
_gitignoreWarningEmitted = true;
|
|
90661
90868
|
return;
|
|
@@ -90900,7 +91107,7 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
90900
91107
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
90901
91108
|
preflightTriggerManager = new PTM(automationConfig);
|
|
90902
91109
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
90903
|
-
const swarmDir =
|
|
91110
|
+
const swarmDir = path110.resolve(ctx.directory, ".swarm");
|
|
90904
91111
|
statusArtifact = new ASA(swarmDir);
|
|
90905
91112
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
90906
91113
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|