opencode-swarm 7.3.1 → 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/index.js +891 -705
- 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",
|
|
@@ -25603,136 +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
|
-
advanceTaskState(session, taskId, "reviewer_run", {
|
|
25624
|
-
telemetrySessionId: input.sessionID
|
|
25625
|
-
});
|
|
25626
|
-
}
|
|
25627
|
-
advanceTaskState(session, taskId, "tests_run", {
|
|
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", {
|
|
25628
25626
|
telemetrySessionId: input.sessionID
|
|
25629
25627
|
});
|
|
25630
|
-
} catch (err2) {
|
|
25631
|
-
warn(`[delegation-gate] toolAfter stage-b-parallel: could not advance ${taskId} (${eligibleState}) → tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25632
|
-
}
|
|
25633
|
-
}
|
|
25634
|
-
}
|
|
25635
|
-
const seedTaskId = getSeedTaskId(session);
|
|
25636
|
-
if (seedTaskId) {
|
|
25637
|
-
for (const [, otherSession] of swarmState.agentSessions) {
|
|
25638
|
-
if (otherSession === session)
|
|
25639
|
-
continue;
|
|
25640
|
-
if (!otherSession.taskWorkflowStates)
|
|
25641
|
-
continue;
|
|
25642
|
-
if (!otherSession.taskWorkflowStates.has(seedTaskId)) {
|
|
25643
|
-
otherSession.taskWorkflowStates.set(seedTaskId, "coder_delegated");
|
|
25644
|
-
}
|
|
25645
|
-
const seedState = otherSession.taskWorkflowStates.get(seedTaskId);
|
|
25646
|
-
if (!seedState || !stageBEligibleStates.includes(seedState)) {
|
|
25647
|
-
continue;
|
|
25648
|
-
}
|
|
25649
|
-
const seedEligibleState = seedState;
|
|
25650
|
-
recordStageBCompletion(otherSession, seedTaskId, targetAgent);
|
|
25651
|
-
if (hasBothStageBCompletions(otherSession, seedTaskId)) {
|
|
25652
|
-
try {
|
|
25653
|
-
if (seedEligibleState === "coder_delegated" || seedEligibleState === "pre_check_passed") {
|
|
25654
|
-
advanceTaskState(otherSession, seedTaskId, "reviewer_run", { emitTelemetry: false });
|
|
25655
|
-
}
|
|
25656
|
-
advanceTaskState(otherSession, seedTaskId, "tests_run", {
|
|
25657
|
-
emitTelemetry: false
|
|
25658
|
-
});
|
|
25659
|
-
} catch (err2) {
|
|
25660
|
-
warn(`[delegation-gate] toolAfter cross-session stage-b-parallel: could not advance ${seedTaskId} (${seedEligibleState}) → tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25661
|
-
}
|
|
25662
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)}`);
|
|
25663
25634
|
}
|
|
25664
25635
|
}
|
|
25665
25636
|
}
|
|
25666
|
-
|
|
25667
|
-
if (
|
|
25668
|
-
for (const [
|
|
25669
|
-
if (
|
|
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)) {
|
|
25670
25654
|
try {
|
|
25671
|
-
|
|
25672
|
-
|
|
25655
|
+
if (seedEligibleState === "coder_delegated" || seedEligibleState === "pre_check_passed") {
|
|
25656
|
+
advanceTaskState(otherSession, seedTaskId, "reviewer_run", { emitTelemetry: false });
|
|
25657
|
+
}
|
|
25658
|
+
advanceTaskState(otherSession, seedTaskId, "tests_run", {
|
|
25659
|
+
emitTelemetry: false
|
|
25673
25660
|
});
|
|
25674
25661
|
} catch (err2) {
|
|
25675
|
-
warn(`[delegation-gate] toolAfter: could not advance ${
|
|
25662
|
+
warn(`[delegation-gate] toolAfter cross-session stage-b-parallel: could not advance ${seedTaskId} (${seedEligibleState}) → tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25676
25663
|
}
|
|
25677
25664
|
}
|
|
25678
25665
|
}
|
|
25679
25666
|
}
|
|
25680
|
-
|
|
25681
|
-
|
|
25682
|
-
|
|
25683
|
-
|
|
25684
|
-
|
|
25685
|
-
|
|
25686
|
-
|
|
25687
|
-
|
|
25688
|
-
|
|
25689
|
-
|
|
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)}`);
|
|
25690
25678
|
}
|
|
25691
25679
|
}
|
|
25692
25680
|
}
|
|
25693
|
-
|
|
25694
|
-
|
|
25695
|
-
|
|
25696
|
-
|
|
25697
|
-
|
|
25698
|
-
|
|
25699
|
-
|
|
25700
|
-
|
|
25701
|
-
|
|
25702
|
-
|
|
25703
|
-
|
|
25704
|
-
|
|
25705
|
-
|
|
25706
|
-
|
|
25707
|
-
|
|
25708
|
-
|
|
25709
|
-
|
|
25710
|
-
|
|
25711
|
-
|
|
25712
|
-
|
|
25713
|
-
|
|
25714
|
-
|
|
25715
|
-
|
|
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)}`);
|
|
25691
|
+
}
|
|
25692
|
+
}
|
|
25693
|
+
}
|
|
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)}`);
|
|
25716
25714
|
}
|
|
25717
25715
|
}
|
|
25718
25716
|
}
|
|
25719
|
-
|
|
25720
|
-
|
|
25721
|
-
|
|
25722
|
-
|
|
25723
|
-
|
|
25724
|
-
|
|
25725
|
-
|
|
25726
|
-
|
|
25727
|
-
|
|
25728
|
-
|
|
25729
|
-
|
|
25730
|
-
|
|
25731
|
-
|
|
25732
|
-
|
|
25733
|
-
} catch (err2) {
|
|
25734
|
-
warn(`[delegation-gate] toolAfter cross-session: could not advance ${taskId} (${state}) → tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25735
|
-
}
|
|
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)}`);
|
|
25736
25731
|
}
|
|
25737
25732
|
}
|
|
25738
25733
|
}
|
|
@@ -25792,75 +25787,73 @@ function createDelegationGateHook(config2, directory) {
|
|
|
25792
25787
|
if (target === "test_engineer")
|
|
25793
25788
|
hasTestEngineer = true;
|
|
25794
25789
|
}
|
|
25795
|
-
if (
|
|
25796
|
-
|
|
25797
|
-
|
|
25798
|
-
|
|
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
|
+
}
|
|
25799
25803
|
}
|
|
25800
|
-
|
|
25801
|
-
|
|
25802
|
-
|
|
25803
|
-
|
|
25804
|
-
|
|
25805
|
-
|
|
25806
|
-
|
|
25807
|
-
}
|
|
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)}`);
|
|
25808
25812
|
}
|
|
25809
25813
|
}
|
|
25810
25814
|
}
|
|
25811
|
-
|
|
25812
|
-
|
|
25813
|
-
|
|
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") {
|
|
25814
25828
|
try {
|
|
25815
|
-
advanceTaskState(
|
|
25829
|
+
advanceTaskState(otherSession, taskId, "reviewer_run", {
|
|
25830
|
+
emitTelemetry: false
|
|
25831
|
+
});
|
|
25816
25832
|
} catch (err2) {
|
|
25817
|
-
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)}`);
|
|
25818
25834
|
}
|
|
25819
25835
|
}
|
|
25820
25836
|
}
|
|
25821
25837
|
}
|
|
25822
|
-
|
|
25823
|
-
|
|
25824
|
-
|
|
25825
|
-
|
|
25826
|
-
|
|
25827
|
-
|
|
25828
|
-
|
|
25829
|
-
|
|
25830
|
-
|
|
25831
|
-
|
|
25832
|
-
for (const [taskId, state] of otherSession.taskWorkflowStates) {
|
|
25833
|
-
if (state === "coder_delegated" || state === "pre_check_passed") {
|
|
25834
|
-
try {
|
|
25835
|
-
advanceTaskState(otherSession, taskId, "reviewer_run", {
|
|
25836
|
-
emitTelemetry: false
|
|
25837
|
-
});
|
|
25838
|
-
} catch (err2) {
|
|
25839
|
-
warn(`[delegation-gate] fallback cross-session: could not advance ${taskId} (${state}) → reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25840
|
-
}
|
|
25841
|
-
}
|
|
25842
|
-
}
|
|
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");
|
|
25843
25848
|
}
|
|
25844
|
-
|
|
25845
|
-
|
|
25846
|
-
|
|
25847
|
-
|
|
25848
|
-
|
|
25849
|
-
|
|
25850
|
-
|
|
25851
|
-
|
|
25852
|
-
if (seedTaskId && !otherSession.taskWorkflowStates.has(seedTaskId)) {
|
|
25853
|
-
otherSession.taskWorkflowStates.set(seedTaskId, "reviewer_run");
|
|
25854
|
-
}
|
|
25855
|
-
for (const [taskId, state] of otherSession.taskWorkflowStates) {
|
|
25856
|
-
if (state === "reviewer_run") {
|
|
25857
|
-
try {
|
|
25858
|
-
advanceTaskState(otherSession, taskId, "tests_run", {
|
|
25859
|
-
emitTelemetry: false
|
|
25860
|
-
});
|
|
25861
|
-
} catch (err2) {
|
|
25862
|
-
warn(`[delegation-gate] fallback cross-session: could not advance ${taskId} (${state}) → tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
25863
|
-
}
|
|
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)}`);
|
|
25864
25857
|
}
|
|
25865
25858
|
}
|
|
25866
25859
|
}
|
|
@@ -56153,106 +56146,101 @@ ${validation.warnings.join(`
|
|
|
56153
56146
|
function buildCouncilWorkflow(council) {
|
|
56154
56147
|
if (council?.enabled !== true)
|
|
56155
56148
|
return "";
|
|
56156
|
-
return `## COUNCIL WORKFLOW (
|
|
56149
|
+
return `## COUNCIL WORKFLOW (submit_phase_council_verdicts)
|
|
56157
56150
|
|
|
56158
|
-
CRITICAL: \`
|
|
56151
|
+
CRITICAL: \`submit_phase_council_verdicts\` does NOT run council members.
|
|
56159
56152
|
It synthesizes verdicts that you must collect BEFORE calling it.
|
|
56160
56153
|
|
|
56161
|
-
When \`council.enabled\` is true
|
|
56162
|
-
|
|
56163
|
-
(reviewer + test_engineer
|
|
56164
|
-
|
|
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.
|
|
56165
56158
|
|
|
56166
|
-
###
|
|
56167
|
-
|
|
56168
|
-
|
|
56169
|
-
|
|
56170
|
-
|
|
56171
|
-
|
|
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
|
|
56172
56166
|
|
|
56173
56167
|
### MANDATORY SEQUENCE — never skip or reorder
|
|
56174
56168
|
|
|
56175
|
-
#### STEP 1 — DISPATCH all council members
|
|
56176
|
-
|
|
56177
|
-
|
|
56178
|
-
|
|
56179
|
-
|
|
56180
|
-
- \`
|
|
56181
|
-
- \`
|
|
56182
|
-
- \`
|
|
56183
|
-
|
|
56184
|
-
|
|
56185
|
-
|
|
56186
|
-
|
|
56187
|
-
|
|
56188
|
-
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.
|
|
56189
56181
|
|
|
56190
56182
|
#### STEP 2 — COLLECT verdicts
|
|
56191
56183
|
Read each agent's response and extract their \`CouncilMemberVerdict\` object.
|
|
56192
|
-
Each member must return
|
|
56184
|
+
Each member must return: \`agent\`, \`verdict\` (APPROVE|CONCERNS|REJECT),
|
|
56193
56185
|
\`confidence\` (0.0–1.0), \`findings[]\`, \`criteriaAssessed[]\`, \`criteriaUnmet[]\`,
|
|
56194
56186
|
\`durationMs\`.
|
|
56195
56187
|
|
|
56196
56188
|
Do NOT fabricate, infer, or substitute a verdict. If an agent did not return
|
|
56197
|
-
a valid verdict, re-dispatch that agent.
|
|
56189
|
+
a valid verdict object, re-dispatch that agent.
|
|
56198
56190
|
|
|
56199
|
-
#### STEP 3 — CALL
|
|
56200
|
-
ONLY after collecting real verdicts from
|
|
56201
|
-
\`
|
|
56202
|
-
|
|
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.
|
|
56203
56202
|
|
|
56204
56203
|
#### STEP 4 — READ the response
|
|
56205
|
-
Inspect \`membersAbsent
|
|
56206
|
-
|
|
56207
|
-
|
|
56208
|
-
|
|
56209
|
-
|
|
56210
|
-
|
|
56211
|
-
|
|
56212
|
-
|
|
56213
|
-
|
|
56214
|
-
|
|
56215
|
-
|
|
56216
|
-
|
|
56217
|
-
|
|
56218
|
-
|
|
56219
|
-
- **
|
|
56220
|
-
|
|
56221
|
-
|
|
56222
|
-
|
|
56223
|
-
|
|
56224
|
-
|
|
56225
|
-
|
|
56226
|
-
|
|
56227
|
-
-
|
|
56228
|
-
with the BLOCKING flag. The coder must resolve all
|
|
56229
|
-
\`requiredFixes\` before re-submitting. Maximum
|
|
56230
|
-
\`council.maxRounds\` rounds (default 3). If
|
|
56231
|
-
\`roundNumber >= maxRounds\` and verdict is still REJECT,
|
|
56232
|
-
surface \`unifiedFeedbackMd\` to the user and HALT — do NOT
|
|
56233
|
-
auto-advance.
|
|
56234
|
-
|
|
56235
|
-
### ANTI-PATTERNS — any of these are council bypass violations
|
|
56236
|
-
- ✗ Calling \`submit_council_verdicts\` without first dispatching council members.
|
|
56237
|
-
- ✗ 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.
|
|
56238
56227
|
- ✗ Claiming "Council APPROVED" when \`membersAbsent\` is non-empty.
|
|
56239
|
-
- ✗
|
|
56240
|
-
- ✗
|
|
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.
|
|
56241
56232
|
|
|
56242
56233
|
### ROUND 2 DELIBERATION
|
|
56243
|
-
If round 1 produces REJECT or CONCERNS, dispatch only the
|
|
56244
|
-
for round 2 focused on the specific
|
|
56245
|
-
NEW agent responses —
|
|
56246
|
-
\`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.
|
|
56247
56237
|
|
|
56248
56238
|
### Retry protocol
|
|
56249
|
-
On re-submission after REJECT
|
|
56250
|
-
|
|
56251
|
-
|
|
56252
|
-
|
|
56253
|
-
|
|
56254
|
-
sending it to the coder — the coder never sees contradictory instructions
|
|
56255
|
-
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.`;
|
|
56256
56244
|
}
|
|
56257
56245
|
function buildYourToolsList(council) {
|
|
56258
56246
|
const tools = AGENT_TOOL_MAP.architect ?? [];
|
|
@@ -56260,7 +56248,7 @@ function buildYourToolsList(council) {
|
|
|
56260
56248
|
const qaCouncilEnabled = council?.enabled === true;
|
|
56261
56249
|
const generalCouncilEnabled = council?.general?.enabled === true;
|
|
56262
56250
|
const filtered = sorted.filter((t) => {
|
|
56263
|
-
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")) {
|
|
56264
56252
|
return false;
|
|
56265
56253
|
}
|
|
56266
56254
|
if (!generalCouncilEnabled && t === "convene_general_council") {
|
|
@@ -56294,7 +56282,7 @@ function buildAvailableToolsList(council) {
|
|
|
56294
56282
|
const qaCouncilEnabled = council?.enabled === true;
|
|
56295
56283
|
const generalCouncilEnabled = council?.general?.enabled === true;
|
|
56296
56284
|
const filtered = sorted.filter((t) => {
|
|
56297
|
-
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")) {
|
|
56298
56286
|
return false;
|
|
56299
56287
|
}
|
|
56300
56288
|
if (!generalCouncilEnabled && t === "convene_general_council") {
|
|
@@ -56680,7 +56668,7 @@ TIER 3 — CRITICAL
|
|
|
56680
56668
|
Pipeline: Full Stage A. Stage B = {{AGENT_PREFIX}}reviewer×2 + {{AGENT_PREFIX}}test_engineer×2.
|
|
56681
56669
|
Rationale: Security paths need adversarial review.
|
|
56682
56670
|
|
|
56683
|
-
|
|
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.
|
|
56684
56672
|
|
|
56685
56673
|
CLASSIFICATION RULES:
|
|
56686
56674
|
- Multi-tier → use HIGHEST tier.
|
|
@@ -56707,7 +56695,7 @@ Stage B runs by default for TIER 1-3 classifications. Stage A passing does not s
|
|
|
56707
56695
|
Stage B is where logic errors, security flaws, edge cases, and behavioral bugs are caught.
|
|
56708
56696
|
You MUST delegate to each Stage B agent and wait for their response.
|
|
56709
56697
|
|
|
56710
|
-
|
|
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.
|
|
56711
56699
|
|
|
56712
56700
|
A task is complete ONLY when BOTH stages pass.
|
|
56713
56701
|
|
|
@@ -65000,7 +64988,7 @@ var init_curator_drift = __esm(() => {
|
|
|
65000
64988
|
// src/index.ts
|
|
65001
64989
|
init_package();
|
|
65002
64990
|
init_agents2();
|
|
65003
|
-
import * as
|
|
64991
|
+
import * as path110 from "node:path";
|
|
65004
64992
|
|
|
65005
64993
|
// src/background/index.ts
|
|
65006
64994
|
init_event_bus();
|
|
@@ -76481,6 +76469,10 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
76481
76469
|
}
|
|
76482
76470
|
}
|
|
76483
76471
|
|
|
76472
|
+
// src/council/council-service.ts
|
|
76473
|
+
import fs59 from "node:fs";
|
|
76474
|
+
import path77 from "node:path";
|
|
76475
|
+
|
|
76484
76476
|
// src/council/types.ts
|
|
76485
76477
|
var COUNCIL_DEFAULTS = {
|
|
76486
76478
|
enabled: false,
|
|
@@ -76605,6 +76597,143 @@ function buildUnifiedFeedback(taskId, verdict, vetoedBy, requiredFixes, advisory
|
|
|
76605
76597
|
return lines.join(`
|
|
76606
76598
|
`);
|
|
76607
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
|
+
}
|
|
76608
76737
|
|
|
76609
76738
|
// src/council/criteria-store.ts
|
|
76610
76739
|
import { existsSync as existsSync39, mkdirSync as mkdirSync20, readFileSync as readFileSync37, writeFileSync as writeFileSync13 } from "node:fs";
|
|
@@ -76773,8 +76902,8 @@ var submit_council_verdicts = createSwarmTool({
|
|
|
76773
76902
|
// src/tools/convene-general-council.ts
|
|
76774
76903
|
init_zod();
|
|
76775
76904
|
init_loader();
|
|
76776
|
-
import * as
|
|
76777
|
-
import * as
|
|
76905
|
+
import * as fs60 from "node:fs";
|
|
76906
|
+
import * as path78 from "node:path";
|
|
76778
76907
|
|
|
76779
76908
|
// src/council/general-council-advisory.ts
|
|
76780
76909
|
var ADVISORY_HEADER = "[general_council] (advisory; not blocking)";
|
|
@@ -77202,13 +77331,13 @@ var convene_general_council = createSwarmTool({
|
|
|
77202
77331
|
const round1 = input.round1Responses;
|
|
77203
77332
|
const round2 = input.round2Responses ?? [];
|
|
77204
77333
|
const result = synthesizeGeneralCouncil(input.question, input.mode, round1, round2);
|
|
77205
|
-
const evidenceDir =
|
|
77334
|
+
const evidenceDir = path78.join(workingDir, ".swarm", "council", "general");
|
|
77206
77335
|
const safeTimestamp = result.timestamp.replace(/[:.]/g, "-");
|
|
77207
77336
|
const evidenceFile = `${safeTimestamp}-${input.mode}.json`;
|
|
77208
|
-
const evidencePath =
|
|
77337
|
+
const evidencePath = path78.join(evidenceDir, evidenceFile);
|
|
77209
77338
|
try {
|
|
77210
|
-
await
|
|
77211
|
-
await
|
|
77339
|
+
await fs60.promises.mkdir(evidenceDir, { recursive: true });
|
|
77340
|
+
await fs60.promises.writeFile(evidencePath, JSON.stringify(result, null, 2));
|
|
77212
77341
|
} catch (err2) {
|
|
77213
77342
|
const message = err2 instanceof Error ? err2.message : String(err2);
|
|
77214
77343
|
console.warn(`[convene_general_council] Failed to write evidence to ${evidencePath}: ${message}`);
|
|
@@ -77439,8 +77568,8 @@ init_scope_persistence();
|
|
|
77439
77568
|
init_state();
|
|
77440
77569
|
init_task_id();
|
|
77441
77570
|
init_create_tool();
|
|
77442
|
-
import * as
|
|
77443
|
-
import * as
|
|
77571
|
+
import * as fs61 from "node:fs";
|
|
77572
|
+
import * as path79 from "node:path";
|
|
77444
77573
|
function validateTaskIdFormat2(taskId) {
|
|
77445
77574
|
return validateTaskIdFormat(taskId);
|
|
77446
77575
|
}
|
|
@@ -77514,8 +77643,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
77514
77643
|
};
|
|
77515
77644
|
}
|
|
77516
77645
|
}
|
|
77517
|
-
normalizedDir =
|
|
77518
|
-
const pathParts = normalizedDir.split(
|
|
77646
|
+
normalizedDir = path79.normalize(args2.working_directory);
|
|
77647
|
+
const pathParts = normalizedDir.split(path79.sep);
|
|
77519
77648
|
if (pathParts.includes("..")) {
|
|
77520
77649
|
return {
|
|
77521
77650
|
success: false,
|
|
@@ -77525,11 +77654,11 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
77525
77654
|
]
|
|
77526
77655
|
};
|
|
77527
77656
|
}
|
|
77528
|
-
const resolvedDir =
|
|
77657
|
+
const resolvedDir = path79.resolve(normalizedDir);
|
|
77529
77658
|
try {
|
|
77530
|
-
const realPath =
|
|
77531
|
-
const planPath2 =
|
|
77532
|
-
if (!
|
|
77659
|
+
const realPath = fs61.realpathSync(resolvedDir);
|
|
77660
|
+
const planPath2 = path79.join(realPath, ".swarm", "plan.json");
|
|
77661
|
+
if (!fs61.existsSync(planPath2)) {
|
|
77533
77662
|
return {
|
|
77534
77663
|
success: false,
|
|
77535
77664
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -77552,8 +77681,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
77552
77681
|
console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
|
|
77553
77682
|
}
|
|
77554
77683
|
const directory = normalizedDir || fallbackDir;
|
|
77555
|
-
const planPath =
|
|
77556
|
-
if (!
|
|
77684
|
+
const planPath = path79.resolve(directory, ".swarm", "plan.json");
|
|
77685
|
+
if (!fs61.existsSync(planPath)) {
|
|
77557
77686
|
return {
|
|
77558
77687
|
success: false,
|
|
77559
77688
|
message: "No plan found",
|
|
@@ -77562,7 +77691,7 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
77562
77691
|
}
|
|
77563
77692
|
let planContent;
|
|
77564
77693
|
try {
|
|
77565
|
-
planContent = JSON.parse(
|
|
77694
|
+
planContent = JSON.parse(fs61.readFileSync(planPath, "utf-8"));
|
|
77566
77695
|
} catch {
|
|
77567
77696
|
return {
|
|
77568
77697
|
success: false,
|
|
@@ -77592,8 +77721,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
77592
77721
|
const normalizeErrors = [];
|
|
77593
77722
|
const dir = normalizedDir || fallbackDir || process.cwd();
|
|
77594
77723
|
const mergedFiles = rawMergedFiles.map((file3) => {
|
|
77595
|
-
if (
|
|
77596
|
-
const relativePath =
|
|
77724
|
+
if (path79.isAbsolute(file3)) {
|
|
77725
|
+
const relativePath = path79.relative(dir, file3).replace(/\\/g, "/");
|
|
77597
77726
|
if (relativePath.startsWith("..")) {
|
|
77598
77727
|
normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
|
|
77599
77728
|
return file3;
|
|
@@ -77653,8 +77782,8 @@ var declare_scope = createSwarmTool({
|
|
|
77653
77782
|
// src/tools/diff.ts
|
|
77654
77783
|
init_zod();
|
|
77655
77784
|
import * as child_process7 from "node:child_process";
|
|
77656
|
-
import * as
|
|
77657
|
-
import * as
|
|
77785
|
+
import * as fs62 from "node:fs";
|
|
77786
|
+
import * as path80 from "node:path";
|
|
77658
77787
|
init_create_tool();
|
|
77659
77788
|
var MAX_DIFF_LINES = 500;
|
|
77660
77789
|
var DIFF_TIMEOUT_MS = 30000;
|
|
@@ -77683,20 +77812,20 @@ function validateBase(base) {
|
|
|
77683
77812
|
function validatePaths(paths) {
|
|
77684
77813
|
if (!paths)
|
|
77685
77814
|
return null;
|
|
77686
|
-
for (const
|
|
77687
|
-
if (!
|
|
77815
|
+
for (const path81 of paths) {
|
|
77816
|
+
if (!path81 || path81.length === 0) {
|
|
77688
77817
|
return "empty path not allowed";
|
|
77689
77818
|
}
|
|
77690
|
-
if (
|
|
77819
|
+
if (path81.length > MAX_PATH_LENGTH) {
|
|
77691
77820
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
77692
77821
|
}
|
|
77693
|
-
if (SHELL_METACHARACTERS2.test(
|
|
77822
|
+
if (SHELL_METACHARACTERS2.test(path81)) {
|
|
77694
77823
|
return "path contains shell metacharacters";
|
|
77695
77824
|
}
|
|
77696
|
-
if (
|
|
77825
|
+
if (path81.startsWith("-")) {
|
|
77697
77826
|
return 'path cannot start with "-" (option-like arguments not allowed)';
|
|
77698
77827
|
}
|
|
77699
|
-
if (CONTROL_CHAR_PATTERN2.test(
|
|
77828
|
+
if (CONTROL_CHAR_PATTERN2.test(path81)) {
|
|
77700
77829
|
return "path contains control characters";
|
|
77701
77830
|
}
|
|
77702
77831
|
}
|
|
@@ -77802,8 +77931,8 @@ var diff = createSwarmTool({
|
|
|
77802
77931
|
if (parts2.length >= 3) {
|
|
77803
77932
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
77804
77933
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
77805
|
-
const
|
|
77806
|
-
files.push({ path:
|
|
77934
|
+
const path81 = parts2[2];
|
|
77935
|
+
files.push({ path: path81, additions, deletions });
|
|
77807
77936
|
}
|
|
77808
77937
|
}
|
|
77809
77938
|
const contractChanges = [];
|
|
@@ -77843,7 +77972,7 @@ var diff = createSwarmTool({
|
|
|
77843
77972
|
} else if (base === "unstaged") {
|
|
77844
77973
|
const oldRef = `:${file3.path}`;
|
|
77845
77974
|
oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
|
|
77846
|
-
newContent =
|
|
77975
|
+
newContent = fs62.readFileSync(path80.join(directory, file3.path), "utf-8");
|
|
77847
77976
|
} else {
|
|
77848
77977
|
const oldRef = `${base}:${file3.path}`;
|
|
77849
77978
|
oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
|
|
@@ -77917,8 +78046,8 @@ var diff = createSwarmTool({
|
|
|
77917
78046
|
// src/tools/diff-summary.ts
|
|
77918
78047
|
init_zod();
|
|
77919
78048
|
import * as child_process8 from "node:child_process";
|
|
77920
|
-
import * as
|
|
77921
|
-
import * as
|
|
78049
|
+
import * as fs63 from "node:fs";
|
|
78050
|
+
import * as path81 from "node:path";
|
|
77922
78051
|
init_create_tool();
|
|
77923
78052
|
var diff_summary = createSwarmTool({
|
|
77924
78053
|
description: "Generate a filtered semantic diff summary from AST analysis. Returns SemanticDiffSummary with optional filtering by classification or riskLevel.",
|
|
@@ -77966,7 +78095,7 @@ var diff_summary = createSwarmTool({
|
|
|
77966
78095
|
}
|
|
77967
78096
|
try {
|
|
77968
78097
|
let oldContent;
|
|
77969
|
-
const newContent =
|
|
78098
|
+
const newContent = fs63.readFileSync(path81.join(workingDir, filePath), "utf-8");
|
|
77970
78099
|
if (fileExistsInHead) {
|
|
77971
78100
|
oldContent = child_process8.execFileSync("git", ["show", `HEAD:${filePath}`], {
|
|
77972
78101
|
encoding: "utf-8",
|
|
@@ -78194,8 +78323,8 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
78194
78323
|
init_zod();
|
|
78195
78324
|
init_create_tool();
|
|
78196
78325
|
init_path_security();
|
|
78197
|
-
import * as
|
|
78198
|
-
import * as
|
|
78326
|
+
import * as fs64 from "node:fs";
|
|
78327
|
+
import * as path82 from "node:path";
|
|
78199
78328
|
var MAX_FILE_SIZE_BYTES6 = 1024 * 1024;
|
|
78200
78329
|
var MAX_EVIDENCE_FILES = 1000;
|
|
78201
78330
|
var EVIDENCE_DIR3 = ".swarm/evidence";
|
|
@@ -78222,9 +78351,9 @@ function validateRequiredTypes(input) {
|
|
|
78222
78351
|
return null;
|
|
78223
78352
|
}
|
|
78224
78353
|
function isPathWithinSwarm2(filePath, cwd) {
|
|
78225
|
-
const normalizedCwd =
|
|
78226
|
-
const swarmPath =
|
|
78227
|
-
const normalizedPath =
|
|
78354
|
+
const normalizedCwd = path82.resolve(cwd);
|
|
78355
|
+
const swarmPath = path82.join(normalizedCwd, ".swarm");
|
|
78356
|
+
const normalizedPath = path82.resolve(filePath);
|
|
78228
78357
|
return normalizedPath.startsWith(swarmPath);
|
|
78229
78358
|
}
|
|
78230
78359
|
function parseCompletedTasks(planContent) {
|
|
@@ -78240,12 +78369,12 @@ function parseCompletedTasks(planContent) {
|
|
|
78240
78369
|
}
|
|
78241
78370
|
function readEvidenceFiles(evidenceDir, _cwd) {
|
|
78242
78371
|
const evidence = [];
|
|
78243
|
-
if (!
|
|
78372
|
+
if (!fs64.existsSync(evidenceDir) || !fs64.statSync(evidenceDir).isDirectory()) {
|
|
78244
78373
|
return evidence;
|
|
78245
78374
|
}
|
|
78246
78375
|
let files;
|
|
78247
78376
|
try {
|
|
78248
|
-
files =
|
|
78377
|
+
files = fs64.readdirSync(evidenceDir);
|
|
78249
78378
|
} catch {
|
|
78250
78379
|
return evidence;
|
|
78251
78380
|
}
|
|
@@ -78254,14 +78383,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
78254
78383
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
78255
78384
|
continue;
|
|
78256
78385
|
}
|
|
78257
|
-
const filePath =
|
|
78386
|
+
const filePath = path82.join(evidenceDir, filename);
|
|
78258
78387
|
try {
|
|
78259
|
-
const resolvedPath =
|
|
78260
|
-
const evidenceDirResolved =
|
|
78388
|
+
const resolvedPath = path82.resolve(filePath);
|
|
78389
|
+
const evidenceDirResolved = path82.resolve(evidenceDir);
|
|
78261
78390
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
78262
78391
|
continue;
|
|
78263
78392
|
}
|
|
78264
|
-
const stat6 =
|
|
78393
|
+
const stat6 = fs64.lstatSync(filePath);
|
|
78265
78394
|
if (!stat6.isFile()) {
|
|
78266
78395
|
continue;
|
|
78267
78396
|
}
|
|
@@ -78270,7 +78399,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
78270
78399
|
}
|
|
78271
78400
|
let fileStat;
|
|
78272
78401
|
try {
|
|
78273
|
-
fileStat =
|
|
78402
|
+
fileStat = fs64.statSync(filePath);
|
|
78274
78403
|
if (fileStat.size > MAX_FILE_SIZE_BYTES6) {
|
|
78275
78404
|
continue;
|
|
78276
78405
|
}
|
|
@@ -78279,7 +78408,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
78279
78408
|
}
|
|
78280
78409
|
let content;
|
|
78281
78410
|
try {
|
|
78282
|
-
content =
|
|
78411
|
+
content = fs64.readFileSync(filePath, "utf-8");
|
|
78283
78412
|
} catch {
|
|
78284
78413
|
continue;
|
|
78285
78414
|
}
|
|
@@ -78375,7 +78504,7 @@ var evidence_check = createSwarmTool({
|
|
|
78375
78504
|
return JSON.stringify(errorResult, null, 2);
|
|
78376
78505
|
}
|
|
78377
78506
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
|
|
78378
|
-
const planPath =
|
|
78507
|
+
const planPath = path82.join(cwd, PLAN_FILE);
|
|
78379
78508
|
if (!isPathWithinSwarm2(planPath, cwd)) {
|
|
78380
78509
|
const errorResult = {
|
|
78381
78510
|
error: "plan file path validation failed",
|
|
@@ -78389,7 +78518,7 @@ var evidence_check = createSwarmTool({
|
|
|
78389
78518
|
}
|
|
78390
78519
|
let planContent;
|
|
78391
78520
|
try {
|
|
78392
|
-
planContent =
|
|
78521
|
+
planContent = fs64.readFileSync(planPath, "utf-8");
|
|
78393
78522
|
} catch {
|
|
78394
78523
|
const result2 = {
|
|
78395
78524
|
message: "No completed tasks found in plan.",
|
|
@@ -78407,7 +78536,7 @@ var evidence_check = createSwarmTool({
|
|
|
78407
78536
|
};
|
|
78408
78537
|
return JSON.stringify(result2, null, 2);
|
|
78409
78538
|
}
|
|
78410
|
-
const evidenceDir =
|
|
78539
|
+
const evidenceDir = path82.join(cwd, EVIDENCE_DIR3);
|
|
78411
78540
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
78412
78541
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
78413
78542
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -78424,8 +78553,8 @@ var evidence_check = createSwarmTool({
|
|
|
78424
78553
|
// src/tools/file-extractor.ts
|
|
78425
78554
|
init_zod();
|
|
78426
78555
|
init_create_tool();
|
|
78427
|
-
import * as
|
|
78428
|
-
import * as
|
|
78556
|
+
import * as fs65 from "node:fs";
|
|
78557
|
+
import * as path83 from "node:path";
|
|
78429
78558
|
var EXT_MAP = {
|
|
78430
78559
|
python: ".py",
|
|
78431
78560
|
py: ".py",
|
|
@@ -78487,8 +78616,8 @@ var extract_code_blocks = createSwarmTool({
|
|
|
78487
78616
|
execute: async (args2, directory) => {
|
|
78488
78617
|
const { content, output_dir, prefix } = args2;
|
|
78489
78618
|
const targetDir = output_dir || directory;
|
|
78490
|
-
if (!
|
|
78491
|
-
|
|
78619
|
+
if (!fs65.existsSync(targetDir)) {
|
|
78620
|
+
fs65.mkdirSync(targetDir, { recursive: true });
|
|
78492
78621
|
}
|
|
78493
78622
|
if (!content) {
|
|
78494
78623
|
return "Error: content is required";
|
|
@@ -78506,16 +78635,16 @@ var extract_code_blocks = createSwarmTool({
|
|
|
78506
78635
|
if (prefix) {
|
|
78507
78636
|
filename = `${prefix}_${filename}`;
|
|
78508
78637
|
}
|
|
78509
|
-
let filepath =
|
|
78510
|
-
const base =
|
|
78511
|
-
const ext =
|
|
78638
|
+
let filepath = path83.join(targetDir, filename);
|
|
78639
|
+
const base = path83.basename(filepath, path83.extname(filepath));
|
|
78640
|
+
const ext = path83.extname(filepath);
|
|
78512
78641
|
let counter = 1;
|
|
78513
|
-
while (
|
|
78514
|
-
filepath =
|
|
78642
|
+
while (fs65.existsSync(filepath)) {
|
|
78643
|
+
filepath = path83.join(targetDir, `${base}_${counter}${ext}`);
|
|
78515
78644
|
counter++;
|
|
78516
78645
|
}
|
|
78517
78646
|
try {
|
|
78518
|
-
|
|
78647
|
+
fs65.writeFileSync(filepath, code.trim(), "utf-8");
|
|
78519
78648
|
savedFiles.push(filepath);
|
|
78520
78649
|
} catch (error93) {
|
|
78521
78650
|
errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
@@ -78774,8 +78903,8 @@ var gitingest = createSwarmTool({
|
|
|
78774
78903
|
init_zod();
|
|
78775
78904
|
init_create_tool();
|
|
78776
78905
|
init_path_security();
|
|
78777
|
-
import * as
|
|
78778
|
-
import * as
|
|
78906
|
+
import * as fs66 from "node:fs";
|
|
78907
|
+
import * as path84 from "node:path";
|
|
78779
78908
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
78780
78909
|
var MAX_SYMBOL_LENGTH = 256;
|
|
78781
78910
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
@@ -78823,7 +78952,7 @@ function validateSymbolInput(symbol3) {
|
|
|
78823
78952
|
return null;
|
|
78824
78953
|
}
|
|
78825
78954
|
function isBinaryFile2(filePath, buffer) {
|
|
78826
|
-
const ext =
|
|
78955
|
+
const ext = path84.extname(filePath).toLowerCase();
|
|
78827
78956
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
78828
78957
|
return false;
|
|
78829
78958
|
}
|
|
@@ -78847,15 +78976,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
78847
78976
|
const imports = [];
|
|
78848
78977
|
let _resolvedTarget;
|
|
78849
78978
|
try {
|
|
78850
|
-
_resolvedTarget =
|
|
78979
|
+
_resolvedTarget = path84.resolve(targetFile);
|
|
78851
78980
|
} catch {
|
|
78852
78981
|
_resolvedTarget = targetFile;
|
|
78853
78982
|
}
|
|
78854
|
-
const targetBasename =
|
|
78983
|
+
const targetBasename = path84.basename(targetFile, path84.extname(targetFile));
|
|
78855
78984
|
const targetWithExt = targetFile;
|
|
78856
78985
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
78857
|
-
const normalizedTargetWithExt =
|
|
78858
|
-
const normalizedTargetWithoutExt =
|
|
78986
|
+
const normalizedTargetWithExt = path84.normalize(targetWithExt).replace(/\\/g, "/");
|
|
78987
|
+
const normalizedTargetWithoutExt = path84.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
78859
78988
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
78860
78989
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
78861
78990
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -78878,9 +79007,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
78878
79007
|
}
|
|
78879
79008
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
78880
79009
|
let isMatch = false;
|
|
78881
|
-
const _targetDir =
|
|
78882
|
-
const targetExt =
|
|
78883
|
-
const targetBasenameNoExt =
|
|
79010
|
+
const _targetDir = path84.dirname(targetFile);
|
|
79011
|
+
const targetExt = path84.extname(targetFile);
|
|
79012
|
+
const targetBasenameNoExt = path84.basename(targetFile, targetExt);
|
|
78884
79013
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
78885
79014
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
78886
79015
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -78937,7 +79066,7 @@ var SKIP_DIRECTORIES4 = new Set([
|
|
|
78937
79066
|
function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
|
|
78938
79067
|
let entries;
|
|
78939
79068
|
try {
|
|
78940
|
-
entries =
|
|
79069
|
+
entries = fs66.readdirSync(dir);
|
|
78941
79070
|
} catch (e) {
|
|
78942
79071
|
stats.fileErrors.push({
|
|
78943
79072
|
path: dir,
|
|
@@ -78948,13 +79077,13 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
78948
79077
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
78949
79078
|
for (const entry of entries) {
|
|
78950
79079
|
if (SKIP_DIRECTORIES4.has(entry)) {
|
|
78951
|
-
stats.skippedDirs.push(
|
|
79080
|
+
stats.skippedDirs.push(path84.join(dir, entry));
|
|
78952
79081
|
continue;
|
|
78953
79082
|
}
|
|
78954
|
-
const fullPath =
|
|
79083
|
+
const fullPath = path84.join(dir, entry);
|
|
78955
79084
|
let stat6;
|
|
78956
79085
|
try {
|
|
78957
|
-
stat6 =
|
|
79086
|
+
stat6 = fs66.statSync(fullPath);
|
|
78958
79087
|
} catch (e) {
|
|
78959
79088
|
stats.fileErrors.push({
|
|
78960
79089
|
path: fullPath,
|
|
@@ -78965,7 +79094,7 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
78965
79094
|
if (stat6.isDirectory()) {
|
|
78966
79095
|
findSourceFiles2(fullPath, files, stats);
|
|
78967
79096
|
} else if (stat6.isFile()) {
|
|
78968
|
-
const ext =
|
|
79097
|
+
const ext = path84.extname(fullPath).toLowerCase();
|
|
78969
79098
|
if (SUPPORTED_EXTENSIONS3.includes(ext)) {
|
|
78970
79099
|
files.push(fullPath);
|
|
78971
79100
|
}
|
|
@@ -79022,8 +79151,8 @@ var imports = createSwarmTool({
|
|
|
79022
79151
|
return JSON.stringify(errorResult, null, 2);
|
|
79023
79152
|
}
|
|
79024
79153
|
try {
|
|
79025
|
-
const targetFile =
|
|
79026
|
-
if (!
|
|
79154
|
+
const targetFile = path84.resolve(file3);
|
|
79155
|
+
if (!fs66.existsSync(targetFile)) {
|
|
79027
79156
|
const errorResult = {
|
|
79028
79157
|
error: `target file not found: ${file3}`,
|
|
79029
79158
|
target: file3,
|
|
@@ -79033,7 +79162,7 @@ var imports = createSwarmTool({
|
|
|
79033
79162
|
};
|
|
79034
79163
|
return JSON.stringify(errorResult, null, 2);
|
|
79035
79164
|
}
|
|
79036
|
-
const targetStat =
|
|
79165
|
+
const targetStat = fs66.statSync(targetFile);
|
|
79037
79166
|
if (!targetStat.isFile()) {
|
|
79038
79167
|
const errorResult = {
|
|
79039
79168
|
error: "target must be a file, not a directory",
|
|
@@ -79044,7 +79173,7 @@ var imports = createSwarmTool({
|
|
|
79044
79173
|
};
|
|
79045
79174
|
return JSON.stringify(errorResult, null, 2);
|
|
79046
79175
|
}
|
|
79047
|
-
const baseDir =
|
|
79176
|
+
const baseDir = path84.dirname(targetFile);
|
|
79048
79177
|
const scanStats = {
|
|
79049
79178
|
skippedDirs: [],
|
|
79050
79179
|
skippedFiles: 0,
|
|
@@ -79059,12 +79188,12 @@ var imports = createSwarmTool({
|
|
|
79059
79188
|
if (consumers.length >= MAX_CONSUMERS)
|
|
79060
79189
|
break;
|
|
79061
79190
|
try {
|
|
79062
|
-
const stat6 =
|
|
79191
|
+
const stat6 = fs66.statSync(filePath);
|
|
79063
79192
|
if (stat6.size > MAX_FILE_SIZE_BYTES7) {
|
|
79064
79193
|
skippedFileCount++;
|
|
79065
79194
|
continue;
|
|
79066
79195
|
}
|
|
79067
|
-
const buffer =
|
|
79196
|
+
const buffer = fs66.readFileSync(filePath);
|
|
79068
79197
|
if (isBinaryFile2(filePath, buffer)) {
|
|
79069
79198
|
skippedFileCount++;
|
|
79070
79199
|
continue;
|
|
@@ -79589,8 +79718,8 @@ init_schema();
|
|
|
79589
79718
|
init_qa_gate_profile();
|
|
79590
79719
|
init_manager2();
|
|
79591
79720
|
init_curator();
|
|
79592
|
-
import * as
|
|
79593
|
-
import * as
|
|
79721
|
+
import * as fs68 from "node:fs";
|
|
79722
|
+
import * as path86 from "node:path";
|
|
79594
79723
|
init_knowledge_curator();
|
|
79595
79724
|
init_knowledge_reader();
|
|
79596
79725
|
init_knowledge_store();
|
|
@@ -79602,20 +79731,20 @@ init_file_locks();
|
|
|
79602
79731
|
init_plan_schema();
|
|
79603
79732
|
init_ledger();
|
|
79604
79733
|
init_manager();
|
|
79605
|
-
import * as
|
|
79606
|
-
import * as
|
|
79734
|
+
import * as fs67 from "node:fs";
|
|
79735
|
+
import * as path85 from "node:path";
|
|
79607
79736
|
async function writeCheckpoint(directory) {
|
|
79608
79737
|
try {
|
|
79609
79738
|
const plan = await loadPlan(directory);
|
|
79610
79739
|
if (!plan)
|
|
79611
79740
|
return;
|
|
79612
|
-
const swarmDir =
|
|
79613
|
-
|
|
79614
|
-
const jsonPath =
|
|
79615
|
-
const mdPath =
|
|
79616
|
-
|
|
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");
|
|
79617
79746
|
const md = derivePlanMarkdown(plan);
|
|
79618
|
-
|
|
79747
|
+
fs67.writeFileSync(mdPath, md, "utf8");
|
|
79619
79748
|
} catch (error93) {
|
|
79620
79749
|
console.warn(`[checkpoint] Failed to write SWARM_PLAN checkpoint: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
79621
79750
|
}
|
|
@@ -79847,8 +79976,8 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
79847
79976
|
let driftCheckEnabled = true;
|
|
79848
79977
|
let driftHasSpecMd = false;
|
|
79849
79978
|
try {
|
|
79850
|
-
const specMdPath =
|
|
79851
|
-
driftHasSpecMd =
|
|
79979
|
+
const specMdPath = path86.join(dir, ".swarm", "spec.md");
|
|
79980
|
+
driftHasSpecMd = fs68.existsSync(specMdPath);
|
|
79852
79981
|
const gatePlan = await loadPlan(dir);
|
|
79853
79982
|
if (gatePlan) {
|
|
79854
79983
|
const gatePlanId = `${gatePlan.swarm}-${gatePlan.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
|
|
@@ -79869,9 +79998,9 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
79869
79998
|
} else {
|
|
79870
79999
|
let phaseType;
|
|
79871
80000
|
try {
|
|
79872
|
-
const planPath =
|
|
79873
|
-
if (
|
|
79874
|
-
const planRaw =
|
|
80001
|
+
const planPath = path86.join(dir, ".swarm", "plan.json");
|
|
80002
|
+
if (fs68.existsSync(planPath)) {
|
|
80003
|
+
const planRaw = fs68.readFileSync(planPath, "utf-8");
|
|
79875
80004
|
const plan = JSON.parse(planRaw);
|
|
79876
80005
|
const targetPhase = plan.phases?.find((p) => p.id === phase);
|
|
79877
80006
|
phaseType = targetPhase?.type;
|
|
@@ -79882,11 +80011,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
79882
80011
|
warnings.push(`Phase ${phase} is annotated as 'non-code'. Drift verification was skipped per phase type annotation.`);
|
|
79883
80012
|
} else {
|
|
79884
80013
|
try {
|
|
79885
|
-
const driftEvidencePath =
|
|
80014
|
+
const driftEvidencePath = path86.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
|
|
79886
80015
|
let driftVerdictFound = false;
|
|
79887
80016
|
let driftVerdictApproved = false;
|
|
79888
80017
|
try {
|
|
79889
|
-
const driftEvidenceContent =
|
|
80018
|
+
const driftEvidenceContent = fs68.readFileSync(driftEvidencePath, "utf-8");
|
|
79890
80019
|
const driftEvidence = JSON.parse(driftEvidenceContent);
|
|
79891
80020
|
const entries = driftEvidence.entries ?? [];
|
|
79892
80021
|
for (const entry of entries) {
|
|
@@ -79920,9 +80049,9 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
79920
80049
|
let incompleteTaskCount = 0;
|
|
79921
80050
|
let planParseable = false;
|
|
79922
80051
|
try {
|
|
79923
|
-
const planPath =
|
|
79924
|
-
if (
|
|
79925
|
-
const planRaw =
|
|
80052
|
+
const planPath = path86.join(dir, ".swarm", "plan.json");
|
|
80053
|
+
if (fs68.existsSync(planPath)) {
|
|
80054
|
+
const planRaw = fs68.readFileSync(planPath, "utf-8");
|
|
79926
80055
|
const plan = JSON.parse(planRaw);
|
|
79927
80056
|
planParseable = true;
|
|
79928
80057
|
const planPhase = plan.phases?.find((p) => p.id === phase);
|
|
@@ -79987,11 +80116,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
79987
80116
|
const overrides = session2?.qaGateSessionOverrides ?? {};
|
|
79988
80117
|
const effective = getEffectiveGates(profile, overrides);
|
|
79989
80118
|
if (effective.hallucination_guard === true) {
|
|
79990
|
-
const hgPath =
|
|
80119
|
+
const hgPath = path86.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
|
|
79991
80120
|
let hgVerdictFound = false;
|
|
79992
80121
|
let hgVerdictApproved = false;
|
|
79993
80122
|
try {
|
|
79994
|
-
const hgContent =
|
|
80123
|
+
const hgContent = fs68.readFileSync(hgPath, "utf-8");
|
|
79995
80124
|
const hgBundle = JSON.parse(hgContent);
|
|
79996
80125
|
for (const entry of hgBundle.entries ?? []) {
|
|
79997
80126
|
if (typeof entry.type === "string" && entry.type.includes("hallucination") && typeof entry.verdict === "string") {
|
|
@@ -80059,11 +80188,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
80059
80188
|
const overrides = session2?.qaGateSessionOverrides ?? {};
|
|
80060
80189
|
const effective = getEffectiveGates(profile, overrides);
|
|
80061
80190
|
if (effective.mutation_test === true) {
|
|
80062
|
-
const mgPath =
|
|
80191
|
+
const mgPath = path86.join(dir, ".swarm", "evidence", String(phase), "mutation-gate.json");
|
|
80063
80192
|
let mgVerdictFound = false;
|
|
80064
80193
|
let mgVerdict;
|
|
80065
80194
|
try {
|
|
80066
|
-
const mgContent =
|
|
80195
|
+
const mgContent = fs68.readFileSync(mgPath, "utf-8");
|
|
80067
80196
|
const mgBundle = JSON.parse(mgContent);
|
|
80068
80197
|
for (const entry of mgBundle.entries ?? []) {
|
|
80069
80198
|
if (typeof entry.type === "string" && entry.type === "mutation-gate" && typeof entry.verdict === "string") {
|
|
@@ -80133,14 +80262,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
80133
80262
|
const effective = getEffectiveGates(profile, overrides);
|
|
80134
80263
|
if (effective.council_mode === true) {
|
|
80135
80264
|
councilModeEnabled = true;
|
|
80136
|
-
const pcPath =
|
|
80265
|
+
const pcPath = path86.join(dir, ".swarm", "evidence", String(phase), "phase-council.json");
|
|
80137
80266
|
let pcVerdictFound = false;
|
|
80138
80267
|
let _pcVerdict;
|
|
80139
80268
|
let pcQuorumSize;
|
|
80140
80269
|
let pcTimestamp;
|
|
80141
80270
|
let pcPhaseNumber;
|
|
80142
80271
|
try {
|
|
80143
|
-
const pcContent =
|
|
80272
|
+
const pcContent = fs68.readFileSync(pcPath, "utf-8");
|
|
80144
80273
|
const pcBundle = JSON.parse(pcContent);
|
|
80145
80274
|
for (const entry of pcBundle.entries ?? []) {
|
|
80146
80275
|
if (typeof entry.type === "string" && entry.type === "phase-council" && typeof entry.verdict === "string") {
|
|
@@ -80249,11 +80378,11 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
80249
80378
|
status: "blocked",
|
|
80250
80379
|
reason: "PHASE_COUNCIL_REQUIRED",
|
|
80251
80380
|
phase_council_required: true,
|
|
80252
|
-
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.`,
|
|
80253
80382
|
agentsDispatched,
|
|
80254
80383
|
agentsMissing: [],
|
|
80255
80384
|
warnings: [
|
|
80256
|
-
`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.`
|
|
80257
80386
|
]
|
|
80258
80387
|
}, null, 2);
|
|
80259
80388
|
}
|
|
@@ -80335,7 +80464,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
80335
80464
|
}
|
|
80336
80465
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
80337
80466
|
try {
|
|
80338
|
-
const projectName =
|
|
80467
|
+
const projectName = path86.basename(dir);
|
|
80339
80468
|
const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
|
|
80340
80469
|
if (curationResult) {
|
|
80341
80470
|
const sessionState = swarmState.agentSessions.get(sessionID);
|
|
@@ -80415,7 +80544,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
80415
80544
|
let phaseRequiredAgents;
|
|
80416
80545
|
try {
|
|
80417
80546
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
80418
|
-
const planRaw =
|
|
80547
|
+
const planRaw = fs68.readFileSync(planPath, "utf-8");
|
|
80419
80548
|
const plan = JSON.parse(planRaw);
|
|
80420
80549
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
80421
80550
|
phaseRequiredAgents = phaseObj?.required_agents;
|
|
@@ -80430,7 +80559,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
80430
80559
|
if (agentsMissing.length > 0) {
|
|
80431
80560
|
try {
|
|
80432
80561
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
80433
|
-
const planRaw =
|
|
80562
|
+
const planRaw = fs68.readFileSync(planPath, "utf-8");
|
|
80434
80563
|
const plan = JSON.parse(planRaw);
|
|
80435
80564
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
80436
80565
|
if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
|
|
@@ -80470,7 +80599,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
80470
80599
|
if (phaseCompleteConfig.regression_sweep?.enforce) {
|
|
80471
80600
|
try {
|
|
80472
80601
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
80473
|
-
const planRaw =
|
|
80602
|
+
const planRaw = fs68.readFileSync(planPath, "utf-8");
|
|
80474
80603
|
const plan = JSON.parse(planRaw);
|
|
80475
80604
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
80476
80605
|
if (targetPhase) {
|
|
@@ -80524,7 +80653,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
80524
80653
|
}
|
|
80525
80654
|
try {
|
|
80526
80655
|
const eventsPath = validateSwarmPath(dir, "events.jsonl");
|
|
80527
|
-
|
|
80656
|
+
fs68.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
80528
80657
|
`, "utf-8");
|
|
80529
80658
|
} catch (writeError) {
|
|
80530
80659
|
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -80599,12 +80728,12 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
80599
80728
|
warnings.push(`Warning: failed to update plan.json phase status`);
|
|
80600
80729
|
try {
|
|
80601
80730
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
80602
|
-
const planRaw =
|
|
80731
|
+
const planRaw = fs68.readFileSync(planPath, "utf-8");
|
|
80603
80732
|
const plan2 = JSON.parse(planRaw);
|
|
80604
80733
|
const phaseObj = plan2.phases.find((p) => p.id === phase);
|
|
80605
80734
|
if (phaseObj) {
|
|
80606
80735
|
phaseObj.status = "complete";
|
|
80607
|
-
|
|
80736
|
+
fs68.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
|
|
80608
80737
|
}
|
|
80609
80738
|
} catch {}
|
|
80610
80739
|
} else if (plan) {
|
|
@@ -80641,12 +80770,12 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
80641
80770
|
warnings.push(`Warning: failed to update plan.json phase status`);
|
|
80642
80771
|
try {
|
|
80643
80772
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
80644
|
-
const planRaw =
|
|
80773
|
+
const planRaw = fs68.readFileSync(planPath, "utf-8");
|
|
80645
80774
|
const plan = JSON.parse(planRaw);
|
|
80646
80775
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
80647
80776
|
if (phaseObj) {
|
|
80648
80777
|
phaseObj.status = "complete";
|
|
80649
|
-
|
|
80778
|
+
fs68.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
|
|
80650
80779
|
}
|
|
80651
80780
|
} catch {}
|
|
80652
80781
|
}
|
|
@@ -80704,8 +80833,8 @@ init_discovery();
|
|
|
80704
80833
|
init_utils();
|
|
80705
80834
|
init_bun_compat();
|
|
80706
80835
|
init_create_tool();
|
|
80707
|
-
import * as
|
|
80708
|
-
import * as
|
|
80836
|
+
import * as fs69 from "node:fs";
|
|
80837
|
+
import * as path87 from "node:path";
|
|
80709
80838
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
80710
80839
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
80711
80840
|
function isValidEcosystem(value) {
|
|
@@ -80733,31 +80862,31 @@ function validateArgs3(args2) {
|
|
|
80733
80862
|
function detectEcosystems(directory) {
|
|
80734
80863
|
const ecosystems = [];
|
|
80735
80864
|
const cwd = directory;
|
|
80736
|
-
if (
|
|
80865
|
+
if (fs69.existsSync(path87.join(cwd, "package.json"))) {
|
|
80737
80866
|
ecosystems.push("npm");
|
|
80738
80867
|
}
|
|
80739
|
-
if (
|
|
80868
|
+
if (fs69.existsSync(path87.join(cwd, "pyproject.toml")) || fs69.existsSync(path87.join(cwd, "requirements.txt"))) {
|
|
80740
80869
|
ecosystems.push("pip");
|
|
80741
80870
|
}
|
|
80742
|
-
if (
|
|
80871
|
+
if (fs69.existsSync(path87.join(cwd, "Cargo.toml"))) {
|
|
80743
80872
|
ecosystems.push("cargo");
|
|
80744
80873
|
}
|
|
80745
|
-
if (
|
|
80874
|
+
if (fs69.existsSync(path87.join(cwd, "go.mod"))) {
|
|
80746
80875
|
ecosystems.push("go");
|
|
80747
80876
|
}
|
|
80748
80877
|
try {
|
|
80749
|
-
const files =
|
|
80878
|
+
const files = fs69.readdirSync(cwd);
|
|
80750
80879
|
if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
80751
80880
|
ecosystems.push("dotnet");
|
|
80752
80881
|
}
|
|
80753
80882
|
} catch {}
|
|
80754
|
-
if (
|
|
80883
|
+
if (fs69.existsSync(path87.join(cwd, "Gemfile")) || fs69.existsSync(path87.join(cwd, "Gemfile.lock"))) {
|
|
80755
80884
|
ecosystems.push("ruby");
|
|
80756
80885
|
}
|
|
80757
|
-
if (
|
|
80886
|
+
if (fs69.existsSync(path87.join(cwd, "pubspec.yaml"))) {
|
|
80758
80887
|
ecosystems.push("dart");
|
|
80759
80888
|
}
|
|
80760
|
-
if (
|
|
80889
|
+
if (fs69.existsSync(path87.join(cwd, "composer.lock"))) {
|
|
80761
80890
|
ecosystems.push("composer");
|
|
80762
80891
|
}
|
|
80763
80892
|
return ecosystems;
|
|
@@ -81892,8 +82021,8 @@ var pkg_audit = createSwarmTool({
|
|
|
81892
82021
|
// src/tools/placeholder-scan.ts
|
|
81893
82022
|
init_zod();
|
|
81894
82023
|
init_manager2();
|
|
81895
|
-
import * as
|
|
81896
|
-
import * as
|
|
82024
|
+
import * as fs70 from "node:fs";
|
|
82025
|
+
import * as path88 from "node:path";
|
|
81897
82026
|
init_utils();
|
|
81898
82027
|
init_create_tool();
|
|
81899
82028
|
var MAX_FILE_SIZE = 1024 * 1024;
|
|
@@ -82016,7 +82145,7 @@ function isScaffoldFile(filePath) {
|
|
|
82016
82145
|
if (SCAFFOLD_PATH_PATTERNS.some((pattern) => pattern.test(normalizedPath))) {
|
|
82017
82146
|
return true;
|
|
82018
82147
|
}
|
|
82019
|
-
const filename =
|
|
82148
|
+
const filename = path88.basename(filePath);
|
|
82020
82149
|
if (SCAFFOLD_FILENAME_PATTERNS.some((pattern) => pattern.test(filename))) {
|
|
82021
82150
|
return true;
|
|
82022
82151
|
}
|
|
@@ -82033,7 +82162,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
|
|
|
82033
82162
|
if (regex.test(normalizedPath)) {
|
|
82034
82163
|
return true;
|
|
82035
82164
|
}
|
|
82036
|
-
const filename =
|
|
82165
|
+
const filename = path88.basename(filePath);
|
|
82037
82166
|
const filenameRegex = new RegExp(`^${regexPattern}$`, "i");
|
|
82038
82167
|
if (filenameRegex.test(filename)) {
|
|
82039
82168
|
return true;
|
|
@@ -82042,7 +82171,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
|
|
|
82042
82171
|
return false;
|
|
82043
82172
|
}
|
|
82044
82173
|
function isParserSupported(filePath) {
|
|
82045
|
-
const ext =
|
|
82174
|
+
const ext = path88.extname(filePath).toLowerCase();
|
|
82046
82175
|
return SUPPORTED_PARSER_EXTENSIONS.has(ext);
|
|
82047
82176
|
}
|
|
82048
82177
|
function isPlanFile(filePath) {
|
|
@@ -82289,28 +82418,28 @@ async function placeholderScan(input, directory) {
|
|
|
82289
82418
|
let filesScanned = 0;
|
|
82290
82419
|
const filesWithFindings = new Set;
|
|
82291
82420
|
for (const filePath of changed_files) {
|
|
82292
|
-
const fullPath =
|
|
82293
|
-
const resolvedDirectory =
|
|
82294
|
-
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) {
|
|
82295
82424
|
continue;
|
|
82296
82425
|
}
|
|
82297
|
-
if (!
|
|
82426
|
+
if (!fs70.existsSync(fullPath)) {
|
|
82298
82427
|
continue;
|
|
82299
82428
|
}
|
|
82300
82429
|
if (isAllowedByGlobs(filePath, allow_globs)) {
|
|
82301
82430
|
continue;
|
|
82302
82431
|
}
|
|
82303
|
-
const relativeFilePath =
|
|
82432
|
+
const relativeFilePath = path88.relative(directory, fullPath).replace(/\\/g, "/");
|
|
82304
82433
|
if (FILE_ALLOWLIST.some((allowed) => relativeFilePath.endsWith(allowed))) {
|
|
82305
82434
|
continue;
|
|
82306
82435
|
}
|
|
82307
82436
|
let content;
|
|
82308
82437
|
try {
|
|
82309
|
-
const stat6 =
|
|
82438
|
+
const stat6 = fs70.statSync(fullPath);
|
|
82310
82439
|
if (stat6.size > MAX_FILE_SIZE) {
|
|
82311
82440
|
continue;
|
|
82312
82441
|
}
|
|
82313
|
-
content =
|
|
82442
|
+
content = fs70.readFileSync(fullPath, "utf-8");
|
|
82314
82443
|
} catch {
|
|
82315
82444
|
continue;
|
|
82316
82445
|
}
|
|
@@ -82371,8 +82500,8 @@ var placeholder_scan = createSwarmTool({
|
|
|
82371
82500
|
}
|
|
82372
82501
|
});
|
|
82373
82502
|
// src/tools/pre-check-batch.ts
|
|
82374
|
-
import * as
|
|
82375
|
-
import * as
|
|
82503
|
+
import * as fs73 from "node:fs";
|
|
82504
|
+
import * as path91 from "node:path";
|
|
82376
82505
|
init_zod();
|
|
82377
82506
|
init_manager2();
|
|
82378
82507
|
init_utils();
|
|
@@ -82509,8 +82638,8 @@ var quality_budget = createSwarmTool({
|
|
|
82509
82638
|
init_zod();
|
|
82510
82639
|
init_manager2();
|
|
82511
82640
|
init_detector();
|
|
82512
|
-
import * as
|
|
82513
|
-
import * as
|
|
82641
|
+
import * as fs72 from "node:fs";
|
|
82642
|
+
import * as path90 from "node:path";
|
|
82514
82643
|
import { extname as extname18 } from "node:path";
|
|
82515
82644
|
|
|
82516
82645
|
// src/sast/rules/c.ts
|
|
@@ -83403,25 +83532,25 @@ init_create_tool();
|
|
|
83403
83532
|
// src/tools/sast-baseline.ts
|
|
83404
83533
|
init_utils2();
|
|
83405
83534
|
import * as crypto8 from "node:crypto";
|
|
83406
|
-
import * as
|
|
83407
|
-
import * as
|
|
83535
|
+
import * as fs71 from "node:fs";
|
|
83536
|
+
import * as path89 from "node:path";
|
|
83408
83537
|
var BASELINE_SCHEMA_VERSION = "1.0.0";
|
|
83409
83538
|
var MAX_BASELINE_FINDINGS = 2000;
|
|
83410
83539
|
var MAX_BASELINE_BYTES = 2 * 1048576;
|
|
83411
83540
|
var LOCK_RETRY_DELAYS_MS = [50, 100, 200, 400, 800];
|
|
83412
83541
|
function normalizeFindingPath(directory, file3) {
|
|
83413
|
-
const resolved =
|
|
83414
|
-
const rel =
|
|
83542
|
+
const resolved = path89.isAbsolute(file3) ? file3 : path89.resolve(directory, file3);
|
|
83543
|
+
const rel = path89.relative(path89.resolve(directory), resolved);
|
|
83415
83544
|
return rel.replace(/\\/g, "/");
|
|
83416
83545
|
}
|
|
83417
83546
|
function baselineRelPath(phase) {
|
|
83418
|
-
return
|
|
83547
|
+
return path89.join("evidence", String(phase), "sast-baseline.json");
|
|
83419
83548
|
}
|
|
83420
83549
|
function tempRelPath(phase) {
|
|
83421
|
-
return
|
|
83550
|
+
return path89.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
|
|
83422
83551
|
}
|
|
83423
83552
|
function lockRelPath(phase) {
|
|
83424
|
-
return
|
|
83553
|
+
return path89.join("evidence", String(phase), "sast-baseline.json.lock");
|
|
83425
83554
|
}
|
|
83426
83555
|
function getLine(lines, idx) {
|
|
83427
83556
|
if (idx < 0 || idx >= lines.length)
|
|
@@ -83438,7 +83567,7 @@ function fingerprintFinding(finding, directory, occurrenceIndex) {
|
|
|
83438
83567
|
}
|
|
83439
83568
|
const lineNum = finding.location.line;
|
|
83440
83569
|
try {
|
|
83441
|
-
const content =
|
|
83570
|
+
const content = fs71.readFileSync(finding.location.file, "utf-8");
|
|
83442
83571
|
const lines = content.split(`
|
|
83443
83572
|
`);
|
|
83444
83573
|
const idx = lineNum - 1;
|
|
@@ -83469,7 +83598,7 @@ function assignOccurrenceIndices(findings, directory) {
|
|
|
83469
83598
|
try {
|
|
83470
83599
|
if (relFile.startsWith(".."))
|
|
83471
83600
|
throw new Error("escapes workspace");
|
|
83472
|
-
const content =
|
|
83601
|
+
const content = fs71.readFileSync(finding.location.file, "utf-8");
|
|
83473
83602
|
const lines = content.split(`
|
|
83474
83603
|
`);
|
|
83475
83604
|
const idx = lineNum - 1;
|
|
@@ -83498,11 +83627,11 @@ function assignOccurrenceIndices(findings, directory) {
|
|
|
83498
83627
|
async function acquireLock(lockPath) {
|
|
83499
83628
|
for (let attempt = 0;attempt <= LOCK_RETRY_DELAYS_MS.length; attempt++) {
|
|
83500
83629
|
try {
|
|
83501
|
-
const fd =
|
|
83502
|
-
|
|
83630
|
+
const fd = fs71.openSync(lockPath, "wx");
|
|
83631
|
+
fs71.closeSync(fd);
|
|
83503
83632
|
return () => {
|
|
83504
83633
|
try {
|
|
83505
|
-
|
|
83634
|
+
fs71.unlinkSync(lockPath);
|
|
83506
83635
|
} catch {}
|
|
83507
83636
|
};
|
|
83508
83637
|
} catch {
|
|
@@ -83542,13 +83671,13 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
83542
83671
|
message: e instanceof Error ? e.message : "Path validation failed"
|
|
83543
83672
|
};
|
|
83544
83673
|
}
|
|
83545
|
-
|
|
83546
|
-
|
|
83674
|
+
fs71.mkdirSync(path89.dirname(baselinePath), { recursive: true });
|
|
83675
|
+
fs71.mkdirSync(path89.dirname(tempPath), { recursive: true });
|
|
83547
83676
|
const releaseLock = await acquireLock(lockPath);
|
|
83548
83677
|
try {
|
|
83549
83678
|
let existing = null;
|
|
83550
83679
|
try {
|
|
83551
|
-
const raw =
|
|
83680
|
+
const raw = fs71.readFileSync(baselinePath, "utf-8");
|
|
83552
83681
|
const parsed = JSON.parse(raw);
|
|
83553
83682
|
if (parsed.schema_version === BASELINE_SCHEMA_VERSION) {
|
|
83554
83683
|
existing = parsed;
|
|
@@ -83608,8 +83737,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
83608
83737
|
message: `Baseline would exceed size cap (${json4.length} bytes > ${MAX_BASELINE_BYTES})`
|
|
83609
83738
|
};
|
|
83610
83739
|
}
|
|
83611
|
-
|
|
83612
|
-
|
|
83740
|
+
fs71.writeFileSync(tempPath, json4, "utf-8");
|
|
83741
|
+
fs71.renameSync(tempPath, baselinePath);
|
|
83613
83742
|
return {
|
|
83614
83743
|
status: "merged",
|
|
83615
83744
|
path: baselinePath,
|
|
@@ -83640,8 +83769,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
83640
83769
|
message: `Baseline would exceed size cap (${json3.length} bytes > ${MAX_BASELINE_BYTES})`
|
|
83641
83770
|
};
|
|
83642
83771
|
}
|
|
83643
|
-
|
|
83644
|
-
|
|
83772
|
+
fs71.writeFileSync(tempPath, json3, "utf-8");
|
|
83773
|
+
fs71.renameSync(tempPath, baselinePath);
|
|
83645
83774
|
return {
|
|
83646
83775
|
status: "written",
|
|
83647
83776
|
path: baselinePath,
|
|
@@ -83666,7 +83795,7 @@ function loadBaseline(directory, phase) {
|
|
|
83666
83795
|
};
|
|
83667
83796
|
}
|
|
83668
83797
|
try {
|
|
83669
|
-
const raw =
|
|
83798
|
+
const raw = fs71.readFileSync(baselinePath, "utf-8");
|
|
83670
83799
|
const parsed = JSON.parse(raw);
|
|
83671
83800
|
if (parsed.schema_version !== BASELINE_SCHEMA_VERSION) {
|
|
83672
83801
|
return {
|
|
@@ -83708,17 +83837,17 @@ var SEVERITY_ORDER = {
|
|
|
83708
83837
|
};
|
|
83709
83838
|
function shouldSkipFile(filePath) {
|
|
83710
83839
|
try {
|
|
83711
|
-
const stats =
|
|
83840
|
+
const stats = fs72.statSync(filePath);
|
|
83712
83841
|
if (stats.size > MAX_FILE_SIZE_BYTES8) {
|
|
83713
83842
|
return { skip: true, reason: "file too large" };
|
|
83714
83843
|
}
|
|
83715
83844
|
if (stats.size === 0) {
|
|
83716
83845
|
return { skip: true, reason: "empty file" };
|
|
83717
83846
|
}
|
|
83718
|
-
const fd =
|
|
83847
|
+
const fd = fs72.openSync(filePath, "r");
|
|
83719
83848
|
const buffer = Buffer.alloc(8192);
|
|
83720
|
-
const bytesRead =
|
|
83721
|
-
|
|
83849
|
+
const bytesRead = fs72.readSync(fd, buffer, 0, 8192, 0);
|
|
83850
|
+
fs72.closeSync(fd);
|
|
83722
83851
|
if (bytesRead > 0) {
|
|
83723
83852
|
let nullCount = 0;
|
|
83724
83853
|
for (let i2 = 0;i2 < bytesRead; i2++) {
|
|
@@ -83757,7 +83886,7 @@ function countBySeverity(findings) {
|
|
|
83757
83886
|
}
|
|
83758
83887
|
function scanFileWithTierA(filePath, language) {
|
|
83759
83888
|
try {
|
|
83760
|
-
const content =
|
|
83889
|
+
const content = fs72.readFileSync(filePath, "utf-8");
|
|
83761
83890
|
const findings = executeRulesSync(filePath, content, language);
|
|
83762
83891
|
return findings.map((f) => ({
|
|
83763
83892
|
rule_id: f.rule_id,
|
|
@@ -83810,13 +83939,13 @@ async function sastScan(input, directory, config3) {
|
|
|
83810
83939
|
_filesSkipped++;
|
|
83811
83940
|
continue;
|
|
83812
83941
|
}
|
|
83813
|
-
const resolvedPath =
|
|
83814
|
-
const resolvedDirectory =
|
|
83815
|
-
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) {
|
|
83816
83945
|
_filesSkipped++;
|
|
83817
83946
|
continue;
|
|
83818
83947
|
}
|
|
83819
|
-
if (!
|
|
83948
|
+
if (!fs72.existsSync(resolvedPath)) {
|
|
83820
83949
|
_filesSkipped++;
|
|
83821
83950
|
continue;
|
|
83822
83951
|
}
|
|
@@ -84123,18 +84252,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
84123
84252
|
let resolved;
|
|
84124
84253
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
84125
84254
|
if (isWinAbs) {
|
|
84126
|
-
resolved =
|
|
84127
|
-
} else if (
|
|
84128
|
-
resolved =
|
|
84255
|
+
resolved = path91.win32.resolve(inputPath);
|
|
84256
|
+
} else if (path91.isAbsolute(inputPath)) {
|
|
84257
|
+
resolved = path91.resolve(inputPath);
|
|
84129
84258
|
} else {
|
|
84130
|
-
resolved =
|
|
84259
|
+
resolved = path91.resolve(baseDir, inputPath);
|
|
84131
84260
|
}
|
|
84132
|
-
const workspaceResolved =
|
|
84261
|
+
const workspaceResolved = path91.resolve(workspaceDir);
|
|
84133
84262
|
let relative20;
|
|
84134
84263
|
if (isWinAbs) {
|
|
84135
|
-
relative20 =
|
|
84264
|
+
relative20 = path91.win32.relative(workspaceResolved, resolved);
|
|
84136
84265
|
} else {
|
|
84137
|
-
relative20 =
|
|
84266
|
+
relative20 = path91.relative(workspaceResolved, resolved);
|
|
84138
84267
|
}
|
|
84139
84268
|
if (relative20.startsWith("..")) {
|
|
84140
84269
|
return "path traversal detected";
|
|
@@ -84199,7 +84328,7 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
84199
84328
|
if (typeof file3 !== "string") {
|
|
84200
84329
|
continue;
|
|
84201
84330
|
}
|
|
84202
|
-
const resolvedPath =
|
|
84331
|
+
const resolvedPath = path91.resolve(file3);
|
|
84203
84332
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
84204
84333
|
if (validationError) {
|
|
84205
84334
|
continue;
|
|
@@ -84356,7 +84485,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
84356
84485
|
skippedFiles++;
|
|
84357
84486
|
continue;
|
|
84358
84487
|
}
|
|
84359
|
-
const resolvedPath =
|
|
84488
|
+
const resolvedPath = path91.resolve(file3);
|
|
84360
84489
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
84361
84490
|
if (validationError) {
|
|
84362
84491
|
skippedFiles++;
|
|
@@ -84374,14 +84503,14 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
84374
84503
|
};
|
|
84375
84504
|
}
|
|
84376
84505
|
for (const file3 of validatedFiles) {
|
|
84377
|
-
const ext =
|
|
84506
|
+
const ext = path91.extname(file3).toLowerCase();
|
|
84378
84507
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
84379
84508
|
skippedFiles++;
|
|
84380
84509
|
continue;
|
|
84381
84510
|
}
|
|
84382
84511
|
let stat6;
|
|
84383
84512
|
try {
|
|
84384
|
-
stat6 =
|
|
84513
|
+
stat6 = fs73.statSync(file3);
|
|
84385
84514
|
} catch {
|
|
84386
84515
|
skippedFiles++;
|
|
84387
84516
|
continue;
|
|
@@ -84392,7 +84521,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
84392
84521
|
}
|
|
84393
84522
|
let content;
|
|
84394
84523
|
try {
|
|
84395
|
-
const buffer =
|
|
84524
|
+
const buffer = fs73.readFileSync(file3);
|
|
84396
84525
|
if (buffer.includes(0)) {
|
|
84397
84526
|
skippedFiles++;
|
|
84398
84527
|
continue;
|
|
@@ -84593,7 +84722,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
|
|
|
84593
84722
|
const preexistingFindings = [];
|
|
84594
84723
|
for (const finding of findings) {
|
|
84595
84724
|
const filePath = finding.location.file;
|
|
84596
|
-
const normalised =
|
|
84725
|
+
const normalised = path91.relative(directory, filePath).replace(/\\/g, "/");
|
|
84597
84726
|
const changedLines = changedLineRanges.get(normalised);
|
|
84598
84727
|
if (changedLines?.has(finding.location.line)) {
|
|
84599
84728
|
newFindings.push(finding);
|
|
@@ -84644,7 +84773,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
|
|
|
84644
84773
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
84645
84774
|
continue;
|
|
84646
84775
|
}
|
|
84647
|
-
changedFiles.push(
|
|
84776
|
+
changedFiles.push(path91.resolve(directory, file3));
|
|
84648
84777
|
}
|
|
84649
84778
|
if (changedFiles.length === 0) {
|
|
84650
84779
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -84845,7 +84974,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
84845
84974
|
};
|
|
84846
84975
|
return JSON.stringify(errorResult, null, 2);
|
|
84847
84976
|
}
|
|
84848
|
-
const resolvedDirectory =
|
|
84977
|
+
const resolvedDirectory = path91.resolve(typedArgs.directory);
|
|
84849
84978
|
const workspaceAnchor = resolvedDirectory;
|
|
84850
84979
|
const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
|
|
84851
84980
|
if (dirError) {
|
|
@@ -84886,7 +85015,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
84886
85015
|
});
|
|
84887
85016
|
// src/tools/repo-map.ts
|
|
84888
85017
|
init_zod();
|
|
84889
|
-
import * as
|
|
85018
|
+
import * as path92 from "node:path";
|
|
84890
85019
|
init_path_security();
|
|
84891
85020
|
init_create_tool();
|
|
84892
85021
|
var VALID_ACTIONS = [
|
|
@@ -84911,7 +85040,7 @@ function validateFile(p) {
|
|
|
84911
85040
|
return "file contains control characters";
|
|
84912
85041
|
if (containsPathTraversal(p))
|
|
84913
85042
|
return "file contains path traversal";
|
|
84914
|
-
if (
|
|
85043
|
+
if (path92.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
|
|
84915
85044
|
return "file must be a workspace-relative path, not absolute";
|
|
84916
85045
|
}
|
|
84917
85046
|
return null;
|
|
@@ -84934,8 +85063,8 @@ function ok(action, payload) {
|
|
|
84934
85063
|
}
|
|
84935
85064
|
function toRelativeGraphPath(input, workspaceRoot) {
|
|
84936
85065
|
const normalized = input.replace(/\\/g, "/");
|
|
84937
|
-
if (
|
|
84938
|
-
const rel =
|
|
85066
|
+
if (path92.isAbsolute(normalized)) {
|
|
85067
|
+
const rel = path92.relative(workspaceRoot, normalized).replace(/\\/g, "/");
|
|
84939
85068
|
return normalizeGraphPath2(rel);
|
|
84940
85069
|
}
|
|
84941
85070
|
return normalizeGraphPath2(normalized);
|
|
@@ -85079,8 +85208,8 @@ var repo_map = createSwarmTool({
|
|
|
85079
85208
|
// src/tools/req-coverage.ts
|
|
85080
85209
|
init_zod();
|
|
85081
85210
|
init_create_tool();
|
|
85082
|
-
import * as
|
|
85083
|
-
import * as
|
|
85211
|
+
import * as fs74 from "node:fs";
|
|
85212
|
+
import * as path93 from "node:path";
|
|
85084
85213
|
var SPEC_FILE = ".swarm/spec.md";
|
|
85085
85214
|
var EVIDENCE_DIR4 = ".swarm/evidence";
|
|
85086
85215
|
var OBLIGATION_KEYWORDS = ["MUST", "SHOULD", "SHALL"];
|
|
@@ -85139,19 +85268,19 @@ function extractObligationAndText(id, lineText) {
|
|
|
85139
85268
|
var PHASE_TASK_ID_REGEX = /^\d+\.\d+(\.\d+)*$/;
|
|
85140
85269
|
function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
85141
85270
|
const touchedFiles = new Set;
|
|
85142
|
-
if (!
|
|
85271
|
+
if (!fs74.existsSync(evidenceDir) || !fs74.statSync(evidenceDir).isDirectory()) {
|
|
85143
85272
|
return [];
|
|
85144
85273
|
}
|
|
85145
85274
|
let entries;
|
|
85146
85275
|
try {
|
|
85147
|
-
entries =
|
|
85276
|
+
entries = fs74.readdirSync(evidenceDir);
|
|
85148
85277
|
} catch {
|
|
85149
85278
|
return [];
|
|
85150
85279
|
}
|
|
85151
85280
|
for (const entry of entries) {
|
|
85152
|
-
const entryPath =
|
|
85281
|
+
const entryPath = path93.join(evidenceDir, entry);
|
|
85153
85282
|
try {
|
|
85154
|
-
const stat6 =
|
|
85283
|
+
const stat6 = fs74.statSync(entryPath);
|
|
85155
85284
|
if (!stat6.isDirectory()) {
|
|
85156
85285
|
continue;
|
|
85157
85286
|
}
|
|
@@ -85165,14 +85294,14 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
85165
85294
|
if (entryPhase !== String(phase)) {
|
|
85166
85295
|
continue;
|
|
85167
85296
|
}
|
|
85168
|
-
const evidenceFilePath =
|
|
85297
|
+
const evidenceFilePath = path93.join(entryPath, "evidence.json");
|
|
85169
85298
|
try {
|
|
85170
|
-
const resolvedPath =
|
|
85171
|
-
const evidenceDirResolved =
|
|
85172
|
-
if (!resolvedPath.startsWith(evidenceDirResolved +
|
|
85299
|
+
const resolvedPath = path93.resolve(evidenceFilePath);
|
|
85300
|
+
const evidenceDirResolved = path93.resolve(evidenceDir);
|
|
85301
|
+
if (!resolvedPath.startsWith(evidenceDirResolved + path93.sep)) {
|
|
85173
85302
|
continue;
|
|
85174
85303
|
}
|
|
85175
|
-
const stat6 =
|
|
85304
|
+
const stat6 = fs74.lstatSync(evidenceFilePath);
|
|
85176
85305
|
if (!stat6.isFile()) {
|
|
85177
85306
|
continue;
|
|
85178
85307
|
}
|
|
@@ -85184,7 +85313,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
85184
85313
|
}
|
|
85185
85314
|
let content;
|
|
85186
85315
|
try {
|
|
85187
|
-
content =
|
|
85316
|
+
content = fs74.readFileSync(evidenceFilePath, "utf-8");
|
|
85188
85317
|
} catch {
|
|
85189
85318
|
continue;
|
|
85190
85319
|
}
|
|
@@ -85203,7 +85332,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
85203
85332
|
if (Array.isArray(diffEntry.files_changed)) {
|
|
85204
85333
|
for (const file3 of diffEntry.files_changed) {
|
|
85205
85334
|
if (typeof file3 === "string") {
|
|
85206
|
-
touchedFiles.add(
|
|
85335
|
+
touchedFiles.add(path93.resolve(cwd, file3));
|
|
85207
85336
|
}
|
|
85208
85337
|
}
|
|
85209
85338
|
}
|
|
@@ -85216,12 +85345,12 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
85216
85345
|
}
|
|
85217
85346
|
function searchFileForKeywords(filePath, keywords, cwd) {
|
|
85218
85347
|
try {
|
|
85219
|
-
const resolvedPath =
|
|
85220
|
-
const cwdResolved =
|
|
85348
|
+
const resolvedPath = path93.resolve(filePath);
|
|
85349
|
+
const cwdResolved = path93.resolve(cwd);
|
|
85221
85350
|
if (!resolvedPath.startsWith(cwdResolved)) {
|
|
85222
85351
|
return false;
|
|
85223
85352
|
}
|
|
85224
|
-
const content =
|
|
85353
|
+
const content = fs74.readFileSync(resolvedPath, "utf-8");
|
|
85225
85354
|
for (const keyword of keywords) {
|
|
85226
85355
|
const regex = new RegExp(`\\b${keyword}\\b`, "i");
|
|
85227
85356
|
if (regex.test(content)) {
|
|
@@ -85351,10 +85480,10 @@ var req_coverage = createSwarmTool({
|
|
|
85351
85480
|
}, null, 2);
|
|
85352
85481
|
}
|
|
85353
85482
|
const cwd = inputDirectory || directory;
|
|
85354
|
-
const specPath =
|
|
85483
|
+
const specPath = path93.join(cwd, SPEC_FILE);
|
|
85355
85484
|
let specContent;
|
|
85356
85485
|
try {
|
|
85357
|
-
specContent =
|
|
85486
|
+
specContent = fs74.readFileSync(specPath, "utf-8");
|
|
85358
85487
|
} catch (readError) {
|
|
85359
85488
|
return JSON.stringify({
|
|
85360
85489
|
success: false,
|
|
@@ -85378,7 +85507,7 @@ var req_coverage = createSwarmTool({
|
|
|
85378
85507
|
message: "No FR requirements found in spec.md"
|
|
85379
85508
|
}, null, 2);
|
|
85380
85509
|
}
|
|
85381
|
-
const evidenceDir =
|
|
85510
|
+
const evidenceDir = path93.join(cwd, EVIDENCE_DIR4);
|
|
85382
85511
|
const touchedFiles = readTouchedFiles(evidenceDir, phase, cwd);
|
|
85383
85512
|
const analyzedRequirements = [];
|
|
85384
85513
|
let coveredCount = 0;
|
|
@@ -85404,12 +85533,12 @@ var req_coverage = createSwarmTool({
|
|
|
85404
85533
|
requirements: analyzedRequirements
|
|
85405
85534
|
};
|
|
85406
85535
|
const reportFilename = `req-coverage-phase-${phase}.json`;
|
|
85407
|
-
const reportPath =
|
|
85536
|
+
const reportPath = path93.join(evidenceDir, reportFilename);
|
|
85408
85537
|
try {
|
|
85409
|
-
if (!
|
|
85410
|
-
|
|
85538
|
+
if (!fs74.existsSync(evidenceDir)) {
|
|
85539
|
+
fs74.mkdirSync(evidenceDir, { recursive: true });
|
|
85411
85540
|
}
|
|
85412
|
-
|
|
85541
|
+
fs74.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8");
|
|
85413
85542
|
} catch (writeError) {
|
|
85414
85543
|
console.warn(`Failed to write coverage report: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
85415
85544
|
}
|
|
@@ -85491,8 +85620,8 @@ init_plan_schema();
|
|
|
85491
85620
|
init_qa_gate_profile();
|
|
85492
85621
|
init_file_locks();
|
|
85493
85622
|
import * as crypto9 from "node:crypto";
|
|
85494
|
-
import * as
|
|
85495
|
-
import * as
|
|
85623
|
+
import * as fs75 from "node:fs";
|
|
85624
|
+
import * as path94 from "node:path";
|
|
85496
85625
|
init_ledger();
|
|
85497
85626
|
init_manager();
|
|
85498
85627
|
init_state();
|
|
@@ -85570,17 +85699,17 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
85570
85699
|
};
|
|
85571
85700
|
}
|
|
85572
85701
|
if (args2.working_directory && fallbackDir) {
|
|
85573
|
-
const resolvedTarget =
|
|
85574
|
-
const resolvedRoot =
|
|
85702
|
+
const resolvedTarget = path94.resolve(args2.working_directory);
|
|
85703
|
+
const resolvedRoot = path94.resolve(fallbackDir);
|
|
85575
85704
|
let fallbackExists = false;
|
|
85576
85705
|
try {
|
|
85577
|
-
|
|
85706
|
+
fs75.accessSync(resolvedRoot, fs75.constants.F_OK);
|
|
85578
85707
|
fallbackExists = true;
|
|
85579
85708
|
} catch {
|
|
85580
85709
|
fallbackExists = false;
|
|
85581
85710
|
}
|
|
85582
85711
|
if (fallbackExists) {
|
|
85583
|
-
const isSubdirectory = resolvedTarget.startsWith(resolvedRoot +
|
|
85712
|
+
const isSubdirectory = resolvedTarget.startsWith(resolvedRoot + path94.sep);
|
|
85584
85713
|
if (isSubdirectory) {
|
|
85585
85714
|
return {
|
|
85586
85715
|
success: false,
|
|
@@ -85596,11 +85725,11 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
85596
85725
|
let specMtime;
|
|
85597
85726
|
let specHash;
|
|
85598
85727
|
if (process.env.SWARM_SKIP_SPEC_GATE !== "1") {
|
|
85599
|
-
const specPath =
|
|
85728
|
+
const specPath = path94.join(targetWorkspace, ".swarm", "spec.md");
|
|
85600
85729
|
try {
|
|
85601
|
-
const stat6 = await
|
|
85730
|
+
const stat6 = await fs75.promises.stat(specPath);
|
|
85602
85731
|
specMtime = stat6.mtime.toISOString();
|
|
85603
|
-
const content = await
|
|
85732
|
+
const content = await fs75.promises.readFile(specPath, "utf8");
|
|
85604
85733
|
specHash = crypto9.createHash("sha256").update(content).digest("hex");
|
|
85605
85734
|
} catch {
|
|
85606
85735
|
return {
|
|
@@ -85612,10 +85741,10 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
85612
85741
|
}
|
|
85613
85742
|
}
|
|
85614
85743
|
if (process.env.SWARM_SKIP_GATE_SELECTION !== "1") {
|
|
85615
|
-
const contextPath =
|
|
85744
|
+
const contextPath = path94.join(targetWorkspace, ".swarm", "context.md");
|
|
85616
85745
|
let contextContent = "";
|
|
85617
85746
|
try {
|
|
85618
|
-
contextContent = await
|
|
85747
|
+
contextContent = await fs75.promises.readFile(contextPath, "utf8");
|
|
85619
85748
|
} catch {}
|
|
85620
85749
|
const hasPendingSection = contextContent.includes("## Pending QA Gate Selection");
|
|
85621
85750
|
if (!hasPendingSection) {
|
|
@@ -85762,14 +85891,14 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
85762
85891
|
}
|
|
85763
85892
|
await writeCheckpoint(dir).catch(() => {});
|
|
85764
85893
|
try {
|
|
85765
|
-
const markerPath =
|
|
85894
|
+
const markerPath = path94.join(dir, ".swarm", ".plan-write-marker");
|
|
85766
85895
|
const marker = JSON.stringify({
|
|
85767
85896
|
source: "save_plan",
|
|
85768
85897
|
timestamp: new Date().toISOString(),
|
|
85769
85898
|
phases_count: plan.phases.length,
|
|
85770
85899
|
tasks_count: tasksCount
|
|
85771
85900
|
});
|
|
85772
|
-
await
|
|
85901
|
+
await fs75.promises.writeFile(markerPath, marker, "utf8");
|
|
85773
85902
|
} catch {}
|
|
85774
85903
|
const warnings = [];
|
|
85775
85904
|
let criticReviewFound = false;
|
|
@@ -85785,7 +85914,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
85785
85914
|
return {
|
|
85786
85915
|
success: true,
|
|
85787
85916
|
message: "Plan saved successfully",
|
|
85788
|
-
plan_path:
|
|
85917
|
+
plan_path: path94.join(dir, ".swarm", "plan.json"),
|
|
85789
85918
|
phases_count: plan.phases.length,
|
|
85790
85919
|
tasks_count: tasksCount,
|
|
85791
85920
|
...resolvedProfile !== undefined ? { execution_profile: resolvedProfile } : {},
|
|
@@ -85837,8 +85966,8 @@ var save_plan = createSwarmTool({
|
|
|
85837
85966
|
// src/tools/sbom-generate.ts
|
|
85838
85967
|
init_zod();
|
|
85839
85968
|
init_manager2();
|
|
85840
|
-
import * as
|
|
85841
|
-
import * as
|
|
85969
|
+
import * as fs76 from "node:fs";
|
|
85970
|
+
import * as path95 from "node:path";
|
|
85842
85971
|
|
|
85843
85972
|
// src/sbom/detectors/index.ts
|
|
85844
85973
|
init_utils();
|
|
@@ -86686,9 +86815,9 @@ function findManifestFiles(rootDir) {
|
|
|
86686
86815
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
86687
86816
|
function searchDir(dir) {
|
|
86688
86817
|
try {
|
|
86689
|
-
const entries =
|
|
86818
|
+
const entries = fs76.readdirSync(dir, { withFileTypes: true });
|
|
86690
86819
|
for (const entry of entries) {
|
|
86691
|
-
const fullPath =
|
|
86820
|
+
const fullPath = path95.join(dir, entry.name);
|
|
86692
86821
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
86693
86822
|
continue;
|
|
86694
86823
|
}
|
|
@@ -86697,7 +86826,7 @@ function findManifestFiles(rootDir) {
|
|
|
86697
86826
|
} else if (entry.isFile()) {
|
|
86698
86827
|
for (const pattern of patterns) {
|
|
86699
86828
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
86700
|
-
manifestFiles.push(
|
|
86829
|
+
manifestFiles.push(path95.relative(rootDir, fullPath));
|
|
86701
86830
|
break;
|
|
86702
86831
|
}
|
|
86703
86832
|
}
|
|
@@ -86713,13 +86842,13 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
86713
86842
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
86714
86843
|
for (const dir of directories) {
|
|
86715
86844
|
try {
|
|
86716
|
-
const entries =
|
|
86845
|
+
const entries = fs76.readdirSync(dir, { withFileTypes: true });
|
|
86717
86846
|
for (const entry of entries) {
|
|
86718
|
-
const fullPath =
|
|
86847
|
+
const fullPath = path95.join(dir, entry.name);
|
|
86719
86848
|
if (entry.isFile()) {
|
|
86720
86849
|
for (const pattern of patterns) {
|
|
86721
86850
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
86722
|
-
found.push(
|
|
86851
|
+
found.push(path95.relative(workingDir, fullPath));
|
|
86723
86852
|
break;
|
|
86724
86853
|
}
|
|
86725
86854
|
}
|
|
@@ -86732,11 +86861,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
86732
86861
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
86733
86862
|
const dirs = new Set;
|
|
86734
86863
|
for (const file3 of changedFiles) {
|
|
86735
|
-
let currentDir =
|
|
86864
|
+
let currentDir = path95.dirname(file3);
|
|
86736
86865
|
while (true) {
|
|
86737
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
86738
|
-
dirs.add(
|
|
86739
|
-
const parent =
|
|
86866
|
+
if (currentDir && currentDir !== "." && currentDir !== path95.sep) {
|
|
86867
|
+
dirs.add(path95.join(workingDir, currentDir));
|
|
86868
|
+
const parent = path95.dirname(currentDir);
|
|
86740
86869
|
if (parent === currentDir)
|
|
86741
86870
|
break;
|
|
86742
86871
|
currentDir = parent;
|
|
@@ -86750,7 +86879,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
86750
86879
|
}
|
|
86751
86880
|
function ensureOutputDir(outputDir) {
|
|
86752
86881
|
try {
|
|
86753
|
-
|
|
86882
|
+
fs76.mkdirSync(outputDir, { recursive: true });
|
|
86754
86883
|
} catch (error93) {
|
|
86755
86884
|
if (!error93 || error93.code !== "EEXIST") {
|
|
86756
86885
|
throw error93;
|
|
@@ -86820,7 +86949,7 @@ var sbom_generate = createSwarmTool({
|
|
|
86820
86949
|
const changedFiles = obj.changed_files;
|
|
86821
86950
|
const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
|
|
86822
86951
|
const workingDir = directory;
|
|
86823
|
-
const outputDir =
|
|
86952
|
+
const outputDir = path95.isAbsolute(relativeOutputDir) ? relativeOutputDir : path95.join(workingDir, relativeOutputDir);
|
|
86824
86953
|
let manifestFiles = [];
|
|
86825
86954
|
if (scope === "all") {
|
|
86826
86955
|
manifestFiles = findManifestFiles(workingDir);
|
|
@@ -86843,11 +86972,11 @@ var sbom_generate = createSwarmTool({
|
|
|
86843
86972
|
const processedFiles = [];
|
|
86844
86973
|
for (const manifestFile of manifestFiles) {
|
|
86845
86974
|
try {
|
|
86846
|
-
const fullPath =
|
|
86847
|
-
if (!
|
|
86975
|
+
const fullPath = path95.isAbsolute(manifestFile) ? manifestFile : path95.join(workingDir, manifestFile);
|
|
86976
|
+
if (!fs76.existsSync(fullPath)) {
|
|
86848
86977
|
continue;
|
|
86849
86978
|
}
|
|
86850
|
-
const content =
|
|
86979
|
+
const content = fs76.readFileSync(fullPath, "utf-8");
|
|
86851
86980
|
const components = detectComponents(manifestFile, content);
|
|
86852
86981
|
processedFiles.push(manifestFile);
|
|
86853
86982
|
if (components.length > 0) {
|
|
@@ -86860,8 +86989,8 @@ var sbom_generate = createSwarmTool({
|
|
|
86860
86989
|
const bom = generateCycloneDX(allComponents);
|
|
86861
86990
|
const bomJson = serializeCycloneDX(bom);
|
|
86862
86991
|
const filename = generateSbomFilename();
|
|
86863
|
-
const outputPath =
|
|
86864
|
-
|
|
86992
|
+
const outputPath = path95.join(outputDir, filename);
|
|
86993
|
+
fs76.writeFileSync(outputPath, bomJson, "utf-8");
|
|
86865
86994
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
86866
86995
|
try {
|
|
86867
86996
|
const timestamp = new Date().toISOString();
|
|
@@ -86903,8 +87032,8 @@ var sbom_generate = createSwarmTool({
|
|
|
86903
87032
|
// src/tools/schema-drift.ts
|
|
86904
87033
|
init_zod();
|
|
86905
87034
|
init_create_tool();
|
|
86906
|
-
import * as
|
|
86907
|
-
import * as
|
|
87035
|
+
import * as fs77 from "node:fs";
|
|
87036
|
+
import * as path96 from "node:path";
|
|
86908
87037
|
var SPEC_CANDIDATES = [
|
|
86909
87038
|
"openapi.json",
|
|
86910
87039
|
"openapi.yaml",
|
|
@@ -86936,28 +87065,28 @@ function normalizePath3(p) {
|
|
|
86936
87065
|
}
|
|
86937
87066
|
function discoverSpecFile(cwd, specFileArg) {
|
|
86938
87067
|
if (specFileArg) {
|
|
86939
|
-
const resolvedPath =
|
|
86940
|
-
const normalizedCwd = cwd.endsWith(
|
|
87068
|
+
const resolvedPath = path96.resolve(cwd, specFileArg);
|
|
87069
|
+
const normalizedCwd = cwd.endsWith(path96.sep) ? cwd : cwd + path96.sep;
|
|
86941
87070
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
86942
87071
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
86943
87072
|
}
|
|
86944
|
-
const ext =
|
|
87073
|
+
const ext = path96.extname(resolvedPath).toLowerCase();
|
|
86945
87074
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
86946
87075
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
86947
87076
|
}
|
|
86948
|
-
const stats =
|
|
87077
|
+
const stats = fs77.statSync(resolvedPath);
|
|
86949
87078
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
86950
87079
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
86951
87080
|
}
|
|
86952
|
-
if (!
|
|
87081
|
+
if (!fs77.existsSync(resolvedPath)) {
|
|
86953
87082
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
86954
87083
|
}
|
|
86955
87084
|
return resolvedPath;
|
|
86956
87085
|
}
|
|
86957
87086
|
for (const candidate of SPEC_CANDIDATES) {
|
|
86958
|
-
const candidatePath =
|
|
86959
|
-
if (
|
|
86960
|
-
const stats =
|
|
87087
|
+
const candidatePath = path96.resolve(cwd, candidate);
|
|
87088
|
+
if (fs77.existsSync(candidatePath)) {
|
|
87089
|
+
const stats = fs77.statSync(candidatePath);
|
|
86961
87090
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
86962
87091
|
return candidatePath;
|
|
86963
87092
|
}
|
|
@@ -86966,8 +87095,8 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
86966
87095
|
return null;
|
|
86967
87096
|
}
|
|
86968
87097
|
function parseSpec(specFile) {
|
|
86969
|
-
const content =
|
|
86970
|
-
const ext =
|
|
87098
|
+
const content = fs77.readFileSync(specFile, "utf-8");
|
|
87099
|
+
const ext = path96.extname(specFile).toLowerCase();
|
|
86971
87100
|
if (ext === ".json") {
|
|
86972
87101
|
return parseJsonSpec(content);
|
|
86973
87102
|
}
|
|
@@ -87038,12 +87167,12 @@ function extractRoutes(cwd) {
|
|
|
87038
87167
|
function walkDir(dir) {
|
|
87039
87168
|
let entries;
|
|
87040
87169
|
try {
|
|
87041
|
-
entries =
|
|
87170
|
+
entries = fs77.readdirSync(dir, { withFileTypes: true });
|
|
87042
87171
|
} catch {
|
|
87043
87172
|
return;
|
|
87044
87173
|
}
|
|
87045
87174
|
for (const entry of entries) {
|
|
87046
|
-
const fullPath =
|
|
87175
|
+
const fullPath = path96.join(dir, entry.name);
|
|
87047
87176
|
if (entry.isSymbolicLink()) {
|
|
87048
87177
|
continue;
|
|
87049
87178
|
}
|
|
@@ -87053,7 +87182,7 @@ function extractRoutes(cwd) {
|
|
|
87053
87182
|
}
|
|
87054
87183
|
walkDir(fullPath);
|
|
87055
87184
|
} else if (entry.isFile()) {
|
|
87056
|
-
const ext =
|
|
87185
|
+
const ext = path96.extname(entry.name).toLowerCase();
|
|
87057
87186
|
const baseName = entry.name.toLowerCase();
|
|
87058
87187
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
87059
87188
|
continue;
|
|
@@ -87071,7 +87200,7 @@ function extractRoutes(cwd) {
|
|
|
87071
87200
|
}
|
|
87072
87201
|
function extractRoutesFromFile(filePath) {
|
|
87073
87202
|
const routes = [];
|
|
87074
|
-
const content =
|
|
87203
|
+
const content = fs77.readFileSync(filePath, "utf-8");
|
|
87075
87204
|
const lines = content.split(/\r?\n/);
|
|
87076
87205
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
87077
87206
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -87220,8 +87349,8 @@ init_zod();
|
|
|
87220
87349
|
init_bun_compat();
|
|
87221
87350
|
init_path_security();
|
|
87222
87351
|
init_create_tool();
|
|
87223
|
-
import * as
|
|
87224
|
-
import * as
|
|
87352
|
+
import * as fs78 from "node:fs";
|
|
87353
|
+
import * as path97 from "node:path";
|
|
87225
87354
|
var DEFAULT_MAX_RESULTS = 100;
|
|
87226
87355
|
var DEFAULT_MAX_LINES = 200;
|
|
87227
87356
|
var REGEX_TIMEOUT_MS = 5000;
|
|
@@ -87257,11 +87386,11 @@ function containsWindowsAttacks3(str) {
|
|
|
87257
87386
|
}
|
|
87258
87387
|
function isPathInWorkspace3(filePath, workspace) {
|
|
87259
87388
|
try {
|
|
87260
|
-
const resolvedPath =
|
|
87261
|
-
const realWorkspace =
|
|
87262
|
-
const realResolvedPath =
|
|
87263
|
-
const relativePath =
|
|
87264
|
-
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)) {
|
|
87265
87394
|
return false;
|
|
87266
87395
|
}
|
|
87267
87396
|
return true;
|
|
@@ -87274,12 +87403,12 @@ function validatePathForRead2(filePath, workspace) {
|
|
|
87274
87403
|
}
|
|
87275
87404
|
function findRgInEnvPath() {
|
|
87276
87405
|
const searchPath = process.env.PATH ?? "";
|
|
87277
|
-
for (const dir of searchPath.split(
|
|
87406
|
+
for (const dir of searchPath.split(path97.delimiter)) {
|
|
87278
87407
|
if (!dir)
|
|
87279
87408
|
continue;
|
|
87280
87409
|
const isWindows = process.platform === "win32";
|
|
87281
|
-
const candidate =
|
|
87282
|
-
if (
|
|
87410
|
+
const candidate = path97.join(dir, isWindows ? "rg.exe" : "rg");
|
|
87411
|
+
if (fs78.existsSync(candidate))
|
|
87283
87412
|
return candidate;
|
|
87284
87413
|
}
|
|
87285
87414
|
return null;
|
|
@@ -87406,10 +87535,10 @@ function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
|
|
|
87406
87535
|
return files;
|
|
87407
87536
|
}
|
|
87408
87537
|
try {
|
|
87409
|
-
const entries =
|
|
87538
|
+
const entries = fs78.readdirSync(dir, { withFileTypes: true });
|
|
87410
87539
|
for (const entry of entries) {
|
|
87411
|
-
const fullPath =
|
|
87412
|
-
const relativePath =
|
|
87540
|
+
const fullPath = path97.join(dir, entry.name);
|
|
87541
|
+
const relativePath = path97.relative(workspace, fullPath);
|
|
87413
87542
|
if (!validatePathForRead2(fullPath, workspace)) {
|
|
87414
87543
|
continue;
|
|
87415
87544
|
}
|
|
@@ -87450,13 +87579,13 @@ async function fallbackSearch(opts) {
|
|
|
87450
87579
|
const matches = [];
|
|
87451
87580
|
let total = 0;
|
|
87452
87581
|
for (const file3 of files) {
|
|
87453
|
-
const fullPath =
|
|
87582
|
+
const fullPath = path97.join(opts.workspace, file3);
|
|
87454
87583
|
if (!validatePathForRead2(fullPath, opts.workspace)) {
|
|
87455
87584
|
continue;
|
|
87456
87585
|
}
|
|
87457
87586
|
let stats;
|
|
87458
87587
|
try {
|
|
87459
|
-
stats =
|
|
87588
|
+
stats = fs78.statSync(fullPath);
|
|
87460
87589
|
if (stats.size > MAX_FILE_SIZE_BYTES10) {
|
|
87461
87590
|
continue;
|
|
87462
87591
|
}
|
|
@@ -87465,7 +87594,7 @@ async function fallbackSearch(opts) {
|
|
|
87465
87594
|
}
|
|
87466
87595
|
let content;
|
|
87467
87596
|
try {
|
|
87468
|
-
content =
|
|
87597
|
+
content = fs78.readFileSync(fullPath, "utf-8");
|
|
87469
87598
|
} catch {
|
|
87470
87599
|
continue;
|
|
87471
87600
|
}
|
|
@@ -87577,7 +87706,7 @@ var search = createSwarmTool({
|
|
|
87577
87706
|
message: "Exclude pattern contains invalid Windows-specific sequence"
|
|
87578
87707
|
}, null, 2);
|
|
87579
87708
|
}
|
|
87580
|
-
if (!
|
|
87709
|
+
if (!fs78.existsSync(directory)) {
|
|
87581
87710
|
return JSON.stringify({
|
|
87582
87711
|
error: true,
|
|
87583
87712
|
type: "unknown",
|
|
@@ -87702,12 +87831,136 @@ var set_qa_gates = createSwarmTool({
|
|
|
87702
87831
|
return JSON.stringify(await executeSetQaGates(typedArgs, directory), null, 2);
|
|
87703
87832
|
}
|
|
87704
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
|
+
});
|
|
87705
87958
|
// src/tools/suggest-patch.ts
|
|
87706
87959
|
init_zod();
|
|
87707
87960
|
init_path_security();
|
|
87708
87961
|
init_create_tool();
|
|
87709
|
-
import * as
|
|
87710
|
-
import * as
|
|
87962
|
+
import * as fs79 from "node:fs";
|
|
87963
|
+
import * as path98 from "node:path";
|
|
87711
87964
|
var WINDOWS_RESERVED_NAMES4 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
87712
87965
|
function containsWindowsAttacks4(str) {
|
|
87713
87966
|
if (/:[^\\/]/.test(str))
|
|
@@ -87721,14 +87974,14 @@ function containsWindowsAttacks4(str) {
|
|
|
87721
87974
|
}
|
|
87722
87975
|
function isPathInWorkspace4(filePath, workspace) {
|
|
87723
87976
|
try {
|
|
87724
|
-
const resolvedPath =
|
|
87725
|
-
if (!
|
|
87977
|
+
const resolvedPath = path98.resolve(workspace, filePath);
|
|
87978
|
+
if (!fs79.existsSync(resolvedPath)) {
|
|
87726
87979
|
return true;
|
|
87727
87980
|
}
|
|
87728
|
-
const realWorkspace =
|
|
87729
|
-
const realResolvedPath =
|
|
87730
|
-
const relativePath =
|
|
87731
|
-
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)) {
|
|
87732
87985
|
return false;
|
|
87733
87986
|
}
|
|
87734
87987
|
return true;
|
|
@@ -87900,7 +88153,7 @@ var suggestPatch = createSwarmTool({
|
|
|
87900
88153
|
message: "changes cannot be empty"
|
|
87901
88154
|
}, null, 2);
|
|
87902
88155
|
}
|
|
87903
|
-
if (!
|
|
88156
|
+
if (!fs79.existsSync(directory)) {
|
|
87904
88157
|
return JSON.stringify({
|
|
87905
88158
|
success: false,
|
|
87906
88159
|
error: true,
|
|
@@ -87936,8 +88189,8 @@ var suggestPatch = createSwarmTool({
|
|
|
87936
88189
|
});
|
|
87937
88190
|
continue;
|
|
87938
88191
|
}
|
|
87939
|
-
const fullPath =
|
|
87940
|
-
if (!
|
|
88192
|
+
const fullPath = path98.resolve(directory, change.file);
|
|
88193
|
+
if (!fs79.existsSync(fullPath)) {
|
|
87941
88194
|
errors5.push({
|
|
87942
88195
|
success: false,
|
|
87943
88196
|
error: true,
|
|
@@ -87951,7 +88204,7 @@ var suggestPatch = createSwarmTool({
|
|
|
87951
88204
|
}
|
|
87952
88205
|
let content;
|
|
87953
88206
|
try {
|
|
87954
|
-
content =
|
|
88207
|
+
content = fs79.readFileSync(fullPath, "utf-8");
|
|
87955
88208
|
} catch (err3) {
|
|
87956
88209
|
errors5.push({
|
|
87957
88210
|
success: false,
|
|
@@ -88198,8 +88451,8 @@ var generate_mutants = createSwarmTool({
|
|
|
88198
88451
|
// src/tools/lint-spec.ts
|
|
88199
88452
|
init_spec_schema();
|
|
88200
88453
|
init_create_tool();
|
|
88201
|
-
import * as
|
|
88202
|
-
import * as
|
|
88454
|
+
import * as fs80 from "node:fs";
|
|
88455
|
+
import * as path99 from "node:path";
|
|
88203
88456
|
var SPEC_FILE_NAME = "spec.md";
|
|
88204
88457
|
var SWARM_DIR2 = ".swarm";
|
|
88205
88458
|
var OBLIGATION_KEYWORDS2 = ["MUST", "SHALL", "SHOULD", "MAY"];
|
|
@@ -88252,8 +88505,8 @@ var lint_spec = createSwarmTool({
|
|
|
88252
88505
|
async execute(_args, directory) {
|
|
88253
88506
|
const errors5 = [];
|
|
88254
88507
|
const warnings = [];
|
|
88255
|
-
const specPath =
|
|
88256
|
-
if (!
|
|
88508
|
+
const specPath = path99.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
|
|
88509
|
+
if (!fs80.existsSync(specPath)) {
|
|
88257
88510
|
const result2 = {
|
|
88258
88511
|
valid: false,
|
|
88259
88512
|
specMtime: null,
|
|
@@ -88272,12 +88525,12 @@ var lint_spec = createSwarmTool({
|
|
|
88272
88525
|
}
|
|
88273
88526
|
let specMtime = null;
|
|
88274
88527
|
try {
|
|
88275
|
-
const stats =
|
|
88528
|
+
const stats = fs80.statSync(specPath);
|
|
88276
88529
|
specMtime = stats.mtime.toISOString();
|
|
88277
88530
|
} catch {}
|
|
88278
88531
|
let content;
|
|
88279
88532
|
try {
|
|
88280
|
-
content =
|
|
88533
|
+
content = fs80.readFileSync(specPath, "utf-8");
|
|
88281
88534
|
} catch (e) {
|
|
88282
88535
|
const result2 = {
|
|
88283
88536
|
valid: false,
|
|
@@ -88322,13 +88575,13 @@ var lint_spec = createSwarmTool({
|
|
|
88322
88575
|
});
|
|
88323
88576
|
// src/tools/mutation-test.ts
|
|
88324
88577
|
init_zod();
|
|
88325
|
-
import * as
|
|
88326
|
-
import * as
|
|
88578
|
+
import * as fs81 from "node:fs";
|
|
88579
|
+
import * as path101 from "node:path";
|
|
88327
88580
|
|
|
88328
88581
|
// src/mutation/engine.ts
|
|
88329
88582
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
88330
88583
|
import { unlinkSync as unlinkSync13, writeFileSync as writeFileSync20 } from "node:fs";
|
|
88331
|
-
import * as
|
|
88584
|
+
import * as path100 from "node:path";
|
|
88332
88585
|
|
|
88333
88586
|
// src/mutation/equivalence.ts
|
|
88334
88587
|
function isStaticallyEquivalent(originalCode, mutatedCode) {
|
|
@@ -88463,7 +88716,7 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
|
|
|
88463
88716
|
let patchFile;
|
|
88464
88717
|
try {
|
|
88465
88718
|
const safeId2 = patch.id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
88466
|
-
patchFile =
|
|
88719
|
+
patchFile = path100.join(workingDir, `.mutation_patch_${safeId2}.diff`);
|
|
88467
88720
|
try {
|
|
88468
88721
|
writeFileSync20(patchFile, patch.patch);
|
|
88469
88722
|
} catch (writeErr) {
|
|
@@ -88857,8 +89110,8 @@ var mutation_test = createSwarmTool({
|
|
|
88857
89110
|
];
|
|
88858
89111
|
for (const filePath of uniquePaths) {
|
|
88859
89112
|
try {
|
|
88860
|
-
const resolvedPath =
|
|
88861
|
-
sourceFiles.set(filePath,
|
|
89113
|
+
const resolvedPath = path101.resolve(cwd, filePath);
|
|
89114
|
+
sourceFiles.set(filePath, fs81.readFileSync(resolvedPath, "utf-8"));
|
|
88862
89115
|
} catch {}
|
|
88863
89116
|
}
|
|
88864
89117
|
const report = await executeMutationSuite(typedArgs.patches, typedArgs.test_command, typedArgs.files, cwd, undefined, undefined, sourceFiles.size > 0 ? sourceFiles : undefined);
|
|
@@ -88876,8 +89129,8 @@ var mutation_test = createSwarmTool({
|
|
|
88876
89129
|
init_zod();
|
|
88877
89130
|
init_manager2();
|
|
88878
89131
|
init_detector();
|
|
88879
|
-
import * as
|
|
88880
|
-
import * as
|
|
89132
|
+
import * as fs82 from "node:fs";
|
|
89133
|
+
import * as path102 from "node:path";
|
|
88881
89134
|
init_create_tool();
|
|
88882
89135
|
var MAX_FILE_SIZE2 = 2 * 1024 * 1024;
|
|
88883
89136
|
var BINARY_CHECK_BYTES = 8192;
|
|
@@ -88943,7 +89196,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
88943
89196
|
if (languages?.length) {
|
|
88944
89197
|
const lowerLangs = languages.map((l) => l.toLowerCase());
|
|
88945
89198
|
filesToCheck = filesToCheck.filter((file3) => {
|
|
88946
|
-
const ext =
|
|
89199
|
+
const ext = path102.extname(file3.path).toLowerCase();
|
|
88947
89200
|
const langDef = getLanguageForExtension(ext);
|
|
88948
89201
|
const fileProfile = getProfileForFile(file3.path);
|
|
88949
89202
|
const langId = fileProfile?.id || langDef?.id;
|
|
@@ -88956,7 +89209,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
88956
89209
|
let skippedCount = 0;
|
|
88957
89210
|
for (const fileInfo of filesToCheck) {
|
|
88958
89211
|
const { path: filePath } = fileInfo;
|
|
88959
|
-
const fullPath =
|
|
89212
|
+
const fullPath = path102.isAbsolute(filePath) ? filePath : path102.join(directory, filePath);
|
|
88960
89213
|
const result = {
|
|
88961
89214
|
path: filePath,
|
|
88962
89215
|
language: "",
|
|
@@ -88986,7 +89239,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
88986
89239
|
}
|
|
88987
89240
|
let content;
|
|
88988
89241
|
try {
|
|
88989
|
-
content =
|
|
89242
|
+
content = fs82.readFileSync(fullPath, "utf8");
|
|
88990
89243
|
} catch {
|
|
88991
89244
|
result.skipped_reason = "file_read_error";
|
|
88992
89245
|
skippedCount++;
|
|
@@ -89005,7 +89258,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
89005
89258
|
results.push(result);
|
|
89006
89259
|
continue;
|
|
89007
89260
|
}
|
|
89008
|
-
const ext =
|
|
89261
|
+
const ext = path102.extname(filePath).toLowerCase();
|
|
89009
89262
|
const langDef = getLanguageForExtension(ext);
|
|
89010
89263
|
result.language = profile?.id || langDef?.id || "unknown";
|
|
89011
89264
|
const errors5 = extractSyntaxErrors(parser, content);
|
|
@@ -89097,8 +89350,8 @@ init_zod();
|
|
|
89097
89350
|
init_utils();
|
|
89098
89351
|
init_create_tool();
|
|
89099
89352
|
init_path_security();
|
|
89100
|
-
import * as
|
|
89101
|
-
import * as
|
|
89353
|
+
import * as fs83 from "node:fs";
|
|
89354
|
+
import * as path103 from "node:path";
|
|
89102
89355
|
var MAX_TEXT_LENGTH = 200;
|
|
89103
89356
|
var MAX_FILE_SIZE_BYTES11 = 1024 * 1024;
|
|
89104
89357
|
var SUPPORTED_EXTENSIONS4 = new Set([
|
|
@@ -89164,9 +89417,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
89164
89417
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
89165
89418
|
}
|
|
89166
89419
|
try {
|
|
89167
|
-
const resolvedPath =
|
|
89168
|
-
const normalizedCwd =
|
|
89169
|
-
const normalizedResolved =
|
|
89420
|
+
const resolvedPath = path103.resolve(paths);
|
|
89421
|
+
const normalizedCwd = path103.resolve(cwd);
|
|
89422
|
+
const normalizedResolved = path103.resolve(resolvedPath);
|
|
89170
89423
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
89171
89424
|
return {
|
|
89172
89425
|
error: "paths must be within the current working directory",
|
|
@@ -89182,13 +89435,13 @@ function validatePathsInput(paths, cwd) {
|
|
|
89182
89435
|
}
|
|
89183
89436
|
}
|
|
89184
89437
|
function isSupportedExtension(filePath) {
|
|
89185
|
-
const ext =
|
|
89438
|
+
const ext = path103.extname(filePath).toLowerCase();
|
|
89186
89439
|
return SUPPORTED_EXTENSIONS4.has(ext);
|
|
89187
89440
|
}
|
|
89188
89441
|
function findSourceFiles3(dir, files = []) {
|
|
89189
89442
|
let entries;
|
|
89190
89443
|
try {
|
|
89191
|
-
entries =
|
|
89444
|
+
entries = fs83.readdirSync(dir);
|
|
89192
89445
|
} catch {
|
|
89193
89446
|
return files;
|
|
89194
89447
|
}
|
|
@@ -89197,10 +89450,10 @@ function findSourceFiles3(dir, files = []) {
|
|
|
89197
89450
|
if (SKIP_DIRECTORIES5.has(entry)) {
|
|
89198
89451
|
continue;
|
|
89199
89452
|
}
|
|
89200
|
-
const fullPath =
|
|
89453
|
+
const fullPath = path103.join(dir, entry);
|
|
89201
89454
|
let stat6;
|
|
89202
89455
|
try {
|
|
89203
|
-
stat6 =
|
|
89456
|
+
stat6 = fs83.statSync(fullPath);
|
|
89204
89457
|
} catch {
|
|
89205
89458
|
continue;
|
|
89206
89459
|
}
|
|
@@ -89293,7 +89546,7 @@ var todo_extract = createSwarmTool({
|
|
|
89293
89546
|
return JSON.stringify(errorResult, null, 2);
|
|
89294
89547
|
}
|
|
89295
89548
|
const scanPath = resolvedPath;
|
|
89296
|
-
if (!
|
|
89549
|
+
if (!fs83.existsSync(scanPath)) {
|
|
89297
89550
|
const errorResult = {
|
|
89298
89551
|
error: `path not found: ${pathsInput}`,
|
|
89299
89552
|
total: 0,
|
|
@@ -89303,13 +89556,13 @@ var todo_extract = createSwarmTool({
|
|
|
89303
89556
|
return JSON.stringify(errorResult, null, 2);
|
|
89304
89557
|
}
|
|
89305
89558
|
const filesToScan = [];
|
|
89306
|
-
const stat6 =
|
|
89559
|
+
const stat6 = fs83.statSync(scanPath);
|
|
89307
89560
|
if (stat6.isFile()) {
|
|
89308
89561
|
if (isSupportedExtension(scanPath)) {
|
|
89309
89562
|
filesToScan.push(scanPath);
|
|
89310
89563
|
} else {
|
|
89311
89564
|
const errorResult = {
|
|
89312
|
-
error: `unsupported file extension: ${
|
|
89565
|
+
error: `unsupported file extension: ${path103.extname(scanPath)}`,
|
|
89313
89566
|
total: 0,
|
|
89314
89567
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
89315
89568
|
entries: []
|
|
@@ -89322,11 +89575,11 @@ var todo_extract = createSwarmTool({
|
|
|
89322
89575
|
const allEntries = [];
|
|
89323
89576
|
for (const filePath of filesToScan) {
|
|
89324
89577
|
try {
|
|
89325
|
-
const fileStat =
|
|
89578
|
+
const fileStat = fs83.statSync(filePath);
|
|
89326
89579
|
if (fileStat.size > MAX_FILE_SIZE_BYTES11) {
|
|
89327
89580
|
continue;
|
|
89328
89581
|
}
|
|
89329
|
-
const content =
|
|
89582
|
+
const content = fs83.readFileSync(filePath, "utf-8");
|
|
89330
89583
|
const entries = parseTodoComments(content, filePath, tagsSet);
|
|
89331
89584
|
allEntries.push(...entries);
|
|
89332
89585
|
} catch {}
|
|
@@ -89357,19 +89610,19 @@ init_loader();
|
|
|
89357
89610
|
init_schema();
|
|
89358
89611
|
init_qa_gate_profile();
|
|
89359
89612
|
init_gate_evidence();
|
|
89360
|
-
import * as
|
|
89361
|
-
import * as
|
|
89613
|
+
import * as fs85 from "node:fs";
|
|
89614
|
+
import * as path105 from "node:path";
|
|
89362
89615
|
|
|
89363
89616
|
// src/hooks/diff-scope.ts
|
|
89364
89617
|
init_bun_compat();
|
|
89365
|
-
import * as
|
|
89366
|
-
import * as
|
|
89618
|
+
import * as fs84 from "node:fs";
|
|
89619
|
+
import * as path104 from "node:path";
|
|
89367
89620
|
function getDeclaredScope(taskId, directory) {
|
|
89368
89621
|
try {
|
|
89369
|
-
const planPath =
|
|
89370
|
-
if (!
|
|
89622
|
+
const planPath = path104.join(directory, ".swarm", "plan.json");
|
|
89623
|
+
if (!fs84.existsSync(planPath))
|
|
89371
89624
|
return null;
|
|
89372
|
-
const raw =
|
|
89625
|
+
const raw = fs84.readFileSync(planPath, "utf-8");
|
|
89373
89626
|
const plan = JSON.parse(raw);
|
|
89374
89627
|
for (const phase of plan.phases ?? []) {
|
|
89375
89628
|
for (const task of phase.tasks ?? []) {
|
|
@@ -89485,7 +89738,7 @@ var TIER_3_PATTERNS = [
|
|
|
89485
89738
|
];
|
|
89486
89739
|
function matchesTier3Pattern(files) {
|
|
89487
89740
|
for (const file3 of files) {
|
|
89488
|
-
const fileName =
|
|
89741
|
+
const fileName = path105.basename(file3);
|
|
89489
89742
|
for (const pattern of TIER_3_PATTERNS) {
|
|
89490
89743
|
if (pattern.test(fileName)) {
|
|
89491
89744
|
return true;
|
|
@@ -89499,8 +89752,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
89499
89752
|
if (hasActiveTurboMode()) {
|
|
89500
89753
|
const resolvedDir2 = workingDirectory;
|
|
89501
89754
|
try {
|
|
89502
|
-
const planPath =
|
|
89503
|
-
const planRaw =
|
|
89755
|
+
const planPath = path105.join(resolvedDir2, ".swarm", "plan.json");
|
|
89756
|
+
const planRaw = fs85.readFileSync(planPath, "utf-8");
|
|
89504
89757
|
const plan = JSON.parse(planRaw);
|
|
89505
89758
|
for (const planPhase of plan.phases ?? []) {
|
|
89506
89759
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -89569,8 +89822,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
89569
89822
|
}
|
|
89570
89823
|
try {
|
|
89571
89824
|
const resolvedDir2 = workingDirectory;
|
|
89572
|
-
const planPath =
|
|
89573
|
-
const planRaw =
|
|
89825
|
+
const planPath = path105.join(resolvedDir2, ".swarm", "plan.json");
|
|
89826
|
+
const planRaw = fs85.readFileSync(planPath, "utf-8");
|
|
89574
89827
|
const plan = JSON.parse(planRaw);
|
|
89575
89828
|
for (const planPhase of plan.phases ?? []) {
|
|
89576
89829
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -89713,65 +89966,6 @@ function recoverTaskStateFromDelegations(taskId) {
|
|
|
89713
89966
|
}
|
|
89714
89967
|
}
|
|
89715
89968
|
}
|
|
89716
|
-
function checkCouncilGate(workingDirectory, taskId) {
|
|
89717
|
-
let councilEnabled = false;
|
|
89718
|
-
let effectiveMinimum = 3;
|
|
89719
|
-
try {
|
|
89720
|
-
const config3 = loadPluginConfig(workingDirectory);
|
|
89721
|
-
councilEnabled = config3.council?.enabled === true;
|
|
89722
|
-
effectiveMinimum = config3.council?.requireAllMembers ? 5 : config3.council?.minimumMembers ?? 3;
|
|
89723
|
-
} catch {
|
|
89724
|
-
return { blocked: false, reason: "" };
|
|
89725
|
-
}
|
|
89726
|
-
if (!councilEnabled) {
|
|
89727
|
-
return { blocked: false, reason: "" };
|
|
89728
|
-
}
|
|
89729
|
-
try {
|
|
89730
|
-
const planPath = path104.join(workingDirectory, ".swarm", "plan.json");
|
|
89731
|
-
const planRaw = fs84.readFileSync(planPath, "utf-8");
|
|
89732
|
-
const planObj = JSON.parse(planRaw);
|
|
89733
|
-
if (planObj.swarm && planObj.title) {
|
|
89734
|
-
const planId = `${planObj.swarm}-${planObj.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
|
|
89735
|
-
const profile = getProfile(workingDirectory, planId);
|
|
89736
|
-
if (!profile || !profile.gates.council_mode) {
|
|
89737
|
-
return { blocked: false, reason: "" };
|
|
89738
|
-
}
|
|
89739
|
-
}
|
|
89740
|
-
} catch {
|
|
89741
|
-
return { blocked: false, reason: "" };
|
|
89742
|
-
}
|
|
89743
|
-
let evidence;
|
|
89744
|
-
try {
|
|
89745
|
-
evidence = readTaskEvidenceRaw(workingDirectory, taskId);
|
|
89746
|
-
} catch {
|
|
89747
|
-
return {
|
|
89748
|
-
blocked: true,
|
|
89749
|
-
reason: "council gate required but not yet run — architect must call submit_council_verdicts before advancing this task"
|
|
89750
|
-
};
|
|
89751
|
-
}
|
|
89752
|
-
const councilGate = evidence?.gates?.council;
|
|
89753
|
-
if (!councilGate) {
|
|
89754
|
-
return {
|
|
89755
|
-
blocked: true,
|
|
89756
|
-
reason: "council gate required but not yet run — architect must call submit_council_verdicts before advancing this task"
|
|
89757
|
-
};
|
|
89758
|
-
}
|
|
89759
|
-
if (councilGate.verdict === "REJECT") {
|
|
89760
|
-
return {
|
|
89761
|
-
blocked: true,
|
|
89762
|
-
reason: "council gate blocked advancement — resolve requiredFixes and re-run submit_council_verdicts"
|
|
89763
|
-
};
|
|
89764
|
-
}
|
|
89765
|
-
const rawQuorumSize = councilGate.quorumSize;
|
|
89766
|
-
const quorumSize = typeof rawQuorumSize === "number" && Number.isFinite(rawQuorumSize) && rawQuorumSize >= 1 ? rawQuorumSize : 1;
|
|
89767
|
-
if (quorumSize < effectiveMinimum) {
|
|
89768
|
-
return {
|
|
89769
|
-
blocked: true,
|
|
89770
|
-
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.`
|
|
89771
|
-
};
|
|
89772
|
-
}
|
|
89773
|
-
return { blocked: false, reason: "" };
|
|
89774
|
-
}
|
|
89775
89969
|
async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
89776
89970
|
const statusError = validateStatus(args2.status);
|
|
89777
89971
|
if (statusError) {
|
|
@@ -89818,8 +90012,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
89818
90012
|
};
|
|
89819
90013
|
}
|
|
89820
90014
|
}
|
|
89821
|
-
normalizedDir =
|
|
89822
|
-
const pathParts = normalizedDir.split(
|
|
90015
|
+
normalizedDir = path105.normalize(args2.working_directory);
|
|
90016
|
+
const pathParts = normalizedDir.split(path105.sep);
|
|
89823
90017
|
if (pathParts.includes("..")) {
|
|
89824
90018
|
return {
|
|
89825
90019
|
success: false,
|
|
@@ -89829,11 +90023,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
89829
90023
|
]
|
|
89830
90024
|
};
|
|
89831
90025
|
}
|
|
89832
|
-
const resolvedDir =
|
|
90026
|
+
const resolvedDir = path105.resolve(normalizedDir);
|
|
89833
90027
|
try {
|
|
89834
|
-
const realPath =
|
|
89835
|
-
const planPath =
|
|
89836
|
-
if (!
|
|
90028
|
+
const realPath = fs85.realpathSync(resolvedDir);
|
|
90029
|
+
const planPath = path105.join(realPath, ".swarm", "plan.json");
|
|
90030
|
+
if (!fs85.existsSync(planPath)) {
|
|
89837
90031
|
return {
|
|
89838
90032
|
success: false,
|
|
89839
90033
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -89864,22 +90058,22 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
89864
90058
|
}
|
|
89865
90059
|
if (args2.status === "in_progress") {
|
|
89866
90060
|
try {
|
|
89867
|
-
const evidencePath =
|
|
89868
|
-
|
|
89869
|
-
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");
|
|
89870
90064
|
let writeOk = false;
|
|
89871
90065
|
try {
|
|
89872
|
-
|
|
90066
|
+
fs85.writeSync(fd, JSON.stringify({
|
|
89873
90067
|
taskId: args2.task_id,
|
|
89874
90068
|
required_gates: ["reviewer", "test_engineer"],
|
|
89875
90069
|
gates: {}
|
|
89876
90070
|
}, null, 2));
|
|
89877
90071
|
writeOk = true;
|
|
89878
90072
|
} finally {
|
|
89879
|
-
|
|
90073
|
+
fs85.closeSync(fd);
|
|
89880
90074
|
if (!writeOk) {
|
|
89881
90075
|
try {
|
|
89882
|
-
|
|
90076
|
+
fs85.unlinkSync(evidencePath);
|
|
89883
90077
|
} catch {}
|
|
89884
90078
|
}
|
|
89885
90079
|
}
|
|
@@ -89889,8 +90083,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
89889
90083
|
recoverTaskStateFromDelegations(args2.task_id);
|
|
89890
90084
|
let phaseRequiresReviewer = true;
|
|
89891
90085
|
try {
|
|
89892
|
-
const planPath =
|
|
89893
|
-
const planRaw =
|
|
90086
|
+
const planPath = path105.join(directory, ".swarm", "plan.json");
|
|
90087
|
+
const planRaw = fs85.readFileSync(planPath, "utf-8");
|
|
89894
90088
|
const plan = JSON.parse(planRaw);
|
|
89895
90089
|
const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
|
|
89896
90090
|
if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
|
|
@@ -89907,14 +90101,6 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
89907
90101
|
};
|
|
89908
90102
|
}
|
|
89909
90103
|
}
|
|
89910
|
-
const councilCheck = checkCouncilGate(directory, args2.task_id);
|
|
89911
|
-
if (councilCheck.blocked) {
|
|
89912
|
-
return {
|
|
89913
|
-
success: false,
|
|
89914
|
-
message: councilCheck.reason,
|
|
89915
|
-
errors: [councilCheck.reason]
|
|
89916
|
-
};
|
|
89917
|
-
}
|
|
89918
90104
|
}
|
|
89919
90105
|
const lockTaskId = `update-task-status-${args2.task_id}-${Date.now()}`;
|
|
89920
90106
|
const planFilePath = "plan.json";
|
|
@@ -90124,7 +90310,7 @@ function createWebSearchProvider(config3) {
|
|
|
90124
90310
|
init_create_tool();
|
|
90125
90311
|
init_resolve_working_directory();
|
|
90126
90312
|
var MAX_RESULTS_HARD_CAP = 10;
|
|
90127
|
-
var
|
|
90313
|
+
var ArgsSchema5 = exports_external.object({
|
|
90128
90314
|
query: exports_external.string().min(1).max(500),
|
|
90129
90315
|
max_results: exports_external.number().int().min(1).max(20).optional(),
|
|
90130
90316
|
working_directory: exports_external.string().optional()
|
|
@@ -90137,7 +90323,7 @@ var web_search = createSwarmTool({
|
|
|
90137
90323
|
working_directory: exports_external.string().optional().describe("Project root for config resolution. Optional.")
|
|
90138
90324
|
},
|
|
90139
90325
|
execute: async (args2, directory) => {
|
|
90140
|
-
const parsed =
|
|
90326
|
+
const parsed = ArgsSchema5.safeParse(args2);
|
|
90141
90327
|
if (!parsed.success) {
|
|
90142
90328
|
const fail = {
|
|
90143
90329
|
success: false,
|
|
@@ -90208,8 +90394,8 @@ init_utils2();
|
|
|
90208
90394
|
init_ledger();
|
|
90209
90395
|
init_manager();
|
|
90210
90396
|
init_create_tool();
|
|
90211
|
-
import
|
|
90212
|
-
import
|
|
90397
|
+
import fs86 from "node:fs";
|
|
90398
|
+
import path106 from "node:path";
|
|
90213
90399
|
function derivePlanId5(plan) {
|
|
90214
90400
|
return `${plan.swarm}-${plan.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
|
|
90215
90401
|
}
|
|
@@ -90260,7 +90446,7 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
90260
90446
|
entries: [evidenceEntry]
|
|
90261
90447
|
};
|
|
90262
90448
|
const filename = "drift-verifier.json";
|
|
90263
|
-
const relativePath =
|
|
90449
|
+
const relativePath = path106.join("evidence", String(phase), filename);
|
|
90264
90450
|
let validatedPath;
|
|
90265
90451
|
try {
|
|
90266
90452
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -90271,12 +90457,12 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
90271
90457
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
90272
90458
|
}, null, 2);
|
|
90273
90459
|
}
|
|
90274
|
-
const evidenceDir =
|
|
90460
|
+
const evidenceDir = path106.dirname(validatedPath);
|
|
90275
90461
|
try {
|
|
90276
|
-
await
|
|
90277
|
-
const tempPath =
|
|
90278
|
-
await
|
|
90279
|
-
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);
|
|
90280
90466
|
let snapshotInfo;
|
|
90281
90467
|
let snapshotError;
|
|
90282
90468
|
let qaProfileLocked;
|
|
@@ -90370,8 +90556,8 @@ var write_drift_evidence = createSwarmTool({
|
|
|
90370
90556
|
init_zod();
|
|
90371
90557
|
init_utils2();
|
|
90372
90558
|
init_create_tool();
|
|
90373
|
-
import
|
|
90374
|
-
import
|
|
90559
|
+
import fs87 from "node:fs";
|
|
90560
|
+
import path107 from "node:path";
|
|
90375
90561
|
function normalizeVerdict2(verdict) {
|
|
90376
90562
|
switch (verdict) {
|
|
90377
90563
|
case "APPROVED":
|
|
@@ -90419,7 +90605,7 @@ async function executeWriteHallucinationEvidence(args2, directory) {
|
|
|
90419
90605
|
entries: [evidenceEntry]
|
|
90420
90606
|
};
|
|
90421
90607
|
const filename = "hallucination-guard.json";
|
|
90422
|
-
const relativePath =
|
|
90608
|
+
const relativePath = path107.join("evidence", String(phase), filename);
|
|
90423
90609
|
let validatedPath;
|
|
90424
90610
|
try {
|
|
90425
90611
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -90430,12 +90616,12 @@ async function executeWriteHallucinationEvidence(args2, directory) {
|
|
|
90430
90616
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
90431
90617
|
}, null, 2);
|
|
90432
90618
|
}
|
|
90433
|
-
const evidenceDir =
|
|
90619
|
+
const evidenceDir = path107.dirname(validatedPath);
|
|
90434
90620
|
try {
|
|
90435
|
-
await
|
|
90436
|
-
const tempPath =
|
|
90437
|
-
await
|
|
90438
|
-
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);
|
|
90439
90625
|
return JSON.stringify({
|
|
90440
90626
|
success: true,
|
|
90441
90627
|
phase,
|
|
@@ -90481,8 +90667,8 @@ var write_hallucination_evidence = createSwarmTool({
|
|
|
90481
90667
|
init_zod();
|
|
90482
90668
|
init_utils2();
|
|
90483
90669
|
init_create_tool();
|
|
90484
|
-
import
|
|
90485
|
-
import
|
|
90670
|
+
import fs88 from "node:fs";
|
|
90671
|
+
import path108 from "node:path";
|
|
90486
90672
|
function normalizeVerdict3(verdict) {
|
|
90487
90673
|
switch (verdict) {
|
|
90488
90674
|
case "PASS":
|
|
@@ -90556,7 +90742,7 @@ async function executeWriteMutationEvidence(args2, directory) {
|
|
|
90556
90742
|
entries: [evidenceEntry]
|
|
90557
90743
|
};
|
|
90558
90744
|
const filename = "mutation-gate.json";
|
|
90559
|
-
const relativePath =
|
|
90745
|
+
const relativePath = path108.join("evidence", String(phase), filename);
|
|
90560
90746
|
let validatedPath;
|
|
90561
90747
|
try {
|
|
90562
90748
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -90567,12 +90753,12 @@ async function executeWriteMutationEvidence(args2, directory) {
|
|
|
90567
90753
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
90568
90754
|
}, null, 2);
|
|
90569
90755
|
}
|
|
90570
|
-
const evidenceDir =
|
|
90756
|
+
const evidenceDir = path108.dirname(validatedPath);
|
|
90571
90757
|
try {
|
|
90572
|
-
await
|
|
90573
|
-
const tempPath =
|
|
90574
|
-
await
|
|
90575
|
-
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);
|
|
90576
90762
|
return JSON.stringify({
|
|
90577
90763
|
success: true,
|
|
90578
90764
|
phase,
|
|
@@ -90626,20 +90812,20 @@ init_write_retro();
|
|
|
90626
90812
|
init_utils();
|
|
90627
90813
|
|
|
90628
90814
|
// src/utils/gitignore-warning.ts
|
|
90629
|
-
import * as
|
|
90630
|
-
import * as
|
|
90815
|
+
import * as fs89 from "node:fs";
|
|
90816
|
+
import * as path109 from "node:path";
|
|
90631
90817
|
var _gitignoreWarningEmitted = false;
|
|
90632
90818
|
function findGitRoot(startDir) {
|
|
90633
90819
|
let current = startDir;
|
|
90634
90820
|
while (true) {
|
|
90635
90821
|
try {
|
|
90636
|
-
const gitPath =
|
|
90637
|
-
const stat6 =
|
|
90822
|
+
const gitPath = path109.join(current, ".git");
|
|
90823
|
+
const stat6 = fs89.statSync(gitPath);
|
|
90638
90824
|
if (stat6.isDirectory()) {
|
|
90639
90825
|
return current;
|
|
90640
90826
|
}
|
|
90641
90827
|
} catch {}
|
|
90642
|
-
const parent =
|
|
90828
|
+
const parent = path109.dirname(current);
|
|
90643
90829
|
if (parent === current) {
|
|
90644
90830
|
return null;
|
|
90645
90831
|
}
|
|
@@ -90659,7 +90845,7 @@ function fileCoversSwarm(content) {
|
|
|
90659
90845
|
}
|
|
90660
90846
|
function readFileSafe(filePath) {
|
|
90661
90847
|
try {
|
|
90662
|
-
return
|
|
90848
|
+
return fs89.readFileSync(filePath, "utf8");
|
|
90663
90849
|
} catch {
|
|
90664
90850
|
return null;
|
|
90665
90851
|
}
|
|
@@ -90671,12 +90857,12 @@ function warnIfSwarmNotGitignored(directory, quiet = false) {
|
|
|
90671
90857
|
const gitRoot = findGitRoot(directory);
|
|
90672
90858
|
if (!gitRoot)
|
|
90673
90859
|
return;
|
|
90674
|
-
const gitignoreContent = readFileSafe(
|
|
90860
|
+
const gitignoreContent = readFileSafe(path109.join(gitRoot, ".gitignore"));
|
|
90675
90861
|
if (gitignoreContent !== null && fileCoversSwarm(gitignoreContent)) {
|
|
90676
90862
|
_gitignoreWarningEmitted = true;
|
|
90677
90863
|
return;
|
|
90678
90864
|
}
|
|
90679
|
-
const excludeContent = readFileSafe(
|
|
90865
|
+
const excludeContent = readFileSafe(path109.join(gitRoot, ".git", "info", "exclude"));
|
|
90680
90866
|
if (excludeContent !== null && fileCoversSwarm(excludeContent)) {
|
|
90681
90867
|
_gitignoreWarningEmitted = true;
|
|
90682
90868
|
return;
|
|
@@ -90921,7 +91107,7 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
90921
91107
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
90922
91108
|
preflightTriggerManager = new PTM(automationConfig);
|
|
90923
91109
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
90924
|
-
const swarmDir =
|
|
91110
|
+
const swarmDir = path110.resolve(ctx.directory, ".swarm");
|
|
90925
91111
|
statusArtifact = new ASA(swarmDir);
|
|
90926
91112
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
90927
91113
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|