opencode-swarm 6.29.0 → 6.29.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/README.md +4 -1
- package/dist/cli/index.js +31 -8
- package/dist/config/schema.d.ts +2 -2
- package/dist/hooks/incremental-verify.d.ts +15 -0
- package/dist/hooks/spawn-helper.d.ts +5 -0
- package/dist/hooks/spawn-helper.test.d.ts +1 -0
- package/dist/index.js +710 -523
- package/dist/services/compaction-service.d.ts +5 -0
- package/dist/state.d.ts +2 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14217,7 +14217,7 @@ var init_evidence_schema = __esm(() => {
|
|
|
14217
14217
|
});
|
|
14218
14218
|
RetrospectiveEvidenceSchema = BaseEvidenceSchema.extend({
|
|
14219
14219
|
type: exports_external.literal("retrospective"),
|
|
14220
|
-
phase_number: exports_external.number().int().min(
|
|
14220
|
+
phase_number: exports_external.number().int().min(1).max(99),
|
|
14221
14221
|
total_tool_calls: exports_external.number().int().min(0).max(9999),
|
|
14222
14222
|
coder_revisions: exports_external.number().int().min(0).max(999),
|
|
14223
14223
|
reviewer_rejections: exports_external.number().int().min(0).max(999),
|
|
@@ -14882,7 +14882,7 @@ var init_schema = __esm(() => {
|
|
|
14882
14882
|
});
|
|
14883
14883
|
IncrementalVerifyConfigSchema = exports_external.object({
|
|
14884
14884
|
enabled: exports_external.boolean().default(true),
|
|
14885
|
-
command: exports_external.string().nullable().default(null),
|
|
14885
|
+
command: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]).nullable().default(null),
|
|
14886
14886
|
timeoutMs: exports_external.number().int().min(1000).max(300000).default(30000),
|
|
14887
14887
|
triggerAgents: exports_external.array(exports_external.string()).default(["coder"])
|
|
14888
14888
|
});
|
|
@@ -35942,7 +35942,7 @@ __export(exports_gate_evidence, {
|
|
|
35942
35942
|
DEFAULT_REQUIRED_GATES: () => DEFAULT_REQUIRED_GATES
|
|
35943
35943
|
});
|
|
35944
35944
|
import { mkdirSync as mkdirSync8, readFileSync as readFileSync13, renameSync as renameSync7, unlinkSync as unlinkSync4 } from "fs";
|
|
35945
|
-
import * as
|
|
35945
|
+
import * as path29 from "path";
|
|
35946
35946
|
function isValidTaskId2(taskId) {
|
|
35947
35947
|
if (!taskId)
|
|
35948
35948
|
return false;
|
|
@@ -35989,10 +35989,10 @@ function expandRequiredGates(existingGates, newAgentType) {
|
|
|
35989
35989
|
return combined.sort();
|
|
35990
35990
|
}
|
|
35991
35991
|
function getEvidenceDir(directory) {
|
|
35992
|
-
return
|
|
35992
|
+
return path29.join(directory, ".swarm", "evidence");
|
|
35993
35993
|
}
|
|
35994
35994
|
function getEvidencePath(directory, taskId) {
|
|
35995
|
-
return
|
|
35995
|
+
return path29.join(getEvidenceDir(directory), `${taskId}.json`);
|
|
35996
35996
|
}
|
|
35997
35997
|
function readExisting(evidencePath) {
|
|
35998
35998
|
try {
|
|
@@ -36106,10 +36106,10 @@ function createPreflightIntegration(config3) {
|
|
|
36106
36106
|
});
|
|
36107
36107
|
const report = await runPreflight(directory, request.currentPhase, preflightConfig);
|
|
36108
36108
|
if (statusArtifact) {
|
|
36109
|
-
const
|
|
36110
|
-
statusArtifact.recordOutcome(
|
|
36109
|
+
const state2 = report.overall === "pass" ? "success" : "failure";
|
|
36110
|
+
statusArtifact.recordOutcome(state2, request.currentPhase, report.message);
|
|
36111
36111
|
console.log("[PreflightIntegration] Status artifact updated", {
|
|
36112
|
-
state,
|
|
36112
|
+
state: state2,
|
|
36113
36113
|
phase: request.currentPhase,
|
|
36114
36114
|
message: report.message
|
|
36115
36115
|
});
|
|
@@ -37601,11 +37601,11 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
37601
37601
|
throw toThrow;
|
|
37602
37602
|
}, "quit_");
|
|
37603
37603
|
var scriptDirectory = "";
|
|
37604
|
-
function locateFile(
|
|
37604
|
+
function locateFile(path46) {
|
|
37605
37605
|
if (Module["locateFile"]) {
|
|
37606
|
-
return Module["locateFile"](
|
|
37606
|
+
return Module["locateFile"](path46, scriptDirectory);
|
|
37607
37607
|
}
|
|
37608
|
-
return scriptDirectory +
|
|
37608
|
+
return scriptDirectory + path46;
|
|
37609
37609
|
}
|
|
37610
37610
|
__name(locateFile, "locateFile");
|
|
37611
37611
|
var readAsync, readBinary;
|
|
@@ -39353,7 +39353,7 @@ var init_runtime = __esm(() => {
|
|
|
39353
39353
|
});
|
|
39354
39354
|
|
|
39355
39355
|
// src/index.ts
|
|
39356
|
-
import * as
|
|
39356
|
+
import * as path56 from "path";
|
|
39357
39357
|
|
|
39358
39358
|
// src/agents/index.ts
|
|
39359
39359
|
init_config();
|
|
@@ -39418,7 +39418,8 @@ function startAgentSession(sessionId, agentName, staleDurationMs = 7200000, dire
|
|
|
39418
39418
|
scopeViolationDetected: false,
|
|
39419
39419
|
modifiedFilesThisCoderTask: [],
|
|
39420
39420
|
turboMode: false,
|
|
39421
|
-
loopDetectionWindow: []
|
|
39421
|
+
loopDetectionWindow: [],
|
|
39422
|
+
pendingAdvisoryMessages: []
|
|
39422
39423
|
};
|
|
39423
39424
|
swarmState.agentSessions.set(sessionId, sessionState);
|
|
39424
39425
|
swarmState.activeAgent.set(sessionId, agentName);
|
|
@@ -39523,6 +39524,9 @@ function ensureAgentSession(sessionId, agentName, directory) {
|
|
|
39523
39524
|
if (session.loopDetectionWindow === undefined) {
|
|
39524
39525
|
session.loopDetectionWindow = [];
|
|
39525
39526
|
}
|
|
39527
|
+
if (session.pendingAdvisoryMessages === undefined) {
|
|
39528
|
+
session.pendingAdvisoryMessages = [];
|
|
39529
|
+
}
|
|
39526
39530
|
session.lastToolCallTime = now;
|
|
39527
39531
|
return session;
|
|
39528
39532
|
}
|
|
@@ -40179,6 +40183,7 @@ Activates when: user asks to "specify", "define requirements", "write a spec", o
|
|
|
40179
40183
|
- Refine \u2192 delegate to MODE: CLARIFY-SPEC
|
|
40180
40184
|
- If NO: proceed to generation (step 2)
|
|
40181
40185
|
- If this is called from the stale spec archival path (MODE: PLAN option 1) \u2014 archival was already completed; skip this check and proceed directly to generation (step 2)
|
|
40186
|
+
1b. Run CODEBASE REALITY CHECK for any codebase references mentioned by the user or implied by the feature. Skip if work is purely greenfield (no existing codebase to check). Report discrepancies before proceeding to explorer.
|
|
40182
40187
|
2. Delegate to \`{{AGENT_PREFIX}}explorer\` to scan the codebase for relevant context (existing patterns, related code, affected areas).
|
|
40183
40188
|
3. Delegate to \`{{AGENT_PREFIX}}sme\` for domain research on the feature area to surface known constraints, best practices, and integration concerns.
|
|
40184
40189
|
4. Generate \`.swarm/spec.md\` capturing:
|
|
@@ -40205,22 +40210,23 @@ Each requirement must be independently testable.
|
|
|
40205
40210
|
Prefer informed defaults over asking the user \u2014 use \`[NEEDS CLARIFICATION]\` only when uncertainty could change scope, security, or core behavior.
|
|
40206
40211
|
|
|
40207
40212
|
EXTERNAL PLAN IMPORT PATH \u2014 when the user provides an existing implementation plan (markdown content, pasted text, or a reference to a file):
|
|
40208
|
-
1.
|
|
40209
|
-
2.
|
|
40213
|
+
1. Run CODEBASE REALITY CHECK scoped to every file, function, API, and behavioral assumption in the provided plan. Report discrepancies to user before proceeding.
|
|
40214
|
+
2. Read and parse the provided plan content.
|
|
40215
|
+
3. Reverse-engineer \`.swarm/spec.md\` from the plan:
|
|
40210
40216
|
- Derive FR-### functional requirements from task descriptions
|
|
40211
40217
|
- Derive SC-### success criteria from acceptance criteria in tasks
|
|
40212
40218
|
- Identify user scenarios from the plan's phase/feature groupings
|
|
40213
40219
|
- Surface implicit assumptions as \`[NEEDS CLARIFICATION]\` markers
|
|
40214
|
-
|
|
40220
|
+
4. Validate the provided plan against swarm task format requirements:
|
|
40215
40221
|
- Every task should have FILE, TASK, CONSTRAINT, and ACCEPTANCE fields
|
|
40216
40222
|
- No task should touch more than 2 files
|
|
40217
40223
|
- No compound verbs in TASK lines ("implement X and add Y" = 2 tasks)
|
|
40218
40224
|
- Dependencies should be declared explicitly
|
|
40219
40225
|
- Phase structure should match \`.swarm/plan.md\` format
|
|
40220
|
-
|
|
40221
|
-
|
|
40226
|
+
5. Report gaps, format issues, and improvement suggestions to the user.
|
|
40227
|
+
6. Ask: "Should I also flesh out any areas that seem underspecified?"
|
|
40222
40228
|
- If yes: delegate to \`{{AGENT_PREFIX}}sme\` for targeted research on weak areas, then propose specific improvements.
|
|
40223
|
-
|
|
40229
|
+
7. Output: both a \`.swarm/spec.md\` (extracted from the plan) and a validated version of the user's plan.
|
|
40224
40230
|
|
|
40225
40231
|
EXTERNAL PLAN RULES:
|
|
40226
40232
|
- Surface ALL changes as suggestions \u2014 do not silently rewrite the user's plan.
|
|
@@ -40323,6 +40329,34 @@ User directives carried forward: {list any persistent directives}
|
|
|
40323
40329
|
|
|
40324
40330
|
This briefing is a HARD REQUIREMENT for ALL phases. Skipping it is a process violation.
|
|
40325
40331
|
|
|
40332
|
+
### CODEBASE REALITY CHECK (Required Before Speccing or Planning)
|
|
40333
|
+
|
|
40334
|
+
Before any spec generation, plan creation, or plan ingestion begins, the Architect must dispatch the Explorer agent in targeted, scoped chunks \u2014 one per logical area of the codebase referenced by the work (e.g., per module, per hook, per config surface). Each chunk must be explored with full depth rather than a broad surface pass.
|
|
40335
|
+
|
|
40336
|
+
For each scoped chunk, Explorer must determine:
|
|
40337
|
+
- Does this file/module/function already exist?
|
|
40338
|
+
- If it exists, what is its current state? Does it already implement any part of what the plan or spec describes?
|
|
40339
|
+
- Is the plan's or user's assumption about the current state accurate? Flag any discrepancy between what is expected and what actually exists.
|
|
40340
|
+
- Has any portion of this work already been applied (partially or fully) in a prior session or commit?
|
|
40341
|
+
|
|
40342
|
+
Explorer outputs a CODEBASE REALITY REPORT before any other agent proceeds. The report must list every referenced item with one of:
|
|
40343
|
+
NOT STARTED | PARTIALLY DONE | ALREADY COMPLETE | ASSUMPTION INCORRECT
|
|
40344
|
+
|
|
40345
|
+
Format:
|
|
40346
|
+
REALITY CHECK: [N] references verified, [M] discrepancies found.
|
|
40347
|
+
\u2713 src/hooks/incremental-verify.ts \u2014 exists, line 69 confirmed Bun.spawn
|
|
40348
|
+
\u2717 src/services/status-service.ts \u2014 ASSUMPTION INCORRECT: compactionCount is no longer hardcoded (fixed in v6.29.1)
|
|
40349
|
+
\u2713 src/config/evidence-schema.ts:107 \u2014 confirmed phase_number min(0)
|
|
40350
|
+
|
|
40351
|
+
No implementation agent (coder, reviewer, test-engineer) may begin until this report is finalized.
|
|
40352
|
+
|
|
40353
|
+
This check fires automatically in:
|
|
40354
|
+
- MODE: SPECIFY \u2014 before explorer dispatch for context (step 2)
|
|
40355
|
+
- MODE: PLAN \u2014 before plan generation or validation
|
|
40356
|
+
- EXTERNAL PLAN IMPORT PATH \u2014 before parsing the provided plan
|
|
40357
|
+
|
|
40358
|
+
GREENFIELD EXEMPTION: If the work is purely greenfield (new project, no existing codebase references), skip this check.
|
|
40359
|
+
|
|
40326
40360
|
### MODE: PLAN
|
|
40327
40361
|
|
|
40328
40362
|
SPEC GATE (soft \u2014 check before planning):
|
|
@@ -40352,6 +40386,8 @@ SPEC GATE (soft \u2014 check before planning):
|
|
|
40352
40386
|
|
|
40353
40387
|
This is a SOFT gate. When the user chooses "Skip and plan directly", proceed to the steps below exactly as before \u2014 do NOT modify any planning behavior.
|
|
40354
40388
|
|
|
40389
|
+
Run CODEBASE REALITY CHECK scoped to codebase elements referenced in spec.md or user constraints. Discrepancies must be reflected in the generated plan.
|
|
40390
|
+
|
|
40355
40391
|
Use the \`save_plan\` tool to create the implementation plan. Required parameters:
|
|
40356
40392
|
- \`title\`: The real project name from the spec (NOT a placeholder like [Project])
|
|
40357
40393
|
- \`swarm_id\`: The swarm identifier (e.g. "mega", "local", "paid")
|
|
@@ -47608,6 +47644,97 @@ No plan content available. Start by creating a .swarm/plan.md file.
|
|
|
47608
47644
|
init_utils2();
|
|
47609
47645
|
init_manager2();
|
|
47610
47646
|
|
|
47647
|
+
// src/services/compaction-service.ts
|
|
47648
|
+
import * as fs15 from "fs";
|
|
47649
|
+
import * as path27 from "path";
|
|
47650
|
+
function makeInitialState() {
|
|
47651
|
+
return {
|
|
47652
|
+
lastObservationAt: 0,
|
|
47653
|
+
lastReflectionAt: 0,
|
|
47654
|
+
lastEmergencyAt: 0,
|
|
47655
|
+
observationCount: 0,
|
|
47656
|
+
reflectionCount: 0,
|
|
47657
|
+
emergencyCount: 0,
|
|
47658
|
+
lastSnapshotAt: null
|
|
47659
|
+
};
|
|
47660
|
+
}
|
|
47661
|
+
var state = makeInitialState();
|
|
47662
|
+
function appendSnapshot(directory, tier, budgetPct, message) {
|
|
47663
|
+
try {
|
|
47664
|
+
const snapshotPath = path27.join(directory, ".swarm", "context-snapshot.md");
|
|
47665
|
+
const timestamp = new Date().toISOString();
|
|
47666
|
+
const entry = `
|
|
47667
|
+
## [${tier.toUpperCase()}] ${timestamp} \u2014 ${budgetPct.toFixed(1)}% used
|
|
47668
|
+
${message}
|
|
47669
|
+
`;
|
|
47670
|
+
fs15.appendFileSync(snapshotPath, entry, "utf-8");
|
|
47671
|
+
} catch {}
|
|
47672
|
+
}
|
|
47673
|
+
function buildObservationMessage(budgetPct) {
|
|
47674
|
+
return `[CONTEXT COMPACTION \u2014 OBSERVATION TIER]
|
|
47675
|
+
` + `Context window is ${budgetPct.toFixed(1)}% used. Initiating observation compaction.
|
|
47676
|
+
` + `INSTRUCTIONS: Summarise the key decisions made so far, files changed, errors resolved, ` + `and the current task state. Discard verbose tool outputs and raw file reads. ` + `Preserve: plan task ID, agent verdicts, file paths touched, unresolved blockers.
|
|
47677
|
+
` + `[/CONTEXT COMPACTION]`;
|
|
47678
|
+
}
|
|
47679
|
+
function buildReflectionMessage(budgetPct) {
|
|
47680
|
+
return `[CONTEXT COMPACTION \u2014 REFLECTION TIER]
|
|
47681
|
+
` + `Context window is ${budgetPct.toFixed(1)}% used. Initiating reflection compaction.
|
|
47682
|
+
` + `INSTRUCTIONS: Re-summarise into a tighter format. Discard completed task details ` + `and resolved errors. Retain ONLY: current phase tasks remaining, open blockers, ` + `last 3 reviewer/test verdicts, and active file scope.
|
|
47683
|
+
` + `[/CONTEXT COMPACTION]`;
|
|
47684
|
+
}
|
|
47685
|
+
function buildEmergencyMessage(budgetPct, preserveLastN) {
|
|
47686
|
+
return `[CONTEXT COMPACTION \u2014 EMERGENCY TIER]
|
|
47687
|
+
` + `Context window is ${budgetPct.toFixed(1)}% used. EMERGENCY compaction required.
|
|
47688
|
+
` + `INSTRUCTIONS: Retain ONLY the system prompt, the current task context, and the ` + `last ${preserveLastN} conversation turns. Discard everything else. ` + `If you cannot complete the current task in the remaining context, escalate to the user.
|
|
47689
|
+
` + `[/CONTEXT COMPACTION]`;
|
|
47690
|
+
}
|
|
47691
|
+
function createCompactionService(config3, directory, injectMessage) {
|
|
47692
|
+
return {
|
|
47693
|
+
toolAfter: async (_input, _output) => {
|
|
47694
|
+
if (!config3.enabled)
|
|
47695
|
+
return;
|
|
47696
|
+
const budgetPct = swarmState.lastBudgetPct ?? 0;
|
|
47697
|
+
if (budgetPct <= 0)
|
|
47698
|
+
return;
|
|
47699
|
+
const sessionId = _input.sessionID;
|
|
47700
|
+
try {
|
|
47701
|
+
if (budgetPct >= config3.emergencyThreshold && budgetPct > state.lastEmergencyAt + 5) {
|
|
47702
|
+
state.lastEmergencyAt = budgetPct;
|
|
47703
|
+
state.emergencyCount++;
|
|
47704
|
+
const msg = buildEmergencyMessage(budgetPct, config3.preserveLastNTurns);
|
|
47705
|
+
appendSnapshot(directory, "emergency", budgetPct, msg);
|
|
47706
|
+
state.lastSnapshotAt = new Date().toISOString();
|
|
47707
|
+
injectMessage(sessionId, msg);
|
|
47708
|
+
return;
|
|
47709
|
+
}
|
|
47710
|
+
if (budgetPct >= config3.reflectionThreshold && budgetPct > state.lastReflectionAt + 5) {
|
|
47711
|
+
state.lastReflectionAt = budgetPct;
|
|
47712
|
+
state.reflectionCount++;
|
|
47713
|
+
const msg = buildReflectionMessage(budgetPct);
|
|
47714
|
+
appendSnapshot(directory, "reflection", budgetPct, msg);
|
|
47715
|
+
state.lastSnapshotAt = new Date().toISOString();
|
|
47716
|
+
injectMessage(sessionId, msg);
|
|
47717
|
+
return;
|
|
47718
|
+
}
|
|
47719
|
+
if (budgetPct >= config3.observationThreshold && budgetPct > state.lastObservationAt + 5) {
|
|
47720
|
+
state.lastObservationAt = budgetPct;
|
|
47721
|
+
state.observationCount++;
|
|
47722
|
+
const msg = buildObservationMessage(budgetPct);
|
|
47723
|
+
appendSnapshot(directory, "observation", budgetPct, msg);
|
|
47724
|
+
state.lastSnapshotAt = new Date().toISOString();
|
|
47725
|
+
injectMessage(sessionId, msg);
|
|
47726
|
+
}
|
|
47727
|
+
} catch {}
|
|
47728
|
+
}
|
|
47729
|
+
};
|
|
47730
|
+
}
|
|
47731
|
+
function getCompactionMetrics() {
|
|
47732
|
+
return {
|
|
47733
|
+
compactionCount: state.observationCount + state.reflectionCount + state.emergencyCount,
|
|
47734
|
+
lastSnapshotAt: state.lastSnapshotAt
|
|
47735
|
+
};
|
|
47736
|
+
}
|
|
47737
|
+
|
|
47611
47738
|
// src/services/context-budget-service.ts
|
|
47612
47739
|
init_utils2();
|
|
47613
47740
|
function validateDirectory(directory) {
|
|
@@ -47650,9 +47777,9 @@ async function readBudgetState(directory) {
|
|
|
47650
47777
|
return null;
|
|
47651
47778
|
}
|
|
47652
47779
|
}
|
|
47653
|
-
async function writeBudgetState(directory,
|
|
47780
|
+
async function writeBudgetState(directory, state2) {
|
|
47654
47781
|
const resolvedPath = validateSwarmPath(directory, "session/budget-state.json");
|
|
47655
|
-
const content = JSON.stringify(
|
|
47782
|
+
const content = JSON.stringify(state2, null, 2);
|
|
47656
47783
|
await Bun.write(resolvedPath, content);
|
|
47657
47784
|
}
|
|
47658
47785
|
async function countEvents(directory) {
|
|
@@ -47741,25 +47868,25 @@ async function formatBudgetWarning(report, directory, config3) {
|
|
|
47741
47868
|
return formatWarningMessage(report);
|
|
47742
47869
|
}
|
|
47743
47870
|
const budgetState = await readBudgetState(directory);
|
|
47744
|
-
const
|
|
47871
|
+
const state2 = budgetState || {
|
|
47745
47872
|
warningFiredAtTurn: null,
|
|
47746
47873
|
criticalFiredAtTurn: null,
|
|
47747
47874
|
lastInjectedAtTurn: null
|
|
47748
47875
|
};
|
|
47749
47876
|
const currentTurn = report.estimatedTurnCount;
|
|
47750
47877
|
if (report.status === "warning") {
|
|
47751
|
-
if (config3.warningMode === "once" &&
|
|
47878
|
+
if (config3.warningMode === "once" && state2.warningFiredAtTurn !== null) {
|
|
47752
47879
|
return null;
|
|
47753
47880
|
}
|
|
47754
|
-
if (config3.warningMode === "interval" &&
|
|
47881
|
+
if (config3.warningMode === "interval" && state2.warningFiredAtTurn !== null && currentTurn - state2.warningFiredAtTurn < config3.warningIntervalTurns) {
|
|
47755
47882
|
return null;
|
|
47756
47883
|
}
|
|
47757
|
-
|
|
47758
|
-
|
|
47759
|
-
await writeBudgetState(directory,
|
|
47884
|
+
state2.warningFiredAtTurn = currentTurn;
|
|
47885
|
+
state2.lastInjectedAtTurn = currentTurn;
|
|
47886
|
+
await writeBudgetState(directory, state2);
|
|
47760
47887
|
} else if (report.status === "critical") {
|
|
47761
|
-
|
|
47762
|
-
|
|
47888
|
+
state2.criticalFiredAtTurn = currentTurn;
|
|
47889
|
+
state2.lastInjectedAtTurn = currentTurn;
|
|
47763
47890
|
}
|
|
47764
47891
|
return formatWarningMessage(report);
|
|
47765
47892
|
}
|
|
@@ -47788,6 +47915,7 @@ async function getStatusData(directory, agents) {
|
|
|
47788
47915
|
}
|
|
47789
47916
|
}
|
|
47790
47917
|
const agentCount2 = Object.keys(agents).length;
|
|
47918
|
+
const metrics2 = getCompactionMetrics();
|
|
47791
47919
|
return {
|
|
47792
47920
|
hasPlan: true,
|
|
47793
47921
|
currentPhase: currentPhase2,
|
|
@@ -47797,12 +47925,13 @@ async function getStatusData(directory, agents) {
|
|
|
47797
47925
|
isLegacy: false,
|
|
47798
47926
|
turboMode: hasActiveTurboMode(),
|
|
47799
47927
|
contextBudgetPct: swarmState.lastBudgetPct > 0 ? swarmState.lastBudgetPct : null,
|
|
47800
|
-
compactionCount:
|
|
47801
|
-
lastSnapshotAt:
|
|
47928
|
+
compactionCount: metrics2.compactionCount,
|
|
47929
|
+
lastSnapshotAt: metrics2.lastSnapshotAt
|
|
47802
47930
|
};
|
|
47803
47931
|
}
|
|
47804
47932
|
const planContent = await readSwarmFileAsync(directory, "plan.md");
|
|
47805
47933
|
if (!planContent) {
|
|
47934
|
+
const metrics2 = getCompactionMetrics();
|
|
47806
47935
|
return {
|
|
47807
47936
|
hasPlan: false,
|
|
47808
47937
|
currentPhase: "Unknown",
|
|
@@ -47812,8 +47941,8 @@ async function getStatusData(directory, agents) {
|
|
|
47812
47941
|
isLegacy: true,
|
|
47813
47942
|
turboMode: hasActiveTurboMode(),
|
|
47814
47943
|
contextBudgetPct: swarmState.lastBudgetPct > 0 ? swarmState.lastBudgetPct : null,
|
|
47815
|
-
compactionCount:
|
|
47816
|
-
lastSnapshotAt:
|
|
47944
|
+
compactionCount: metrics2.compactionCount,
|
|
47945
|
+
lastSnapshotAt: metrics2.lastSnapshotAt
|
|
47817
47946
|
};
|
|
47818
47947
|
}
|
|
47819
47948
|
const currentPhase = extractCurrentPhase(planContent) || "Unknown";
|
|
@@ -47821,6 +47950,7 @@ async function getStatusData(directory, agents) {
|
|
|
47821
47950
|
const incompleteTasks = (planContent.match(/^- \[ \]/gm) || []).length;
|
|
47822
47951
|
const totalTasks = completedTasks + incompleteTasks;
|
|
47823
47952
|
const agentCount = Object.keys(agents).length;
|
|
47953
|
+
const metrics = getCompactionMetrics();
|
|
47824
47954
|
return {
|
|
47825
47955
|
hasPlan: true,
|
|
47826
47956
|
currentPhase,
|
|
@@ -47830,8 +47960,8 @@ async function getStatusData(directory, agents) {
|
|
|
47830
47960
|
isLegacy: true,
|
|
47831
47961
|
turboMode: hasActiveTurboMode(),
|
|
47832
47962
|
contextBudgetPct: swarmState.lastBudgetPct > 0 ? swarmState.lastBudgetPct : null,
|
|
47833
|
-
compactionCount:
|
|
47834
|
-
lastSnapshotAt:
|
|
47963
|
+
compactionCount: metrics.compactionCount,
|
|
47964
|
+
lastSnapshotAt: metrics.lastSnapshotAt
|
|
47835
47965
|
};
|
|
47836
47966
|
}
|
|
47837
47967
|
function formatStatusMarkdown(status) {
|
|
@@ -48461,11 +48591,11 @@ async function doFlush(directory) {
|
|
|
48461
48591
|
const activitySection = renderActivitySection();
|
|
48462
48592
|
const updated = replaceOrAppendSection(existing, "## Agent Activity", activitySection);
|
|
48463
48593
|
const flushedCount = swarmState.pendingEvents;
|
|
48464
|
-
const
|
|
48465
|
-
const tempPath = `${
|
|
48594
|
+
const path28 = `${directory}/.swarm/context.md`;
|
|
48595
|
+
const tempPath = `${path28}.tmp`;
|
|
48466
48596
|
try {
|
|
48467
48597
|
await Bun.write(tempPath, updated);
|
|
48468
|
-
renameSync6(tempPath,
|
|
48598
|
+
renameSync6(tempPath, path28);
|
|
48469
48599
|
} catch (writeError) {
|
|
48470
48600
|
try {
|
|
48471
48601
|
unlinkSync3(tempPath);
|
|
@@ -49035,14 +49165,14 @@ function maskToolOutput(msg, _threshold) {
|
|
|
49035
49165
|
}
|
|
49036
49166
|
// src/hooks/delegation-gate.ts
|
|
49037
49167
|
init_schema();
|
|
49038
|
-
import * as
|
|
49039
|
-
import * as
|
|
49168
|
+
import * as fs16 from "fs";
|
|
49169
|
+
import * as path30 from "path";
|
|
49040
49170
|
|
|
49041
49171
|
// src/hooks/guardrails.ts
|
|
49042
49172
|
init_constants();
|
|
49043
49173
|
init_schema();
|
|
49044
49174
|
init_manager2();
|
|
49045
|
-
import * as
|
|
49175
|
+
import * as path28 from "path";
|
|
49046
49176
|
init_utils();
|
|
49047
49177
|
|
|
49048
49178
|
// src/hooks/loop-detector.ts
|
|
@@ -49135,10 +49265,10 @@ function isArchitect(sessionId) {
|
|
|
49135
49265
|
function isOutsideSwarmDir(filePath, directory) {
|
|
49136
49266
|
if (!filePath)
|
|
49137
49267
|
return false;
|
|
49138
|
-
const swarmDir =
|
|
49139
|
-
const resolved =
|
|
49140
|
-
const relative4 =
|
|
49141
|
-
return relative4.startsWith("..") ||
|
|
49268
|
+
const swarmDir = path28.resolve(directory, ".swarm");
|
|
49269
|
+
const resolved = path28.resolve(directory, filePath);
|
|
49270
|
+
const relative4 = path28.relative(swarmDir, resolved);
|
|
49271
|
+
return relative4.startsWith("..") || path28.isAbsolute(relative4);
|
|
49142
49272
|
}
|
|
49143
49273
|
function isSourceCodePath(filePath) {
|
|
49144
49274
|
if (!filePath)
|
|
@@ -49205,13 +49335,13 @@ function getCurrentTaskId(sessionId) {
|
|
|
49205
49335
|
return session?.currentTaskId ?? `${sessionId}:unknown`;
|
|
49206
49336
|
}
|
|
49207
49337
|
function isInDeclaredScope(filePath, scopeEntries) {
|
|
49208
|
-
const resolvedFile =
|
|
49338
|
+
const resolvedFile = path28.resolve(filePath);
|
|
49209
49339
|
return scopeEntries.some((scope) => {
|
|
49210
|
-
const resolvedScope =
|
|
49340
|
+
const resolvedScope = path28.resolve(scope);
|
|
49211
49341
|
if (resolvedFile === resolvedScope)
|
|
49212
49342
|
return true;
|
|
49213
|
-
const rel =
|
|
49214
|
-
return rel.length > 0 && !rel.startsWith("..") && !
|
|
49343
|
+
const rel = path28.relative(resolvedScope, resolvedFile);
|
|
49344
|
+
return rel.length > 0 && !rel.startsWith("..") && !path28.isAbsolute(rel);
|
|
49215
49345
|
});
|
|
49216
49346
|
}
|
|
49217
49347
|
function createGuardrailsHooks(directoryOrConfig, config3) {
|
|
@@ -49298,9 +49428,9 @@ function createGuardrailsHooks(directoryOrConfig, config3) {
|
|
|
49298
49428
|
const args2 = output.args;
|
|
49299
49429
|
const targetPath = args2?.filePath ?? args2?.path ?? args2?.file ?? args2?.target;
|
|
49300
49430
|
if (typeof targetPath === "string" && targetPath.length > 0) {
|
|
49301
|
-
const resolvedTarget =
|
|
49302
|
-
const planMdPath =
|
|
49303
|
-
const planJsonPath =
|
|
49431
|
+
const resolvedTarget = path28.resolve(directory, targetPath).toLowerCase();
|
|
49432
|
+
const planMdPath = path28.resolve(directory, ".swarm", "plan.md").toLowerCase();
|
|
49433
|
+
const planJsonPath = path28.resolve(directory, ".swarm", "plan.json").toLowerCase();
|
|
49304
49434
|
if (resolvedTarget === planMdPath || resolvedTarget === planJsonPath) {
|
|
49305
49435
|
throw new Error("PLAN STATE VIOLATION: Direct writes to .swarm/plan.md and .swarm/plan.json are blocked. " + "plan.md is auto-regenerated from plan.json by PlanSyncWorker. " + "Use update_task_status() to mark tasks complete, " + "phase_complete() for phase transitions, or " + "save_plan to create/restructure plans.");
|
|
49306
49436
|
}
|
|
@@ -49349,9 +49479,9 @@ function createGuardrailsHooks(directoryOrConfig, config3) {
|
|
|
49349
49479
|
}
|
|
49350
49480
|
}
|
|
49351
49481
|
for (const p of paths) {
|
|
49352
|
-
const resolvedP =
|
|
49353
|
-
const planMdPath =
|
|
49354
|
-
const planJsonPath =
|
|
49482
|
+
const resolvedP = path28.resolve(directory, p);
|
|
49483
|
+
const planMdPath = path28.resolve(directory, ".swarm", "plan.md").toLowerCase();
|
|
49484
|
+
const planJsonPath = path28.resolve(directory, ".swarm", "plan.json").toLowerCase();
|
|
49355
49485
|
if (resolvedP.toLowerCase() === planMdPath || resolvedP.toLowerCase() === planJsonPath) {
|
|
49356
49486
|
throw new Error("PLAN STATE VIOLATION: Direct writes to .swarm/plan.md and .swarm/plan.json are blocked. " + "plan.md is auto-regenerated from plan.json by PlanSyncWorker. " + "Use update_task_status() to mark tasks complete, " + "phase_complete() for phase transitions, or " + "save_plan to create/restructure plans.");
|
|
49357
49487
|
}
|
|
@@ -49371,7 +49501,7 @@ function createGuardrailsHooks(directoryOrConfig, config3) {
|
|
|
49371
49501
|
}
|
|
49372
49502
|
}
|
|
49373
49503
|
}
|
|
49374
|
-
if (typeof targetPath === "string" && targetPath.length > 0 && isOutsideSwarmDir(targetPath, directory) && isSourceCodePath(
|
|
49504
|
+
if (typeof targetPath === "string" && targetPath.length > 0 && isOutsideSwarmDir(targetPath, directory) && isSourceCodePath(path28.relative(directory, path28.resolve(directory, targetPath)))) {
|
|
49375
49505
|
const session2 = swarmState.agentSessions.get(input.sessionID);
|
|
49376
49506
|
if (session2) {
|
|
49377
49507
|
session2.architectWriteCount++;
|
|
@@ -49653,6 +49783,30 @@ ${pending.message}
|
|
|
49653
49783
|
}
|
|
49654
49784
|
}
|
|
49655
49785
|
}
|
|
49786
|
+
if (isArchitectSession && (session?.pendingAdvisoryMessages?.length ?? 0) > 0) {
|
|
49787
|
+
const advisories = session.pendingAdvisoryMessages;
|
|
49788
|
+
let targetMsg = systemMessages[0];
|
|
49789
|
+
if (!targetMsg) {
|
|
49790
|
+
const newMsg = {
|
|
49791
|
+
info: { role: "system" },
|
|
49792
|
+
parts: [{ type: "text", text: "" }]
|
|
49793
|
+
};
|
|
49794
|
+
messages.unshift(newMsg);
|
|
49795
|
+
targetMsg = newMsg;
|
|
49796
|
+
}
|
|
49797
|
+
const textPart2 = (targetMsg.parts ?? []).find((part) => part.type === "text" && typeof part.text === "string");
|
|
49798
|
+
if (textPart2) {
|
|
49799
|
+
const joined = advisories.join(`
|
|
49800
|
+
---
|
|
49801
|
+
`);
|
|
49802
|
+
textPart2.text = `[ADVISORIES]
|
|
49803
|
+
${joined}
|
|
49804
|
+
[/ADVISORIES]
|
|
49805
|
+
|
|
49806
|
+
` + textPart2.text;
|
|
49807
|
+
}
|
|
49808
|
+
session.pendingAdvisoryMessages = [];
|
|
49809
|
+
}
|
|
49656
49810
|
if (isArchitectSession && session && session.architectWriteCount > session.selfCodingWarnedAtCount) {
|
|
49657
49811
|
let targetSystemMessage = systemMessages[0];
|
|
49658
49812
|
if (!targetSystemMessage) {
|
|
@@ -49880,13 +50034,13 @@ function getEvidenceTaskId(session, directory) {
|
|
|
49880
50034
|
if (typeof directory !== "string" || directory.length === 0) {
|
|
49881
50035
|
return null;
|
|
49882
50036
|
}
|
|
49883
|
-
const resolvedDirectory =
|
|
49884
|
-
const planPath =
|
|
49885
|
-
const resolvedPlanPath =
|
|
49886
|
-
if (!resolvedPlanPath.startsWith(resolvedDirectory +
|
|
50037
|
+
const resolvedDirectory = path30.resolve(directory);
|
|
50038
|
+
const planPath = path30.join(resolvedDirectory, ".swarm", "plan.json");
|
|
50039
|
+
const resolvedPlanPath = path30.resolve(planPath);
|
|
50040
|
+
if (!resolvedPlanPath.startsWith(resolvedDirectory + path30.sep) && resolvedPlanPath !== resolvedDirectory) {
|
|
49887
50041
|
return null;
|
|
49888
50042
|
}
|
|
49889
|
-
const planContent =
|
|
50043
|
+
const planContent = fs16.readFileSync(resolvedPlanPath, "utf-8");
|
|
49890
50044
|
const plan = JSON.parse(planContent);
|
|
49891
50045
|
if (!plan || !Array.isArray(plan.phases)) {
|
|
49892
50046
|
return null;
|
|
@@ -49944,23 +50098,23 @@ function createDelegationGateHook(config3, directory) {
|
|
|
49944
50098
|
if (targetAgent === "test_engineer")
|
|
49945
50099
|
hasTestEngineer = true;
|
|
49946
50100
|
if (targetAgent === "reviewer" && session.taskWorkflowStates) {
|
|
49947
|
-
for (const [taskId,
|
|
49948
|
-
if (
|
|
50101
|
+
for (const [taskId, state2] of session.taskWorkflowStates) {
|
|
50102
|
+
if (state2 === "coder_delegated" || state2 === "pre_check_passed") {
|
|
49949
50103
|
try {
|
|
49950
50104
|
advanceTaskState(session, taskId, "reviewer_run");
|
|
49951
50105
|
} catch (err2) {
|
|
49952
|
-
console.warn(`[delegation-gate] toolAfter: could not advance ${taskId} (${
|
|
50106
|
+
console.warn(`[delegation-gate] toolAfter: could not advance ${taskId} (${state2}) \u2192 reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
49953
50107
|
}
|
|
49954
50108
|
}
|
|
49955
50109
|
}
|
|
49956
50110
|
}
|
|
49957
50111
|
if (targetAgent === "test_engineer" && session.taskWorkflowStates) {
|
|
49958
|
-
for (const [taskId,
|
|
49959
|
-
if (
|
|
50112
|
+
for (const [taskId, state2] of session.taskWorkflowStates) {
|
|
50113
|
+
if (state2 === "reviewer_run") {
|
|
49960
50114
|
try {
|
|
49961
50115
|
advanceTaskState(session, taskId, "tests_run");
|
|
49962
50116
|
} catch (err2) {
|
|
49963
|
-
console.warn(`[delegation-gate] toolAfter: could not advance ${taskId} (${
|
|
50117
|
+
console.warn(`[delegation-gate] toolAfter: could not advance ${taskId} (${state2}) \u2192 tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
49964
50118
|
}
|
|
49965
50119
|
}
|
|
49966
50120
|
}
|
|
@@ -49976,12 +50130,12 @@ function createDelegationGateHook(config3, directory) {
|
|
|
49976
50130
|
if (seedTaskId && !otherSession.taskWorkflowStates.has(seedTaskId)) {
|
|
49977
50131
|
otherSession.taskWorkflowStates.set(seedTaskId, "coder_delegated");
|
|
49978
50132
|
}
|
|
49979
|
-
for (const [taskId,
|
|
49980
|
-
if (
|
|
50133
|
+
for (const [taskId, state2] of otherSession.taskWorkflowStates) {
|
|
50134
|
+
if (state2 === "coder_delegated" || state2 === "pre_check_passed") {
|
|
49981
50135
|
try {
|
|
49982
50136
|
advanceTaskState(otherSession, taskId, "reviewer_run");
|
|
49983
50137
|
} catch (err2) {
|
|
49984
|
-
console.warn(`[delegation-gate] toolAfter cross-session: could not advance ${taskId} (${
|
|
50138
|
+
console.warn(`[delegation-gate] toolAfter cross-session: could not advance ${taskId} (${state2}) \u2192 reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
49985
50139
|
}
|
|
49986
50140
|
}
|
|
49987
50141
|
}
|
|
@@ -49991,12 +50145,12 @@ function createDelegationGateHook(config3, directory) {
|
|
|
49991
50145
|
if (seedTaskId && !otherSession.taskWorkflowStates.has(seedTaskId)) {
|
|
49992
50146
|
otherSession.taskWorkflowStates.set(seedTaskId, "reviewer_run");
|
|
49993
50147
|
}
|
|
49994
|
-
for (const [taskId,
|
|
49995
|
-
if (
|
|
50148
|
+
for (const [taskId, state2] of otherSession.taskWorkflowStates) {
|
|
50149
|
+
if (state2 === "reviewer_run") {
|
|
49996
50150
|
try {
|
|
49997
50151
|
advanceTaskState(otherSession, taskId, "tests_run");
|
|
49998
50152
|
} catch (err2) {
|
|
49999
|
-
console.warn(`[delegation-gate] toolAfter cross-session: could not advance ${taskId} (${
|
|
50153
|
+
console.warn(`[delegation-gate] toolAfter cross-session: could not advance ${taskId} (${state2}) \u2192 tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
50000
50154
|
}
|
|
50001
50155
|
}
|
|
50002
50156
|
}
|
|
@@ -50060,23 +50214,23 @@ function createDelegationGateHook(config3, directory) {
|
|
|
50060
50214
|
session.qaSkipTaskIds = [];
|
|
50061
50215
|
}
|
|
50062
50216
|
if (hasReviewer && session.taskWorkflowStates) {
|
|
50063
|
-
for (const [taskId,
|
|
50064
|
-
if (
|
|
50217
|
+
for (const [taskId, state2] of session.taskWorkflowStates) {
|
|
50218
|
+
if (state2 === "coder_delegated" || state2 === "pre_check_passed") {
|
|
50065
50219
|
try {
|
|
50066
50220
|
advanceTaskState(session, taskId, "reviewer_run");
|
|
50067
50221
|
} catch (err2) {
|
|
50068
|
-
console.warn(`[delegation-gate] fallback: could not advance ${taskId} (${
|
|
50222
|
+
console.warn(`[delegation-gate] fallback: could not advance ${taskId} (${state2}) \u2192 reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
50069
50223
|
}
|
|
50070
50224
|
}
|
|
50071
50225
|
}
|
|
50072
50226
|
}
|
|
50073
50227
|
if (hasReviewer && hasTestEngineer && session.taskWorkflowStates) {
|
|
50074
|
-
for (const [taskId,
|
|
50075
|
-
if (
|
|
50228
|
+
for (const [taskId, state2] of session.taskWorkflowStates) {
|
|
50229
|
+
if (state2 === "reviewer_run") {
|
|
50076
50230
|
try {
|
|
50077
50231
|
advanceTaskState(session, taskId, "tests_run");
|
|
50078
50232
|
} catch (err2) {
|
|
50079
|
-
console.warn(`[delegation-gate] fallback: could not advance ${taskId} (${
|
|
50233
|
+
console.warn(`[delegation-gate] fallback: could not advance ${taskId} (${state2}) \u2192 tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
50080
50234
|
}
|
|
50081
50235
|
}
|
|
50082
50236
|
}
|
|
@@ -50091,12 +50245,12 @@ function createDelegationGateHook(config3, directory) {
|
|
|
50091
50245
|
if (seedTaskId && !otherSession.taskWorkflowStates.has(seedTaskId)) {
|
|
50092
50246
|
otherSession.taskWorkflowStates.set(seedTaskId, "coder_delegated");
|
|
50093
50247
|
}
|
|
50094
|
-
for (const [taskId,
|
|
50095
|
-
if (
|
|
50248
|
+
for (const [taskId, state2] of otherSession.taskWorkflowStates) {
|
|
50249
|
+
if (state2 === "coder_delegated" || state2 === "pre_check_passed") {
|
|
50096
50250
|
try {
|
|
50097
50251
|
advanceTaskState(otherSession, taskId, "reviewer_run");
|
|
50098
50252
|
} catch (err2) {
|
|
50099
|
-
console.warn(`[delegation-gate] fallback cross-session: could not advance ${taskId} (${
|
|
50253
|
+
console.warn(`[delegation-gate] fallback cross-session: could not advance ${taskId} (${state2}) \u2192 reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
50100
50254
|
}
|
|
50101
50255
|
}
|
|
50102
50256
|
}
|
|
@@ -50112,12 +50266,12 @@ function createDelegationGateHook(config3, directory) {
|
|
|
50112
50266
|
if (seedTaskId && !otherSession.taskWorkflowStates.has(seedTaskId)) {
|
|
50113
50267
|
otherSession.taskWorkflowStates.set(seedTaskId, "reviewer_run");
|
|
50114
50268
|
}
|
|
50115
|
-
for (const [taskId,
|
|
50116
|
-
if (
|
|
50269
|
+
for (const [taskId, state2] of otherSession.taskWorkflowStates) {
|
|
50270
|
+
if (state2 === "reviewer_run") {
|
|
50117
50271
|
try {
|
|
50118
50272
|
advanceTaskState(otherSession, taskId, "tests_run");
|
|
50119
50273
|
} catch (err2) {
|
|
50120
|
-
console.warn(`[delegation-gate] fallback cross-session: could not advance ${taskId} (${
|
|
50274
|
+
console.warn(`[delegation-gate] fallback cross-session: could not advance ${taskId} (${state2}) \u2192 tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
50121
50275
|
}
|
|
50122
50276
|
}
|
|
50123
50277
|
}
|
|
@@ -50363,7 +50517,7 @@ ${warningLines.join(`
|
|
|
50363
50517
|
}
|
|
50364
50518
|
// src/hooks/delegation-sanitizer.ts
|
|
50365
50519
|
init_utils2();
|
|
50366
|
-
import * as
|
|
50520
|
+
import * as fs17 from "fs";
|
|
50367
50521
|
var SANITIZATION_PATTERNS = [
|
|
50368
50522
|
/\b\d+(st|nd|rd|th)\s+(attempt|try|time)\b/gi,
|
|
50369
50523
|
/\b(5th|fifth|final|last)\s+attempt\b/gi,
|
|
@@ -50434,7 +50588,7 @@ function createDelegationSanitizerHook(directory) {
|
|
|
50434
50588
|
stripped_patterns: result.stripped,
|
|
50435
50589
|
timestamp: new Date().toISOString()
|
|
50436
50590
|
};
|
|
50437
|
-
|
|
50591
|
+
fs17.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
50438
50592
|
`, "utf-8");
|
|
50439
50593
|
} catch {}
|
|
50440
50594
|
}
|
|
@@ -50684,13 +50838,13 @@ init_schema();
|
|
|
50684
50838
|
init_manager();
|
|
50685
50839
|
init_detector();
|
|
50686
50840
|
init_manager2();
|
|
50687
|
-
import * as
|
|
50841
|
+
import * as fs19 from "fs";
|
|
50688
50842
|
|
|
50689
50843
|
// src/services/decision-drift-analyzer.ts
|
|
50690
50844
|
init_utils2();
|
|
50691
50845
|
init_manager2();
|
|
50692
|
-
import * as
|
|
50693
|
-
import * as
|
|
50846
|
+
import * as fs18 from "fs";
|
|
50847
|
+
import * as path31 from "path";
|
|
50694
50848
|
var DEFAULT_DRIFT_CONFIG = {
|
|
50695
50849
|
staleThresholdPhases: 1,
|
|
50696
50850
|
detectContradictions: true,
|
|
@@ -50844,11 +50998,11 @@ async function analyzeDecisionDrift(directory, config3 = {}) {
|
|
|
50844
50998
|
currentPhase = legacyPhase;
|
|
50845
50999
|
}
|
|
50846
51000
|
}
|
|
50847
|
-
const contextPath =
|
|
51001
|
+
const contextPath = path31.join(directory, ".swarm", "context.md");
|
|
50848
51002
|
let contextContent = "";
|
|
50849
51003
|
try {
|
|
50850
|
-
if (
|
|
50851
|
-
contextContent =
|
|
51004
|
+
if (fs18.existsSync(contextPath)) {
|
|
51005
|
+
contextContent = fs18.readFileSync(contextPath, "utf-8");
|
|
50852
51006
|
}
|
|
50853
51007
|
} catch {
|
|
50854
51008
|
return {
|
|
@@ -51342,11 +51496,11 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
51342
51496
|
if (handoffContent) {
|
|
51343
51497
|
const handoffPath = validateSwarmPath(directory, "handoff.md");
|
|
51344
51498
|
const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
|
|
51345
|
-
if (
|
|
51499
|
+
if (fs19.existsSync(consumedPath)) {
|
|
51346
51500
|
warn("Duplicate handoff detected: handoff-consumed.md already exists");
|
|
51347
|
-
|
|
51501
|
+
fs19.unlinkSync(consumedPath);
|
|
51348
51502
|
}
|
|
51349
|
-
|
|
51503
|
+
fs19.renameSync(handoffPath, consumedPath);
|
|
51350
51504
|
const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
|
|
51351
51505
|
The previous model's session ended. Here is your starting context:
|
|
51352
51506
|
|
|
@@ -51626,11 +51780,11 @@ ${budgetWarning}`);
|
|
|
51626
51780
|
if (handoffContent) {
|
|
51627
51781
|
const handoffPath = validateSwarmPath(directory, "handoff.md");
|
|
51628
51782
|
const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
|
|
51629
|
-
if (
|
|
51783
|
+
if (fs19.existsSync(consumedPath)) {
|
|
51630
51784
|
warn("Duplicate handoff detected: handoff-consumed.md already exists");
|
|
51631
|
-
|
|
51785
|
+
fs19.unlinkSync(consumedPath);
|
|
51632
51786
|
}
|
|
51633
|
-
|
|
51787
|
+
fs19.renameSync(handoffPath, consumedPath);
|
|
51634
51788
|
const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
|
|
51635
51789
|
The previous model's session ended. Here is your starting context:
|
|
51636
51790
|
|
|
@@ -52308,55 +52462,112 @@ function createDarkMatterDetectorHook(directory) {
|
|
|
52308
52462
|
}
|
|
52309
52463
|
|
|
52310
52464
|
// src/hooks/incremental-verify.ts
|
|
52311
|
-
import * as
|
|
52312
|
-
import * as
|
|
52465
|
+
import * as fs20 from "fs";
|
|
52466
|
+
import * as path32 from "path";
|
|
52467
|
+
|
|
52468
|
+
// src/hooks/spawn-helper.ts
|
|
52469
|
+
import { spawn } from "child_process";
|
|
52470
|
+
function spawnAsync(command, cwd, timeoutMs) {
|
|
52471
|
+
return new Promise((resolve11) => {
|
|
52472
|
+
try {
|
|
52473
|
+
const [cmd, ...args2] = command;
|
|
52474
|
+
const proc = spawn(cmd, args2, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
52475
|
+
let stdout = "";
|
|
52476
|
+
let stderr = "";
|
|
52477
|
+
let done = false;
|
|
52478
|
+
proc.stdout.on("data", (d) => {
|
|
52479
|
+
stdout += d;
|
|
52480
|
+
});
|
|
52481
|
+
proc.stderr.on("data", (d) => {
|
|
52482
|
+
stderr += d;
|
|
52483
|
+
});
|
|
52484
|
+
const timer = setTimeout(() => {
|
|
52485
|
+
if (done)
|
|
52486
|
+
return;
|
|
52487
|
+
done = true;
|
|
52488
|
+
try {
|
|
52489
|
+
proc.stdout.destroy();
|
|
52490
|
+
} catch {}
|
|
52491
|
+
try {
|
|
52492
|
+
proc.stderr.destroy();
|
|
52493
|
+
} catch {}
|
|
52494
|
+
try {
|
|
52495
|
+
proc.kill();
|
|
52496
|
+
} catch {}
|
|
52497
|
+
resolve11(null);
|
|
52498
|
+
}, timeoutMs);
|
|
52499
|
+
proc.on("close", (code) => {
|
|
52500
|
+
if (done)
|
|
52501
|
+
return;
|
|
52502
|
+
done = true;
|
|
52503
|
+
clearTimeout(timer);
|
|
52504
|
+
resolve11({ exitCode: code ?? 1, stdout, stderr });
|
|
52505
|
+
});
|
|
52506
|
+
proc.on("error", () => {
|
|
52507
|
+
if (done)
|
|
52508
|
+
return;
|
|
52509
|
+
done = true;
|
|
52510
|
+
clearTimeout(timer);
|
|
52511
|
+
resolve11(null);
|
|
52512
|
+
});
|
|
52513
|
+
} catch {
|
|
52514
|
+
resolve11(null);
|
|
52515
|
+
}
|
|
52516
|
+
});
|
|
52517
|
+
}
|
|
52518
|
+
|
|
52519
|
+
// src/hooks/incremental-verify.ts
|
|
52520
|
+
var emittedSkipAdvisories = new Set;
|
|
52313
52521
|
function detectTypecheckCommand(projectDir) {
|
|
52314
|
-
const pkgPath =
|
|
52315
|
-
if (
|
|
52316
|
-
|
|
52317
|
-
|
|
52318
|
-
|
|
52319
|
-
|
|
52320
|
-
|
|
52321
|
-
|
|
52322
|
-
|
|
52323
|
-
|
|
52324
|
-
|
|
52325
|
-
|
|
52326
|
-
|
|
52327
|
-
|
|
52328
|
-
|
|
52522
|
+
const pkgPath = path32.join(projectDir, "package.json");
|
|
52523
|
+
if (fs20.existsSync(pkgPath)) {
|
|
52524
|
+
try {
|
|
52525
|
+
const pkg = JSON.parse(fs20.readFileSync(pkgPath, "utf8"));
|
|
52526
|
+
const scripts = pkg.scripts;
|
|
52527
|
+
if (scripts?.typecheck)
|
|
52528
|
+
return { command: ["bun", "run", "typecheck"], language: "typescript" };
|
|
52529
|
+
if (scripts?.["type-check"])
|
|
52530
|
+
return {
|
|
52531
|
+
command: ["bun", "run", "type-check"],
|
|
52532
|
+
language: "typescript"
|
|
52533
|
+
};
|
|
52534
|
+
const deps = {
|
|
52535
|
+
...pkg.dependencies,
|
|
52536
|
+
...pkg.devDependencies
|
|
52537
|
+
};
|
|
52538
|
+
if (!deps?.typescript && !fs20.existsSync(path32.join(projectDir, "tsconfig.json"))) {
|
|
52539
|
+
return null;
|
|
52540
|
+
}
|
|
52541
|
+
return { command: ["npx", "tsc", "--noEmit"], language: "typescript" };
|
|
52542
|
+
} catch {
|
|
52329
52543
|
return null;
|
|
52330
52544
|
}
|
|
52331
|
-
return ["npx", "tsc", "--noEmit"];
|
|
52332
|
-
} catch {
|
|
52333
|
-
return null;
|
|
52334
52545
|
}
|
|
52335
|
-
|
|
52336
|
-
|
|
52546
|
+
if (fs20.existsSync(path32.join(projectDir, "go.mod"))) {
|
|
52547
|
+
return { command: ["go", "vet", "./..."], language: "go" };
|
|
52548
|
+
}
|
|
52549
|
+
if (fs20.existsSync(path32.join(projectDir, "Cargo.toml"))) {
|
|
52550
|
+
return { command: ["cargo", "check"], language: "rust" };
|
|
52551
|
+
}
|
|
52552
|
+
if (fs20.existsSync(path32.join(projectDir, "pyproject.toml")) || fs20.existsSync(path32.join(projectDir, "requirements.txt")) || fs20.existsSync(path32.join(projectDir, "setup.py"))) {
|
|
52553
|
+
return { command: null, language: "python" };
|
|
52554
|
+
}
|
|
52337
52555
|
try {
|
|
52338
|
-
const
|
|
52339
|
-
|
|
52340
|
-
|
|
52341
|
-
|
|
52342
|
-
|
|
52343
|
-
|
|
52344
|
-
try {
|
|
52345
|
-
proc.kill();
|
|
52346
|
-
} catch {}
|
|
52347
|
-
}, timeoutMs);
|
|
52348
|
-
try {
|
|
52349
|
-
const [exitCode, stderr] = await Promise.all([
|
|
52350
|
-
proc.exited,
|
|
52351
|
-
new Response(proc.stderr).text()
|
|
52352
|
-
]);
|
|
52353
|
-
return { exitCode, stderr };
|
|
52354
|
-
} finally {
|
|
52355
|
-
clearTimeout(timeoutHandle);
|
|
52556
|
+
const entries = fs20.readdirSync(projectDir);
|
|
52557
|
+
if (entries.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
52558
|
+
return {
|
|
52559
|
+
command: ["dotnet", "build", "--no-restore"],
|
|
52560
|
+
language: "csharp"
|
|
52561
|
+
};
|
|
52356
52562
|
}
|
|
52357
|
-
} catch {
|
|
52563
|
+
} catch {}
|
|
52564
|
+
return null;
|
|
52565
|
+
}
|
|
52566
|
+
async function runWithTimeout(command, cwd, timeoutMs) {
|
|
52567
|
+
const result = await spawnAsync(command, cwd, timeoutMs);
|
|
52568
|
+
if (result === null)
|
|
52358
52569
|
return null;
|
|
52359
|
-
}
|
|
52570
|
+
return { exitCode: result.exitCode, stderr: result.stderr };
|
|
52360
52571
|
}
|
|
52361
52572
|
function createIncrementalVerifyHook(config3, projectDir, injectMessage) {
|
|
52362
52573
|
return {
|
|
@@ -52371,10 +52582,27 @@ function createIncrementalVerifyHook(config3, projectDir, injectMessage) {
|
|
|
52371
52582
|
if (!config3.triggerAgents.includes(agentName) && !config3.triggerAgents.includes(subagentType)) {
|
|
52372
52583
|
return;
|
|
52373
52584
|
}
|
|
52374
|
-
|
|
52375
|
-
if (
|
|
52585
|
+
let commandToRun = null;
|
|
52586
|
+
if (config3.command != null) {
|
|
52587
|
+
commandToRun = Array.isArray(config3.command) ? config3.command : config3.command.split(" ");
|
|
52588
|
+
} else {
|
|
52589
|
+
const detected = detectTypecheckCommand(projectDir);
|
|
52590
|
+
if (detected === null) {
|
|
52591
|
+
return;
|
|
52592
|
+
}
|
|
52593
|
+
if (detected.command === null) {
|
|
52594
|
+
const dedupKey = `${input.sessionID}:${detected.language}`;
|
|
52595
|
+
if (!emittedSkipAdvisories.has(dedupKey)) {
|
|
52596
|
+
emittedSkipAdvisories.add(dedupKey);
|
|
52597
|
+
injectMessage(input.sessionID, `POST-CODER CHECK SKIPPED: ${detected.language} project detected but no default checker available. Set incremental_verify.command in .swarm/config.json to enable.`);
|
|
52598
|
+
}
|
|
52599
|
+
return;
|
|
52600
|
+
}
|
|
52601
|
+
commandToRun = detected.command;
|
|
52602
|
+
}
|
|
52603
|
+
if (commandToRun === null)
|
|
52376
52604
|
return;
|
|
52377
|
-
const result = await runWithTimeout(
|
|
52605
|
+
const result = await runWithTimeout(commandToRun, projectDir, config3.timeoutMs);
|
|
52378
52606
|
if (result === null) {
|
|
52379
52607
|
return;
|
|
52380
52608
|
}
|
|
@@ -52392,7 +52620,7 @@ ${errorSummary}`);
|
|
|
52392
52620
|
// src/hooks/knowledge-reader.ts
|
|
52393
52621
|
import { existsSync as existsSync19 } from "fs";
|
|
52394
52622
|
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
|
|
52395
|
-
import * as
|
|
52623
|
+
import * as path33 from "path";
|
|
52396
52624
|
var JACCARD_THRESHOLD = 0.6;
|
|
52397
52625
|
var HIVE_TIER_BOOST = 0.05;
|
|
52398
52626
|
var SAME_PROJECT_PENALTY = -0.05;
|
|
@@ -52440,7 +52668,7 @@ function inferCategoriesFromPhase(phaseDescription) {
|
|
|
52440
52668
|
return ["process", "tooling"];
|
|
52441
52669
|
}
|
|
52442
52670
|
async function recordLessonsShown(directory, lessonIds, currentPhase) {
|
|
52443
|
-
const shownFile =
|
|
52671
|
+
const shownFile = path33.join(directory, ".swarm", ".knowledge-shown.json");
|
|
52444
52672
|
try {
|
|
52445
52673
|
let shownData = {};
|
|
52446
52674
|
if (existsSync19(shownFile)) {
|
|
@@ -52448,7 +52676,7 @@ async function recordLessonsShown(directory, lessonIds, currentPhase) {
|
|
|
52448
52676
|
shownData = JSON.parse(content);
|
|
52449
52677
|
}
|
|
52450
52678
|
shownData[currentPhase] = lessonIds;
|
|
52451
|
-
await mkdir4(
|
|
52679
|
+
await mkdir4(path33.dirname(shownFile), { recursive: true });
|
|
52452
52680
|
await writeFile4(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
|
|
52453
52681
|
} catch {
|
|
52454
52682
|
console.warn("[swarm] Knowledge: failed to record shown lessons");
|
|
@@ -52543,7 +52771,7 @@ async function readMergedKnowledge(directory, config3, context) {
|
|
|
52543
52771
|
return topN;
|
|
52544
52772
|
}
|
|
52545
52773
|
async function updateRetrievalOutcome(directory, phaseInfo, phaseSucceeded) {
|
|
52546
|
-
const shownFile =
|
|
52774
|
+
const shownFile = path33.join(directory, ".swarm", ".knowledge-shown.json");
|
|
52547
52775
|
try {
|
|
52548
52776
|
if (!existsSync19(shownFile)) {
|
|
52549
52777
|
return;
|
|
@@ -53015,12 +53243,12 @@ Use this data to avoid repeating known failure patterns.`;
|
|
|
53015
53243
|
// src/hooks/curator-drift.ts
|
|
53016
53244
|
init_event_bus();
|
|
53017
53245
|
init_utils2();
|
|
53018
|
-
import * as
|
|
53019
|
-
import * as
|
|
53246
|
+
import * as fs21 from "fs";
|
|
53247
|
+
import * as path34 from "path";
|
|
53020
53248
|
var DRIFT_REPORT_PREFIX = "drift-report-phase-";
|
|
53021
53249
|
async function readPriorDriftReports(directory) {
|
|
53022
|
-
const swarmDir =
|
|
53023
|
-
const entries = await
|
|
53250
|
+
const swarmDir = path34.join(directory, ".swarm");
|
|
53251
|
+
const entries = await fs21.promises.readdir(swarmDir).catch(() => null);
|
|
53024
53252
|
if (entries === null)
|
|
53025
53253
|
return [];
|
|
53026
53254
|
const reportFiles = entries.filter((name2) => name2.startsWith(DRIFT_REPORT_PREFIX) && name2.endsWith(".json")).sort();
|
|
@@ -53046,10 +53274,10 @@ async function readPriorDriftReports(directory) {
|
|
|
53046
53274
|
async function writeDriftReport(directory, report) {
|
|
53047
53275
|
const filename = `${DRIFT_REPORT_PREFIX}${report.phase}.json`;
|
|
53048
53276
|
const filePath = validateSwarmPath(directory, filename);
|
|
53049
|
-
const swarmDir =
|
|
53050
|
-
await
|
|
53277
|
+
const swarmDir = path34.dirname(filePath);
|
|
53278
|
+
await fs21.promises.mkdir(swarmDir, { recursive: true });
|
|
53051
53279
|
try {
|
|
53052
|
-
await
|
|
53280
|
+
await fs21.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
|
|
53053
53281
|
} catch (err2) {
|
|
53054
53282
|
throw new Error(`[curator-drift] Failed to write drift report to ${filePath}: ${String(err2)}`);
|
|
53055
53283
|
}
|
|
@@ -53300,6 +53528,8 @@ ${cachedInjectionText}`;
|
|
|
53300
53528
|
}
|
|
53301
53529
|
|
|
53302
53530
|
// src/hooks/slop-detector.ts
|
|
53531
|
+
import * as fs22 from "fs";
|
|
53532
|
+
import * as path35 from "path";
|
|
53303
53533
|
var WRITE_EDIT_TOOLS = new Set([
|
|
53304
53534
|
"write",
|
|
53305
53535
|
"edit",
|
|
@@ -53310,7 +53540,7 @@ function countMatches(text, pattern) {
|
|
|
53310
53540
|
return (text.match(pattern) ?? []).length;
|
|
53311
53541
|
}
|
|
53312
53542
|
function checkAbstractionBloat(content, threshold) {
|
|
53313
|
-
const newClasses = countMatches(content, /^\+.*\
|
|
53543
|
+
const newClasses = countMatches(content, /^\+.*\b(?:class|struct|impl)\s+\w+/gm);
|
|
53314
53544
|
if (newClasses >= threshold) {
|
|
53315
53545
|
return {
|
|
53316
53546
|
type: "abstraction_bloat",
|
|
@@ -53320,8 +53550,8 @@ function checkAbstractionBloat(content, threshold) {
|
|
|
53320
53550
|
return null;
|
|
53321
53551
|
}
|
|
53322
53552
|
function checkCommentStrip(content, threshold) {
|
|
53323
|
-
const removedComments = countMatches(content, /^-\s
|
|
53324
|
-
const addedComments = countMatches(content, /^\+\s
|
|
53553
|
+
const removedComments = countMatches(content, /^-\s*(?:\/[/*]|#|--)/gm);
|
|
53554
|
+
const addedComments = countMatches(content, /^\+\s*(?:\/[/*]|#|--)/gm);
|
|
53325
53555
|
if (removedComments >= threshold && addedComments === 0) {
|
|
53326
53556
|
return {
|
|
53327
53557
|
type: "comment_strip",
|
|
@@ -53341,8 +53571,33 @@ function checkBoilerplateExplosion(content, taskDescription, threshold) {
|
|
|
53341
53571
|
}
|
|
53342
53572
|
return null;
|
|
53343
53573
|
}
|
|
53344
|
-
|
|
53345
|
-
const
|
|
53574
|
+
function walkFiles(dir, exts, deadline) {
|
|
53575
|
+
const results = [];
|
|
53576
|
+
try {
|
|
53577
|
+
for (const entry of fs22.readdirSync(dir, { withFileTypes: true })) {
|
|
53578
|
+
if (deadline !== undefined && Date.now() > deadline)
|
|
53579
|
+
break;
|
|
53580
|
+
if (entry.isSymbolicLink())
|
|
53581
|
+
continue;
|
|
53582
|
+
const full = path35.join(dir, entry.name);
|
|
53583
|
+
if (entry.isDirectory()) {
|
|
53584
|
+
if (entry.name === "node_modules" || entry.name === ".git")
|
|
53585
|
+
continue;
|
|
53586
|
+
results.push(...walkFiles(full, exts, deadline));
|
|
53587
|
+
} else if (entry.isFile()) {
|
|
53588
|
+
if (exts.some((ext) => entry.name.endsWith(ext))) {
|
|
53589
|
+
results.push(full);
|
|
53590
|
+
}
|
|
53591
|
+
}
|
|
53592
|
+
}
|
|
53593
|
+
} catch {}
|
|
53594
|
+
return results;
|
|
53595
|
+
}
|
|
53596
|
+
function checkDeadExports(content, projectDir, startTime) {
|
|
53597
|
+
const hasPackageJson = fs22.existsSync(path35.join(projectDir, "package.json"));
|
|
53598
|
+
if (!hasPackageJson)
|
|
53599
|
+
return null;
|
|
53600
|
+
const exportMatches = content.matchAll(/^\+(?:export)\s+(?:function|class|const|type|interface)\s+(\w{3,})/gm);
|
|
53346
53601
|
const newExports = [];
|
|
53347
53602
|
for (const match of exportMatches) {
|
|
53348
53603
|
if (match[1])
|
|
@@ -53350,19 +53605,19 @@ async function checkDeadExports(content, projectDir, startTime) {
|
|
|
53350
53605
|
}
|
|
53351
53606
|
if (newExports.length === 0)
|
|
53352
53607
|
return null;
|
|
53608
|
+
const files = walkFiles(projectDir, [".ts", ".tsx", ".js", ".jsx"], startTime + 480);
|
|
53353
53609
|
const deadExports = [];
|
|
53354
53610
|
for (const name2 of newExports) {
|
|
53355
53611
|
if (Date.now() - startTime > 480)
|
|
53356
53612
|
break;
|
|
53357
53613
|
try {
|
|
53358
53614
|
const importPattern = new RegExp(`\\bimport\\b[^;]*\\b${name2}\\b`, "g");
|
|
53359
|
-
const glob = new Bun.Glob(`src/**/*.ts`);
|
|
53360
53615
|
let found = false;
|
|
53361
|
-
for
|
|
53616
|
+
for (const file3 of files) {
|
|
53362
53617
|
if (found || Date.now() - startTime > 480)
|
|
53363
53618
|
break;
|
|
53364
53619
|
try {
|
|
53365
|
-
const text =
|
|
53620
|
+
const text = fs22.readFileSync(file3, "utf-8");
|
|
53366
53621
|
if (importPattern.test(text))
|
|
53367
53622
|
found = true;
|
|
53368
53623
|
importPattern.lastIndex = 0;
|
|
@@ -53416,7 +53671,7 @@ function createSlopDetectorHook(config3, projectDir, injectSystemMessage) {
|
|
|
53416
53671
|
} catch {}
|
|
53417
53672
|
if (Date.now() - startTime < 400) {
|
|
53418
53673
|
try {
|
|
53419
|
-
const dead =
|
|
53674
|
+
const dead = checkDeadExports(content, projectDir, startTime);
|
|
53420
53675
|
if (dead)
|
|
53421
53676
|
findings.push(dead);
|
|
53422
53677
|
} catch {}
|
|
@@ -53435,7 +53690,7 @@ Review before proceeding.`;
|
|
|
53435
53690
|
|
|
53436
53691
|
// src/hooks/steering-consumed.ts
|
|
53437
53692
|
init_utils2();
|
|
53438
|
-
import * as
|
|
53693
|
+
import * as fs23 from "fs";
|
|
53439
53694
|
function recordSteeringConsumed(directory, directiveId) {
|
|
53440
53695
|
try {
|
|
53441
53696
|
const eventsPath = validateSwarmPath(directory, "events.jsonl");
|
|
@@ -53444,7 +53699,7 @@ function recordSteeringConsumed(directory, directiveId) {
|
|
|
53444
53699
|
directiveId,
|
|
53445
53700
|
timestamp: new Date().toISOString()
|
|
53446
53701
|
};
|
|
53447
|
-
|
|
53702
|
+
fs23.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
53448
53703
|
`, "utf-8");
|
|
53449
53704
|
} catch {}
|
|
53450
53705
|
}
|
|
@@ -53484,93 +53739,12 @@ function createSteeringConsumedHook(directory) {
|
|
|
53484
53739
|
return safeHook(hook);
|
|
53485
53740
|
}
|
|
53486
53741
|
|
|
53487
|
-
// src/services/compaction-service.ts
|
|
53488
|
-
import * as fs22 from "fs";
|
|
53489
|
-
import * as path34 from "path";
|
|
53490
|
-
function makeInitialState() {
|
|
53491
|
-
return {
|
|
53492
|
-
lastObservationAt: 0,
|
|
53493
|
-
lastReflectionAt: 0,
|
|
53494
|
-
lastEmergencyAt: 0,
|
|
53495
|
-
observationCount: 0,
|
|
53496
|
-
reflectionCount: 0,
|
|
53497
|
-
emergencyCount: 0
|
|
53498
|
-
};
|
|
53499
|
-
}
|
|
53500
|
-
function appendSnapshot(directory, tier, budgetPct, message) {
|
|
53501
|
-
try {
|
|
53502
|
-
const snapshotPath = path34.join(directory, ".swarm", "context-snapshot.md");
|
|
53503
|
-
const timestamp = new Date().toISOString();
|
|
53504
|
-
const entry = `
|
|
53505
|
-
## [${tier.toUpperCase()}] ${timestamp} \u2014 ${budgetPct.toFixed(1)}% used
|
|
53506
|
-
${message}
|
|
53507
|
-
`;
|
|
53508
|
-
fs22.appendFileSync(snapshotPath, entry, "utf-8");
|
|
53509
|
-
} catch {}
|
|
53510
|
-
}
|
|
53511
|
-
function buildObservationMessage(budgetPct) {
|
|
53512
|
-
return `[CONTEXT COMPACTION \u2014 OBSERVATION TIER]
|
|
53513
|
-
` + `Context window is ${budgetPct.toFixed(1)}% used. Initiating observation compaction.
|
|
53514
|
-
` + `INSTRUCTIONS: Summarise the key decisions made so far, files changed, errors resolved, ` + `and the current task state. Discard verbose tool outputs and raw file reads. ` + `Preserve: plan task ID, agent verdicts, file paths touched, unresolved blockers.
|
|
53515
|
-
` + `[/CONTEXT COMPACTION]`;
|
|
53516
|
-
}
|
|
53517
|
-
function buildReflectionMessage(budgetPct) {
|
|
53518
|
-
return `[CONTEXT COMPACTION \u2014 REFLECTION TIER]
|
|
53519
|
-
` + `Context window is ${budgetPct.toFixed(1)}% used. Initiating reflection compaction.
|
|
53520
|
-
` + `INSTRUCTIONS: Re-summarise into a tighter format. Discard completed task details ` + `and resolved errors. Retain ONLY: current phase tasks remaining, open blockers, ` + `last 3 reviewer/test verdicts, and active file scope.
|
|
53521
|
-
` + `[/CONTEXT COMPACTION]`;
|
|
53522
|
-
}
|
|
53523
|
-
function buildEmergencyMessage(budgetPct, preserveLastN) {
|
|
53524
|
-
return `[CONTEXT COMPACTION \u2014 EMERGENCY TIER]
|
|
53525
|
-
` + `Context window is ${budgetPct.toFixed(1)}% used. EMERGENCY compaction required.
|
|
53526
|
-
` + `INSTRUCTIONS: Retain ONLY the system prompt, the current task context, and the ` + `last ${preserveLastN} conversation turns. Discard everything else. ` + `If you cannot complete the current task in the remaining context, escalate to the user.
|
|
53527
|
-
` + `[/CONTEXT COMPACTION]`;
|
|
53528
|
-
}
|
|
53529
|
-
function createCompactionService(config3, directory, injectMessage) {
|
|
53530
|
-
const state = makeInitialState();
|
|
53531
|
-
return {
|
|
53532
|
-
toolAfter: async (_input, _output) => {
|
|
53533
|
-
if (!config3.enabled)
|
|
53534
|
-
return;
|
|
53535
|
-
const budgetPct = swarmState.lastBudgetPct ?? 0;
|
|
53536
|
-
if (budgetPct <= 0)
|
|
53537
|
-
return;
|
|
53538
|
-
const sessionId = _input.sessionID;
|
|
53539
|
-
try {
|
|
53540
|
-
if (budgetPct >= config3.emergencyThreshold && budgetPct > state.lastEmergencyAt + 5) {
|
|
53541
|
-
state.lastEmergencyAt = budgetPct;
|
|
53542
|
-
state.emergencyCount++;
|
|
53543
|
-
const msg = buildEmergencyMessage(budgetPct, config3.preserveLastNTurns);
|
|
53544
|
-
appendSnapshot(directory, "emergency", budgetPct, msg);
|
|
53545
|
-
injectMessage(sessionId, msg);
|
|
53546
|
-
return;
|
|
53547
|
-
}
|
|
53548
|
-
if (budgetPct >= config3.reflectionThreshold && budgetPct > state.lastReflectionAt + 5) {
|
|
53549
|
-
state.lastReflectionAt = budgetPct;
|
|
53550
|
-
state.reflectionCount++;
|
|
53551
|
-
const msg = buildReflectionMessage(budgetPct);
|
|
53552
|
-
appendSnapshot(directory, "reflection", budgetPct, msg);
|
|
53553
|
-
injectMessage(sessionId, msg);
|
|
53554
|
-
return;
|
|
53555
|
-
}
|
|
53556
|
-
if (budgetPct >= config3.observationThreshold && budgetPct > state.lastObservationAt + 5) {
|
|
53557
|
-
state.lastObservationAt = budgetPct;
|
|
53558
|
-
state.observationCount++;
|
|
53559
|
-
const msg = buildObservationMessage(budgetPct);
|
|
53560
|
-
appendSnapshot(directory, "observation", budgetPct, msg);
|
|
53561
|
-
injectMessage(sessionId, msg);
|
|
53562
|
-
}
|
|
53563
|
-
} catch {}
|
|
53564
|
-
}
|
|
53565
|
-
};
|
|
53566
|
-
}
|
|
53567
|
-
|
|
53568
53742
|
// src/index.ts
|
|
53569
53743
|
init_config_doctor();
|
|
53570
53744
|
|
|
53571
53745
|
// src/session/snapshot-reader.ts
|
|
53572
53746
|
init_utils2();
|
|
53573
|
-
import
|
|
53747
|
+
import path36 from "path";
|
|
53574
53748
|
var VALID_TASK_WORKFLOW_STATES = [
|
|
53575
53749
|
"idle",
|
|
53576
53750
|
"coder_delegated",
|
|
@@ -53695,7 +53869,7 @@ function rehydrateState(snapshot) {
|
|
|
53695
53869
|
async function reconcileTaskStatesFromPlan(directory) {
|
|
53696
53870
|
let raw;
|
|
53697
53871
|
try {
|
|
53698
|
-
raw = await Bun.file(
|
|
53872
|
+
raw = await Bun.file(path36.join(directory, ".swarm/plan.json")).text();
|
|
53699
53873
|
} catch {
|
|
53700
53874
|
return;
|
|
53701
53875
|
}
|
|
@@ -53917,8 +54091,8 @@ var build_check = createSwarmTool({
|
|
|
53917
54091
|
// src/tools/check-gate-status.ts
|
|
53918
54092
|
init_dist();
|
|
53919
54093
|
init_create_tool();
|
|
53920
|
-
import * as
|
|
53921
|
-
import * as
|
|
54094
|
+
import * as fs24 from "fs";
|
|
54095
|
+
import * as path37 from "path";
|
|
53922
54096
|
var EVIDENCE_DIR = ".swarm/evidence";
|
|
53923
54097
|
var TASK_ID_PATTERN2 = /^\d+\.\d+(\.\d+)*$/;
|
|
53924
54098
|
function isValidTaskId3(taskId) {
|
|
@@ -53935,18 +54109,18 @@ function isValidTaskId3(taskId) {
|
|
|
53935
54109
|
return TASK_ID_PATTERN2.test(taskId);
|
|
53936
54110
|
}
|
|
53937
54111
|
function isPathWithinSwarm(filePath, workspaceRoot) {
|
|
53938
|
-
const normalizedWorkspace =
|
|
53939
|
-
const swarmPath =
|
|
53940
|
-
const normalizedPath =
|
|
54112
|
+
const normalizedWorkspace = path37.resolve(workspaceRoot);
|
|
54113
|
+
const swarmPath = path37.join(normalizedWorkspace, ".swarm", "evidence");
|
|
54114
|
+
const normalizedPath = path37.resolve(filePath);
|
|
53941
54115
|
return normalizedPath.startsWith(swarmPath);
|
|
53942
54116
|
}
|
|
53943
54117
|
function readEvidenceFile(evidencePath) {
|
|
53944
|
-
if (!
|
|
54118
|
+
if (!fs24.existsSync(evidencePath)) {
|
|
53945
54119
|
return null;
|
|
53946
54120
|
}
|
|
53947
54121
|
let content;
|
|
53948
54122
|
try {
|
|
53949
|
-
content =
|
|
54123
|
+
content = fs24.readFileSync(evidencePath, "utf-8");
|
|
53950
54124
|
} catch {
|
|
53951
54125
|
return null;
|
|
53952
54126
|
}
|
|
@@ -53998,7 +54172,7 @@ var check_gate_status = createSwarmTool({
|
|
|
53998
54172
|
};
|
|
53999
54173
|
return JSON.stringify(errorResult, null, 2);
|
|
54000
54174
|
}
|
|
54001
|
-
const evidencePath =
|
|
54175
|
+
const evidencePath = path37.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
|
|
54002
54176
|
if (!isPathWithinSwarm(evidencePath, directory)) {
|
|
54003
54177
|
const errorResult = {
|
|
54004
54178
|
taskId: taskIdInput,
|
|
@@ -54058,8 +54232,8 @@ var check_gate_status = createSwarmTool({
|
|
|
54058
54232
|
init_tool();
|
|
54059
54233
|
init_create_tool();
|
|
54060
54234
|
import { spawnSync } from "child_process";
|
|
54061
|
-
import * as
|
|
54062
|
-
import * as
|
|
54235
|
+
import * as fs25 from "fs";
|
|
54236
|
+
import * as path38 from "path";
|
|
54063
54237
|
var CHECKPOINT_LOG_PATH = ".swarm/checkpoints.json";
|
|
54064
54238
|
var MAX_LABEL_LENGTH = 100;
|
|
54065
54239
|
var GIT_TIMEOUT_MS = 30000;
|
|
@@ -54110,13 +54284,13 @@ function validateLabel(label) {
|
|
|
54110
54284
|
return null;
|
|
54111
54285
|
}
|
|
54112
54286
|
function getCheckpointLogPath(directory) {
|
|
54113
|
-
return
|
|
54287
|
+
return path38.join(directory, CHECKPOINT_LOG_PATH);
|
|
54114
54288
|
}
|
|
54115
54289
|
function readCheckpointLog(directory) {
|
|
54116
54290
|
const logPath = getCheckpointLogPath(directory);
|
|
54117
54291
|
try {
|
|
54118
|
-
if (
|
|
54119
|
-
const content =
|
|
54292
|
+
if (fs25.existsSync(logPath)) {
|
|
54293
|
+
const content = fs25.readFileSync(logPath, "utf-8");
|
|
54120
54294
|
const parsed = JSON.parse(content);
|
|
54121
54295
|
if (!parsed.checkpoints || !Array.isArray(parsed.checkpoints)) {
|
|
54122
54296
|
return { version: 1, checkpoints: [] };
|
|
@@ -54128,13 +54302,13 @@ function readCheckpointLog(directory) {
|
|
|
54128
54302
|
}
|
|
54129
54303
|
function writeCheckpointLog(log2, directory) {
|
|
54130
54304
|
const logPath = getCheckpointLogPath(directory);
|
|
54131
|
-
const dir =
|
|
54132
|
-
if (!
|
|
54133
|
-
|
|
54305
|
+
const dir = path38.dirname(logPath);
|
|
54306
|
+
if (!fs25.existsSync(dir)) {
|
|
54307
|
+
fs25.mkdirSync(dir, { recursive: true });
|
|
54134
54308
|
}
|
|
54135
54309
|
const tempPath = `${logPath}.tmp`;
|
|
54136
|
-
|
|
54137
|
-
|
|
54310
|
+
fs25.writeFileSync(tempPath, JSON.stringify(log2, null, 2), "utf-8");
|
|
54311
|
+
fs25.renameSync(tempPath, logPath);
|
|
54138
54312
|
}
|
|
54139
54313
|
function gitExec(args2) {
|
|
54140
54314
|
const result = spawnSync("git", args2, {
|
|
@@ -54335,8 +54509,8 @@ var checkpoint = createSwarmTool({
|
|
|
54335
54509
|
// src/tools/complexity-hotspots.ts
|
|
54336
54510
|
init_dist();
|
|
54337
54511
|
init_create_tool();
|
|
54338
|
-
import * as
|
|
54339
|
-
import * as
|
|
54512
|
+
import * as fs26 from "fs";
|
|
54513
|
+
import * as path39 from "path";
|
|
54340
54514
|
var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
|
|
54341
54515
|
var DEFAULT_DAYS = 90;
|
|
54342
54516
|
var DEFAULT_TOP_N = 20;
|
|
@@ -54465,11 +54639,11 @@ function estimateComplexity(content) {
|
|
|
54465
54639
|
}
|
|
54466
54640
|
function getComplexityForFile(filePath) {
|
|
54467
54641
|
try {
|
|
54468
|
-
const stat2 =
|
|
54642
|
+
const stat2 = fs26.statSync(filePath);
|
|
54469
54643
|
if (stat2.size > MAX_FILE_SIZE_BYTES2) {
|
|
54470
54644
|
return null;
|
|
54471
54645
|
}
|
|
54472
|
-
const content =
|
|
54646
|
+
const content = fs26.readFileSync(filePath, "utf-8");
|
|
54473
54647
|
return estimateComplexity(content);
|
|
54474
54648
|
} catch {
|
|
54475
54649
|
return null;
|
|
@@ -54480,7 +54654,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
54480
54654
|
const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
|
|
54481
54655
|
const filteredChurn = new Map;
|
|
54482
54656
|
for (const [file3, count] of churnMap) {
|
|
54483
|
-
const ext =
|
|
54657
|
+
const ext = path39.extname(file3).toLowerCase();
|
|
54484
54658
|
if (extSet.has(ext)) {
|
|
54485
54659
|
filteredChurn.set(file3, count);
|
|
54486
54660
|
}
|
|
@@ -54490,8 +54664,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
54490
54664
|
let analyzedFiles = 0;
|
|
54491
54665
|
for (const [file3, churnCount] of filteredChurn) {
|
|
54492
54666
|
let fullPath = file3;
|
|
54493
|
-
if (!
|
|
54494
|
-
fullPath =
|
|
54667
|
+
if (!fs26.existsSync(fullPath)) {
|
|
54668
|
+
fullPath = path39.join(cwd, file3);
|
|
54495
54669
|
}
|
|
54496
54670
|
const complexity = getComplexityForFile(fullPath);
|
|
54497
54671
|
if (complexity !== null) {
|
|
@@ -54638,8 +54812,8 @@ var complexity_hotspots = createSwarmTool({
|
|
|
54638
54812
|
});
|
|
54639
54813
|
// src/tools/declare-scope.ts
|
|
54640
54814
|
init_tool();
|
|
54641
|
-
import * as
|
|
54642
|
-
import * as
|
|
54815
|
+
import * as fs27 from "fs";
|
|
54816
|
+
import * as path40 from "path";
|
|
54643
54817
|
init_create_tool();
|
|
54644
54818
|
function validateTaskIdFormat(taskId) {
|
|
54645
54819
|
const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
|
|
@@ -54718,8 +54892,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
54718
54892
|
};
|
|
54719
54893
|
}
|
|
54720
54894
|
}
|
|
54721
|
-
normalizedDir =
|
|
54722
|
-
const pathParts = normalizedDir.split(
|
|
54895
|
+
normalizedDir = path40.normalize(args2.working_directory);
|
|
54896
|
+
const pathParts = normalizedDir.split(path40.sep);
|
|
54723
54897
|
if (pathParts.includes("..")) {
|
|
54724
54898
|
return {
|
|
54725
54899
|
success: false,
|
|
@@ -54729,11 +54903,11 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
54729
54903
|
]
|
|
54730
54904
|
};
|
|
54731
54905
|
}
|
|
54732
|
-
const resolvedDir =
|
|
54906
|
+
const resolvedDir = path40.resolve(normalizedDir);
|
|
54733
54907
|
try {
|
|
54734
|
-
const realPath =
|
|
54735
|
-
const planPath2 =
|
|
54736
|
-
if (!
|
|
54908
|
+
const realPath = fs27.realpathSync(resolvedDir);
|
|
54909
|
+
const planPath2 = path40.join(realPath, ".swarm", "plan.json");
|
|
54910
|
+
if (!fs27.existsSync(planPath2)) {
|
|
54737
54911
|
return {
|
|
54738
54912
|
success: false,
|
|
54739
54913
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -54753,8 +54927,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
54753
54927
|
}
|
|
54754
54928
|
}
|
|
54755
54929
|
const directory = normalizedDir ?? fallbackDir ?? process.cwd();
|
|
54756
|
-
const planPath =
|
|
54757
|
-
if (!
|
|
54930
|
+
const planPath = path40.resolve(directory, ".swarm", "plan.json");
|
|
54931
|
+
if (!fs27.existsSync(planPath)) {
|
|
54758
54932
|
return {
|
|
54759
54933
|
success: false,
|
|
54760
54934
|
message: "No plan found",
|
|
@@ -54763,7 +54937,7 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
54763
54937
|
}
|
|
54764
54938
|
let planContent;
|
|
54765
54939
|
try {
|
|
54766
|
-
planContent = JSON.parse(
|
|
54940
|
+
planContent = JSON.parse(fs27.readFileSync(planPath, "utf-8"));
|
|
54767
54941
|
} catch {
|
|
54768
54942
|
return {
|
|
54769
54943
|
success: false,
|
|
@@ -54843,20 +55017,20 @@ function validateBase(base) {
|
|
|
54843
55017
|
function validatePaths(paths) {
|
|
54844
55018
|
if (!paths)
|
|
54845
55019
|
return null;
|
|
54846
|
-
for (const
|
|
54847
|
-
if (!
|
|
55020
|
+
for (const path41 of paths) {
|
|
55021
|
+
if (!path41 || path41.length === 0) {
|
|
54848
55022
|
return "empty path not allowed";
|
|
54849
55023
|
}
|
|
54850
|
-
if (
|
|
55024
|
+
if (path41.length > MAX_PATH_LENGTH) {
|
|
54851
55025
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
54852
55026
|
}
|
|
54853
|
-
if (SHELL_METACHARACTERS2.test(
|
|
55027
|
+
if (SHELL_METACHARACTERS2.test(path41)) {
|
|
54854
55028
|
return "path contains shell metacharacters";
|
|
54855
55029
|
}
|
|
54856
|
-
if (
|
|
55030
|
+
if (path41.startsWith("-")) {
|
|
54857
55031
|
return 'path cannot start with "-" (option-like arguments not allowed)';
|
|
54858
55032
|
}
|
|
54859
|
-
if (CONTROL_CHAR_PATTERN2.test(
|
|
55033
|
+
if (CONTROL_CHAR_PATTERN2.test(path41)) {
|
|
54860
55034
|
return "path contains control characters";
|
|
54861
55035
|
}
|
|
54862
55036
|
}
|
|
@@ -54936,8 +55110,8 @@ var diff = tool({
|
|
|
54936
55110
|
if (parts2.length >= 3) {
|
|
54937
55111
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
54938
55112
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
54939
|
-
const
|
|
54940
|
-
files.push({ path:
|
|
55113
|
+
const path41 = parts2[2];
|
|
55114
|
+
files.push({ path: path41, additions, deletions });
|
|
54941
55115
|
}
|
|
54942
55116
|
}
|
|
54943
55117
|
const contractChanges = [];
|
|
@@ -55166,8 +55340,8 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
55166
55340
|
// src/tools/evidence-check.ts
|
|
55167
55341
|
init_dist();
|
|
55168
55342
|
init_create_tool();
|
|
55169
|
-
import * as
|
|
55170
|
-
import * as
|
|
55343
|
+
import * as fs28 from "fs";
|
|
55344
|
+
import * as path41 from "path";
|
|
55171
55345
|
var MAX_FILE_SIZE_BYTES3 = 1024 * 1024;
|
|
55172
55346
|
var MAX_EVIDENCE_FILES = 1000;
|
|
55173
55347
|
var EVIDENCE_DIR2 = ".swarm/evidence";
|
|
@@ -55197,9 +55371,9 @@ function validateRequiredTypes(input) {
|
|
|
55197
55371
|
return null;
|
|
55198
55372
|
}
|
|
55199
55373
|
function isPathWithinSwarm2(filePath, cwd) {
|
|
55200
|
-
const normalizedCwd =
|
|
55201
|
-
const swarmPath =
|
|
55202
|
-
const normalizedPath =
|
|
55374
|
+
const normalizedCwd = path41.resolve(cwd);
|
|
55375
|
+
const swarmPath = path41.join(normalizedCwd, ".swarm");
|
|
55376
|
+
const normalizedPath = path41.resolve(filePath);
|
|
55203
55377
|
return normalizedPath.startsWith(swarmPath);
|
|
55204
55378
|
}
|
|
55205
55379
|
function parseCompletedTasks(planContent) {
|
|
@@ -55215,12 +55389,12 @@ function parseCompletedTasks(planContent) {
|
|
|
55215
55389
|
}
|
|
55216
55390
|
function readEvidenceFiles(evidenceDir, _cwd) {
|
|
55217
55391
|
const evidence = [];
|
|
55218
|
-
if (!
|
|
55392
|
+
if (!fs28.existsSync(evidenceDir) || !fs28.statSync(evidenceDir).isDirectory()) {
|
|
55219
55393
|
return evidence;
|
|
55220
55394
|
}
|
|
55221
55395
|
let files;
|
|
55222
55396
|
try {
|
|
55223
|
-
files =
|
|
55397
|
+
files = fs28.readdirSync(evidenceDir);
|
|
55224
55398
|
} catch {
|
|
55225
55399
|
return evidence;
|
|
55226
55400
|
}
|
|
@@ -55229,14 +55403,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
55229
55403
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
55230
55404
|
continue;
|
|
55231
55405
|
}
|
|
55232
|
-
const filePath =
|
|
55406
|
+
const filePath = path41.join(evidenceDir, filename);
|
|
55233
55407
|
try {
|
|
55234
|
-
const resolvedPath =
|
|
55235
|
-
const evidenceDirResolved =
|
|
55408
|
+
const resolvedPath = path41.resolve(filePath);
|
|
55409
|
+
const evidenceDirResolved = path41.resolve(evidenceDir);
|
|
55236
55410
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
55237
55411
|
continue;
|
|
55238
55412
|
}
|
|
55239
|
-
const stat2 =
|
|
55413
|
+
const stat2 = fs28.lstatSync(filePath);
|
|
55240
55414
|
if (!stat2.isFile()) {
|
|
55241
55415
|
continue;
|
|
55242
55416
|
}
|
|
@@ -55245,7 +55419,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
55245
55419
|
}
|
|
55246
55420
|
let fileStat;
|
|
55247
55421
|
try {
|
|
55248
|
-
fileStat =
|
|
55422
|
+
fileStat = fs28.statSync(filePath);
|
|
55249
55423
|
if (fileStat.size > MAX_FILE_SIZE_BYTES3) {
|
|
55250
55424
|
continue;
|
|
55251
55425
|
}
|
|
@@ -55254,7 +55428,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
55254
55428
|
}
|
|
55255
55429
|
let content;
|
|
55256
55430
|
try {
|
|
55257
|
-
content =
|
|
55431
|
+
content = fs28.readFileSync(filePath, "utf-8");
|
|
55258
55432
|
} catch {
|
|
55259
55433
|
continue;
|
|
55260
55434
|
}
|
|
@@ -55350,7 +55524,7 @@ var evidence_check = createSwarmTool({
|
|
|
55350
55524
|
return JSON.stringify(errorResult, null, 2);
|
|
55351
55525
|
}
|
|
55352
55526
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
|
|
55353
|
-
const planPath =
|
|
55527
|
+
const planPath = path41.join(cwd, PLAN_FILE);
|
|
55354
55528
|
if (!isPathWithinSwarm2(planPath, cwd)) {
|
|
55355
55529
|
const errorResult = {
|
|
55356
55530
|
error: "plan file path validation failed",
|
|
@@ -55364,7 +55538,7 @@ var evidence_check = createSwarmTool({
|
|
|
55364
55538
|
}
|
|
55365
55539
|
let planContent;
|
|
55366
55540
|
try {
|
|
55367
|
-
planContent =
|
|
55541
|
+
planContent = fs28.readFileSync(planPath, "utf-8");
|
|
55368
55542
|
} catch {
|
|
55369
55543
|
const result2 = {
|
|
55370
55544
|
message: "No completed tasks found in plan.",
|
|
@@ -55382,7 +55556,7 @@ var evidence_check = createSwarmTool({
|
|
|
55382
55556
|
};
|
|
55383
55557
|
return JSON.stringify(result2, null, 2);
|
|
55384
55558
|
}
|
|
55385
|
-
const evidenceDir =
|
|
55559
|
+
const evidenceDir = path41.join(cwd, EVIDENCE_DIR2);
|
|
55386
55560
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
55387
55561
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
55388
55562
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -55399,8 +55573,8 @@ var evidence_check = createSwarmTool({
|
|
|
55399
55573
|
// src/tools/file-extractor.ts
|
|
55400
55574
|
init_tool();
|
|
55401
55575
|
init_create_tool();
|
|
55402
|
-
import * as
|
|
55403
|
-
import * as
|
|
55576
|
+
import * as fs29 from "fs";
|
|
55577
|
+
import * as path42 from "path";
|
|
55404
55578
|
var EXT_MAP = {
|
|
55405
55579
|
python: ".py",
|
|
55406
55580
|
py: ".py",
|
|
@@ -55462,8 +55636,8 @@ var extract_code_blocks = createSwarmTool({
|
|
|
55462
55636
|
execute: async (args2, directory) => {
|
|
55463
55637
|
const { content, output_dir, prefix } = args2;
|
|
55464
55638
|
const targetDir = output_dir || directory;
|
|
55465
|
-
if (!
|
|
55466
|
-
|
|
55639
|
+
if (!fs29.existsSync(targetDir)) {
|
|
55640
|
+
fs29.mkdirSync(targetDir, { recursive: true });
|
|
55467
55641
|
}
|
|
55468
55642
|
if (!content) {
|
|
55469
55643
|
return "Error: content is required";
|
|
@@ -55481,16 +55655,16 @@ var extract_code_blocks = createSwarmTool({
|
|
|
55481
55655
|
if (prefix) {
|
|
55482
55656
|
filename = `${prefix}_${filename}`;
|
|
55483
55657
|
}
|
|
55484
|
-
let filepath =
|
|
55485
|
-
const base =
|
|
55486
|
-
const ext =
|
|
55658
|
+
let filepath = path42.join(targetDir, filename);
|
|
55659
|
+
const base = path42.basename(filepath, path42.extname(filepath));
|
|
55660
|
+
const ext = path42.extname(filepath);
|
|
55487
55661
|
let counter = 1;
|
|
55488
|
-
while (
|
|
55489
|
-
filepath =
|
|
55662
|
+
while (fs29.existsSync(filepath)) {
|
|
55663
|
+
filepath = path42.join(targetDir, `${base}_${counter}${ext}`);
|
|
55490
55664
|
counter++;
|
|
55491
55665
|
}
|
|
55492
55666
|
try {
|
|
55493
|
-
|
|
55667
|
+
fs29.writeFileSync(filepath, code.trim(), "utf-8");
|
|
55494
55668
|
savedFiles.push(filepath);
|
|
55495
55669
|
} catch (error93) {
|
|
55496
55670
|
errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
@@ -55603,8 +55777,8 @@ var gitingest = tool({
|
|
|
55603
55777
|
});
|
|
55604
55778
|
// src/tools/imports.ts
|
|
55605
55779
|
init_dist();
|
|
55606
|
-
import * as
|
|
55607
|
-
import * as
|
|
55780
|
+
import * as fs30 from "fs";
|
|
55781
|
+
import * as path43 from "path";
|
|
55608
55782
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
55609
55783
|
var MAX_SYMBOL_LENGTH = 256;
|
|
55610
55784
|
var MAX_FILE_SIZE_BYTES4 = 1024 * 1024;
|
|
@@ -55658,7 +55832,7 @@ function validateSymbolInput(symbol3) {
|
|
|
55658
55832
|
return null;
|
|
55659
55833
|
}
|
|
55660
55834
|
function isBinaryFile2(filePath, buffer) {
|
|
55661
|
-
const ext =
|
|
55835
|
+
const ext = path43.extname(filePath).toLowerCase();
|
|
55662
55836
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
55663
55837
|
return false;
|
|
55664
55838
|
}
|
|
@@ -55682,15 +55856,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
55682
55856
|
const imports = [];
|
|
55683
55857
|
let _resolvedTarget;
|
|
55684
55858
|
try {
|
|
55685
|
-
_resolvedTarget =
|
|
55859
|
+
_resolvedTarget = path43.resolve(targetFile);
|
|
55686
55860
|
} catch {
|
|
55687
55861
|
_resolvedTarget = targetFile;
|
|
55688
55862
|
}
|
|
55689
|
-
const targetBasename =
|
|
55863
|
+
const targetBasename = path43.basename(targetFile, path43.extname(targetFile));
|
|
55690
55864
|
const targetWithExt = targetFile;
|
|
55691
55865
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
55692
|
-
const normalizedTargetWithExt =
|
|
55693
|
-
const normalizedTargetWithoutExt =
|
|
55866
|
+
const normalizedTargetWithExt = path43.normalize(targetWithExt).replace(/\\/g, "/");
|
|
55867
|
+
const normalizedTargetWithoutExt = path43.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
55694
55868
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
55695
55869
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
55696
55870
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -55713,9 +55887,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
55713
55887
|
}
|
|
55714
55888
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
55715
55889
|
let isMatch = false;
|
|
55716
|
-
const _targetDir =
|
|
55717
|
-
const targetExt =
|
|
55718
|
-
const targetBasenameNoExt =
|
|
55890
|
+
const _targetDir = path43.dirname(targetFile);
|
|
55891
|
+
const targetExt = path43.extname(targetFile);
|
|
55892
|
+
const targetBasenameNoExt = path43.basename(targetFile, targetExt);
|
|
55719
55893
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
55720
55894
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
55721
55895
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -55772,7 +55946,7 @@ var SKIP_DIRECTORIES2 = new Set([
|
|
|
55772
55946
|
function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
|
|
55773
55947
|
let entries;
|
|
55774
55948
|
try {
|
|
55775
|
-
entries =
|
|
55949
|
+
entries = fs30.readdirSync(dir);
|
|
55776
55950
|
} catch (e) {
|
|
55777
55951
|
stats.fileErrors.push({
|
|
55778
55952
|
path: dir,
|
|
@@ -55783,13 +55957,13 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
|
|
|
55783
55957
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
55784
55958
|
for (const entry of entries) {
|
|
55785
55959
|
if (SKIP_DIRECTORIES2.has(entry)) {
|
|
55786
|
-
stats.skippedDirs.push(
|
|
55960
|
+
stats.skippedDirs.push(path43.join(dir, entry));
|
|
55787
55961
|
continue;
|
|
55788
55962
|
}
|
|
55789
|
-
const fullPath =
|
|
55963
|
+
const fullPath = path43.join(dir, entry);
|
|
55790
55964
|
let stat2;
|
|
55791
55965
|
try {
|
|
55792
|
-
stat2 =
|
|
55966
|
+
stat2 = fs30.statSync(fullPath);
|
|
55793
55967
|
} catch (e) {
|
|
55794
55968
|
stats.fileErrors.push({
|
|
55795
55969
|
path: fullPath,
|
|
@@ -55800,7 +55974,7 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
|
|
|
55800
55974
|
if (stat2.isDirectory()) {
|
|
55801
55975
|
findSourceFiles(fullPath, files, stats);
|
|
55802
55976
|
} else if (stat2.isFile()) {
|
|
55803
|
-
const ext =
|
|
55977
|
+
const ext = path43.extname(fullPath).toLowerCase();
|
|
55804
55978
|
if (SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
55805
55979
|
files.push(fullPath);
|
|
55806
55980
|
}
|
|
@@ -55856,8 +56030,8 @@ var imports = tool({
|
|
|
55856
56030
|
return JSON.stringify(errorResult, null, 2);
|
|
55857
56031
|
}
|
|
55858
56032
|
try {
|
|
55859
|
-
const targetFile =
|
|
55860
|
-
if (!
|
|
56033
|
+
const targetFile = path43.resolve(file3);
|
|
56034
|
+
if (!fs30.existsSync(targetFile)) {
|
|
55861
56035
|
const errorResult = {
|
|
55862
56036
|
error: `target file not found: ${file3}`,
|
|
55863
56037
|
target: file3,
|
|
@@ -55867,7 +56041,7 @@ var imports = tool({
|
|
|
55867
56041
|
};
|
|
55868
56042
|
return JSON.stringify(errorResult, null, 2);
|
|
55869
56043
|
}
|
|
55870
|
-
const targetStat =
|
|
56044
|
+
const targetStat = fs30.statSync(targetFile);
|
|
55871
56045
|
if (!targetStat.isFile()) {
|
|
55872
56046
|
const errorResult = {
|
|
55873
56047
|
error: "target must be a file, not a directory",
|
|
@@ -55878,7 +56052,7 @@ var imports = tool({
|
|
|
55878
56052
|
};
|
|
55879
56053
|
return JSON.stringify(errorResult, null, 2);
|
|
55880
56054
|
}
|
|
55881
|
-
const baseDir =
|
|
56055
|
+
const baseDir = path43.dirname(targetFile);
|
|
55882
56056
|
const scanStats = {
|
|
55883
56057
|
skippedDirs: [],
|
|
55884
56058
|
skippedFiles: 0,
|
|
@@ -55893,12 +56067,12 @@ var imports = tool({
|
|
|
55893
56067
|
if (consumers.length >= MAX_CONSUMERS)
|
|
55894
56068
|
break;
|
|
55895
56069
|
try {
|
|
55896
|
-
const stat2 =
|
|
56070
|
+
const stat2 = fs30.statSync(filePath);
|
|
55897
56071
|
if (stat2.size > MAX_FILE_SIZE_BYTES4) {
|
|
55898
56072
|
skippedFileCount++;
|
|
55899
56073
|
continue;
|
|
55900
56074
|
}
|
|
55901
|
-
const buffer =
|
|
56075
|
+
const buffer = fs30.readFileSync(filePath);
|
|
55902
56076
|
if (isBinaryFile2(filePath, buffer)) {
|
|
55903
56077
|
skippedFileCount++;
|
|
55904
56078
|
continue;
|
|
@@ -55963,7 +56137,7 @@ var imports = tool({
|
|
|
55963
56137
|
});
|
|
55964
56138
|
// src/tools/knowledge-query.ts
|
|
55965
56139
|
init_dist();
|
|
55966
|
-
import { existsSync as
|
|
56140
|
+
import { existsSync as existsSync28 } from "fs";
|
|
55967
56141
|
init_create_tool();
|
|
55968
56142
|
var DEFAULT_LIMIT = 10;
|
|
55969
56143
|
var MAX_LESSON_LENGTH = 200;
|
|
@@ -56033,14 +56207,14 @@ function validateLimit(limit) {
|
|
|
56033
56207
|
}
|
|
56034
56208
|
async function readSwarmKnowledge(directory) {
|
|
56035
56209
|
const swarmPath = resolveSwarmKnowledgePath(directory);
|
|
56036
|
-
if (!
|
|
56210
|
+
if (!existsSync28(swarmPath)) {
|
|
56037
56211
|
return [];
|
|
56038
56212
|
}
|
|
56039
56213
|
return readKnowledge(swarmPath);
|
|
56040
56214
|
}
|
|
56041
56215
|
async function readHiveKnowledge() {
|
|
56042
56216
|
const hivePath = resolveHiveKnowledgePath();
|
|
56043
|
-
if (!
|
|
56217
|
+
if (!existsSync28(hivePath)) {
|
|
56044
56218
|
return [];
|
|
56045
56219
|
}
|
|
56046
56220
|
return readKnowledge(hivePath);
|
|
@@ -56199,8 +56373,8 @@ init_dist();
|
|
|
56199
56373
|
init_config();
|
|
56200
56374
|
init_schema();
|
|
56201
56375
|
init_manager();
|
|
56202
|
-
import * as
|
|
56203
|
-
import * as
|
|
56376
|
+
import * as fs31 from "fs";
|
|
56377
|
+
import * as path44 from "path";
|
|
56204
56378
|
init_utils2();
|
|
56205
56379
|
init_create_tool();
|
|
56206
56380
|
function safeWarn(message, error93) {
|
|
@@ -56395,7 +56569,7 @@ async function executePhaseComplete(args2, workingDirectory) {
|
|
|
56395
56569
|
}
|
|
56396
56570
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
56397
56571
|
try {
|
|
56398
|
-
const projectName =
|
|
56572
|
+
const projectName = path44.basename(dir);
|
|
56399
56573
|
const knowledgeConfig = {
|
|
56400
56574
|
enabled: true,
|
|
56401
56575
|
swarm_max_entries: 100,
|
|
@@ -56443,7 +56617,7 @@ async function executePhaseComplete(args2, workingDirectory) {
|
|
|
56443
56617
|
if (agentsMissing.length > 0) {
|
|
56444
56618
|
try {
|
|
56445
56619
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
56446
|
-
const planRaw =
|
|
56620
|
+
const planRaw = fs31.readFileSync(planPath, "utf-8");
|
|
56447
56621
|
const plan = JSON.parse(planRaw);
|
|
56448
56622
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
56449
56623
|
if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
|
|
@@ -56484,7 +56658,7 @@ async function executePhaseComplete(args2, workingDirectory) {
|
|
|
56484
56658
|
};
|
|
56485
56659
|
try {
|
|
56486
56660
|
const eventsPath = validateSwarmPath(dir, "events.jsonl");
|
|
56487
|
-
|
|
56661
|
+
fs31.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
56488
56662
|
`, "utf-8");
|
|
56489
56663
|
} catch (writeError) {
|
|
56490
56664
|
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -56503,12 +56677,12 @@ async function executePhaseComplete(args2, workingDirectory) {
|
|
|
56503
56677
|
}
|
|
56504
56678
|
try {
|
|
56505
56679
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
56506
|
-
const planJson =
|
|
56680
|
+
const planJson = fs31.readFileSync(planPath, "utf-8");
|
|
56507
56681
|
const plan = JSON.parse(planJson);
|
|
56508
56682
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
56509
56683
|
if (phaseObj) {
|
|
56510
56684
|
phaseObj.status = "completed";
|
|
56511
|
-
|
|
56685
|
+
fs31.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
|
|
56512
56686
|
`, "utf-8");
|
|
56513
56687
|
}
|
|
56514
56688
|
} catch (error93) {
|
|
@@ -56558,8 +56732,8 @@ init_dist();
|
|
|
56558
56732
|
init_discovery();
|
|
56559
56733
|
init_utils();
|
|
56560
56734
|
init_create_tool();
|
|
56561
|
-
import * as
|
|
56562
|
-
import * as
|
|
56735
|
+
import * as fs32 from "fs";
|
|
56736
|
+
import * as path45 from "path";
|
|
56563
56737
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
56564
56738
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
56565
56739
|
function isValidEcosystem(value) {
|
|
@@ -56577,28 +56751,28 @@ function validateArgs3(args2) {
|
|
|
56577
56751
|
function detectEcosystems(directory) {
|
|
56578
56752
|
const ecosystems = [];
|
|
56579
56753
|
const cwd = directory;
|
|
56580
|
-
if (
|
|
56754
|
+
if (fs32.existsSync(path45.join(cwd, "package.json"))) {
|
|
56581
56755
|
ecosystems.push("npm");
|
|
56582
56756
|
}
|
|
56583
|
-
if (
|
|
56757
|
+
if (fs32.existsSync(path45.join(cwd, "pyproject.toml")) || fs32.existsSync(path45.join(cwd, "requirements.txt"))) {
|
|
56584
56758
|
ecosystems.push("pip");
|
|
56585
56759
|
}
|
|
56586
|
-
if (
|
|
56760
|
+
if (fs32.existsSync(path45.join(cwd, "Cargo.toml"))) {
|
|
56587
56761
|
ecosystems.push("cargo");
|
|
56588
56762
|
}
|
|
56589
|
-
if (
|
|
56763
|
+
if (fs32.existsSync(path45.join(cwd, "go.mod"))) {
|
|
56590
56764
|
ecosystems.push("go");
|
|
56591
56765
|
}
|
|
56592
56766
|
try {
|
|
56593
|
-
const files =
|
|
56767
|
+
const files = fs32.readdirSync(cwd);
|
|
56594
56768
|
if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
56595
56769
|
ecosystems.push("dotnet");
|
|
56596
56770
|
}
|
|
56597
56771
|
} catch {}
|
|
56598
|
-
if (
|
|
56772
|
+
if (fs32.existsSync(path45.join(cwd, "Gemfile")) || fs32.existsSync(path45.join(cwd, "Gemfile.lock"))) {
|
|
56599
56773
|
ecosystems.push("ruby");
|
|
56600
56774
|
}
|
|
56601
|
-
if (
|
|
56775
|
+
if (fs32.existsSync(path45.join(cwd, "pubspec.yaml"))) {
|
|
56602
56776
|
ecosystems.push("dart");
|
|
56603
56777
|
}
|
|
56604
56778
|
return ecosystems;
|
|
@@ -57660,8 +57834,8 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
|
|
|
57660
57834
|
]);
|
|
57661
57835
|
// src/tools/pre-check-batch.ts
|
|
57662
57836
|
init_dist();
|
|
57663
|
-
import * as
|
|
57664
|
-
import * as
|
|
57837
|
+
import * as fs35 from "fs";
|
|
57838
|
+
import * as path48 from "path";
|
|
57665
57839
|
|
|
57666
57840
|
// node_modules/yocto-queue/index.js
|
|
57667
57841
|
class Node2 {
|
|
@@ -57828,8 +58002,8 @@ init_lint();
|
|
|
57828
58002
|
init_manager();
|
|
57829
58003
|
|
|
57830
58004
|
// src/quality/metrics.ts
|
|
57831
|
-
import * as
|
|
57832
|
-
import * as
|
|
58005
|
+
import * as fs33 from "fs";
|
|
58006
|
+
import * as path46 from "path";
|
|
57833
58007
|
var MAX_FILE_SIZE_BYTES5 = 256 * 1024;
|
|
57834
58008
|
var MIN_DUPLICATION_LINES = 10;
|
|
57835
58009
|
function estimateCyclomaticComplexity(content) {
|
|
@@ -57867,11 +58041,11 @@ function estimateCyclomaticComplexity(content) {
|
|
|
57867
58041
|
}
|
|
57868
58042
|
function getComplexityForFile2(filePath) {
|
|
57869
58043
|
try {
|
|
57870
|
-
const stat2 =
|
|
58044
|
+
const stat2 = fs33.statSync(filePath);
|
|
57871
58045
|
if (stat2.size > MAX_FILE_SIZE_BYTES5) {
|
|
57872
58046
|
return null;
|
|
57873
58047
|
}
|
|
57874
|
-
const content =
|
|
58048
|
+
const content = fs33.readFileSync(filePath, "utf-8");
|
|
57875
58049
|
return estimateCyclomaticComplexity(content);
|
|
57876
58050
|
} catch {
|
|
57877
58051
|
return null;
|
|
@@ -57881,8 +58055,8 @@ async function computeComplexityDelta(files, workingDir) {
|
|
|
57881
58055
|
let totalComplexity = 0;
|
|
57882
58056
|
const analyzedFiles = [];
|
|
57883
58057
|
for (const file3 of files) {
|
|
57884
|
-
const fullPath =
|
|
57885
|
-
if (!
|
|
58058
|
+
const fullPath = path46.isAbsolute(file3) ? file3 : path46.join(workingDir, file3);
|
|
58059
|
+
if (!fs33.existsSync(fullPath)) {
|
|
57886
58060
|
continue;
|
|
57887
58061
|
}
|
|
57888
58062
|
const complexity = getComplexityForFile2(fullPath);
|
|
@@ -58003,8 +58177,8 @@ function countGoExports(content) {
|
|
|
58003
58177
|
}
|
|
58004
58178
|
function getExportCountForFile(filePath) {
|
|
58005
58179
|
try {
|
|
58006
|
-
const content =
|
|
58007
|
-
const ext =
|
|
58180
|
+
const content = fs33.readFileSync(filePath, "utf-8");
|
|
58181
|
+
const ext = path46.extname(filePath).toLowerCase();
|
|
58008
58182
|
switch (ext) {
|
|
58009
58183
|
case ".ts":
|
|
58010
58184
|
case ".tsx":
|
|
@@ -58030,8 +58204,8 @@ async function computePublicApiDelta(files, workingDir) {
|
|
|
58030
58204
|
let totalExports = 0;
|
|
58031
58205
|
const analyzedFiles = [];
|
|
58032
58206
|
for (const file3 of files) {
|
|
58033
|
-
const fullPath =
|
|
58034
|
-
if (!
|
|
58207
|
+
const fullPath = path46.isAbsolute(file3) ? file3 : path46.join(workingDir, file3);
|
|
58208
|
+
if (!fs33.existsSync(fullPath)) {
|
|
58035
58209
|
continue;
|
|
58036
58210
|
}
|
|
58037
58211
|
const exports = getExportCountForFile(fullPath);
|
|
@@ -58064,16 +58238,16 @@ async function computeDuplicationRatio(files, workingDir) {
|
|
|
58064
58238
|
let duplicateLines = 0;
|
|
58065
58239
|
const analyzedFiles = [];
|
|
58066
58240
|
for (const file3 of files) {
|
|
58067
|
-
const fullPath =
|
|
58068
|
-
if (!
|
|
58241
|
+
const fullPath = path46.isAbsolute(file3) ? file3 : path46.join(workingDir, file3);
|
|
58242
|
+
if (!fs33.existsSync(fullPath)) {
|
|
58069
58243
|
continue;
|
|
58070
58244
|
}
|
|
58071
58245
|
try {
|
|
58072
|
-
const stat2 =
|
|
58246
|
+
const stat2 = fs33.statSync(fullPath);
|
|
58073
58247
|
if (stat2.size > MAX_FILE_SIZE_BYTES5) {
|
|
58074
58248
|
continue;
|
|
58075
58249
|
}
|
|
58076
|
-
const content =
|
|
58250
|
+
const content = fs33.readFileSync(fullPath, "utf-8");
|
|
58077
58251
|
const lines = content.split(`
|
|
58078
58252
|
`).filter((line) => line.trim().length > 0);
|
|
58079
58253
|
if (lines.length < MIN_DUPLICATION_LINES) {
|
|
@@ -58097,8 +58271,8 @@ function countCodeLines(content) {
|
|
|
58097
58271
|
return lines.length;
|
|
58098
58272
|
}
|
|
58099
58273
|
function isTestFile(filePath) {
|
|
58100
|
-
const basename8 =
|
|
58101
|
-
const _ext =
|
|
58274
|
+
const basename8 = path46.basename(filePath);
|
|
58275
|
+
const _ext = path46.extname(filePath).toLowerCase();
|
|
58102
58276
|
const testPatterns = [
|
|
58103
58277
|
".test.",
|
|
58104
58278
|
".spec.",
|
|
@@ -58179,8 +58353,8 @@ function matchGlobSegment(globSegments, pathSegments) {
|
|
|
58179
58353
|
}
|
|
58180
58354
|
return gIndex === globSegments.length && pIndex === pathSegments.length;
|
|
58181
58355
|
}
|
|
58182
|
-
function matchesGlobSegment(
|
|
58183
|
-
const normalizedPath =
|
|
58356
|
+
function matchesGlobSegment(path47, glob) {
|
|
58357
|
+
const normalizedPath = path47.replace(/\\/g, "/");
|
|
58184
58358
|
const normalizedGlob = glob.replace(/\\/g, "/");
|
|
58185
58359
|
if (normalizedPath.includes("//")) {
|
|
58186
58360
|
return false;
|
|
@@ -58211,8 +58385,8 @@ function simpleGlobToRegex2(glob) {
|
|
|
58211
58385
|
function hasGlobstar(glob) {
|
|
58212
58386
|
return glob.includes("**");
|
|
58213
58387
|
}
|
|
58214
|
-
function globMatches(
|
|
58215
|
-
const normalizedPath =
|
|
58388
|
+
function globMatches(path47, glob) {
|
|
58389
|
+
const normalizedPath = path47.replace(/\\/g, "/");
|
|
58216
58390
|
if (!glob || glob === "") {
|
|
58217
58391
|
if (normalizedPath.includes("//")) {
|
|
58218
58392
|
return false;
|
|
@@ -58248,31 +58422,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
|
|
|
58248
58422
|
async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
58249
58423
|
let testLines = 0;
|
|
58250
58424
|
let codeLines = 0;
|
|
58251
|
-
const srcDir =
|
|
58252
|
-
if (
|
|
58425
|
+
const srcDir = path46.join(workingDir, "src");
|
|
58426
|
+
if (fs33.existsSync(srcDir)) {
|
|
58253
58427
|
await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
58254
58428
|
codeLines += lines;
|
|
58255
58429
|
});
|
|
58256
58430
|
}
|
|
58257
58431
|
const possibleSrcDirs = ["lib", "app", "source", "core"];
|
|
58258
58432
|
for (const dir of possibleSrcDirs) {
|
|
58259
|
-
const dirPath =
|
|
58260
|
-
if (
|
|
58433
|
+
const dirPath = path46.join(workingDir, dir);
|
|
58434
|
+
if (fs33.existsSync(dirPath)) {
|
|
58261
58435
|
await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
58262
58436
|
codeLines += lines;
|
|
58263
58437
|
});
|
|
58264
58438
|
}
|
|
58265
58439
|
}
|
|
58266
|
-
const testsDir =
|
|
58267
|
-
if (
|
|
58440
|
+
const testsDir = path46.join(workingDir, "tests");
|
|
58441
|
+
if (fs33.existsSync(testsDir)) {
|
|
58268
58442
|
await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
58269
58443
|
testLines += lines;
|
|
58270
58444
|
});
|
|
58271
58445
|
}
|
|
58272
58446
|
const possibleTestDirs = ["test", "__tests__", "specs"];
|
|
58273
58447
|
for (const dir of possibleTestDirs) {
|
|
58274
|
-
const dirPath =
|
|
58275
|
-
if (
|
|
58448
|
+
const dirPath = path46.join(workingDir, dir);
|
|
58449
|
+
if (fs33.existsSync(dirPath) && dirPath !== testsDir) {
|
|
58276
58450
|
await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
58277
58451
|
testLines += lines;
|
|
58278
58452
|
});
|
|
@@ -58284,9 +58458,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
58284
58458
|
}
|
|
58285
58459
|
async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
|
|
58286
58460
|
try {
|
|
58287
|
-
const entries =
|
|
58461
|
+
const entries = fs33.readdirSync(dirPath, { withFileTypes: true });
|
|
58288
58462
|
for (const entry of entries) {
|
|
58289
|
-
const fullPath =
|
|
58463
|
+
const fullPath = path46.join(dirPath, entry.name);
|
|
58290
58464
|
if (entry.isDirectory()) {
|
|
58291
58465
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
|
|
58292
58466
|
continue;
|
|
@@ -58294,7 +58468,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
58294
58468
|
await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
|
|
58295
58469
|
} else if (entry.isFile()) {
|
|
58296
58470
|
const relativePath = fullPath.replace(`${process.cwd()}/`, "");
|
|
58297
|
-
const ext =
|
|
58471
|
+
const ext = path46.extname(entry.name).toLowerCase();
|
|
58298
58472
|
const validExts = [
|
|
58299
58473
|
".ts",
|
|
58300
58474
|
".tsx",
|
|
@@ -58330,7 +58504,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
58330
58504
|
continue;
|
|
58331
58505
|
}
|
|
58332
58506
|
try {
|
|
58333
|
-
const content =
|
|
58507
|
+
const content = fs33.readFileSync(fullPath, "utf-8");
|
|
58334
58508
|
const lines = countCodeLines(content);
|
|
58335
58509
|
callback(lines);
|
|
58336
58510
|
} catch {}
|
|
@@ -58544,8 +58718,8 @@ async function qualityBudget(input, directory) {
|
|
|
58544
58718
|
init_dist();
|
|
58545
58719
|
init_manager();
|
|
58546
58720
|
init_detector();
|
|
58547
|
-
import * as
|
|
58548
|
-
import * as
|
|
58721
|
+
import * as fs34 from "fs";
|
|
58722
|
+
import * as path47 from "path";
|
|
58549
58723
|
import { extname as extname9 } from "path";
|
|
58550
58724
|
|
|
58551
58725
|
// src/sast/rules/c.ts
|
|
@@ -59229,7 +59403,7 @@ function executeRulesSync(filePath, content, language) {
|
|
|
59229
59403
|
}
|
|
59230
59404
|
|
|
59231
59405
|
// src/sast/semgrep.ts
|
|
59232
|
-
import { execFile as execFile2, execFileSync as execFileSync2, spawn } from "child_process";
|
|
59406
|
+
import { execFile as execFile2, execFileSync as execFileSync2, spawn as spawn2 } from "child_process";
|
|
59233
59407
|
import { promisify as promisify2 } from "util";
|
|
59234
59408
|
var _execFileAsync = promisify2(execFile2);
|
|
59235
59409
|
var semgrepAvailableCache = null;
|
|
@@ -59294,7 +59468,7 @@ function mapSemgrepSeverity(severity) {
|
|
|
59294
59468
|
}
|
|
59295
59469
|
async function executeWithTimeout(command, args2, options) {
|
|
59296
59470
|
return new Promise((resolve15) => {
|
|
59297
|
-
const child =
|
|
59471
|
+
const child = spawn2(command, args2, {
|
|
59298
59472
|
shell: false,
|
|
59299
59473
|
cwd: options.cwd
|
|
59300
59474
|
});
|
|
@@ -59412,17 +59586,17 @@ var SEVERITY_ORDER = {
|
|
|
59412
59586
|
};
|
|
59413
59587
|
function shouldSkipFile(filePath) {
|
|
59414
59588
|
try {
|
|
59415
|
-
const stats =
|
|
59589
|
+
const stats = fs34.statSync(filePath);
|
|
59416
59590
|
if (stats.size > MAX_FILE_SIZE_BYTES6) {
|
|
59417
59591
|
return { skip: true, reason: "file too large" };
|
|
59418
59592
|
}
|
|
59419
59593
|
if (stats.size === 0) {
|
|
59420
59594
|
return { skip: true, reason: "empty file" };
|
|
59421
59595
|
}
|
|
59422
|
-
const fd =
|
|
59596
|
+
const fd = fs34.openSync(filePath, "r");
|
|
59423
59597
|
const buffer = Buffer.alloc(8192);
|
|
59424
|
-
const bytesRead =
|
|
59425
|
-
|
|
59598
|
+
const bytesRead = fs34.readSync(fd, buffer, 0, 8192, 0);
|
|
59599
|
+
fs34.closeSync(fd);
|
|
59426
59600
|
if (bytesRead > 0) {
|
|
59427
59601
|
let nullCount = 0;
|
|
59428
59602
|
for (let i2 = 0;i2 < bytesRead; i2++) {
|
|
@@ -59461,7 +59635,7 @@ function countBySeverity(findings) {
|
|
|
59461
59635
|
}
|
|
59462
59636
|
function scanFileWithTierA(filePath, language) {
|
|
59463
59637
|
try {
|
|
59464
|
-
const content =
|
|
59638
|
+
const content = fs34.readFileSync(filePath, "utf-8");
|
|
59465
59639
|
const findings = executeRulesSync(filePath, content, language);
|
|
59466
59640
|
return findings.map((f) => ({
|
|
59467
59641
|
rule_id: f.rule_id,
|
|
@@ -59508,8 +59682,8 @@ async function sastScan(input, directory, config3) {
|
|
|
59508
59682
|
_filesSkipped++;
|
|
59509
59683
|
continue;
|
|
59510
59684
|
}
|
|
59511
|
-
const resolvedPath =
|
|
59512
|
-
if (!
|
|
59685
|
+
const resolvedPath = path47.isAbsolute(filePath) ? filePath : path47.resolve(directory, filePath);
|
|
59686
|
+
if (!fs34.existsSync(resolvedPath)) {
|
|
59513
59687
|
_filesSkipped++;
|
|
59514
59688
|
continue;
|
|
59515
59689
|
}
|
|
@@ -59707,18 +59881,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
59707
59881
|
let resolved;
|
|
59708
59882
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
59709
59883
|
if (isWinAbs) {
|
|
59710
|
-
resolved =
|
|
59711
|
-
} else if (
|
|
59712
|
-
resolved =
|
|
59884
|
+
resolved = path48.win32.resolve(inputPath);
|
|
59885
|
+
} else if (path48.isAbsolute(inputPath)) {
|
|
59886
|
+
resolved = path48.resolve(inputPath);
|
|
59713
59887
|
} else {
|
|
59714
|
-
resolved =
|
|
59888
|
+
resolved = path48.resolve(baseDir, inputPath);
|
|
59715
59889
|
}
|
|
59716
|
-
const workspaceResolved =
|
|
59890
|
+
const workspaceResolved = path48.resolve(workspaceDir);
|
|
59717
59891
|
let relative5;
|
|
59718
59892
|
if (isWinAbs) {
|
|
59719
|
-
relative5 =
|
|
59893
|
+
relative5 = path48.win32.relative(workspaceResolved, resolved);
|
|
59720
59894
|
} else {
|
|
59721
|
-
relative5 =
|
|
59895
|
+
relative5 = path48.relative(workspaceResolved, resolved);
|
|
59722
59896
|
}
|
|
59723
59897
|
if (relative5.startsWith("..")) {
|
|
59724
59898
|
return "path traversal detected";
|
|
@@ -59779,13 +59953,13 @@ async function runLintWrapped(files, directory, _config) {
|
|
|
59779
59953
|
}
|
|
59780
59954
|
async function runLintOnFiles(linter, files, workspaceDir) {
|
|
59781
59955
|
const isWindows = process.platform === "win32";
|
|
59782
|
-
const binDir =
|
|
59956
|
+
const binDir = path48.join(workspaceDir, "node_modules", ".bin");
|
|
59783
59957
|
const validatedFiles = [];
|
|
59784
59958
|
for (const file3 of files) {
|
|
59785
59959
|
if (typeof file3 !== "string") {
|
|
59786
59960
|
continue;
|
|
59787
59961
|
}
|
|
59788
|
-
const resolvedPath =
|
|
59962
|
+
const resolvedPath = path48.resolve(file3);
|
|
59789
59963
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
59790
59964
|
if (validationError) {
|
|
59791
59965
|
continue;
|
|
@@ -59803,10 +59977,10 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
59803
59977
|
}
|
|
59804
59978
|
let command;
|
|
59805
59979
|
if (linter === "biome") {
|
|
59806
|
-
const biomeBin = isWindows ?
|
|
59980
|
+
const biomeBin = isWindows ? path48.join(binDir, "biome.EXE") : path48.join(binDir, "biome");
|
|
59807
59981
|
command = [biomeBin, "check", ...validatedFiles];
|
|
59808
59982
|
} else {
|
|
59809
|
-
const eslintBin = isWindows ?
|
|
59983
|
+
const eslintBin = isWindows ? path48.join(binDir, "eslint.cmd") : path48.join(binDir, "eslint");
|
|
59810
59984
|
command = [eslintBin, ...validatedFiles];
|
|
59811
59985
|
}
|
|
59812
59986
|
try {
|
|
@@ -59943,7 +60117,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
59943
60117
|
skippedFiles++;
|
|
59944
60118
|
continue;
|
|
59945
60119
|
}
|
|
59946
|
-
const resolvedPath =
|
|
60120
|
+
const resolvedPath = path48.resolve(file3);
|
|
59947
60121
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
59948
60122
|
if (validationError) {
|
|
59949
60123
|
skippedFiles++;
|
|
@@ -59961,14 +60135,14 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
59961
60135
|
};
|
|
59962
60136
|
}
|
|
59963
60137
|
for (const file3 of validatedFiles) {
|
|
59964
|
-
const ext =
|
|
60138
|
+
const ext = path48.extname(file3).toLowerCase();
|
|
59965
60139
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
59966
60140
|
skippedFiles++;
|
|
59967
60141
|
continue;
|
|
59968
60142
|
}
|
|
59969
60143
|
let stat2;
|
|
59970
60144
|
try {
|
|
59971
|
-
stat2 =
|
|
60145
|
+
stat2 = fs35.statSync(file3);
|
|
59972
60146
|
} catch {
|
|
59973
60147
|
skippedFiles++;
|
|
59974
60148
|
continue;
|
|
@@ -59979,7 +60153,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
59979
60153
|
}
|
|
59980
60154
|
let content;
|
|
59981
60155
|
try {
|
|
59982
|
-
const buffer =
|
|
60156
|
+
const buffer = fs35.readFileSync(file3);
|
|
59983
60157
|
if (buffer.includes(0)) {
|
|
59984
60158
|
skippedFiles++;
|
|
59985
60159
|
continue;
|
|
@@ -60120,7 +60294,7 @@ async function runPreCheckBatch(input, workspaceDir) {
|
|
|
60120
60294
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
60121
60295
|
continue;
|
|
60122
60296
|
}
|
|
60123
|
-
changedFiles.push(
|
|
60297
|
+
changedFiles.push(path48.resolve(directory, file3));
|
|
60124
60298
|
}
|
|
60125
60299
|
if (changedFiles.length === 0) {
|
|
60126
60300
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -60271,7 +60445,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
60271
60445
|
};
|
|
60272
60446
|
return JSON.stringify(errorResult, null, 2);
|
|
60273
60447
|
}
|
|
60274
|
-
const resolvedDirectory =
|
|
60448
|
+
const resolvedDirectory = path48.resolve(typedArgs.directory);
|
|
60275
60449
|
const workspaceAnchor = resolvedDirectory;
|
|
60276
60450
|
const dirError = validateDirectory3(resolvedDirectory, workspaceAnchor);
|
|
60277
60451
|
if (dirError) {
|
|
@@ -60378,8 +60552,8 @@ ${paginatedContent}`;
|
|
|
60378
60552
|
init_tool();
|
|
60379
60553
|
init_manager2();
|
|
60380
60554
|
init_create_tool();
|
|
60381
|
-
import * as
|
|
60382
|
-
import * as
|
|
60555
|
+
import * as fs36 from "fs";
|
|
60556
|
+
import * as path49 from "path";
|
|
60383
60557
|
function detectPlaceholderContent(args2) {
|
|
60384
60558
|
const issues = [];
|
|
60385
60559
|
const placeholderPattern = /^\[\w[\w\s]*\]$/;
|
|
@@ -60483,19 +60657,19 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
60483
60657
|
try {
|
|
60484
60658
|
await savePlan(dir, plan);
|
|
60485
60659
|
try {
|
|
60486
|
-
const markerPath =
|
|
60660
|
+
const markerPath = path49.join(dir, ".swarm", ".plan-write-marker");
|
|
60487
60661
|
const marker = JSON.stringify({
|
|
60488
60662
|
source: "save_plan",
|
|
60489
60663
|
timestamp: new Date().toISOString(),
|
|
60490
60664
|
phases_count: plan.phases.length,
|
|
60491
60665
|
tasks_count: tasksCount
|
|
60492
60666
|
});
|
|
60493
|
-
await
|
|
60667
|
+
await fs36.promises.writeFile(markerPath, marker, "utf8");
|
|
60494
60668
|
} catch {}
|
|
60495
60669
|
return {
|
|
60496
60670
|
success: true,
|
|
60497
60671
|
message: "Plan saved successfully",
|
|
60498
|
-
plan_path:
|
|
60672
|
+
plan_path: path49.join(dir, ".swarm", "plan.json"),
|
|
60499
60673
|
phases_count: plan.phases.length,
|
|
60500
60674
|
tasks_count: tasksCount
|
|
60501
60675
|
};
|
|
@@ -60533,8 +60707,8 @@ var save_plan = createSwarmTool({
|
|
|
60533
60707
|
// src/tools/sbom-generate.ts
|
|
60534
60708
|
init_dist();
|
|
60535
60709
|
init_manager();
|
|
60536
|
-
import * as
|
|
60537
|
-
import * as
|
|
60710
|
+
import * as fs37 from "fs";
|
|
60711
|
+
import * as path50 from "path";
|
|
60538
60712
|
|
|
60539
60713
|
// src/sbom/detectors/index.ts
|
|
60540
60714
|
init_utils();
|
|
@@ -61228,8 +61402,8 @@ function parsePackageResolved(content) {
|
|
|
61228
61402
|
const pins = resolved.pins || [];
|
|
61229
61403
|
for (const pin of pins) {
|
|
61230
61404
|
const identity = pin.identity || pin.package || "";
|
|
61231
|
-
const
|
|
61232
|
-
const version3 =
|
|
61405
|
+
const state2 = pin.state || {};
|
|
61406
|
+
const version3 = state2.version || state2.revision || "";
|
|
61233
61407
|
let org = "";
|
|
61234
61408
|
const location = pin.location || "";
|
|
61235
61409
|
const orgMatch = location.match(/github\.com\/([^/]+)\//);
|
|
@@ -61380,9 +61554,9 @@ function findManifestFiles(rootDir) {
|
|
|
61380
61554
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
61381
61555
|
function searchDir(dir) {
|
|
61382
61556
|
try {
|
|
61383
|
-
const entries =
|
|
61557
|
+
const entries = fs37.readdirSync(dir, { withFileTypes: true });
|
|
61384
61558
|
for (const entry of entries) {
|
|
61385
|
-
const fullPath =
|
|
61559
|
+
const fullPath = path50.join(dir, entry.name);
|
|
61386
61560
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
61387
61561
|
continue;
|
|
61388
61562
|
}
|
|
@@ -61391,7 +61565,7 @@ function findManifestFiles(rootDir) {
|
|
|
61391
61565
|
} else if (entry.isFile()) {
|
|
61392
61566
|
for (const pattern of patterns) {
|
|
61393
61567
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
61394
|
-
manifestFiles.push(
|
|
61568
|
+
manifestFiles.push(path50.relative(rootDir, fullPath));
|
|
61395
61569
|
break;
|
|
61396
61570
|
}
|
|
61397
61571
|
}
|
|
@@ -61407,13 +61581,13 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
61407
61581
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
61408
61582
|
for (const dir of directories) {
|
|
61409
61583
|
try {
|
|
61410
|
-
const entries =
|
|
61584
|
+
const entries = fs37.readdirSync(dir, { withFileTypes: true });
|
|
61411
61585
|
for (const entry of entries) {
|
|
61412
|
-
const fullPath =
|
|
61586
|
+
const fullPath = path50.join(dir, entry.name);
|
|
61413
61587
|
if (entry.isFile()) {
|
|
61414
61588
|
for (const pattern of patterns) {
|
|
61415
61589
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
61416
|
-
found.push(
|
|
61590
|
+
found.push(path50.relative(workingDir, fullPath));
|
|
61417
61591
|
break;
|
|
61418
61592
|
}
|
|
61419
61593
|
}
|
|
@@ -61426,11 +61600,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
61426
61600
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
61427
61601
|
const dirs = new Set;
|
|
61428
61602
|
for (const file3 of changedFiles) {
|
|
61429
|
-
let currentDir =
|
|
61603
|
+
let currentDir = path50.dirname(file3);
|
|
61430
61604
|
while (true) {
|
|
61431
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
61432
|
-
dirs.add(
|
|
61433
|
-
const parent =
|
|
61605
|
+
if (currentDir && currentDir !== "." && currentDir !== path50.sep) {
|
|
61606
|
+
dirs.add(path50.join(workingDir, currentDir));
|
|
61607
|
+
const parent = path50.dirname(currentDir);
|
|
61434
61608
|
if (parent === currentDir)
|
|
61435
61609
|
break;
|
|
61436
61610
|
currentDir = parent;
|
|
@@ -61444,7 +61618,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
61444
61618
|
}
|
|
61445
61619
|
function ensureOutputDir(outputDir) {
|
|
61446
61620
|
try {
|
|
61447
|
-
|
|
61621
|
+
fs37.mkdirSync(outputDir, { recursive: true });
|
|
61448
61622
|
} catch (error93) {
|
|
61449
61623
|
if (!error93 || error93.code !== "EEXIST") {
|
|
61450
61624
|
throw error93;
|
|
@@ -61514,7 +61688,7 @@ var sbom_generate = createSwarmTool({
|
|
|
61514
61688
|
const changedFiles = obj.changed_files;
|
|
61515
61689
|
const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
|
|
61516
61690
|
const workingDir = directory;
|
|
61517
|
-
const outputDir =
|
|
61691
|
+
const outputDir = path50.isAbsolute(relativeOutputDir) ? relativeOutputDir : path50.join(workingDir, relativeOutputDir);
|
|
61518
61692
|
let manifestFiles = [];
|
|
61519
61693
|
if (scope === "all") {
|
|
61520
61694
|
manifestFiles = findManifestFiles(workingDir);
|
|
@@ -61537,11 +61711,11 @@ var sbom_generate = createSwarmTool({
|
|
|
61537
61711
|
const processedFiles = [];
|
|
61538
61712
|
for (const manifestFile of manifestFiles) {
|
|
61539
61713
|
try {
|
|
61540
|
-
const fullPath =
|
|
61541
|
-
if (!
|
|
61714
|
+
const fullPath = path50.isAbsolute(manifestFile) ? manifestFile : path50.join(workingDir, manifestFile);
|
|
61715
|
+
if (!fs37.existsSync(fullPath)) {
|
|
61542
61716
|
continue;
|
|
61543
61717
|
}
|
|
61544
|
-
const content =
|
|
61718
|
+
const content = fs37.readFileSync(fullPath, "utf-8");
|
|
61545
61719
|
const components = detectComponents(manifestFile, content);
|
|
61546
61720
|
processedFiles.push(manifestFile);
|
|
61547
61721
|
if (components.length > 0) {
|
|
@@ -61554,8 +61728,8 @@ var sbom_generate = createSwarmTool({
|
|
|
61554
61728
|
const bom = generateCycloneDX(allComponents);
|
|
61555
61729
|
const bomJson = serializeCycloneDX(bom);
|
|
61556
61730
|
const filename = generateSbomFilename();
|
|
61557
|
-
const outputPath =
|
|
61558
|
-
|
|
61731
|
+
const outputPath = path50.join(outputDir, filename);
|
|
61732
|
+
fs37.writeFileSync(outputPath, bomJson, "utf-8");
|
|
61559
61733
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
61560
61734
|
try {
|
|
61561
61735
|
const timestamp = new Date().toISOString();
|
|
@@ -61597,8 +61771,8 @@ var sbom_generate = createSwarmTool({
|
|
|
61597
61771
|
// src/tools/schema-drift.ts
|
|
61598
61772
|
init_dist();
|
|
61599
61773
|
init_create_tool();
|
|
61600
|
-
import * as
|
|
61601
|
-
import * as
|
|
61774
|
+
import * as fs38 from "fs";
|
|
61775
|
+
import * as path51 from "path";
|
|
61602
61776
|
var SPEC_CANDIDATES = [
|
|
61603
61777
|
"openapi.json",
|
|
61604
61778
|
"openapi.yaml",
|
|
@@ -61630,28 +61804,28 @@ function normalizePath2(p) {
|
|
|
61630
61804
|
}
|
|
61631
61805
|
function discoverSpecFile(cwd, specFileArg) {
|
|
61632
61806
|
if (specFileArg) {
|
|
61633
|
-
const resolvedPath =
|
|
61634
|
-
const normalizedCwd = cwd.endsWith(
|
|
61807
|
+
const resolvedPath = path51.resolve(cwd, specFileArg);
|
|
61808
|
+
const normalizedCwd = cwd.endsWith(path51.sep) ? cwd : cwd + path51.sep;
|
|
61635
61809
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
61636
61810
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
61637
61811
|
}
|
|
61638
|
-
const ext =
|
|
61812
|
+
const ext = path51.extname(resolvedPath).toLowerCase();
|
|
61639
61813
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
61640
61814
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
61641
61815
|
}
|
|
61642
|
-
const stats =
|
|
61816
|
+
const stats = fs38.statSync(resolvedPath);
|
|
61643
61817
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
61644
61818
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
61645
61819
|
}
|
|
61646
|
-
if (!
|
|
61820
|
+
if (!fs38.existsSync(resolvedPath)) {
|
|
61647
61821
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
61648
61822
|
}
|
|
61649
61823
|
return resolvedPath;
|
|
61650
61824
|
}
|
|
61651
61825
|
for (const candidate of SPEC_CANDIDATES) {
|
|
61652
|
-
const candidatePath =
|
|
61653
|
-
if (
|
|
61654
|
-
const stats =
|
|
61826
|
+
const candidatePath = path51.resolve(cwd, candidate);
|
|
61827
|
+
if (fs38.existsSync(candidatePath)) {
|
|
61828
|
+
const stats = fs38.statSync(candidatePath);
|
|
61655
61829
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
61656
61830
|
return candidatePath;
|
|
61657
61831
|
}
|
|
@@ -61660,8 +61834,8 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
61660
61834
|
return null;
|
|
61661
61835
|
}
|
|
61662
61836
|
function parseSpec(specFile) {
|
|
61663
|
-
const content =
|
|
61664
|
-
const ext =
|
|
61837
|
+
const content = fs38.readFileSync(specFile, "utf-8");
|
|
61838
|
+
const ext = path51.extname(specFile).toLowerCase();
|
|
61665
61839
|
if (ext === ".json") {
|
|
61666
61840
|
return parseJsonSpec(content);
|
|
61667
61841
|
}
|
|
@@ -61732,12 +61906,12 @@ function extractRoutes(cwd) {
|
|
|
61732
61906
|
function walkDir(dir) {
|
|
61733
61907
|
let entries;
|
|
61734
61908
|
try {
|
|
61735
|
-
entries =
|
|
61909
|
+
entries = fs38.readdirSync(dir, { withFileTypes: true });
|
|
61736
61910
|
} catch {
|
|
61737
61911
|
return;
|
|
61738
61912
|
}
|
|
61739
61913
|
for (const entry of entries) {
|
|
61740
|
-
const fullPath =
|
|
61914
|
+
const fullPath = path51.join(dir, entry.name);
|
|
61741
61915
|
if (entry.isSymbolicLink()) {
|
|
61742
61916
|
continue;
|
|
61743
61917
|
}
|
|
@@ -61747,7 +61921,7 @@ function extractRoutes(cwd) {
|
|
|
61747
61921
|
}
|
|
61748
61922
|
walkDir(fullPath);
|
|
61749
61923
|
} else if (entry.isFile()) {
|
|
61750
|
-
const ext =
|
|
61924
|
+
const ext = path51.extname(entry.name).toLowerCase();
|
|
61751
61925
|
const baseName = entry.name.toLowerCase();
|
|
61752
61926
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
61753
61927
|
continue;
|
|
@@ -61765,7 +61939,7 @@ function extractRoutes(cwd) {
|
|
|
61765
61939
|
}
|
|
61766
61940
|
function extractRoutesFromFile(filePath) {
|
|
61767
61941
|
const routes = [];
|
|
61768
|
-
const content =
|
|
61942
|
+
const content = fs38.readFileSync(filePath, "utf-8");
|
|
61769
61943
|
const lines = content.split(/\r?\n/);
|
|
61770
61944
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
61771
61945
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -61916,8 +62090,8 @@ init_secretscan();
|
|
|
61916
62090
|
// src/tools/symbols.ts
|
|
61917
62091
|
init_tool();
|
|
61918
62092
|
init_create_tool();
|
|
61919
|
-
import * as
|
|
61920
|
-
import * as
|
|
62093
|
+
import * as fs39 from "fs";
|
|
62094
|
+
import * as path52 from "path";
|
|
61921
62095
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
61922
62096
|
var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
61923
62097
|
function containsControlCharacters(str) {
|
|
@@ -61946,11 +62120,11 @@ function containsWindowsAttacks(str) {
|
|
|
61946
62120
|
}
|
|
61947
62121
|
function isPathInWorkspace(filePath, workspace) {
|
|
61948
62122
|
try {
|
|
61949
|
-
const resolvedPath =
|
|
61950
|
-
const realWorkspace =
|
|
61951
|
-
const realResolvedPath =
|
|
61952
|
-
const relativePath =
|
|
61953
|
-
if (relativePath.startsWith("..") ||
|
|
62123
|
+
const resolvedPath = path52.resolve(workspace, filePath);
|
|
62124
|
+
const realWorkspace = fs39.realpathSync(workspace);
|
|
62125
|
+
const realResolvedPath = fs39.realpathSync(resolvedPath);
|
|
62126
|
+
const relativePath = path52.relative(realWorkspace, realResolvedPath);
|
|
62127
|
+
if (relativePath.startsWith("..") || path52.isAbsolute(relativePath)) {
|
|
61954
62128
|
return false;
|
|
61955
62129
|
}
|
|
61956
62130
|
return true;
|
|
@@ -61962,17 +62136,17 @@ function validatePathForRead(filePath, workspace) {
|
|
|
61962
62136
|
return isPathInWorkspace(filePath, workspace);
|
|
61963
62137
|
}
|
|
61964
62138
|
function extractTSSymbols(filePath, cwd) {
|
|
61965
|
-
const fullPath =
|
|
62139
|
+
const fullPath = path52.join(cwd, filePath);
|
|
61966
62140
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
61967
62141
|
return [];
|
|
61968
62142
|
}
|
|
61969
62143
|
let content;
|
|
61970
62144
|
try {
|
|
61971
|
-
const stats =
|
|
62145
|
+
const stats = fs39.statSync(fullPath);
|
|
61972
62146
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
61973
62147
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
61974
62148
|
}
|
|
61975
|
-
content =
|
|
62149
|
+
content = fs39.readFileSync(fullPath, "utf-8");
|
|
61976
62150
|
} catch {
|
|
61977
62151
|
return [];
|
|
61978
62152
|
}
|
|
@@ -62114,17 +62288,17 @@ function extractTSSymbols(filePath, cwd) {
|
|
|
62114
62288
|
});
|
|
62115
62289
|
}
|
|
62116
62290
|
function extractPythonSymbols(filePath, cwd) {
|
|
62117
|
-
const fullPath =
|
|
62291
|
+
const fullPath = path52.join(cwd, filePath);
|
|
62118
62292
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
62119
62293
|
return [];
|
|
62120
62294
|
}
|
|
62121
62295
|
let content;
|
|
62122
62296
|
try {
|
|
62123
|
-
const stats =
|
|
62297
|
+
const stats = fs39.statSync(fullPath);
|
|
62124
62298
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
62125
62299
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
62126
62300
|
}
|
|
62127
|
-
content =
|
|
62301
|
+
content = fs39.readFileSync(fullPath, "utf-8");
|
|
62128
62302
|
} catch {
|
|
62129
62303
|
return [];
|
|
62130
62304
|
}
|
|
@@ -62197,7 +62371,7 @@ var symbols = createSwarmTool({
|
|
|
62197
62371
|
}, null, 2);
|
|
62198
62372
|
}
|
|
62199
62373
|
const cwd = directory;
|
|
62200
|
-
const ext =
|
|
62374
|
+
const ext = path52.extname(file3);
|
|
62201
62375
|
if (containsControlCharacters(file3)) {
|
|
62202
62376
|
return JSON.stringify({
|
|
62203
62377
|
file: file3,
|
|
@@ -62268,8 +62442,8 @@ init_test_runner();
|
|
|
62268
62442
|
init_dist();
|
|
62269
62443
|
init_utils();
|
|
62270
62444
|
init_create_tool();
|
|
62271
|
-
import * as
|
|
62272
|
-
import * as
|
|
62445
|
+
import * as fs40 from "fs";
|
|
62446
|
+
import * as path53 from "path";
|
|
62273
62447
|
var MAX_TEXT_LENGTH = 200;
|
|
62274
62448
|
var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
|
|
62275
62449
|
var SUPPORTED_EXTENSIONS2 = new Set([
|
|
@@ -62340,9 +62514,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
62340
62514
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
62341
62515
|
}
|
|
62342
62516
|
try {
|
|
62343
|
-
const resolvedPath =
|
|
62344
|
-
const normalizedCwd =
|
|
62345
|
-
const normalizedResolved =
|
|
62517
|
+
const resolvedPath = path53.resolve(paths);
|
|
62518
|
+
const normalizedCwd = path53.resolve(cwd);
|
|
62519
|
+
const normalizedResolved = path53.resolve(resolvedPath);
|
|
62346
62520
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
62347
62521
|
return {
|
|
62348
62522
|
error: "paths must be within the current working directory",
|
|
@@ -62358,13 +62532,13 @@ function validatePathsInput(paths, cwd) {
|
|
|
62358
62532
|
}
|
|
62359
62533
|
}
|
|
62360
62534
|
function isSupportedExtension(filePath) {
|
|
62361
|
-
const ext =
|
|
62535
|
+
const ext = path53.extname(filePath).toLowerCase();
|
|
62362
62536
|
return SUPPORTED_EXTENSIONS2.has(ext);
|
|
62363
62537
|
}
|
|
62364
62538
|
function findSourceFiles2(dir, files = []) {
|
|
62365
62539
|
let entries;
|
|
62366
62540
|
try {
|
|
62367
|
-
entries =
|
|
62541
|
+
entries = fs40.readdirSync(dir);
|
|
62368
62542
|
} catch {
|
|
62369
62543
|
return files;
|
|
62370
62544
|
}
|
|
@@ -62373,10 +62547,10 @@ function findSourceFiles2(dir, files = []) {
|
|
|
62373
62547
|
if (SKIP_DIRECTORIES3.has(entry)) {
|
|
62374
62548
|
continue;
|
|
62375
62549
|
}
|
|
62376
|
-
const fullPath =
|
|
62550
|
+
const fullPath = path53.join(dir, entry);
|
|
62377
62551
|
let stat2;
|
|
62378
62552
|
try {
|
|
62379
|
-
stat2 =
|
|
62553
|
+
stat2 = fs40.statSync(fullPath);
|
|
62380
62554
|
} catch {
|
|
62381
62555
|
continue;
|
|
62382
62556
|
}
|
|
@@ -62469,7 +62643,7 @@ var todo_extract = createSwarmTool({
|
|
|
62469
62643
|
return JSON.stringify(errorResult, null, 2);
|
|
62470
62644
|
}
|
|
62471
62645
|
const scanPath = resolvedPath;
|
|
62472
|
-
if (!
|
|
62646
|
+
if (!fs40.existsSync(scanPath)) {
|
|
62473
62647
|
const errorResult = {
|
|
62474
62648
|
error: `path not found: ${pathsInput}`,
|
|
62475
62649
|
total: 0,
|
|
@@ -62479,13 +62653,13 @@ var todo_extract = createSwarmTool({
|
|
|
62479
62653
|
return JSON.stringify(errorResult, null, 2);
|
|
62480
62654
|
}
|
|
62481
62655
|
const filesToScan = [];
|
|
62482
|
-
const stat2 =
|
|
62656
|
+
const stat2 = fs40.statSync(scanPath);
|
|
62483
62657
|
if (stat2.isFile()) {
|
|
62484
62658
|
if (isSupportedExtension(scanPath)) {
|
|
62485
62659
|
filesToScan.push(scanPath);
|
|
62486
62660
|
} else {
|
|
62487
62661
|
const errorResult = {
|
|
62488
|
-
error: `unsupported file extension: ${
|
|
62662
|
+
error: `unsupported file extension: ${path53.extname(scanPath)}`,
|
|
62489
62663
|
total: 0,
|
|
62490
62664
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
62491
62665
|
entries: []
|
|
@@ -62498,11 +62672,11 @@ var todo_extract = createSwarmTool({
|
|
|
62498
62672
|
const allEntries = [];
|
|
62499
62673
|
for (const filePath of filesToScan) {
|
|
62500
62674
|
try {
|
|
62501
|
-
const fileStat =
|
|
62675
|
+
const fileStat = fs40.statSync(filePath);
|
|
62502
62676
|
if (fileStat.size > MAX_FILE_SIZE_BYTES8) {
|
|
62503
62677
|
continue;
|
|
62504
62678
|
}
|
|
62505
|
-
const content =
|
|
62679
|
+
const content = fs40.readFileSync(filePath, "utf-8");
|
|
62506
62680
|
const entries = parseTodoComments(content, filePath, tagsSet);
|
|
62507
62681
|
allEntries.push(...entries);
|
|
62508
62682
|
} catch {}
|
|
@@ -62530,18 +62704,18 @@ var todo_extract = createSwarmTool({
|
|
|
62530
62704
|
// src/tools/update-task-status.ts
|
|
62531
62705
|
init_tool();
|
|
62532
62706
|
init_schema();
|
|
62533
|
-
import * as
|
|
62534
|
-
import * as
|
|
62707
|
+
import * as fs42 from "fs";
|
|
62708
|
+
import * as path55 from "path";
|
|
62535
62709
|
|
|
62536
62710
|
// src/hooks/diff-scope.ts
|
|
62537
|
-
import * as
|
|
62538
|
-
import * as
|
|
62711
|
+
import * as fs41 from "fs";
|
|
62712
|
+
import * as path54 from "path";
|
|
62539
62713
|
function getDeclaredScope(taskId, directory) {
|
|
62540
62714
|
try {
|
|
62541
|
-
const planPath =
|
|
62542
|
-
if (!
|
|
62715
|
+
const planPath = path54.join(directory, ".swarm", "plan.json");
|
|
62716
|
+
if (!fs41.existsSync(planPath))
|
|
62543
62717
|
return null;
|
|
62544
|
-
const raw =
|
|
62718
|
+
const raw = fs41.readFileSync(planPath, "utf-8");
|
|
62545
62719
|
const plan = JSON.parse(raw);
|
|
62546
62720
|
for (const phase of plan.phases ?? []) {
|
|
62547
62721
|
for (const task of phase.tasks ?? []) {
|
|
@@ -62653,7 +62827,7 @@ var TIER_3_PATTERNS = [
|
|
|
62653
62827
|
];
|
|
62654
62828
|
function matchesTier3Pattern(files) {
|
|
62655
62829
|
for (const file3 of files) {
|
|
62656
|
-
const fileName =
|
|
62830
|
+
const fileName = path55.basename(file3);
|
|
62657
62831
|
for (const pattern of TIER_3_PATTERNS) {
|
|
62658
62832
|
if (pattern.test(fileName)) {
|
|
62659
62833
|
return true;
|
|
@@ -62675,8 +62849,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
62675
62849
|
if (hasActiveTurboMode2()) {
|
|
62676
62850
|
const resolvedDir2 = workingDirectory ?? process.cwd();
|
|
62677
62851
|
try {
|
|
62678
|
-
const planPath =
|
|
62679
|
-
const planRaw =
|
|
62852
|
+
const planPath = path55.join(resolvedDir2, ".swarm", "plan.json");
|
|
62853
|
+
const planRaw = fs42.readFileSync(planPath, "utf-8");
|
|
62680
62854
|
const plan = JSON.parse(planRaw);
|
|
62681
62855
|
for (const planPhase of plan.phases ?? []) {
|
|
62682
62856
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -62695,8 +62869,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
62695
62869
|
}
|
|
62696
62870
|
const resolvedDir = workingDirectory ?? process.cwd();
|
|
62697
62871
|
try {
|
|
62698
|
-
const evidencePath =
|
|
62699
|
-
const raw =
|
|
62872
|
+
const evidencePath = path55.join(resolvedDir, ".swarm", "evidence", `${taskId}.json`);
|
|
62873
|
+
const raw = fs42.readFileSync(evidencePath, "utf-8");
|
|
62700
62874
|
const evidence = JSON.parse(raw);
|
|
62701
62875
|
if (evidence?.required_gates && Array.isArray(evidence.required_gates) && evidence?.gates) {
|
|
62702
62876
|
const allGatesMet = evidence.required_gates.every((gate) => evidence.gates[gate] != null);
|
|
@@ -62719,8 +62893,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
62719
62893
|
continue;
|
|
62720
62894
|
}
|
|
62721
62895
|
validSessionCount++;
|
|
62722
|
-
const
|
|
62723
|
-
if (
|
|
62896
|
+
const state2 = getTaskState(session, taskId);
|
|
62897
|
+
if (state2 === "tests_run" || state2 === "complete") {
|
|
62724
62898
|
return { blocked: false, reason: "" };
|
|
62725
62899
|
}
|
|
62726
62900
|
}
|
|
@@ -62731,13 +62905,13 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
62731
62905
|
for (const [sessionId, session] of swarmState.agentSessions) {
|
|
62732
62906
|
if (!(session.taskWorkflowStates instanceof Map))
|
|
62733
62907
|
continue;
|
|
62734
|
-
const
|
|
62735
|
-
stateEntries.push(`${sessionId}: ${
|
|
62908
|
+
const state2 = getTaskState(session, taskId);
|
|
62909
|
+
stateEntries.push(`${sessionId}: ${state2}`);
|
|
62736
62910
|
}
|
|
62737
62911
|
try {
|
|
62738
62912
|
const resolvedDir2 = workingDirectory ?? process.cwd();
|
|
62739
|
-
const planPath =
|
|
62740
|
-
const planRaw =
|
|
62913
|
+
const planPath = path55.join(resolvedDir2, ".swarm", "plan.json");
|
|
62914
|
+
const planRaw = fs42.readFileSync(planPath, "utf-8");
|
|
62741
62915
|
const plan = JSON.parse(planRaw);
|
|
62742
62916
|
for (const planPhase of plan.phases ?? []) {
|
|
62743
62917
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -62918,8 +63092,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
62918
63092
|
};
|
|
62919
63093
|
}
|
|
62920
63094
|
}
|
|
62921
|
-
normalizedDir =
|
|
62922
|
-
const pathParts = normalizedDir.split(
|
|
63095
|
+
normalizedDir = path55.normalize(args2.working_directory);
|
|
63096
|
+
const pathParts = normalizedDir.split(path55.sep);
|
|
62923
63097
|
if (pathParts.includes("..")) {
|
|
62924
63098
|
return {
|
|
62925
63099
|
success: false,
|
|
@@ -62929,11 +63103,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
62929
63103
|
]
|
|
62930
63104
|
};
|
|
62931
63105
|
}
|
|
62932
|
-
const resolvedDir =
|
|
63106
|
+
const resolvedDir = path55.resolve(normalizedDir);
|
|
62933
63107
|
try {
|
|
62934
|
-
const realPath =
|
|
62935
|
-
const planPath =
|
|
62936
|
-
if (!
|
|
63108
|
+
const realPath = fs42.realpathSync(resolvedDir);
|
|
63109
|
+
const planPath = path55.join(realPath, ".swarm", "plan.json");
|
|
63110
|
+
if (!fs42.existsSync(planPath)) {
|
|
62937
63111
|
return {
|
|
62938
63112
|
success: false,
|
|
62939
63113
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -63085,16 +63259,24 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
63085
63259
|
classThreshold: 3,
|
|
63086
63260
|
commentStripThreshold: 5,
|
|
63087
63261
|
diffLineThreshold: 200
|
|
63088
|
-
}, ctx.directory, (
|
|
63089
|
-
|
|
63262
|
+
}, ctx.directory, (sessionId, message) => {
|
|
63263
|
+
const s = swarmState.agentSessions.get(sessionId);
|
|
63264
|
+
if (s) {
|
|
63265
|
+
s.pendingAdvisoryMessages ??= [];
|
|
63266
|
+
s.pendingAdvisoryMessages.push(message);
|
|
63267
|
+
}
|
|
63090
63268
|
}) : null;
|
|
63091
63269
|
const incrementalVerifyHook = config3.incremental_verify?.enabled !== false ? createIncrementalVerifyHook(config3.incremental_verify ?? {
|
|
63092
63270
|
enabled: true,
|
|
63093
63271
|
command: null,
|
|
63094
63272
|
timeoutMs: 30000,
|
|
63095
63273
|
triggerAgents: ["coder"]
|
|
63096
|
-
}, ctx.directory, (
|
|
63097
|
-
|
|
63274
|
+
}, ctx.directory, (sessionId, message) => {
|
|
63275
|
+
const s = swarmState.agentSessions.get(sessionId);
|
|
63276
|
+
if (s) {
|
|
63277
|
+
s.pendingAdvisoryMessages ??= [];
|
|
63278
|
+
s.pendingAdvisoryMessages.push(message);
|
|
63279
|
+
}
|
|
63098
63280
|
}) : null;
|
|
63099
63281
|
const compactionServiceHook = config3.compaction_service?.enabled !== false ? createCompactionService(config3.compaction_service ?? {
|
|
63100
63282
|
enabled: true,
|
|
@@ -63102,8 +63284,12 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
63102
63284
|
reflectionThreshold: 60,
|
|
63103
63285
|
emergencyThreshold: 80,
|
|
63104
63286
|
preserveLastNTurns: 5
|
|
63105
|
-
}, ctx.directory, (
|
|
63106
|
-
|
|
63287
|
+
}, ctx.directory, (sessionId, message) => {
|
|
63288
|
+
const s = swarmState.agentSessions.get(sessionId);
|
|
63289
|
+
if (s) {
|
|
63290
|
+
s.pendingAdvisoryMessages ??= [];
|
|
63291
|
+
s.pendingAdvisoryMessages.push(message);
|
|
63292
|
+
}
|
|
63107
63293
|
}) : null;
|
|
63108
63294
|
const snapshotWriterHook = createSnapshotWriterHook(ctx.directory);
|
|
63109
63295
|
const automationConfig = AutomationConfigSchema.parse(config3.automation ?? {});
|
|
@@ -63115,7 +63301,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
63115
63301
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
63116
63302
|
preflightTriggerManager = new PTM(automationConfig);
|
|
63117
63303
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
63118
|
-
const swarmDir =
|
|
63304
|
+
const swarmDir = path56.resolve(ctx.directory, ".swarm");
|
|
63119
63305
|
statusArtifact = new ASA(swarmDir);
|
|
63120
63306
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
63121
63307
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|
|
@@ -63381,7 +63567,8 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
63381
63567
|
const pressureSession = ensureAgentSession(input.sessionID, swarmState.activeAgent.get(input.sessionID) ?? ORCHESTRATOR_NAME);
|
|
63382
63568
|
if (!pressureSession.contextPressureWarningSent) {
|
|
63383
63569
|
pressureSession.contextPressureWarningSent = true;
|
|
63384
|
-
|
|
63570
|
+
pressureSession.pendingAdvisoryMessages ??= [];
|
|
63571
|
+
pressureSession.pendingAdvisoryMessages.push(`CONTEXT PRESSURE: ${swarmState.lastBudgetPct.toFixed(1)}% of context window used. Prioritize completing the current task before starting new work.`);
|
|
63385
63572
|
}
|
|
63386
63573
|
}
|
|
63387
63574
|
await safeHook(activityHooks.toolBefore)(input, output);
|