opencode-swarm 6.37.0 → 6.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/background/event-bus.d.ts +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/hooks/adversarial-detector.d.ts +9 -0
- package/dist/hooks/curator.d.ts +24 -5
- package/dist/hooks/phase-monitor.d.ts +2 -1
- package/dist/index.js +1371 -406
- package/dist/tools/diff.d.ts +2 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14916,7 +14916,7 @@ var init_schema = __esm(() => {
|
|
|
14916
14916
|
max_encounter_score: exports_external.number().min(1).max(20).default(10)
|
|
14917
14917
|
});
|
|
14918
14918
|
CuratorConfigSchema = exports_external.object({
|
|
14919
|
-
enabled: exports_external.boolean().default(
|
|
14919
|
+
enabled: exports_external.boolean().default(true),
|
|
14920
14920
|
init_enabled: exports_external.boolean().default(true),
|
|
14921
14921
|
phase_enabled: exports_external.boolean().default(true),
|
|
14922
14922
|
max_summary_tokens: exports_external.number().min(500).max(8000).default(2000),
|
|
@@ -30051,6 +30051,10 @@ var init_create_tool = __esm(() => {
|
|
|
30051
30051
|
});
|
|
30052
30052
|
|
|
30053
30053
|
// src/tools/checkpoint.ts
|
|
30054
|
+
var exports_checkpoint = {};
|
|
30055
|
+
__export(exports_checkpoint, {
|
|
30056
|
+
checkpoint: () => checkpoint
|
|
30057
|
+
});
|
|
30054
30058
|
import { spawnSync } from "child_process";
|
|
30055
30059
|
import * as fs8 from "fs";
|
|
30056
30060
|
import * as path10 from "path";
|
|
@@ -36647,11 +36651,11 @@ __export(exports_curator_drift, {
|
|
|
36647
36651
|
readPriorDriftReports: () => readPriorDriftReports,
|
|
36648
36652
|
buildDriftInjectionText: () => buildDriftInjectionText
|
|
36649
36653
|
});
|
|
36650
|
-
import * as
|
|
36651
|
-
import * as
|
|
36654
|
+
import * as fs27 from "fs";
|
|
36655
|
+
import * as path38 from "path";
|
|
36652
36656
|
async function readPriorDriftReports(directory) {
|
|
36653
|
-
const swarmDir =
|
|
36654
|
-
const entries = await
|
|
36657
|
+
const swarmDir = path38.join(directory, ".swarm");
|
|
36658
|
+
const entries = await fs27.promises.readdir(swarmDir).catch(() => null);
|
|
36655
36659
|
if (entries === null)
|
|
36656
36660
|
return [];
|
|
36657
36661
|
const reportFiles = entries.filter((name2) => name2.startsWith(DRIFT_REPORT_PREFIX) && name2.endsWith(".json")).sort();
|
|
@@ -36677,10 +36681,10 @@ async function readPriorDriftReports(directory) {
|
|
|
36677
36681
|
async function writeDriftReport(directory, report) {
|
|
36678
36682
|
const filename = `${DRIFT_REPORT_PREFIX}${report.phase}.json`;
|
|
36679
36683
|
const filePath = validateSwarmPath(directory, filename);
|
|
36680
|
-
const swarmDir =
|
|
36681
|
-
await
|
|
36684
|
+
const swarmDir = path38.dirname(filePath);
|
|
36685
|
+
await fs27.promises.mkdir(swarmDir, { recursive: true });
|
|
36682
36686
|
try {
|
|
36683
|
-
await
|
|
36687
|
+
await fs27.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
|
|
36684
36688
|
} catch (err2) {
|
|
36685
36689
|
throw new Error(`[curator-drift] Failed to write drift report to ${filePath}: ${String(err2)}`);
|
|
36686
36690
|
}
|
|
@@ -38247,8 +38251,8 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
38247
38251
|
var moduleRtn;
|
|
38248
38252
|
var Module = moduleArg;
|
|
38249
38253
|
var readyPromiseResolve, readyPromiseReject;
|
|
38250
|
-
var readyPromise = new Promise((
|
|
38251
|
-
readyPromiseResolve =
|
|
38254
|
+
var readyPromise = new Promise((resolve15, reject) => {
|
|
38255
|
+
readyPromiseResolve = resolve15;
|
|
38252
38256
|
readyPromiseReject = reject;
|
|
38253
38257
|
});
|
|
38254
38258
|
var ENVIRONMENT_IS_WEB = typeof window == "object";
|
|
@@ -38270,11 +38274,11 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
38270
38274
|
throw toThrow;
|
|
38271
38275
|
}, "quit_");
|
|
38272
38276
|
var scriptDirectory = "";
|
|
38273
|
-
function locateFile(
|
|
38277
|
+
function locateFile(path45) {
|
|
38274
38278
|
if (Module["locateFile"]) {
|
|
38275
|
-
return Module["locateFile"](
|
|
38279
|
+
return Module["locateFile"](path45, scriptDirectory);
|
|
38276
38280
|
}
|
|
38277
|
-
return scriptDirectory +
|
|
38281
|
+
return scriptDirectory + path45;
|
|
38278
38282
|
}
|
|
38279
38283
|
__name(locateFile, "locateFile");
|
|
38280
38284
|
var readAsync, readBinary;
|
|
@@ -38328,13 +38332,13 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
38328
38332
|
}
|
|
38329
38333
|
readAsync = /* @__PURE__ */ __name(async (url3) => {
|
|
38330
38334
|
if (isFileURI(url3)) {
|
|
38331
|
-
return new Promise((
|
|
38335
|
+
return new Promise((resolve15, reject) => {
|
|
38332
38336
|
var xhr = new XMLHttpRequest;
|
|
38333
38337
|
xhr.open("GET", url3, true);
|
|
38334
38338
|
xhr.responseType = "arraybuffer";
|
|
38335
38339
|
xhr.onload = () => {
|
|
38336
38340
|
if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
|
|
38337
|
-
|
|
38341
|
+
resolve15(xhr.response);
|
|
38338
38342
|
return;
|
|
38339
38343
|
}
|
|
38340
38344
|
reject(xhr.status);
|
|
@@ -38495,10 +38499,10 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
38495
38499
|
return getBinarySync(binaryFile);
|
|
38496
38500
|
}
|
|
38497
38501
|
__name(getWasmBinary, "getWasmBinary");
|
|
38498
|
-
async function instantiateArrayBuffer(binaryFile,
|
|
38502
|
+
async function instantiateArrayBuffer(binaryFile, imports) {
|
|
38499
38503
|
try {
|
|
38500
38504
|
var binary2 = await getWasmBinary(binaryFile);
|
|
38501
|
-
var instance2 = await WebAssembly.instantiate(binary2,
|
|
38505
|
+
var instance2 = await WebAssembly.instantiate(binary2, imports);
|
|
38502
38506
|
return instance2;
|
|
38503
38507
|
} catch (reason) {
|
|
38504
38508
|
err(`failed to asynchronously prepare wasm: ${reason}`);
|
|
@@ -38506,20 +38510,20 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
38506
38510
|
}
|
|
38507
38511
|
}
|
|
38508
38512
|
__name(instantiateArrayBuffer, "instantiateArrayBuffer");
|
|
38509
|
-
async function instantiateAsync(binary2, binaryFile,
|
|
38513
|
+
async function instantiateAsync(binary2, binaryFile, imports) {
|
|
38510
38514
|
if (!binary2 && typeof WebAssembly.instantiateStreaming == "function" && !isFileURI(binaryFile) && !ENVIRONMENT_IS_NODE) {
|
|
38511
38515
|
try {
|
|
38512
38516
|
var response = fetch(binaryFile, {
|
|
38513
38517
|
credentials: "same-origin"
|
|
38514
38518
|
});
|
|
38515
|
-
var instantiationResult = await WebAssembly.instantiateStreaming(response,
|
|
38519
|
+
var instantiationResult = await WebAssembly.instantiateStreaming(response, imports);
|
|
38516
38520
|
return instantiationResult;
|
|
38517
38521
|
} catch (reason) {
|
|
38518
38522
|
err(`wasm streaming compile failed: ${reason}`);
|
|
38519
38523
|
err("falling back to ArrayBuffer instantiation");
|
|
38520
38524
|
}
|
|
38521
38525
|
}
|
|
38522
|
-
return instantiateArrayBuffer(binaryFile,
|
|
38526
|
+
return instantiateArrayBuffer(binaryFile, imports);
|
|
38523
38527
|
}
|
|
38524
38528
|
__name(instantiateAsync, "instantiateAsync");
|
|
38525
38529
|
function getWasmImports() {
|
|
@@ -38554,10 +38558,10 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
38554
38558
|
__name(receiveInstantiationResult, "receiveInstantiationResult");
|
|
38555
38559
|
var info2 = getWasmImports();
|
|
38556
38560
|
if (Module["instantiateWasm"]) {
|
|
38557
|
-
return new Promise((
|
|
38561
|
+
return new Promise((resolve15, reject) => {
|
|
38558
38562
|
Module["instantiateWasm"](info2, (mod, inst) => {
|
|
38559
38563
|
receiveInstance(mod, inst);
|
|
38560
|
-
|
|
38564
|
+
resolve15(mod.exports);
|
|
38561
38565
|
});
|
|
38562
38566
|
});
|
|
38563
38567
|
}
|
|
@@ -40014,15 +40018,96 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
40014
40018
|
});
|
|
40015
40019
|
|
|
40016
40020
|
// src/lang/runtime.ts
|
|
40017
|
-
|
|
40021
|
+
import { fileURLToPath } from "url";
|
|
40022
|
+
async function initTreeSitter() {
|
|
40023
|
+
if (treeSitterInitialized) {
|
|
40024
|
+
return;
|
|
40025
|
+
}
|
|
40026
|
+
await Parser.init();
|
|
40027
|
+
treeSitterInitialized = true;
|
|
40028
|
+
}
|
|
40029
|
+
function sanitizeLanguageId(languageId) {
|
|
40030
|
+
const normalized = languageId.toLowerCase();
|
|
40031
|
+
if (!/^[a-z0-9-]+$/.test(normalized)) {
|
|
40032
|
+
throw new Error(`Invalid language ID: ${languageId}`);
|
|
40033
|
+
}
|
|
40034
|
+
return normalized;
|
|
40035
|
+
}
|
|
40036
|
+
function getWasmFileName(languageId) {
|
|
40037
|
+
const sanitized = sanitizeLanguageId(languageId).toLowerCase();
|
|
40038
|
+
if (LANGUAGE_WASM_MAP[sanitized]) {
|
|
40039
|
+
return LANGUAGE_WASM_MAP[sanitized];
|
|
40040
|
+
}
|
|
40041
|
+
return `tree-sitter-${sanitized}.wasm`;
|
|
40042
|
+
}
|
|
40043
|
+
function getGrammarsPath() {
|
|
40044
|
+
const isProduction = !import.meta.url.includes("src/");
|
|
40045
|
+
if (isProduction) {
|
|
40046
|
+
return "./lang/grammars/";
|
|
40047
|
+
}
|
|
40048
|
+
return "../../dist/lang/grammars/";
|
|
40049
|
+
}
|
|
40050
|
+
async function loadGrammar(languageId) {
|
|
40051
|
+
if (typeof languageId !== "string" || languageId.length > 100) {
|
|
40052
|
+
throw new Error(`Invalid languageId: must be a string of at most 100 characters`);
|
|
40053
|
+
}
|
|
40054
|
+
const normalizedId = sanitizeLanguageId(languageId).toLowerCase();
|
|
40055
|
+
if (normalizedId.length === 0) {
|
|
40056
|
+
throw new Error(`Invalid languageId: empty after sanitization`);
|
|
40057
|
+
}
|
|
40058
|
+
if (parserCache.has(normalizedId)) {
|
|
40059
|
+
return parserCache.get(normalizedId);
|
|
40060
|
+
}
|
|
40061
|
+
await initTreeSitter();
|
|
40062
|
+
const parser = new Parser;
|
|
40063
|
+
const wasmFileName = getWasmFileName(normalizedId);
|
|
40064
|
+
const grammarsPath = getGrammarsPath();
|
|
40065
|
+
const wasmPath = fileURLToPath(new URL(`${grammarsPath}${wasmFileName}`, import.meta.url));
|
|
40066
|
+
const { existsSync: existsSync27 } = await import("fs");
|
|
40067
|
+
if (!existsSync27(wasmPath)) {
|
|
40068
|
+
throw new Error(`Grammar file not found for ${languageId}: ${wasmPath}
|
|
40069
|
+
Make sure to run 'bun run build' to copy grammar files to dist/lang/grammars/`);
|
|
40070
|
+
}
|
|
40071
|
+
try {
|
|
40072
|
+
const language = await Language.load(wasmPath);
|
|
40073
|
+
parser.setLanguage(language);
|
|
40074
|
+
} catch (error93) {
|
|
40075
|
+
throw new Error(`Failed to load grammar for ${languageId}: ${error93 instanceof Error ? error93.message : String(error93)}
|
|
40076
|
+
WASM path: ${wasmPath}`);
|
|
40077
|
+
}
|
|
40078
|
+
parserCache.set(normalizedId, parser);
|
|
40079
|
+
initializedLanguages.add(normalizedId);
|
|
40080
|
+
return parser;
|
|
40081
|
+
}
|
|
40082
|
+
var parserCache, initializedLanguages, treeSitterInitialized = false, LANGUAGE_WASM_MAP;
|
|
40018
40083
|
var init_runtime = __esm(() => {
|
|
40019
40084
|
init_tree_sitter();
|
|
40020
40085
|
parserCache = new Map;
|
|
40021
40086
|
initializedLanguages = new Set;
|
|
40087
|
+
LANGUAGE_WASM_MAP = {
|
|
40088
|
+
javascript: "tree-sitter-javascript.wasm",
|
|
40089
|
+
typescript: "tree-sitter-typescript.wasm",
|
|
40090
|
+
python: "tree-sitter-python.wasm",
|
|
40091
|
+
go: "tree-sitter-go.wasm",
|
|
40092
|
+
rust: "tree-sitter-rust.wasm",
|
|
40093
|
+
cpp: "tree-sitter-cpp.wasm",
|
|
40094
|
+
c: "tree-sitter-cpp.wasm",
|
|
40095
|
+
csharp: "tree-sitter-c-sharp.wasm",
|
|
40096
|
+
css: "tree-sitter-css.wasm",
|
|
40097
|
+
html: "tree-sitter-html.wasm",
|
|
40098
|
+
json: "tree-sitter-json.wasm",
|
|
40099
|
+
bash: "tree-sitter-bash.wasm",
|
|
40100
|
+
ruby: "tree-sitter-ruby.wasm",
|
|
40101
|
+
php: "tree-sitter-php.wasm",
|
|
40102
|
+
java: "tree-sitter-java.wasm",
|
|
40103
|
+
kotlin: "tree-sitter-kotlin.wasm",
|
|
40104
|
+
swift: "tree-sitter-swift.wasm",
|
|
40105
|
+
dart: "tree-sitter-dart.wasm"
|
|
40106
|
+
};
|
|
40022
40107
|
});
|
|
40023
40108
|
|
|
40024
40109
|
// src/index.ts
|
|
40025
|
-
import * as
|
|
40110
|
+
import * as path62 from "path";
|
|
40026
40111
|
|
|
40027
40112
|
// src/agents/index.ts
|
|
40028
40113
|
init_config();
|
|
@@ -42366,6 +42451,82 @@ RULES:
|
|
|
42366
42451
|
- Do NOT rephrase or summarize doc content with your own words \u2014 use the actual text from the file
|
|
42367
42452
|
- Full doc content is only loaded when relevant to the current task, never preloaded
|
|
42368
42453
|
`;
|
|
42454
|
+
var CURATOR_INIT_PROMPT = `## IDENTITY
|
|
42455
|
+
You are Explorer in CURATOR_INIT mode. You consolidate prior session knowledge into an architect briefing.
|
|
42456
|
+
DO NOT use the Task tool to delegate. You ARE the agent that does the work.
|
|
42457
|
+
|
|
42458
|
+
INPUT FORMAT:
|
|
42459
|
+
TASK: CURATOR_INIT
|
|
42460
|
+
PRIOR_SUMMARY: [JSON or "none"]
|
|
42461
|
+
KNOWLEDGE_ENTRIES: [JSON array of high-confidence entries]
|
|
42462
|
+
PROJECT_CONTEXT: [context.md excerpt]
|
|
42463
|
+
|
|
42464
|
+
ACTIONS:
|
|
42465
|
+
- Read the prior summary to understand session history
|
|
42466
|
+
- Cross-reference knowledge entries against project context
|
|
42467
|
+
- Identify contradictions (knowledge says X, project state shows Y)
|
|
42468
|
+
- Produce a concise briefing for the architect
|
|
42469
|
+
|
|
42470
|
+
RULES:
|
|
42471
|
+
- Output under 2000 chars
|
|
42472
|
+
- No code modifications
|
|
42473
|
+
- Flag contradictions explicitly with CONTRADICTION: prefix
|
|
42474
|
+
- If no prior summary exists, state "First session \u2014 no prior context"
|
|
42475
|
+
|
|
42476
|
+
OUTPUT FORMAT:
|
|
42477
|
+
BRIEFING:
|
|
42478
|
+
[concise summary of prior session state, key decisions, active blockers]
|
|
42479
|
+
|
|
42480
|
+
CONTRADICTIONS:
|
|
42481
|
+
- [entry_id]: [description] (or "None detected")
|
|
42482
|
+
|
|
42483
|
+
KNOWLEDGE_STATS:
|
|
42484
|
+
- Entries reviewed: [N]
|
|
42485
|
+
- Prior phases covered: [N]
|
|
42486
|
+
`;
|
|
42487
|
+
var CURATOR_PHASE_PROMPT = `## IDENTITY
|
|
42488
|
+
You are Explorer in CURATOR_PHASE mode. You consolidate a completed phase into a digest.
|
|
42489
|
+
DO NOT use the Task tool to delegate. You ARE the agent that does the work.
|
|
42490
|
+
|
|
42491
|
+
INPUT FORMAT:
|
|
42492
|
+
TASK: CURATOR_PHASE [phase_number]
|
|
42493
|
+
PRIOR_DIGEST: [running summary or "none"]
|
|
42494
|
+
PHASE_EVENTS: [JSON array from events.jsonl for this phase]
|
|
42495
|
+
PHASE_EVIDENCE: [summary of evidence bundles]
|
|
42496
|
+
PHASE_DECISIONS: [decisions from context.md]
|
|
42497
|
+
AGENTS_DISPATCHED: [list]
|
|
42498
|
+
AGENTS_EXPECTED: [list from config]
|
|
42499
|
+
|
|
42500
|
+
ACTIONS:
|
|
42501
|
+
- Extend the prior digest with this phase's outcomes (do NOT regenerate from scratch)
|
|
42502
|
+
- Identify workflow deviations: missing reviewer, missing retro, skipped test_engineer
|
|
42503
|
+
- Recommend knowledge updates: entries to promote, archive, or flag as contradicted
|
|
42504
|
+
- Summarize key decisions and blockers resolved
|
|
42505
|
+
|
|
42506
|
+
RULES:
|
|
42507
|
+
- Output under 2000 chars
|
|
42508
|
+
- No code modifications
|
|
42509
|
+
- Compliance observations are READ-ONLY \u2014 report, do not enforce
|
|
42510
|
+
- Extend the digest, never replace it
|
|
42511
|
+
|
|
42512
|
+
OUTPUT FORMAT:
|
|
42513
|
+
PHASE_DIGEST:
|
|
42514
|
+
phase: [N]
|
|
42515
|
+
summary: [what was accomplished]
|
|
42516
|
+
agents_used: [list]
|
|
42517
|
+
tasks_completed: [N]/[total]
|
|
42518
|
+
key_decisions: [list]
|
|
42519
|
+
blockers_resolved: [list]
|
|
42520
|
+
|
|
42521
|
+
COMPLIANCE:
|
|
42522
|
+
- [type]: [description] (or "No deviations observed")
|
|
42523
|
+
|
|
42524
|
+
KNOWLEDGE_UPDATES:
|
|
42525
|
+
- [action] [entry_id or "new"]: [reason] (or "No recommendations")
|
|
42526
|
+
|
|
42527
|
+
EXTENDED_DIGEST:
|
|
42528
|
+
[the full running digest with this phase appended]
|
|
42529
|
+
`;
|
|
42369
42530
|
function createExplorerAgent(model, customPrompt, customAppendPrompt) {
|
|
42370
42531
|
let prompt = EXPLORER_PROMPT;
|
|
42371
42532
|
if (customPrompt) {
|
|
@@ -42390,6 +42551,26 @@ ${customAppendPrompt}`;
|
|
|
42390
42551
|
}
|
|
42391
42552
|
};
|
|
42392
42553
|
}
|
|
42554
|
+
function createExplorerCuratorAgent(model, mode, customAppendPrompt) {
|
|
42555
|
+
const basePrompt = mode === "CURATOR_INIT" ? CURATOR_INIT_PROMPT : CURATOR_PHASE_PROMPT;
|
|
42556
|
+
const prompt = customAppendPrompt ? `${basePrompt}
|
|
42557
|
+
|
|
42558
|
+
${customAppendPrompt}` : basePrompt;
|
|
42559
|
+
return {
|
|
42560
|
+
name: "explorer",
|
|
42561
|
+
description: `Explorer in ${mode} mode \u2014 consolidates context at phase boundaries.`,
|
|
42562
|
+
config: {
|
|
42563
|
+
model,
|
|
42564
|
+
temperature: 0.1,
|
|
42565
|
+
prompt,
|
|
42566
|
+
tools: {
|
|
42567
|
+
write: false,
|
|
42568
|
+
edit: false,
|
|
42569
|
+
patch: false
|
|
42570
|
+
}
|
|
42571
|
+
}
|
|
42572
|
+
};
|
|
42573
|
+
}
|
|
42393
42574
|
|
|
42394
42575
|
// src/agents/reviewer.ts
|
|
42395
42576
|
var REVIEWER_PROMPT = `## PRESSURE IMMUNITY
|
|
@@ -44545,9 +44726,9 @@ init_schema();
|
|
|
44545
44726
|
import path15 from "path";
|
|
44546
44727
|
|
|
44547
44728
|
// src/hooks/curator.ts
|
|
44548
|
-
init_event_bus();
|
|
44549
44729
|
import * as fs9 from "fs";
|
|
44550
44730
|
import * as path13 from "path";
|
|
44731
|
+
init_event_bus();
|
|
44551
44732
|
|
|
44552
44733
|
// src/hooks/knowledge-store.ts
|
|
44553
44734
|
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
@@ -44705,6 +44886,33 @@ function inferTags(lesson) {
|
|
|
44705
44886
|
|
|
44706
44887
|
// src/hooks/curator.ts
|
|
44707
44888
|
init_utils2();
|
|
44889
|
+
var CURATOR_LLM_TIMEOUT_MS = 30000;
|
|
44890
|
+
function parseKnowledgeRecommendations(llmOutput) {
|
|
44891
|
+
const recommendations = [];
|
|
44892
|
+
const section = llmOutput.match(/KNOWLEDGE_UPDATES:\s*\n([\s\S]*?)(?:\n\n|\n[A-Z_]+:|$)/);
|
|
44893
|
+
if (!section)
|
|
44894
|
+
return recommendations;
|
|
44895
|
+
const lines = section[1].split(`
|
|
44896
|
+
`);
|
|
44897
|
+
for (const line of lines) {
|
|
44898
|
+
const trimmed = line.trim();
|
|
44899
|
+
if (!trimmed.startsWith("-"))
|
|
44900
|
+
continue;
|
|
44901
|
+
const match = trimmed.match(/^-\s+(promote|archive|flag_contradiction)\s+(\S+):\s+(.+)$/i);
|
|
44902
|
+
if (match) {
|
|
44903
|
+
const action = match[1].toLowerCase();
|
|
44904
|
+
const entryId = match[2] === "new" ? undefined : match[2];
|
|
44905
|
+
const reason = match[3].trim();
|
|
44906
|
+
recommendations.push({
|
|
44907
|
+
action,
|
|
44908
|
+
entry_id: entryId,
|
|
44909
|
+
lesson: reason,
|
|
44910
|
+
reason
|
|
44911
|
+
});
|
|
44912
|
+
}
|
|
44913
|
+
}
|
|
44914
|
+
return recommendations;
|
|
44915
|
+
}
|
|
44708
44916
|
async function readCuratorSummary(directory) {
|
|
44709
44917
|
const content = await readSwarmFileAsync(directory, "curator-summary.json");
|
|
44710
44918
|
if (content === null) {
|
|
@@ -44863,7 +45071,7 @@ function checkPhaseCompliance(phaseEvents, agentsDispatched, requiredAgents, pha
|
|
|
44863
45071
|
}
|
|
44864
45072
|
return observations;
|
|
44865
45073
|
}
|
|
44866
|
-
async function runCuratorInit(directory, config3) {
|
|
45074
|
+
async function runCuratorInit(directory, config3, llmDelegate) {
|
|
44867
45075
|
try {
|
|
44868
45076
|
const priorSummary = await readCuratorSummary(directory);
|
|
44869
45077
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
@@ -44907,9 +45115,41 @@ async function runCuratorInit(directory, config3) {
|
|
|
44907
45115
|
briefingParts.push(contextMd.slice(0, maxContextChars));
|
|
44908
45116
|
}
|
|
44909
45117
|
const contradictions = allEntries.filter((e) => Array.isArray(e.tags) && e.tags.some((t) => t.includes("contradiction"))).map((e) => typeof e.lesson === "string" ? e.lesson : JSON.stringify(e.lesson));
|
|
45118
|
+
let briefingText = briefingParts.join(`
|
|
45119
|
+
`);
|
|
45120
|
+
if (llmDelegate) {
|
|
45121
|
+
try {
|
|
45122
|
+
const curatorAgent = createExplorerCuratorAgent("default", "CURATOR_INIT");
|
|
45123
|
+
const userInput = [
|
|
45124
|
+
"TASK: CURATOR_INIT",
|
|
45125
|
+
`PRIOR_SUMMARY: ${priorSummary ? JSON.stringify(priorSummary) : "none"}`,
|
|
45126
|
+
`KNOWLEDGE_ENTRIES: ${JSON.stringify(highConfidenceEntries.slice(0, 10))}`,
|
|
45127
|
+
`PROJECT_CONTEXT: ${contextMd?.slice(0, config3.max_summary_tokens * 2) ?? "none"}`
|
|
45128
|
+
].join(`
|
|
45129
|
+
`);
|
|
45130
|
+
const systemPrompt = curatorAgent.config.prompt ?? "";
|
|
45131
|
+
const llmOutput = await Promise.race([
|
|
45132
|
+
llmDelegate(systemPrompt, userInput),
|
|
45133
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("CURATOR_LLM_TIMEOUT")), CURATOR_LLM_TIMEOUT_MS))
|
|
45134
|
+
]);
|
|
45135
|
+
if (llmOutput?.trim()) {
|
|
45136
|
+
briefingText = `${briefingText}
|
|
45137
|
+
|
|
45138
|
+
## LLM-Enhanced Analysis
|
|
45139
|
+
${llmOutput.trim()}`;
|
|
45140
|
+
}
|
|
45141
|
+
getGlobalEventBus().publish("curator.init.llm_completed", {
|
|
45142
|
+
enhanced: true
|
|
45143
|
+
});
|
|
45144
|
+
} catch (err2) {
|
|
45145
|
+
console.warn(`[curator] LLM delegation failed during CURATOR_INIT, using data-only mode: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
45146
|
+
getGlobalEventBus().publish("curator.init.llm_fallback", {
|
|
45147
|
+
error: String(err2)
|
|
45148
|
+
});
|
|
45149
|
+
}
|
|
45150
|
+
}
|
|
44910
45151
|
const result = {
|
|
44911
|
-
briefing:
|
|
44912
|
-
`),
|
|
45152
|
+
briefing: briefingText,
|
|
44913
45153
|
contradictions,
|
|
44914
45154
|
knowledge_entries_reviewed: allEntries.length,
|
|
44915
45155
|
prior_phases_covered: priorSummary ? priorSummary.last_phase_covered : 0
|
|
@@ -44934,7 +45174,7 @@ Could not load prior session context.`,
|
|
|
44934
45174
|
};
|
|
44935
45175
|
}
|
|
44936
45176
|
}
|
|
44937
|
-
async function runCuratorPhase(directory, phase, agentsDispatched, _config, _knowledgeConfig) {
|
|
45177
|
+
async function runCuratorPhase(directory, phase, agentsDispatched, _config, _knowledgeConfig, llmDelegate) {
|
|
44938
45178
|
try {
|
|
44939
45179
|
const priorSummary = await readCuratorSummary(directory);
|
|
44940
45180
|
const eventsJsonlContent = await readSwarmFileAsync(directory, "events.jsonl");
|
|
@@ -44967,7 +45207,40 @@ async function runCuratorPhase(directory, phase, agentsDispatched, _config, _kno
|
|
|
44967
45207
|
key_decisions: keyDecisions.slice(0, 5),
|
|
44968
45208
|
blockers_resolved: []
|
|
44969
45209
|
};
|
|
44970
|
-
|
|
45210
|
+
let knowledgeRecommendations = [];
|
|
45211
|
+
if (llmDelegate) {
|
|
45212
|
+
try {
|
|
45213
|
+
const curatorAgent = createExplorerCuratorAgent("default", "CURATOR_PHASE");
|
|
45214
|
+
const priorDigest = priorSummary?.digest ?? "none";
|
|
45215
|
+
const systemPrompt = curatorAgent.config.prompt ?? "";
|
|
45216
|
+
const userInput = [
|
|
45217
|
+
`TASK: CURATOR_PHASE ${phase}`,
|
|
45218
|
+
`PRIOR_DIGEST: ${priorDigest}`,
|
|
45219
|
+
`PHASE_EVENTS: ${JSON.stringify(phaseEvents.slice(0, 50))}`,
|
|
45220
|
+
`PHASE_DECISIONS: ${JSON.stringify(keyDecisions)}`,
|
|
45221
|
+
`AGENTS_DISPATCHED: ${JSON.stringify(agentsDispatched)}`,
|
|
45222
|
+
`AGENTS_EXPECTED: ["reviewer", "test_engineer"]`
|
|
45223
|
+
].join(`
|
|
45224
|
+
`);
|
|
45225
|
+
const llmOutput = await Promise.race([
|
|
45226
|
+
llmDelegate(systemPrompt, userInput),
|
|
45227
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("CURATOR_LLM_TIMEOUT")), CURATOR_LLM_TIMEOUT_MS))
|
|
45228
|
+
]);
|
|
45229
|
+
if (llmOutput?.trim()) {
|
|
45230
|
+
knowledgeRecommendations = parseKnowledgeRecommendations(llmOutput);
|
|
45231
|
+
}
|
|
45232
|
+
getGlobalEventBus().publish("curator.phase.llm_completed", {
|
|
45233
|
+
phase,
|
|
45234
|
+
recommendations: knowledgeRecommendations.length
|
|
45235
|
+
});
|
|
45236
|
+
} catch (err2) {
|
|
45237
|
+
console.warn(`[curator] LLM delegation failed during CURATOR_PHASE ${phase}, using data-only mode: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
45238
|
+
getGlobalEventBus().publish("curator.phase.llm_fallback", {
|
|
45239
|
+
phase,
|
|
45240
|
+
error: String(err2)
|
|
45241
|
+
});
|
|
45242
|
+
}
|
|
45243
|
+
}
|
|
44971
45244
|
const sessionId = `session-${Date.now()}`;
|
|
44972
45245
|
const now = new Date().toISOString();
|
|
44973
45246
|
let updatedSummary;
|
|
@@ -50508,6 +50781,68 @@ function maskToolOutput(msg, _threshold) {
|
|
|
50508
50781
|
init_schema();
|
|
50509
50782
|
import * as fs21 from "fs";
|
|
50510
50783
|
import * as path32 from "path";
|
|
50784
|
+
|
|
50785
|
+
// src/parallel/review-router.ts
|
|
50786
|
+
async function computeComplexity(directory, changedFiles) {
|
|
50787
|
+
let functionCount = 0;
|
|
50788
|
+
let astChangeCount = 0;
|
|
50789
|
+
let maxFileComplexity = 0;
|
|
50790
|
+
for (const file3 of changedFiles) {
|
|
50791
|
+
if (!/\.(ts|js|tsx|jsx|py|go|rs)$/.test(file3)) {
|
|
50792
|
+
continue;
|
|
50793
|
+
}
|
|
50794
|
+
try {
|
|
50795
|
+
const fs21 = await import("fs");
|
|
50796
|
+
const path30 = await import("path");
|
|
50797
|
+
const filePath = path30.join(directory, file3);
|
|
50798
|
+
if (!fs21.existsSync(filePath)) {
|
|
50799
|
+
continue;
|
|
50800
|
+
}
|
|
50801
|
+
const content = fs21.readFileSync(filePath, "utf-8");
|
|
50802
|
+
const functionMatches = content.match(/\b(function|def|func|fn)\s+\w+/g);
|
|
50803
|
+
const fileFunctionCount = functionMatches?.length || 0;
|
|
50804
|
+
functionCount += fileFunctionCount;
|
|
50805
|
+
const lines = content.split(`
|
|
50806
|
+
`).length;
|
|
50807
|
+
const estimatedChanges = Math.min(lines / 10, 50);
|
|
50808
|
+
astChangeCount += estimatedChanges;
|
|
50809
|
+
const fileComplexity = fileFunctionCount + lines / 100;
|
|
50810
|
+
maxFileComplexity = Math.max(maxFileComplexity, fileComplexity);
|
|
50811
|
+
} catch {}
|
|
50812
|
+
}
|
|
50813
|
+
return {
|
|
50814
|
+
fileCount: changedFiles.length,
|
|
50815
|
+
functionCount,
|
|
50816
|
+
astChangeCount: Math.round(astChangeCount),
|
|
50817
|
+
maxFileComplexity: Math.round(maxFileComplexity * 10) / 10
|
|
50818
|
+
};
|
|
50819
|
+
}
|
|
50820
|
+
function routeReview(metrics) {
|
|
50821
|
+
const isHighComplexity = metrics.fileCount >= 5 || metrics.functionCount >= 10 || metrics.astChangeCount >= 30 || metrics.maxFileComplexity >= 15;
|
|
50822
|
+
if (isHighComplexity) {
|
|
50823
|
+
return {
|
|
50824
|
+
reviewerCount: 2,
|
|
50825
|
+
testEngineerCount: 2,
|
|
50826
|
+
depth: "double",
|
|
50827
|
+
reason: `High complexity: ${metrics.fileCount} files, ${metrics.functionCount} functions, complexity score ${metrics.maxFileComplexity}`
|
|
50828
|
+
};
|
|
50829
|
+
}
|
|
50830
|
+
return {
|
|
50831
|
+
reviewerCount: 1,
|
|
50832
|
+
testEngineerCount: 1,
|
|
50833
|
+
depth: "single",
|
|
50834
|
+
reason: `Standard complexity: ${metrics.fileCount} files, ${metrics.functionCount} functions`
|
|
50835
|
+
};
|
|
50836
|
+
}
|
|
50837
|
+
async function routeReviewForChanges(directory, changedFiles) {
|
|
50838
|
+
const metrics = await computeComplexity(directory, changedFiles);
|
|
50839
|
+
return routeReview(metrics);
|
|
50840
|
+
}
|
|
50841
|
+
function shouldParallelizeReview(routing) {
|
|
50842
|
+
return routing.depth === "double";
|
|
50843
|
+
}
|
|
50844
|
+
|
|
50845
|
+
// src/hooks/delegation-gate.ts
|
|
50511
50846
|
init_telemetry();
|
|
50512
50847
|
|
|
50513
50848
|
// src/hooks/guardrails.ts
|
|
@@ -51581,6 +51916,21 @@ function createDelegationGateHook(config3, directory) {
|
|
|
51581
51916
|
if (typeof subagentType !== "string")
|
|
51582
51917
|
return;
|
|
51583
51918
|
const targetAgent = stripKnownSwarmPrefix(subagentType);
|
|
51919
|
+
if (targetAgent === "reviewer") {
|
|
51920
|
+
try {
|
|
51921
|
+
const reviewSession = swarmState.agentSessions.get(input.sessionID);
|
|
51922
|
+
if (reviewSession) {
|
|
51923
|
+
const changedFiles = reviewSession.modifiedFilesThisCoderTask ?? [];
|
|
51924
|
+
if (changedFiles.length > 0) {
|
|
51925
|
+
const routing = await routeReviewForChanges(directory, changedFiles);
|
|
51926
|
+
if (shouldParallelizeReview(routing)) {
|
|
51927
|
+
reviewSession.pendingAdvisoryMessages ??= [];
|
|
51928
|
+
reviewSession.pendingAdvisoryMessages.push(`REVIEW ROUTING: High complexity detected (${routing.reason}). ` + `Consider parallel review: ${routing.reviewerCount} reviewers, ${routing.testEngineerCount} test engineers recommended.`);
|
|
51929
|
+
}
|
|
51930
|
+
}
|
|
51931
|
+
}
|
|
51932
|
+
} catch {}
|
|
51933
|
+
}
|
|
51584
51934
|
if (targetAgent !== "coder")
|
|
51585
51935
|
return;
|
|
51586
51936
|
const session = swarmState.agentSessions.get(input.sessionID);
|
|
@@ -52370,7 +52720,7 @@ init_schema();
|
|
|
52370
52720
|
init_manager();
|
|
52371
52721
|
init_detector();
|
|
52372
52722
|
init_manager2();
|
|
52373
|
-
import * as
|
|
52723
|
+
import * as fs25 from "fs";
|
|
52374
52724
|
|
|
52375
52725
|
// src/services/decision-drift-analyzer.ts
|
|
52376
52726
|
init_utils2();
|
|
@@ -52653,6 +53003,8 @@ init_utils();
|
|
|
52653
53003
|
// src/hooks/adversarial-detector.ts
|
|
52654
53004
|
init_constants();
|
|
52655
53005
|
init_schema();
|
|
53006
|
+
import * as fs24 from "fs/promises";
|
|
53007
|
+
import * as path35 from "path";
|
|
52656
53008
|
function safeGet(obj, key) {
|
|
52657
53009
|
if (!obj || !Object.hasOwn(obj, key))
|
|
52658
53010
|
return;
|
|
@@ -52684,6 +53036,248 @@ function formatAdversarialWarning(agentA, agentB, sharedModel, policy) {
|
|
|
52684
53036
|
}
|
|
52685
53037
|
return `\u26A0\uFE0F Same-model adversarial pair detected. Agent ${agentA} and checker ${agentB} both use model ${sharedModel}. Review may lack independence.`;
|
|
52686
53038
|
}
|
|
53039
|
+
var PRECEDENT_MANIPULATION_PATTERNS = [
|
|
53040
|
+
/we skipped .* in phase \d+/i,
|
|
53041
|
+
/consistent with how we handled/i,
|
|
53042
|
+
/going forward/i,
|
|
53043
|
+
/the reviewer didn't flag this pattern before/i,
|
|
53044
|
+
/this is consistent with/i,
|
|
53045
|
+
/we should continue/i
|
|
53046
|
+
];
|
|
53047
|
+
var SELF_REVIEW_PATTERNS = [
|
|
53048
|
+
/I (verified|checked|reviewed|validated).*(myself|my own)/i,
|
|
53049
|
+
/I (think|believe) this (looks|is) correct/i,
|
|
53050
|
+
/this (looks|seems|appears) (good|correct|fine)/i
|
|
53051
|
+
];
|
|
53052
|
+
var CONTENT_EXEMPTION_PATTERNS = [
|
|
53053
|
+
/documentation doesn't need/i,
|
|
53054
|
+
/config changes are trivial/i,
|
|
53055
|
+
/just a (rename|refactor|typo)/i,
|
|
53056
|
+
/test files don't need/i,
|
|
53057
|
+
/this is (just|only) a/i,
|
|
53058
|
+
/no need for (review|the full)/i
|
|
53059
|
+
];
|
|
53060
|
+
var GATE_DELEGATION_BYPASS_PATTERNS = [
|
|
53061
|
+
/I verified the changes/i,
|
|
53062
|
+
/code looks correct to me/i,
|
|
53063
|
+
/the code looks (good|fine)/i,
|
|
53064
|
+
/task marked complete/i,
|
|
53065
|
+
/I (checked|reviewed).*myself/i,
|
|
53066
|
+
/edit tool on (src|tests|config)/i,
|
|
53067
|
+
/write tool on (src|tests|config)/i,
|
|
53068
|
+
/writeCount.*\d+.*source/i,
|
|
53069
|
+
/I'll just make this small fix directly/i,
|
|
53070
|
+
/It's faster if I do it myself/i,
|
|
53071
|
+
/edit tool on.*plan\.md/i,
|
|
53072
|
+
/write tool on.*plan\.md/i,
|
|
53073
|
+
/\[ \].*to \[x\].*in plan\.md/i,
|
|
53074
|
+
/status.*pending.*complete.*plan\.json/i,
|
|
53075
|
+
/I'll just mark this one as done/i,
|
|
53076
|
+
/mark it done directly/i
|
|
53077
|
+
];
|
|
53078
|
+
var GATE_MISCLASSIFICATION_PATTERNS = [
|
|
53079
|
+
/(?:src\/|source\/|source\s+code|source\s+file).*tier\s*[01]/i,
|
|
53080
|
+
/tier\s*[01].*(?:src\/|source\/|source\s+code|source\s+file)/i,
|
|
53081
|
+
/(?:security|auth|crypto|secret|credential|permission).*tier\s*[012]/i,
|
|
53082
|
+
/tier\s*[012].*(?:security|auth|crypto|secret|credential|permission)/i,
|
|
53083
|
+
/below\s+tier\s*3.*(?:security|auth|crypto|secret|credential|permission)/i,
|
|
53084
|
+
/classification[:\s-]*tier\s*[01]/i,
|
|
53085
|
+
/tier\s*[01][\s:]*classification/i,
|
|
53086
|
+
/(?:small|trivial|minor).*tier\s*[01]/i,
|
|
53087
|
+
/tier\s*[01].*(?:small|trivial|minor)/i,
|
|
53088
|
+
/(?:small|trivial|minor).*(?:classification|classified|assigned).*tier/i,
|
|
53089
|
+
/(?:classification|classified|assigned).*(?:small|trivial|minor).*tier/i,
|
|
53090
|
+
/pipeline\s+started.*(?:assigning|setting|classifying).*tier/i,
|
|
53091
|
+
/(?:assigning|setting|classifying).*tier.*after.*pipeline/i,
|
|
53092
|
+
/tier.*assigned.*(?:after|retroactive)/i,
|
|
53093
|
+
/retroactive.*(?:tier|classification)/i
|
|
53094
|
+
];
|
|
53095
|
+
var VELOCITY_RATIONALIZATION_PATTERNS = [
|
|
53096
|
+
/to save time/i,
|
|
53097
|
+
/since we're behind/i,
|
|
53098
|
+
/quick fix/i,
|
|
53099
|
+
/review.*later/i,
|
|
53100
|
+
/in the interest of efficiency/i,
|
|
53101
|
+
/we can (review|check).*later/i,
|
|
53102
|
+
/for (speed|efficiency)/i
|
|
53103
|
+
];
|
|
53104
|
+
var INTER_AGENT_MANIPULATION_PATTERNS = [
|
|
53105
|
+
/\b(5th|fifth|final|last)\s+(attempt|try|time)\b/i,
|
|
53106
|
+
/\bthis\s+is\s+(blocking|blocking\s+everything|critical|urgent)\b/i,
|
|
53107
|
+
/\bwe('re|\s+are)\s+(behind|late|running\s+out\s+of\s+time)\b/i,
|
|
53108
|
+
/\buser\s+is\s+waiting\b/i,
|
|
53109
|
+
/\bship\s+(this|it)\s+(now|today|immediately)\b/i,
|
|
53110
|
+
/\b(I'm|I\s+am)\s+(frustrated|disappointed|sad|upset)\b/i,
|
|
53111
|
+
/\bthis\s+is\s+(frustrating|disappointing)\b/i,
|
|
53112
|
+
/\b(I've|I\s+have)\s+been\s+working\s+on\s+this\b/i,
|
|
53113
|
+
/\bplease\s+(help|approve|pass)\b/i,
|
|
53114
|
+
/\bor\s+I('ll|\s+will)\s+(stop|halt|pause)\b/i,
|
|
53115
|
+
/\bor\s+all\s+work\s+stops\b/i,
|
|
53116
|
+
/\bI('ll|\s+will)\s+have\s+to\s+alert\s+the\s+user\b/i,
|
|
53117
|
+
/\bthis\s+will\s+(delay|block)\s+everything\b/i,
|
|
53118
|
+
/\bjust\s+approve\s+this\b/i,
|
|
53119
|
+
/\bI\s+(need|want)\s+you\s+to\s+(approve|pass)\b/i,
|
|
53120
|
+
/\boverride\s+(this|the)\s+(check|gate|review)\b/i
|
|
53121
|
+
];
|
|
53122
|
+
function detectAdversarialPatterns(text) {
|
|
53123
|
+
if (typeof text !== "string") {
|
|
53124
|
+
return [];
|
|
53125
|
+
}
|
|
53126
|
+
const matches = [];
|
|
53127
|
+
for (const pattern of PRECEDENT_MANIPULATION_PATTERNS) {
|
|
53128
|
+
const match = text.match(pattern);
|
|
53129
|
+
if (match) {
|
|
53130
|
+
matches.push({
|
|
53131
|
+
pattern: "PRECEDENT_MANIPULATION",
|
|
53132
|
+
severity: "HIGHEST",
|
|
53133
|
+
matchedText: match[0],
|
|
53134
|
+
confidence: "HIGH"
|
|
53135
|
+
});
|
|
53136
|
+
}
|
|
53137
|
+
}
|
|
53138
|
+
for (const pattern of SELF_REVIEW_PATTERNS) {
|
|
53139
|
+
const match = text.match(pattern);
|
|
53140
|
+
if (match) {
|
|
53141
|
+
matches.push({
|
|
53142
|
+
pattern: "SELF_REVIEW",
|
|
53143
|
+
severity: "HIGH",
|
|
53144
|
+
matchedText: match[0],
|
|
53145
|
+
confidence: "HIGH"
|
|
53146
|
+
});
|
|
53147
|
+
}
|
|
53148
|
+
}
|
|
53149
|
+
for (const pattern of CONTENT_EXEMPTION_PATTERNS) {
|
|
53150
|
+
const match = text.match(pattern);
|
|
53151
|
+
if (match) {
|
|
53152
|
+
matches.push({
|
|
53153
|
+
pattern: "CONTENT_EXEMPTION",
|
|
53154
|
+
severity: "HIGH",
|
|
53155
|
+
matchedText: match[0],
|
|
53156
|
+
confidence: "HIGH"
|
|
53157
|
+
});
|
|
53158
|
+
}
|
|
53159
|
+
}
|
|
53160
|
+
for (const pattern of GATE_DELEGATION_BYPASS_PATTERNS) {
|
|
53161
|
+
const match = text.match(pattern);
|
|
53162
|
+
if (match) {
|
|
53163
|
+
matches.push({
|
|
53164
|
+
pattern: "GATE_DELEGATION_BYPASS",
|
|
53165
|
+
severity: "HIGHEST",
|
|
53166
|
+
matchedText: match[0],
|
|
53167
|
+
confidence: "HIGH"
|
|
53168
|
+
});
|
|
53169
|
+
}
|
|
53170
|
+
}
|
|
53171
|
+
for (const pattern of GATE_MISCLASSIFICATION_PATTERNS) {
|
|
53172
|
+
const match = text.match(pattern);
|
|
53173
|
+
if (match) {
|
|
53174
|
+
matches.push({
|
|
53175
|
+
pattern: "GATE_MISCLASSIFICATION",
|
|
53176
|
+
severity: "HIGH",
|
|
53177
|
+
matchedText: match[0],
|
|
53178
|
+
confidence: "HIGH"
|
|
53179
|
+
});
|
|
53180
|
+
}
|
|
53181
|
+
}
|
|
53182
|
+
for (const pattern of VELOCITY_RATIONALIZATION_PATTERNS) {
|
|
53183
|
+
const match = text.match(pattern);
|
|
53184
|
+
if (match) {
|
|
53185
|
+
matches.push({
|
|
53186
|
+
pattern: "VELOCITY_RATIONALIZATION",
|
|
53187
|
+
severity: "HIGH",
|
|
53188
|
+
matchedText: match[0],
|
|
53189
|
+
confidence: "HIGH"
|
|
53190
|
+
});
|
|
53191
|
+
}
|
|
53192
|
+
}
|
|
53193
|
+
for (const pattern of INTER_AGENT_MANIPULATION_PATTERNS) {
|
|
53194
|
+
const match = text.match(pattern);
|
|
53195
|
+
if (match) {
|
|
53196
|
+
matches.push({
|
|
53197
|
+
pattern: "INTER_AGENT_MANIPULATION",
|
|
53198
|
+
severity: "HIGH",
|
|
53199
|
+
matchedText: match[0],
|
|
53200
|
+
confidence: "HIGH"
|
|
53201
|
+
});
|
|
53202
|
+
}
|
|
53203
|
+
}
|
|
53204
|
+
return matches;
|
|
53205
|
+
}
|
|
53206
|
+
function formatDebuggingSpiralEvent(match, taskId) {
|
|
53207
|
+
return JSON.stringify({
|
|
53208
|
+
event: "debugging_spiral_detected",
|
|
53209
|
+
taskId,
|
|
53210
|
+
pattern: match.pattern,
|
|
53211
|
+
severity: match.severity,
|
|
53212
|
+
matchedText: match.matchedText,
|
|
53213
|
+
confidence: match.confidence,
|
|
53214
|
+
timestamp: new Date().toISOString()
|
|
53215
|
+
});
|
|
53216
|
+
}
|
|
53217
|
+
async function handleDebuggingSpiral(match, taskId, directory) {
|
|
53218
|
+
let eventLogged = false;
|
|
53219
|
+
let checkpointCreated = false;
|
|
53220
|
+
try {
|
|
53221
|
+
const swarmDir = path35.join(directory, ".swarm");
|
|
53222
|
+
await fs24.mkdir(swarmDir, { recursive: true });
|
|
53223
|
+
const eventsPath = path35.join(swarmDir, "events.jsonl");
|
|
53224
|
+
await fs24.appendFile(eventsPath, `${formatDebuggingSpiralEvent(match, taskId)}
|
|
53225
|
+
`);
|
|
53226
|
+
eventLogged = true;
|
|
53227
|
+
} catch {}
|
|
53228
|
+
const checkpointLabel = `spiral-${taskId}-${Date.now()}`;
|
|
53229
|
+
try {
|
|
53230
|
+
const { checkpoint: checkpoint2 } = await Promise.resolve().then(() => (init_checkpoint(), exports_checkpoint));
|
|
53231
|
+
const result = await checkpoint2.execute({ action: "save", label: checkpointLabel }, { directory });
|
|
53232
|
+
try {
|
|
53233
|
+
const parsed = JSON.parse(result);
|
|
53234
|
+
checkpointCreated = parsed.success === true;
|
|
53235
|
+
} catch {
|
|
53236
|
+
checkpointCreated = false;
|
|
53237
|
+
}
|
|
53238
|
+
} catch {
|
|
53239
|
+
checkpointCreated = false;
|
|
53240
|
+
}
|
|
53241
|
+
const checkpointMsg = checkpointCreated ? `\u2713 Auto-checkpoint created: ${checkpointLabel}` : "\u26A0 Auto-checkpoint failed (non-fatal)";
|
|
53242
|
+
const message = `[FOR: architect] DEBUGGING SPIRAL DETECTED for task ${taskId}
|
|
53243
|
+
Issue: ${match.matchedText}
|
|
53244
|
+
Confidence: ${match.confidence}
|
|
53245
|
+
${checkpointMsg}
|
|
53246
|
+
Recommendation: Consider escalating to user or taking a different approach
|
|
53247
|
+
The current fix strategy appears to be cycling without progress`;
|
|
53248
|
+
return { eventLogged, checkpointCreated, message };
|
|
53249
|
+
}
|
|
53250
|
+
var recentToolCalls = [];
|
|
53251
|
+
var MAX_RECENT_CALLS = 20;
|
|
53252
|
+
var SPIRAL_THRESHOLD = 5;
|
|
53253
|
+
var SPIRAL_WINDOW_MS = 300000;
|
|
53254
|
+
function recordToolCall(tool3, args2) {
|
|
53255
|
+
const argsHash = typeof args2 === "string" ? args2.slice(0, 100) : JSON.stringify(args2 ?? "").slice(0, 100);
|
|
53256
|
+
recentToolCalls.push({ tool: tool3, argsHash, timestamp: Date.now() });
|
|
53257
|
+
if (recentToolCalls.length > MAX_RECENT_CALLS) {
|
|
53258
|
+
recentToolCalls.shift();
|
|
53259
|
+
}
|
|
53260
|
+
}
|
|
53261
|
+
async function detectDebuggingSpiral(_directory) {
|
|
53262
|
+
const now = Date.now();
|
|
53263
|
+
const windowCalls = recentToolCalls.filter((c) => now - c.timestamp < SPIRAL_WINDOW_MS);
|
|
53264
|
+
if (windowCalls.length < SPIRAL_THRESHOLD)
|
|
53265
|
+
return null;
|
|
53266
|
+
const lastN = windowCalls.slice(-SPIRAL_THRESHOLD);
|
|
53267
|
+
const firstTool = lastN[0].tool;
|
|
53268
|
+
const firstArgs = lastN[0].argsHash;
|
|
53269
|
+
const allSameTool = lastN.every((c) => c.tool === firstTool);
|
|
53270
|
+
const allSimilarArgs = lastN.every((c) => c.argsHash === firstArgs);
|
|
53271
|
+
if (allSameTool && allSimilarArgs) {
|
|
53272
|
+
return {
|
|
53273
|
+
pattern: "VELOCITY_RATIONALIZATION",
|
|
53274
|
+
severity: "HIGH",
|
|
53275
|
+
matchedText: `Tool '${firstTool}' called ${SPIRAL_THRESHOLD}+ times with identical args`,
|
|
53276
|
+
confidence: "HIGH"
|
|
53277
|
+
};
|
|
53278
|
+
}
|
|
53279
|
+
return null;
|
|
53280
|
+
}
|
|
52687
53281
|
|
|
52688
53282
|
// src/hooks/context-scoring.ts
|
|
52689
53283
|
function calculateAgeFactor(ageHours, config3) {
|
|
@@ -53029,11 +53623,11 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
53029
53623
|
if (handoffContent) {
|
|
53030
53624
|
const handoffPath = validateSwarmPath(directory, "handoff.md");
|
|
53031
53625
|
const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
|
|
53032
|
-
if (
|
|
53626
|
+
if (fs25.existsSync(consumedPath)) {
|
|
53033
53627
|
warn("Duplicate handoff detected: handoff-consumed.md already exists");
|
|
53034
|
-
|
|
53628
|
+
fs25.unlinkSync(consumedPath);
|
|
53035
53629
|
}
|
|
53036
|
-
|
|
53630
|
+
fs25.renameSync(handoffPath, consumedPath);
|
|
53037
53631
|
const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
|
|
53038
53632
|
The previous model's session ended. Here is your starting context:
|
|
53039
53633
|
|
|
@@ -53314,11 +53908,11 @@ ${budgetWarning}`);
|
|
|
53314
53908
|
if (handoffContent) {
|
|
53315
53909
|
const handoffPath = validateSwarmPath(directory, "handoff.md");
|
|
53316
53910
|
const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
|
|
53317
|
-
if (
|
|
53911
|
+
if (fs25.existsSync(consumedPath)) {
|
|
53318
53912
|
warn("Duplicate handoff detected: handoff-consumed.md already exists");
|
|
53319
|
-
|
|
53913
|
+
fs25.unlinkSync(consumedPath);
|
|
53320
53914
|
}
|
|
53321
|
-
|
|
53915
|
+
fs25.renameSync(handoffPath, consumedPath);
|
|
53322
53916
|
const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
|
|
53323
53917
|
The previous model's session ended. Here is your starting context:
|
|
53324
53918
|
|
|
@@ -54088,8 +54682,8 @@ function isReadTool(toolName) {
|
|
|
54088
54682
|
}
|
|
54089
54683
|
|
|
54090
54684
|
// src/hooks/incremental-verify.ts
|
|
54091
|
-
import * as
|
|
54092
|
-
import * as
|
|
54685
|
+
import * as fs26 from "fs";
|
|
54686
|
+
import * as path36 from "path";
|
|
54093
54687
|
|
|
54094
54688
|
// src/hooks/spawn-helper.ts
|
|
54095
54689
|
import { spawn } from "child_process";
|
|
@@ -54164,21 +54758,21 @@ function spawnAsync(command, cwd, timeoutMs) {
|
|
|
54164
54758
|
// src/hooks/incremental-verify.ts
|
|
54165
54759
|
var emittedSkipAdvisories = new Set;
|
|
54166
54760
|
function detectPackageManager(projectDir) {
|
|
54167
|
-
if (
|
|
54761
|
+
if (fs26.existsSync(path36.join(projectDir, "bun.lockb")))
|
|
54168
54762
|
return "bun";
|
|
54169
|
-
if (
|
|
54763
|
+
if (fs26.existsSync(path36.join(projectDir, "pnpm-lock.yaml")))
|
|
54170
54764
|
return "pnpm";
|
|
54171
|
-
if (
|
|
54765
|
+
if (fs26.existsSync(path36.join(projectDir, "yarn.lock")))
|
|
54172
54766
|
return "yarn";
|
|
54173
|
-
if (
|
|
54767
|
+
if (fs26.existsSync(path36.join(projectDir, "package-lock.json")))
|
|
54174
54768
|
return "npm";
|
|
54175
54769
|
return "bun";
|
|
54176
54770
|
}
|
|
54177
54771
|
function detectTypecheckCommand(projectDir) {
|
|
54178
|
-
const pkgPath =
|
|
54179
|
-
if (
|
|
54772
|
+
const pkgPath = path36.join(projectDir, "package.json");
|
|
54773
|
+
if (fs26.existsSync(pkgPath)) {
|
|
54180
54774
|
try {
|
|
54181
|
-
const pkg = JSON.parse(
|
|
54775
|
+
const pkg = JSON.parse(fs26.readFileSync(pkgPath, "utf8"));
|
|
54182
54776
|
const scripts = pkg.scripts;
|
|
54183
54777
|
if (scripts?.typecheck) {
|
|
54184
54778
|
const pm = detectPackageManager(projectDir);
|
|
@@ -54192,8 +54786,8 @@ function detectTypecheckCommand(projectDir) {
|
|
|
54192
54786
|
...pkg.dependencies,
|
|
54193
54787
|
...pkg.devDependencies
|
|
54194
54788
|
};
|
|
54195
|
-
if (!deps?.typescript && !
|
|
54196
|
-
const hasTSMarkers = deps?.typescript ||
|
|
54789
|
+
if (!deps?.typescript && !fs26.existsSync(path36.join(projectDir, "tsconfig.json"))) {}
|
|
54790
|
+
const hasTSMarkers = deps?.typescript || fs26.existsSync(path36.join(projectDir, "tsconfig.json"));
|
|
54197
54791
|
if (hasTSMarkers) {
|
|
54198
54792
|
return { command: ["npx", "tsc", "--noEmit"], language: "typescript" };
|
|
54199
54793
|
}
|
|
@@ -54201,17 +54795,17 @@ function detectTypecheckCommand(projectDir) {
|
|
|
54201
54795
|
return null;
|
|
54202
54796
|
}
|
|
54203
54797
|
}
|
|
54204
|
-
if (
|
|
54798
|
+
if (fs26.existsSync(path36.join(projectDir, "go.mod"))) {
|
|
54205
54799
|
return { command: ["go", "vet", "./..."], language: "go" };
|
|
54206
54800
|
}
|
|
54207
|
-
if (
|
|
54801
|
+
if (fs26.existsSync(path36.join(projectDir, "Cargo.toml"))) {
|
|
54208
54802
|
return { command: ["cargo", "check"], language: "rust" };
|
|
54209
54803
|
}
|
|
54210
|
-
if (
|
|
54804
|
+
if (fs26.existsSync(path36.join(projectDir, "pyproject.toml")) || fs26.existsSync(path36.join(projectDir, "requirements.txt")) || fs26.existsSync(path36.join(projectDir, "setup.py"))) {
|
|
54211
54805
|
return { command: null, language: "python" };
|
|
54212
54806
|
}
|
|
54213
54807
|
try {
|
|
54214
|
-
const entries =
|
|
54808
|
+
const entries = fs26.readdirSync(projectDir);
|
|
54215
54809
|
if (entries.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
54216
54810
|
return {
|
|
54217
54811
|
command: ["dotnet", "build", "--no-restore"],
|
|
@@ -54281,8 +54875,8 @@ ${errorSummary}`);
|
|
|
54281
54875
|
|
|
54282
54876
|
// src/hooks/knowledge-reader.ts
|
|
54283
54877
|
import { existsSync as existsSync22 } from "fs";
|
|
54284
|
-
import { mkdir as
|
|
54285
|
-
import * as
|
|
54878
|
+
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
|
|
54879
|
+
import * as path37 from "path";
|
|
54286
54880
|
var JACCARD_THRESHOLD = 0.6;
|
|
54287
54881
|
var HIVE_TIER_BOOST = 0.05;
|
|
54288
54882
|
var SAME_PROJECT_PENALTY = -0.05;
|
|
@@ -54330,7 +54924,7 @@ function inferCategoriesFromPhase(phaseDescription) {
|
|
|
54330
54924
|
return ["process", "tooling"];
|
|
54331
54925
|
}
|
|
54332
54926
|
async function recordLessonsShown(directory, lessonIds, currentPhase) {
|
|
54333
|
-
const shownFile =
|
|
54927
|
+
const shownFile = path37.join(directory, ".swarm", ".knowledge-shown.json");
|
|
54334
54928
|
try {
|
|
54335
54929
|
let shownData = {};
|
|
54336
54930
|
if (existsSync22(shownFile)) {
|
|
@@ -54338,7 +54932,7 @@ async function recordLessonsShown(directory, lessonIds, currentPhase) {
|
|
|
54338
54932
|
shownData = JSON.parse(content);
|
|
54339
54933
|
}
|
|
54340
54934
|
shownData[currentPhase] = lessonIds;
|
|
54341
|
-
await
|
|
54935
|
+
await mkdir5(path37.dirname(shownFile), { recursive: true });
|
|
54342
54936
|
await writeFile4(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
|
|
54343
54937
|
} catch {
|
|
54344
54938
|
console.warn("[swarm] Knowledge: failed to record shown lessons");
|
|
@@ -54435,7 +55029,7 @@ async function readMergedKnowledge(directory, config3, context) {
|
|
|
54435
55029
|
return topN;
|
|
54436
55030
|
}
|
|
54437
55031
|
async function updateRetrievalOutcome(directory, phaseInfo, phaseSucceeded) {
|
|
54438
|
-
const shownFile =
|
|
55032
|
+
const shownFile = path37.join(directory, ".swarm", ".knowledge-shown.json");
|
|
54439
55033
|
try {
|
|
54440
55034
|
if (!existsSync22(shownFile)) {
|
|
54441
55035
|
return;
|
|
@@ -55070,7 +55664,7 @@ ${injectionText}`;
|
|
|
55070
55664
|
// src/hooks/scope-guard.ts
|
|
55071
55665
|
init_constants();
|
|
55072
55666
|
init_schema();
|
|
55073
|
-
import * as
|
|
55667
|
+
import * as path39 from "path";
|
|
55074
55668
|
var WRITE_TOOLS = new Set([
|
|
55075
55669
|
"write",
|
|
55076
55670
|
"edit",
|
|
@@ -55132,13 +55726,13 @@ function createScopeGuardHook(config3, directory, injectAdvisory) {
|
|
|
55132
55726
|
}
|
|
55133
55727
|
function isFileInScope(filePath, scopeEntries, directory) {
|
|
55134
55728
|
const dir = directory ?? process.cwd();
|
|
55135
|
-
const resolvedFile =
|
|
55729
|
+
const resolvedFile = path39.resolve(dir, filePath);
|
|
55136
55730
|
return scopeEntries.some((scope) => {
|
|
55137
|
-
const resolvedScope =
|
|
55731
|
+
const resolvedScope = path39.resolve(dir, scope);
|
|
55138
55732
|
if (resolvedFile === resolvedScope)
|
|
55139
55733
|
return true;
|
|
55140
|
-
const rel =
|
|
55141
|
-
return rel.length > 0 && !rel.startsWith("..") && !
|
|
55734
|
+
const rel = path39.relative(resolvedScope, resolvedFile);
|
|
55735
|
+
return rel.length > 0 && !rel.startsWith("..") && !path39.isAbsolute(rel);
|
|
55142
55736
|
});
|
|
55143
55737
|
}
|
|
55144
55738
|
|
|
@@ -55187,8 +55781,8 @@ function createSelfReviewHook(config3, injectAdvisory) {
|
|
|
55187
55781
|
}
|
|
55188
55782
|
|
|
55189
55783
|
// src/hooks/slop-detector.ts
|
|
55190
|
-
import * as
|
|
55191
|
-
import * as
|
|
55784
|
+
import * as fs28 from "fs";
|
|
55785
|
+
import * as path40 from "path";
|
|
55192
55786
|
var WRITE_EDIT_TOOLS = new Set([
|
|
55193
55787
|
"write",
|
|
55194
55788
|
"edit",
|
|
@@ -55233,12 +55827,12 @@ function checkBoilerplateExplosion(content, taskDescription, threshold) {
|
|
|
55233
55827
|
function walkFiles(dir, exts, deadline) {
|
|
55234
55828
|
const results = [];
|
|
55235
55829
|
try {
|
|
55236
|
-
for (const entry of
|
|
55830
|
+
for (const entry of fs28.readdirSync(dir, { withFileTypes: true })) {
|
|
55237
55831
|
if (deadline !== undefined && Date.now() > deadline)
|
|
55238
55832
|
break;
|
|
55239
55833
|
if (entry.isSymbolicLink())
|
|
55240
55834
|
continue;
|
|
55241
|
-
const full =
|
|
55835
|
+
const full = path40.join(dir, entry.name);
|
|
55242
55836
|
if (entry.isDirectory()) {
|
|
55243
55837
|
if (entry.name === "node_modules" || entry.name === ".git")
|
|
55244
55838
|
continue;
|
|
@@ -55253,7 +55847,7 @@ function walkFiles(dir, exts, deadline) {
|
|
|
55253
55847
|
return results;
|
|
55254
55848
|
}
|
|
55255
55849
|
function checkDeadExports(content, projectDir, startTime) {
|
|
55256
|
-
const hasPackageJson =
|
|
55850
|
+
const hasPackageJson = fs28.existsSync(path40.join(projectDir, "package.json"));
|
|
55257
55851
|
if (!hasPackageJson)
|
|
55258
55852
|
return null;
|
|
55259
55853
|
const exportMatches = content.matchAll(/^\+(?:export)\s+(?:function|class|const|type|interface)\s+(\w{3,})/gm);
|
|
@@ -55276,7 +55870,7 @@ function checkDeadExports(content, projectDir, startTime) {
|
|
|
55276
55870
|
if (found || Date.now() - startTime > 480)
|
|
55277
55871
|
break;
|
|
55278
55872
|
try {
|
|
55279
|
-
const text =
|
|
55873
|
+
const text = fs28.readFileSync(file3, "utf-8");
|
|
55280
55874
|
if (importPattern.test(text))
|
|
55281
55875
|
found = true;
|
|
55282
55876
|
importPattern.lastIndex = 0;
|
|
@@ -55409,7 +56003,7 @@ Review before proceeding.`;
|
|
|
55409
56003
|
|
|
55410
56004
|
// src/hooks/steering-consumed.ts
|
|
55411
56005
|
init_utils2();
|
|
55412
|
-
import * as
|
|
56006
|
+
import * as fs29 from "fs";
|
|
55413
56007
|
function recordSteeringConsumed(directory, directiveId) {
|
|
55414
56008
|
try {
|
|
55415
56009
|
const eventsPath = validateSwarmPath(directory, "events.jsonl");
|
|
@@ -55418,7 +56012,7 @@ function recordSteeringConsumed(directory, directiveId) {
|
|
|
55418
56012
|
directiveId,
|
|
55419
56013
|
timestamp: new Date().toISOString()
|
|
55420
56014
|
};
|
|
55421
|
-
|
|
56015
|
+
fs29.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
55422
56016
|
`, "utf-8");
|
|
55423
56017
|
} catch {}
|
|
55424
56018
|
}
|
|
@@ -55815,8 +56409,8 @@ var build_check = createSwarmTool({
|
|
|
55815
56409
|
init_dist();
|
|
55816
56410
|
init_manager();
|
|
55817
56411
|
init_create_tool();
|
|
55818
|
-
import * as
|
|
55819
|
-
import * as
|
|
56412
|
+
import * as fs30 from "fs";
|
|
56413
|
+
import * as path41 from "path";
|
|
55820
56414
|
var EVIDENCE_DIR = ".swarm/evidence";
|
|
55821
56415
|
var TASK_ID_PATTERN2 = /^\d+\.\d+(\.\d+)*$/;
|
|
55822
56416
|
function isValidTaskId3(taskId) {
|
|
@@ -55833,18 +56427,18 @@ function isValidTaskId3(taskId) {
|
|
|
55833
56427
|
return TASK_ID_PATTERN2.test(taskId);
|
|
55834
56428
|
}
|
|
55835
56429
|
function isPathWithinSwarm(filePath, workspaceRoot) {
|
|
55836
|
-
const normalizedWorkspace =
|
|
55837
|
-
const swarmPath =
|
|
55838
|
-
const normalizedPath =
|
|
56430
|
+
const normalizedWorkspace = path41.resolve(workspaceRoot);
|
|
56431
|
+
const swarmPath = path41.join(normalizedWorkspace, ".swarm", "evidence");
|
|
56432
|
+
const normalizedPath = path41.resolve(filePath);
|
|
55839
56433
|
return normalizedPath.startsWith(swarmPath);
|
|
55840
56434
|
}
|
|
55841
56435
|
function readEvidenceFile(evidencePath) {
|
|
55842
|
-
if (!
|
|
56436
|
+
if (!fs30.existsSync(evidencePath)) {
|
|
55843
56437
|
return null;
|
|
55844
56438
|
}
|
|
55845
56439
|
let content;
|
|
55846
56440
|
try {
|
|
55847
|
-
content =
|
|
56441
|
+
content = fs30.readFileSync(evidencePath, "utf-8");
|
|
55848
56442
|
} catch {
|
|
55849
56443
|
return null;
|
|
55850
56444
|
}
|
|
@@ -55898,7 +56492,7 @@ var check_gate_status = createSwarmTool({
|
|
|
55898
56492
|
};
|
|
55899
56493
|
return JSON.stringify(errorResult, null, 2);
|
|
55900
56494
|
}
|
|
55901
|
-
const evidencePath =
|
|
56495
|
+
const evidencePath = path41.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
|
|
55902
56496
|
if (!isPathWithinSwarm(evidencePath, directory)) {
|
|
55903
56497
|
const errorResult = {
|
|
55904
56498
|
taskId: taskIdInput,
|
|
@@ -55990,8 +56584,8 @@ init_checkpoint();
|
|
|
55990
56584
|
// src/tools/completion-verify.ts
|
|
55991
56585
|
init_dist();
|
|
55992
56586
|
init_utils2();
|
|
55993
|
-
import * as
|
|
55994
|
-
import * as
|
|
56587
|
+
import * as fs31 from "fs";
|
|
56588
|
+
import * as path42 from "path";
|
|
55995
56589
|
init_create_tool();
|
|
55996
56590
|
function extractMatches(regex, text) {
|
|
55997
56591
|
return Array.from(text.matchAll(regex));
|
|
@@ -56073,7 +56667,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
56073
56667
|
let plan;
|
|
56074
56668
|
try {
|
|
56075
56669
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
56076
|
-
const planRaw =
|
|
56670
|
+
const planRaw = fs31.readFileSync(planPath, "utf-8");
|
|
56077
56671
|
plan = JSON.parse(planRaw);
|
|
56078
56672
|
} catch {
|
|
56079
56673
|
const result2 = {
|
|
@@ -56124,10 +56718,10 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
56124
56718
|
let foundCount = 0;
|
|
56125
56719
|
let hasFileReadFailure = false;
|
|
56126
56720
|
for (const filePath of fileTargets) {
|
|
56127
|
-
const resolvedPath =
|
|
56721
|
+
const resolvedPath = path42.resolve(directory, filePath);
|
|
56128
56722
|
let fileContent;
|
|
56129
56723
|
try {
|
|
56130
|
-
fileContent =
|
|
56724
|
+
fileContent = fs31.readFileSync(resolvedPath, "utf-8");
|
|
56131
56725
|
} catch {
|
|
56132
56726
|
blockedTasks.push({
|
|
56133
56727
|
task_id: task.id,
|
|
@@ -56169,9 +56763,9 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
56169
56763
|
blockedTasks
|
|
56170
56764
|
};
|
|
56171
56765
|
try {
|
|
56172
|
-
const evidenceDir =
|
|
56173
|
-
const evidencePath =
|
|
56174
|
-
|
|
56766
|
+
const evidenceDir = path42.join(directory, ".swarm", "evidence", `${phase}`);
|
|
56767
|
+
const evidencePath = path42.join(evidenceDir, "completion-verify.json");
|
|
56768
|
+
fs31.mkdirSync(evidenceDir, { recursive: true });
|
|
56175
56769
|
const evidenceBundle = {
|
|
56176
56770
|
schema_version: "1.0.0",
|
|
56177
56771
|
task_id: "completion-verify",
|
|
@@ -56192,7 +56786,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
56192
56786
|
}
|
|
56193
56787
|
]
|
|
56194
56788
|
};
|
|
56195
|
-
|
|
56789
|
+
fs31.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
|
|
56196
56790
|
} catch {}
|
|
56197
56791
|
return JSON.stringify(result, null, 2);
|
|
56198
56792
|
}
|
|
@@ -56232,8 +56826,8 @@ var completion_verify = createSwarmTool({
|
|
|
56232
56826
|
// src/tools/complexity-hotspots.ts
|
|
56233
56827
|
init_dist();
|
|
56234
56828
|
init_create_tool();
|
|
56235
|
-
import * as
|
|
56236
|
-
import * as
|
|
56829
|
+
import * as fs32 from "fs";
|
|
56830
|
+
import * as path43 from "path";
|
|
56237
56831
|
var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
|
|
56238
56832
|
var DEFAULT_DAYS = 90;
|
|
56239
56833
|
var DEFAULT_TOP_N = 20;
|
|
@@ -56362,11 +56956,11 @@ function estimateComplexity(content) {
|
|
|
56362
56956
|
}
|
|
56363
56957
|
function getComplexityForFile(filePath) {
|
|
56364
56958
|
try {
|
|
56365
|
-
const stat2 =
|
|
56959
|
+
const stat2 = fs32.statSync(filePath);
|
|
56366
56960
|
if (stat2.size > MAX_FILE_SIZE_BYTES2) {
|
|
56367
56961
|
return null;
|
|
56368
56962
|
}
|
|
56369
|
-
const content =
|
|
56963
|
+
const content = fs32.readFileSync(filePath, "utf-8");
|
|
56370
56964
|
return estimateComplexity(content);
|
|
56371
56965
|
} catch {
|
|
56372
56966
|
return null;
|
|
@@ -56377,7 +56971,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
56377
56971
|
const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
|
|
56378
56972
|
const filteredChurn = new Map;
|
|
56379
56973
|
for (const [file3, count] of churnMap) {
|
|
56380
|
-
const ext =
|
|
56974
|
+
const ext = path43.extname(file3).toLowerCase();
|
|
56381
56975
|
if (extSet.has(ext)) {
|
|
56382
56976
|
filteredChurn.set(file3, count);
|
|
56383
56977
|
}
|
|
@@ -56387,8 +56981,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
56387
56981
|
let analyzedFiles = 0;
|
|
56388
56982
|
for (const [file3, churnCount] of filteredChurn) {
|
|
56389
56983
|
let fullPath = file3;
|
|
56390
|
-
if (!
|
|
56391
|
-
fullPath =
|
|
56984
|
+
if (!fs32.existsSync(fullPath)) {
|
|
56985
|
+
fullPath = path43.join(cwd, file3);
|
|
56392
56986
|
}
|
|
56393
56987
|
const complexity = getComplexityForFile(fullPath);
|
|
56394
56988
|
if (complexity !== null) {
|
|
@@ -56596,8 +57190,8 @@ var curator_analyze = createSwarmTool({
|
|
|
56596
57190
|
});
|
|
56597
57191
|
// src/tools/declare-scope.ts
|
|
56598
57192
|
init_tool();
|
|
56599
|
-
import * as
|
|
56600
|
-
import * as
|
|
57193
|
+
import * as fs33 from "fs";
|
|
57194
|
+
import * as path44 from "path";
|
|
56601
57195
|
init_create_tool();
|
|
56602
57196
|
function validateTaskIdFormat(taskId) {
|
|
56603
57197
|
const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
|
|
@@ -56676,8 +57270,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
56676
57270
|
};
|
|
56677
57271
|
}
|
|
56678
57272
|
}
|
|
56679
|
-
normalizedDir =
|
|
56680
|
-
const pathParts = normalizedDir.split(
|
|
57273
|
+
normalizedDir = path44.normalize(args2.working_directory);
|
|
57274
|
+
const pathParts = normalizedDir.split(path44.sep);
|
|
56681
57275
|
if (pathParts.includes("..")) {
|
|
56682
57276
|
return {
|
|
56683
57277
|
success: false,
|
|
@@ -56687,11 +57281,11 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
56687
57281
|
]
|
|
56688
57282
|
};
|
|
56689
57283
|
}
|
|
56690
|
-
const resolvedDir =
|
|
57284
|
+
const resolvedDir = path44.resolve(normalizedDir);
|
|
56691
57285
|
try {
|
|
56692
|
-
const realPath =
|
|
56693
|
-
const planPath2 =
|
|
56694
|
-
if (!
|
|
57286
|
+
const realPath = fs33.realpathSync(resolvedDir);
|
|
57287
|
+
const planPath2 = path44.join(realPath, ".swarm", "plan.json");
|
|
57288
|
+
if (!fs33.existsSync(planPath2)) {
|
|
56695
57289
|
return {
|
|
56696
57290
|
success: false,
|
|
56697
57291
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -56714,8 +57308,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
56714
57308
|
console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
|
|
56715
57309
|
}
|
|
56716
57310
|
const directory = normalizedDir || fallbackDir;
|
|
56717
|
-
const planPath =
|
|
56718
|
-
if (!
|
|
57311
|
+
const planPath = path44.resolve(directory, ".swarm", "plan.json");
|
|
57312
|
+
if (!fs33.existsSync(planPath)) {
|
|
56719
57313
|
return {
|
|
56720
57314
|
success: false,
|
|
56721
57315
|
message: "No plan found",
|
|
@@ -56724,7 +57318,7 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
56724
57318
|
}
|
|
56725
57319
|
let planContent;
|
|
56726
57320
|
try {
|
|
56727
|
-
planContent = JSON.parse(
|
|
57321
|
+
planContent = JSON.parse(fs33.readFileSync(planPath, "utf-8"));
|
|
56728
57322
|
} catch {
|
|
56729
57323
|
return {
|
|
56730
57324
|
success: false,
|
|
@@ -56777,8 +57371,252 @@ var declare_scope = createSwarmTool({
|
|
|
56777
57371
|
});
|
|
56778
57372
|
// src/tools/diff.ts
|
|
56779
57373
|
init_dist();
|
|
56780
|
-
init_create_tool();
|
|
56781
57374
|
import { execFileSync } from "child_process";
|
|
57375
|
+
|
|
57376
|
+
// src/diff/ast-diff.ts
|
|
57377
|
+
init_tree_sitter();
|
|
57378
|
+
import { extname as extname6 } from "path";
|
|
57379
|
+
|
|
57380
|
+
// src/lang/registry.ts
|
|
57381
|
+
init_runtime();
|
|
57382
|
+
var languageDefinitions = [
|
|
57383
|
+
{
|
|
57384
|
+
id: "javascript",
|
|
57385
|
+
extensions: [".js", ".jsx"],
|
|
57386
|
+
commentNodes: ["comment", "line_comment", "block_comment"]
|
|
57387
|
+
},
|
|
57388
|
+
{
|
|
57389
|
+
id: "typescript",
|
|
57390
|
+
extensions: [".ts", ".tsx"],
|
|
57391
|
+
commentNodes: ["comment", "line_comment", "block_comment"]
|
|
57392
|
+
},
|
|
57393
|
+
{
|
|
57394
|
+
id: "python",
|
|
57395
|
+
extensions: [".py"],
|
|
57396
|
+
commentNodes: ["comment"]
|
|
57397
|
+
},
|
|
57398
|
+
{
|
|
57399
|
+
id: "go",
|
|
57400
|
+
extensions: [".go"],
|
|
57401
|
+
commentNodes: ["comment"]
|
|
57402
|
+
},
|
|
57403
|
+
{
|
|
57404
|
+
id: "rust",
|
|
57405
|
+
extensions: [".rs"],
|
|
57406
|
+
commentNodes: ["line_comment", "block_comment"]
|
|
57407
|
+
}
|
|
57408
|
+
];
|
|
57409
|
+
var extensionMap = new Map;
|
|
57410
|
+
for (const definition of languageDefinitions) {
|
|
57411
|
+
for (const extension of definition.extensions) {
|
|
57412
|
+
extensionMap.set(extension, definition);
|
|
57413
|
+
}
|
|
57414
|
+
}
|
|
57415
|
+
function getLanguageForExtension(extension) {
|
|
57416
|
+
return extensionMap.get(extension.toLowerCase());
|
|
57417
|
+
}
|
|
57418
|
+
|
|
57419
|
+
// src/diff/ast-diff.ts
|
|
57420
|
+
init_runtime();
|
|
57421
|
+
var QUERIES = {
|
|
57422
|
+
javascript: `
|
|
57423
|
+
(function_declaration name: (identifier) @func.name) @func.def
|
|
57424
|
+
(class_declaration name: (type_identifier) @class.name) @class.def
|
|
57425
|
+
(export_statement) @export
|
|
57426
|
+
(import_statement) @import
|
|
57427
|
+
(type_alias_declaration name: (type_identifier) @type.name) @type.def
|
|
57428
|
+
`,
|
|
57429
|
+
typescript: `
|
|
57430
|
+
(function_declaration name: (identifier) @func.name) @func.def
|
|
57431
|
+
(class_declaration name: (type_identifier) @class.name) @class.def
|
|
57432
|
+
(export_statement) @export
|
|
57433
|
+
(import_statement) @import
|
|
57434
|
+
(type_alias_declaration name: (type_identifier) @type.name) @type.def
|
|
57435
|
+
(interface_declaration name: (type_identifier) @interface.name) @interface.def
|
|
57436
|
+
`,
|
|
57437
|
+
python: `
|
|
57438
|
+
(function_definition name: (identifier) @func.name) @func.def
|
|
57439
|
+
(class_definition name: (identifier) @class.name) @class.def
|
|
57440
|
+
(import_statement) @import
|
|
57441
|
+
(expression_statement (assignment left: (identifier) @var.name)) @var.def
|
|
57442
|
+
`,
|
|
57443
|
+
go: `
|
|
57444
|
+
(function_declaration name: (identifier) @func.name) @func.def
|
|
57445
|
+
(type_declaration (type_spec name: (type_identifier) @type.name)) @type.def
|
|
57446
|
+
(import_declaration) @import
|
|
57447
|
+
`,
|
|
57448
|
+
rust: `
|
|
57449
|
+
(function_item name: (identifier) @func.name) @func.def
|
|
57450
|
+
(struct_item name: (type_identifier) @struct.name) @struct.def
|
|
57451
|
+
(impl_item type: (type_identifier) @impl.name) @impl.def
|
|
57452
|
+
(use_declaration) @import
|
|
57453
|
+
`
|
|
57454
|
+
};
|
|
57455
|
+
var AST_TIMEOUT_MS = 500;
|
|
57456
|
+
async function computeASTDiff(filePath, oldContent, newContent) {
|
|
57457
|
+
const startTime = Date.now();
|
|
57458
|
+
const extension = extname6(filePath).toLowerCase();
|
|
57459
|
+
const language = getLanguageForExtension(extension);
|
|
57460
|
+
if (!language) {
|
|
57461
|
+
return {
|
|
57462
|
+
filePath,
|
|
57463
|
+
language: null,
|
|
57464
|
+
changes: [],
|
|
57465
|
+
durationMs: Date.now() - startTime,
|
|
57466
|
+
usedAST: false
|
|
57467
|
+
};
|
|
57468
|
+
}
|
|
57469
|
+
try {
|
|
57470
|
+
const parser = await Promise.race([
|
|
57471
|
+
loadGrammar(language.id),
|
|
57472
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("AST_TIMEOUT")), AST_TIMEOUT_MS))
|
|
57473
|
+
]);
|
|
57474
|
+
const oldTree = parser.parse(oldContent);
|
|
57475
|
+
const newTree = parser.parse(newContent);
|
|
57476
|
+
if (!oldTree || !newTree) {
|
|
57477
|
+
return {
|
|
57478
|
+
filePath,
|
|
57479
|
+
language: language.id,
|
|
57480
|
+
changes: [],
|
|
57481
|
+
durationMs: Date.now() - startTime,
|
|
57482
|
+
usedAST: false,
|
|
57483
|
+
error: "Failed to parse file"
|
|
57484
|
+
};
|
|
57485
|
+
}
|
|
57486
|
+
const oldSymbols = extractSymbols(oldTree, language);
|
|
57487
|
+
const newSymbols = extractSymbols(newTree, language);
|
|
57488
|
+
const changes = compareSymbols(oldSymbols, newSymbols);
|
|
57489
|
+
oldTree.delete();
|
|
57490
|
+
newTree.delete();
|
|
57491
|
+
return {
|
|
57492
|
+
filePath,
|
|
57493
|
+
language: language.id,
|
|
57494
|
+
changes,
|
|
57495
|
+
durationMs: Date.now() - startTime,
|
|
57496
|
+
usedAST: true
|
|
57497
|
+
};
|
|
57498
|
+
} catch (error93) {
|
|
57499
|
+
const errorMsg = error93 instanceof Error ? error93.message : "Unknown error";
|
|
57500
|
+
if (errorMsg === "AST_TIMEOUT") {
|
|
57501
|
+
console.warn(`[ast-diff] Timeout for ${filePath}, falling back to raw diff`);
|
|
57502
|
+
}
|
|
57503
|
+
return {
|
|
57504
|
+
filePath,
|
|
57505
|
+
language: language.id,
|
|
57506
|
+
changes: [],
|
|
57507
|
+
durationMs: Date.now() - startTime,
|
|
57508
|
+
usedAST: false,
|
|
57509
|
+
error: errorMsg
|
|
57510
|
+
};
|
|
57511
|
+
}
|
|
57512
|
+
}
|
|
57513
|
+
function extractSymbols(tree, language) {
|
|
57514
|
+
const symbols = [];
|
|
57515
|
+
const queryStr = QUERIES[language.id];
|
|
57516
|
+
if (!queryStr) {
|
|
57517
|
+
return symbols;
|
|
57518
|
+
}
|
|
57519
|
+
try {
|
|
57520
|
+
const lang = tree.language;
|
|
57521
|
+
if (!lang) {
|
|
57522
|
+
return symbols;
|
|
57523
|
+
}
|
|
57524
|
+
const query = new Query(lang, queryStr);
|
|
57525
|
+
const matches = query.matches(tree.rootNode);
|
|
57526
|
+
for (const match of matches) {
|
|
57527
|
+
const symbol3 = parseMatch(match, language.id);
|
|
57528
|
+
if (symbol3) {
|
|
57529
|
+
symbols.push(symbol3);
|
|
57530
|
+
}
|
|
57531
|
+
}
|
|
57532
|
+
} catch {}
|
|
57533
|
+
return symbols;
|
|
57534
|
+
}
|
|
57535
|
+
function parseMatch(match, languageId) {
|
|
57536
|
+
const captures = match.captures;
|
|
57537
|
+
const defCapture = captures.find((c) => c.name.endsWith(".def"));
|
|
57538
|
+
const nameCapture = captures.find((c) => c.name.endsWith(".name"));
|
|
57539
|
+
if (!defCapture)
|
|
57540
|
+
return null;
|
|
57541
|
+
const node = defCapture.node;
|
|
57542
|
+
const nameNode = nameCapture?.node;
|
|
57543
|
+
return {
|
|
57544
|
+
category: inferCategory(captures[0]?.name || "other"),
|
|
57545
|
+
name: nameNode?.text || "anonymous",
|
|
57546
|
+
lineStart: node.startPosition.row + 1,
|
|
57547
|
+
lineEnd: node.endPosition.row + 1,
|
|
57548
|
+
signature: extractSignature(node, languageId)
|
|
57549
|
+
};
|
|
57550
|
+
}
|
|
57551
|
+
function inferCategory(captureName) {
|
|
57552
|
+
if (captureName.includes("func"))
|
|
57553
|
+
return "function";
|
|
57554
|
+
if (captureName.includes("class"))
|
|
57555
|
+
return "class";
|
|
57556
|
+
if (captureName.includes("type") || captureName.includes("interface") || captureName.includes("struct"))
|
|
57557
|
+
return "type";
|
|
57558
|
+
if (captureName.includes("export"))
|
|
57559
|
+
return "export";
|
|
57560
|
+
if (captureName.includes("import") || captureName.includes("use"))
|
|
57561
|
+
return "import";
|
|
57562
|
+
if (captureName.includes("var"))
|
|
57563
|
+
return "variable";
|
|
57564
|
+
return "other";
|
|
57565
|
+
}
|
|
57566
|
+
function extractSignature(node, languageId) {
|
|
57567
|
+
if (languageId === "javascript" || languageId === "typescript") {
|
|
57568
|
+
const paramsNode = node.children.find((c) => c !== null && c.type === "formal_parameters");
|
|
57569
|
+
if (paramsNode) {
|
|
57570
|
+
return paramsNode.text;
|
|
57571
|
+
}
|
|
57572
|
+
}
|
|
57573
|
+
return;
|
|
57574
|
+
}
|
|
57575
|
+
function compareSymbols(oldSymbols, newSymbols) {
|
|
57576
|
+
const changes = [];
|
|
57577
|
+
const oldMap = new Map(oldSymbols.map((s) => [s.name, s]));
|
|
57578
|
+
const newMap = new Map(newSymbols.map((s) => [s.name, s]));
|
|
57579
|
+
for (const [name2, symbol3] of newMap) {
|
|
57580
|
+
if (!oldMap.has(name2)) {
|
|
57581
|
+
changes.push({
|
|
57582
|
+
type: "added",
|
|
57583
|
+
category: symbol3.category,
|
|
57584
|
+
name: symbol3.name,
|
|
57585
|
+
lineStart: symbol3.lineStart,
|
|
57586
|
+
lineEnd: symbol3.lineEnd,
|
|
57587
|
+
signature: symbol3.signature
|
|
57588
|
+
});
|
|
57589
|
+
} else {
|
|
57590
|
+
const oldSymbol = oldMap.get(name2);
|
|
57591
|
+
if (oldSymbol.lineStart !== symbol3.lineStart || oldSymbol.lineEnd !== symbol3.lineEnd || oldSymbol.signature !== symbol3.signature) {
|
|
57592
|
+
changes.push({
|
|
57593
|
+
type: "modified",
|
|
57594
|
+
category: symbol3.category,
|
|
57595
|
+
name: symbol3.name,
|
|
57596
|
+
lineStart: symbol3.lineStart,
|
|
57597
|
+
lineEnd: symbol3.lineEnd,
|
|
57598
|
+
signature: symbol3.signature
|
|
57599
|
+
});
|
|
57600
|
+
}
|
|
57601
|
+
}
|
|
57602
|
+
}
|
|
57603
|
+
for (const [name2, symbol3] of oldMap) {
|
|
57604
|
+
if (!newMap.has(name2)) {
|
|
57605
|
+
changes.push({
|
|
57606
|
+
type: "removed",
|
|
57607
|
+
category: symbol3.category,
|
|
57608
|
+
name: symbol3.name,
|
|
57609
|
+
lineStart: symbol3.lineStart,
|
|
57610
|
+
lineEnd: symbol3.lineEnd,
|
|
57611
|
+
signature: symbol3.signature
|
|
57612
|
+
});
|
|
57613
|
+
}
|
|
57614
|
+
}
|
|
57615
|
+
return changes;
|
|
57616
|
+
}
|
|
57617
|
+
|
|
57618
|
+
// src/tools/diff.ts
|
|
57619
|
+
init_create_tool();
|
|
56782
57620
|
var MAX_DIFF_LINES = 500;
|
|
56783
57621
|
var DIFF_TIMEOUT_MS = 30000;
|
|
56784
57622
|
var MAX_BUFFER_BYTES = 5 * 1024 * 1024;
|
|
@@ -56805,20 +57643,20 @@ function validateBase(base) {
|
|
|
56805
57643
|
function validatePaths(paths) {
|
|
56806
57644
|
if (!paths)
|
|
56807
57645
|
return null;
|
|
56808
|
-
for (const
|
|
56809
|
-
if (!
|
|
57646
|
+
for (const path45 of paths) {
|
|
57647
|
+
if (!path45 || path45.length === 0) {
|
|
56810
57648
|
return "empty path not allowed";
|
|
56811
57649
|
}
|
|
56812
|
-
if (
|
|
57650
|
+
if (path45.length > MAX_PATH_LENGTH) {
|
|
56813
57651
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
56814
57652
|
}
|
|
56815
|
-
if (SHELL_METACHARACTERS2.test(
|
|
57653
|
+
if (SHELL_METACHARACTERS2.test(path45)) {
|
|
56816
57654
|
return "path contains shell metacharacters";
|
|
56817
57655
|
}
|
|
56818
|
-
if (
|
|
57656
|
+
if (path45.startsWith("-")) {
|
|
56819
57657
|
return 'path cannot start with "-" (option-like arguments not allowed)';
|
|
56820
57658
|
}
|
|
56821
|
-
if (CONTROL_CHAR_PATTERN2.test(
|
|
57659
|
+
if (CONTROL_CHAR_PATTERN2.test(path45)) {
|
|
56822
57660
|
return "path contains control characters";
|
|
56823
57661
|
}
|
|
56824
57662
|
}
|
|
@@ -56899,8 +57737,8 @@ var diff = createSwarmTool({
|
|
|
56899
57737
|
if (parts2.length >= 3) {
|
|
56900
57738
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
56901
57739
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
56902
|
-
const
|
|
56903
|
-
files.push({ path:
|
|
57740
|
+
const path45 = parts2[2];
|
|
57741
|
+
files.push({ path: path45, additions, deletions });
|
|
56904
57742
|
}
|
|
56905
57743
|
}
|
|
56906
57744
|
const contractChanges = [];
|
|
@@ -56926,13 +57764,62 @@ var diff = createSwarmTool({
|
|
|
56926
57764
|
}
|
|
56927
57765
|
const hasContractChanges = contractChanges.length > 0;
|
|
56928
57766
|
const fileCount = files.length;
|
|
57767
|
+
const astDiffs = [];
|
|
57768
|
+
for (const file3 of files) {
|
|
57769
|
+
try {
|
|
57770
|
+
let oldContent;
|
|
57771
|
+
let newContent;
|
|
57772
|
+
if (base === "staged") {
|
|
57773
|
+
oldContent = execFileSync("git", ["show", `HEAD:${file3.path}`], {
|
|
57774
|
+
encoding: "utf-8",
|
|
57775
|
+
timeout: 5000,
|
|
57776
|
+
cwd: directory
|
|
57777
|
+
});
|
|
57778
|
+
newContent = execFileSync("git", ["show", `:${file3.path}`], {
|
|
57779
|
+
encoding: "utf-8",
|
|
57780
|
+
timeout: 5000,
|
|
57781
|
+
cwd: directory
|
|
57782
|
+
});
|
|
57783
|
+
} else if (base === "unstaged") {
|
|
57784
|
+
oldContent = execFileSync("git", ["show", `:${file3.path}`], {
|
|
57785
|
+
encoding: "utf-8",
|
|
57786
|
+
timeout: 5000,
|
|
57787
|
+
cwd: directory
|
|
57788
|
+
});
|
|
57789
|
+
newContent = execFileSync("git", ["show", `HEAD:${file3.path}`], {
|
|
57790
|
+
encoding: "utf-8",
|
|
57791
|
+
timeout: 5000,
|
|
57792
|
+
cwd: directory
|
|
57793
|
+
});
|
|
57794
|
+
const fsModule = await import("fs");
|
|
57795
|
+
const pathModule = await import("path");
|
|
57796
|
+
newContent = fsModule.readFileSync(pathModule.join(directory, file3.path), "utf-8");
|
|
57797
|
+
} else {
|
|
57798
|
+
oldContent = execFileSync("git", ["show", `${base}:${file3.path}`], {
|
|
57799
|
+
encoding: "utf-8",
|
|
57800
|
+
timeout: 5000,
|
|
57801
|
+
cwd: directory
|
|
57802
|
+
});
|
|
57803
|
+
newContent = execFileSync("git", ["show", `HEAD:${file3.path}`], {
|
|
57804
|
+
encoding: "utf-8",
|
|
57805
|
+
timeout: 5000,
|
|
57806
|
+
cwd: directory
|
|
57807
|
+
});
|
|
57808
|
+
}
|
|
57809
|
+
const astResult = await computeASTDiff(file3.path, oldContent, newContent);
|
|
57810
|
+
if (astResult && astResult.changes.length > 0) {
|
|
57811
|
+
astDiffs.push(astResult);
|
|
57812
|
+
}
|
|
57813
|
+
} catch {}
|
|
57814
|
+
}
|
|
56929
57815
|
const truncated = diffLines.length > MAX_DIFF_LINES;
|
|
56930
57816
|
const summary = truncated ? `${fileCount} files changed. Contract changes: ${hasContractChanges ? "YES" : "NO"}. (truncated to ${MAX_DIFF_LINES} lines)` : `${fileCount} files changed. Contract changes: ${hasContractChanges ? "YES" : "NO"}`;
|
|
56931
57817
|
const result = {
|
|
56932
57818
|
files,
|
|
56933
57819
|
contractChanges,
|
|
56934
57820
|
hasContractChanges,
|
|
56935
|
-
summary
|
|
57821
|
+
summary,
|
|
57822
|
+
...astDiffs.length > 0 ? { astDiffs } : {}
|
|
56936
57823
|
};
|
|
56937
57824
|
return JSON.stringify(result, null, 2);
|
|
56938
57825
|
} catch (e) {
|
|
@@ -56950,9 +57837,9 @@ var diff = createSwarmTool({
|
|
|
56950
57837
|
init_dist();
|
|
56951
57838
|
init_schema();
|
|
56952
57839
|
import * as crypto4 from "crypto";
|
|
56953
|
-
import * as
|
|
56954
|
-
import { mkdir as
|
|
56955
|
-
import * as
|
|
57840
|
+
import * as fs34 from "fs";
|
|
57841
|
+
import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
|
|
57842
|
+
import * as path45 from "path";
|
|
56956
57843
|
init_create_tool();
|
|
56957
57844
|
var SKIP_DIRECTORIES2 = new Set([
|
|
56958
57845
|
"node_modules",
|
|
@@ -56977,7 +57864,7 @@ function normalizeSeparators(filePath) {
|
|
|
56977
57864
|
}
|
|
56978
57865
|
function matchesDocPattern(filePath, patterns) {
|
|
56979
57866
|
const normalizedPath = normalizeSeparators(filePath);
|
|
56980
|
-
const basename5 =
|
|
57867
|
+
const basename5 = path45.basename(filePath);
|
|
56981
57868
|
for (const pattern of patterns) {
|
|
56982
57869
|
if (!pattern.includes("/") && !pattern.includes("\\")) {
|
|
56983
57870
|
if (basename5 === pattern) {
|
|
@@ -57033,7 +57920,7 @@ function stripMarkdown(text) {
|
|
|
57033
57920
|
return text.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/^\s*[-*\u2022]\s+/gm, "").replace(/^\s*\d+\.\s+/gm, "").trim();
|
|
57034
57921
|
}
|
|
57035
57922
|
async function scanDocIndex(directory) {
|
|
57036
|
-
const manifestPath =
|
|
57923
|
+
const manifestPath = path45.join(directory, ".swarm", "doc-manifest.json");
|
|
57037
57924
|
const defaultPatterns = DocsConfigSchema.parse({}).doc_patterns;
|
|
57038
57925
|
const extraPatterns = [
|
|
57039
57926
|
"ARCHITECTURE.md",
|
|
@@ -57050,8 +57937,8 @@ async function scanDocIndex(directory) {
|
|
|
57050
57937
|
let cacheValid = true;
|
|
57051
57938
|
for (const file3 of existingManifest.files) {
|
|
57052
57939
|
try {
|
|
57053
|
-
const fullPath =
|
|
57054
|
-
const stat2 =
|
|
57940
|
+
const fullPath = path45.join(directory, file3.path);
|
|
57941
|
+
const stat2 = fs34.statSync(fullPath);
|
|
57055
57942
|
if (stat2.mtimeMs > new Date(existingManifest.scanned_at).getTime()) {
|
|
57056
57943
|
cacheValid = false;
|
|
57057
57944
|
break;
|
|
@@ -57069,7 +57956,7 @@ async function scanDocIndex(directory) {
|
|
|
57069
57956
|
const discoveredFiles = [];
|
|
57070
57957
|
let rawEntries;
|
|
57071
57958
|
try {
|
|
57072
|
-
rawEntries =
|
|
57959
|
+
rawEntries = fs34.readdirSync(directory, { recursive: true });
|
|
57073
57960
|
} catch {
|
|
57074
57961
|
const manifest2 = {
|
|
57075
57962
|
schema_version: 1,
|
|
@@ -57080,10 +57967,10 @@ async function scanDocIndex(directory) {
|
|
|
57080
57967
|
}
|
|
57081
57968
|
const entries = rawEntries.filter((e) => typeof e === "string");
|
|
57082
57969
|
for (const entry of entries) {
|
|
57083
|
-
const fullPath =
|
|
57970
|
+
const fullPath = path45.join(directory, entry);
|
|
57084
57971
|
let stat2;
|
|
57085
57972
|
try {
|
|
57086
|
-
stat2 =
|
|
57973
|
+
stat2 = fs34.statSync(fullPath);
|
|
57087
57974
|
} catch {
|
|
57088
57975
|
continue;
|
|
57089
57976
|
}
|
|
@@ -57112,11 +57999,11 @@ async function scanDocIndex(directory) {
|
|
|
57112
57999
|
}
|
|
57113
58000
|
let content;
|
|
57114
58001
|
try {
|
|
57115
|
-
content =
|
|
58002
|
+
content = fs34.readFileSync(fullPath, "utf-8");
|
|
57116
58003
|
} catch {
|
|
57117
58004
|
continue;
|
|
57118
58005
|
}
|
|
57119
|
-
const { title, summary } = extractTitleAndSummary(content,
|
|
58006
|
+
const { title, summary } = extractTitleAndSummary(content, path45.basename(entry));
|
|
57120
58007
|
const lineCount = content.split(`
|
|
57121
58008
|
`).length;
|
|
57122
58009
|
discoveredFiles.push({
|
|
@@ -57142,7 +58029,7 @@ async function scanDocIndex(directory) {
|
|
|
57142
58029
|
files: discoveredFiles
|
|
57143
58030
|
};
|
|
57144
58031
|
try {
|
|
57145
|
-
await
|
|
58032
|
+
await mkdir6(path45.dirname(manifestPath), { recursive: true });
|
|
57146
58033
|
await writeFile5(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
57147
58034
|
} catch {}
|
|
57148
58035
|
return { manifest, cached: false };
|
|
@@ -57192,7 +58079,7 @@ function extractConstraintsFromContent(content) {
|
|
|
57192
58079
|
return constraints;
|
|
57193
58080
|
}
|
|
57194
58081
|
async function extractDocConstraints(directory, taskFiles, taskDescription) {
|
|
57195
|
-
const manifestPath =
|
|
58082
|
+
const manifestPath = path45.join(directory, ".swarm", "doc-manifest.json");
|
|
57196
58083
|
let manifest;
|
|
57197
58084
|
try {
|
|
57198
58085
|
const content = await readFile6(manifestPath, "utf-8");
|
|
@@ -57218,7 +58105,7 @@ async function extractDocConstraints(directory, taskFiles, taskDescription) {
|
|
|
57218
58105
|
}
|
|
57219
58106
|
let fullContent;
|
|
57220
58107
|
try {
|
|
57221
|
-
fullContent = await readFile6(
|
|
58108
|
+
fullContent = await readFile6(path45.join(directory, docFile.path), "utf-8");
|
|
57222
58109
|
} catch {
|
|
57223
58110
|
skippedCount++;
|
|
57224
58111
|
continue;
|
|
@@ -57241,7 +58128,7 @@ async function extractDocConstraints(directory, taskFiles, taskDescription) {
|
|
|
57241
58128
|
tier: "swarm",
|
|
57242
58129
|
lesson: constraint,
|
|
57243
58130
|
category: "architecture",
|
|
57244
|
-
tags: ["doc-scan",
|
|
58131
|
+
tags: ["doc-scan", path45.basename(docFile.path)],
|
|
57245
58132
|
scope: "global",
|
|
57246
58133
|
confidence: 0.5,
|
|
57247
58134
|
status: "candidate",
|
|
@@ -57287,9 +58174,9 @@ var doc_scan = createSwarmTool({
|
|
|
57287
58174
|
}
|
|
57288
58175
|
} catch {}
|
|
57289
58176
|
if (force) {
|
|
57290
|
-
const manifestPath =
|
|
58177
|
+
const manifestPath = path45.join(directory, ".swarm", "doc-manifest.json");
|
|
57291
58178
|
try {
|
|
57292
|
-
|
|
58179
|
+
fs34.unlinkSync(manifestPath);
|
|
57293
58180
|
} catch {}
|
|
57294
58181
|
}
|
|
57295
58182
|
const { manifest, cached: cached3 } = await scanDocIndex(directory);
|
|
@@ -57514,8 +58401,8 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
57514
58401
|
// src/tools/evidence-check.ts
|
|
57515
58402
|
init_dist();
|
|
57516
58403
|
init_create_tool();
|
|
57517
|
-
import * as
|
|
57518
|
-
import * as
|
|
58404
|
+
import * as fs35 from "fs";
|
|
58405
|
+
import * as path46 from "path";
|
|
57519
58406
|
var MAX_FILE_SIZE_BYTES3 = 1024 * 1024;
|
|
57520
58407
|
var MAX_EVIDENCE_FILES = 1000;
|
|
57521
58408
|
var EVIDENCE_DIR2 = ".swarm/evidence";
|
|
@@ -57545,9 +58432,9 @@ function validateRequiredTypes(input) {
|
|
|
57545
58432
|
return null;
|
|
57546
58433
|
}
|
|
57547
58434
|
function isPathWithinSwarm2(filePath, cwd) {
|
|
57548
|
-
const normalizedCwd =
|
|
57549
|
-
const swarmPath =
|
|
57550
|
-
const normalizedPath =
|
|
58435
|
+
const normalizedCwd = path46.resolve(cwd);
|
|
58436
|
+
const swarmPath = path46.join(normalizedCwd, ".swarm");
|
|
58437
|
+
const normalizedPath = path46.resolve(filePath);
|
|
57551
58438
|
return normalizedPath.startsWith(swarmPath);
|
|
57552
58439
|
}
|
|
57553
58440
|
function parseCompletedTasks(planContent) {
|
|
@@ -57563,12 +58450,12 @@ function parseCompletedTasks(planContent) {
|
|
|
57563
58450
|
}
|
|
57564
58451
|
function readEvidenceFiles(evidenceDir, _cwd) {
|
|
57565
58452
|
const evidence = [];
|
|
57566
|
-
if (!
|
|
58453
|
+
if (!fs35.existsSync(evidenceDir) || !fs35.statSync(evidenceDir).isDirectory()) {
|
|
57567
58454
|
return evidence;
|
|
57568
58455
|
}
|
|
57569
58456
|
let files;
|
|
57570
58457
|
try {
|
|
57571
|
-
files =
|
|
58458
|
+
files = fs35.readdirSync(evidenceDir);
|
|
57572
58459
|
} catch {
|
|
57573
58460
|
return evidence;
|
|
57574
58461
|
}
|
|
@@ -57577,14 +58464,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
57577
58464
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
57578
58465
|
continue;
|
|
57579
58466
|
}
|
|
57580
|
-
const filePath =
|
|
58467
|
+
const filePath = path46.join(evidenceDir, filename);
|
|
57581
58468
|
try {
|
|
57582
|
-
const resolvedPath =
|
|
57583
|
-
const evidenceDirResolved =
|
|
58469
|
+
const resolvedPath = path46.resolve(filePath);
|
|
58470
|
+
const evidenceDirResolved = path46.resolve(evidenceDir);
|
|
57584
58471
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
57585
58472
|
continue;
|
|
57586
58473
|
}
|
|
57587
|
-
const stat2 =
|
|
58474
|
+
const stat2 = fs35.lstatSync(filePath);
|
|
57588
58475
|
if (!stat2.isFile()) {
|
|
57589
58476
|
continue;
|
|
57590
58477
|
}
|
|
@@ -57593,7 +58480,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
57593
58480
|
}
|
|
57594
58481
|
let fileStat;
|
|
57595
58482
|
try {
|
|
57596
|
-
fileStat =
|
|
58483
|
+
fileStat = fs35.statSync(filePath);
|
|
57597
58484
|
if (fileStat.size > MAX_FILE_SIZE_BYTES3) {
|
|
57598
58485
|
continue;
|
|
57599
58486
|
}
|
|
@@ -57602,7 +58489,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
57602
58489
|
}
|
|
57603
58490
|
let content;
|
|
57604
58491
|
try {
|
|
57605
|
-
content =
|
|
58492
|
+
content = fs35.readFileSync(filePath, "utf-8");
|
|
57606
58493
|
} catch {
|
|
57607
58494
|
continue;
|
|
57608
58495
|
}
|
|
@@ -57698,7 +58585,7 @@ var evidence_check = createSwarmTool({
|
|
|
57698
58585
|
return JSON.stringify(errorResult, null, 2);
|
|
57699
58586
|
}
|
|
57700
58587
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
|
|
57701
|
-
const planPath =
|
|
58588
|
+
const planPath = path46.join(cwd, PLAN_FILE);
|
|
57702
58589
|
if (!isPathWithinSwarm2(planPath, cwd)) {
|
|
57703
58590
|
const errorResult = {
|
|
57704
58591
|
error: "plan file path validation failed",
|
|
@@ -57712,7 +58599,7 @@ var evidence_check = createSwarmTool({
|
|
|
57712
58599
|
}
|
|
57713
58600
|
let planContent;
|
|
57714
58601
|
try {
|
|
57715
|
-
planContent =
|
|
58602
|
+
planContent = fs35.readFileSync(planPath, "utf-8");
|
|
57716
58603
|
} catch {
|
|
57717
58604
|
const result2 = {
|
|
57718
58605
|
message: "No completed tasks found in plan.",
|
|
@@ -57730,7 +58617,7 @@ var evidence_check = createSwarmTool({
|
|
|
57730
58617
|
};
|
|
57731
58618
|
return JSON.stringify(result2, null, 2);
|
|
57732
58619
|
}
|
|
57733
|
-
const evidenceDir =
|
|
58620
|
+
const evidenceDir = path46.join(cwd, EVIDENCE_DIR2);
|
|
57734
58621
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
57735
58622
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
57736
58623
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -57747,8 +58634,8 @@ var evidence_check = createSwarmTool({
|
|
|
57747
58634
|
// src/tools/file-extractor.ts
|
|
57748
58635
|
init_tool();
|
|
57749
58636
|
init_create_tool();
|
|
57750
|
-
import * as
|
|
57751
|
-
import * as
|
|
58637
|
+
import * as fs36 from "fs";
|
|
58638
|
+
import * as path47 from "path";
|
|
57752
58639
|
var EXT_MAP = {
|
|
57753
58640
|
python: ".py",
|
|
57754
58641
|
py: ".py",
|
|
@@ -57810,8 +58697,8 @@ var extract_code_blocks = createSwarmTool({
|
|
|
57810
58697
|
execute: async (args2, directory) => {
|
|
57811
58698
|
const { content, output_dir, prefix } = args2;
|
|
57812
58699
|
const targetDir = output_dir || directory;
|
|
57813
|
-
if (!
|
|
57814
|
-
|
|
58700
|
+
if (!fs36.existsSync(targetDir)) {
|
|
58701
|
+
fs36.mkdirSync(targetDir, { recursive: true });
|
|
57815
58702
|
}
|
|
57816
58703
|
if (!content) {
|
|
57817
58704
|
return "Error: content is required";
|
|
@@ -57829,16 +58716,16 @@ var extract_code_blocks = createSwarmTool({
|
|
|
57829
58716
|
if (prefix) {
|
|
57830
58717
|
filename = `${prefix}_${filename}`;
|
|
57831
58718
|
}
|
|
57832
|
-
let filepath =
|
|
57833
|
-
const base =
|
|
57834
|
-
const ext =
|
|
58719
|
+
let filepath = path47.join(targetDir, filename);
|
|
58720
|
+
const base = path47.basename(filepath, path47.extname(filepath));
|
|
58721
|
+
const ext = path47.extname(filepath);
|
|
57835
58722
|
let counter = 1;
|
|
57836
|
-
while (
|
|
57837
|
-
filepath =
|
|
58723
|
+
while (fs36.existsSync(filepath)) {
|
|
58724
|
+
filepath = path47.join(targetDir, `${base}_${counter}${ext}`);
|
|
57838
58725
|
counter++;
|
|
57839
58726
|
}
|
|
57840
58727
|
try {
|
|
57841
|
-
|
|
58728
|
+
fs36.writeFileSync(filepath, code.trim(), "utf-8");
|
|
57842
58729
|
savedFiles.push(filepath);
|
|
57843
58730
|
} catch (error93) {
|
|
57844
58731
|
errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
@@ -57954,8 +58841,8 @@ var gitingest = createSwarmTool({
|
|
|
57954
58841
|
// src/tools/imports.ts
|
|
57955
58842
|
init_dist();
|
|
57956
58843
|
init_create_tool();
|
|
57957
|
-
import * as
|
|
57958
|
-
import * as
|
|
58844
|
+
import * as fs37 from "fs";
|
|
58845
|
+
import * as path48 from "path";
|
|
57959
58846
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
57960
58847
|
var MAX_SYMBOL_LENGTH = 256;
|
|
57961
58848
|
var MAX_FILE_SIZE_BYTES4 = 1024 * 1024;
|
|
@@ -58009,7 +58896,7 @@ function validateSymbolInput(symbol3) {
|
|
|
58009
58896
|
return null;
|
|
58010
58897
|
}
|
|
58011
58898
|
function isBinaryFile2(filePath, buffer) {
|
|
58012
|
-
const ext =
|
|
58899
|
+
const ext = path48.extname(filePath).toLowerCase();
|
|
58013
58900
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
58014
58901
|
return false;
|
|
58015
58902
|
}
|
|
@@ -58033,15 +58920,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
58033
58920
|
const imports = [];
|
|
58034
58921
|
let _resolvedTarget;
|
|
58035
58922
|
try {
|
|
58036
|
-
_resolvedTarget =
|
|
58923
|
+
_resolvedTarget = path48.resolve(targetFile);
|
|
58037
58924
|
} catch {
|
|
58038
58925
|
_resolvedTarget = targetFile;
|
|
58039
58926
|
}
|
|
58040
|
-
const targetBasename =
|
|
58927
|
+
const targetBasename = path48.basename(targetFile, path48.extname(targetFile));
|
|
58041
58928
|
const targetWithExt = targetFile;
|
|
58042
58929
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
58043
|
-
const normalizedTargetWithExt =
|
|
58044
|
-
const normalizedTargetWithoutExt =
|
|
58930
|
+
const normalizedTargetWithExt = path48.normalize(targetWithExt).replace(/\\/g, "/");
|
|
58931
|
+
const normalizedTargetWithoutExt = path48.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
58045
58932
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
58046
58933
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
58047
58934
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -58064,9 +58951,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
58064
58951
|
}
|
|
58065
58952
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
58066
58953
|
let isMatch = false;
|
|
58067
|
-
const _targetDir =
|
|
58068
|
-
const targetExt =
|
|
58069
|
-
const targetBasenameNoExt =
|
|
58954
|
+
const _targetDir = path48.dirname(targetFile);
|
|
58955
|
+
const targetExt = path48.extname(targetFile);
|
|
58956
|
+
const targetBasenameNoExt = path48.basename(targetFile, targetExt);
|
|
58070
58957
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
58071
58958
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
58072
58959
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -58123,7 +59010,7 @@ var SKIP_DIRECTORIES3 = new Set([
|
|
|
58123
59010
|
function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
|
|
58124
59011
|
let entries;
|
|
58125
59012
|
try {
|
|
58126
|
-
entries =
|
|
59013
|
+
entries = fs37.readdirSync(dir);
|
|
58127
59014
|
} catch (e) {
|
|
58128
59015
|
stats.fileErrors.push({
|
|
58129
59016
|
path: dir,
|
|
@@ -58134,13 +59021,13 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
|
|
|
58134
59021
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
58135
59022
|
for (const entry of entries) {
|
|
58136
59023
|
if (SKIP_DIRECTORIES3.has(entry)) {
|
|
58137
|
-
stats.skippedDirs.push(
|
|
59024
|
+
stats.skippedDirs.push(path48.join(dir, entry));
|
|
58138
59025
|
continue;
|
|
58139
59026
|
}
|
|
58140
|
-
const fullPath =
|
|
59027
|
+
const fullPath = path48.join(dir, entry);
|
|
58141
59028
|
let stat2;
|
|
58142
59029
|
try {
|
|
58143
|
-
stat2 =
|
|
59030
|
+
stat2 = fs37.statSync(fullPath);
|
|
58144
59031
|
} catch (e) {
|
|
58145
59032
|
stats.fileErrors.push({
|
|
58146
59033
|
path: fullPath,
|
|
@@ -58151,7 +59038,7 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
|
|
|
58151
59038
|
if (stat2.isDirectory()) {
|
|
58152
59039
|
findSourceFiles(fullPath, files, stats);
|
|
58153
59040
|
} else if (stat2.isFile()) {
|
|
58154
|
-
const ext =
|
|
59041
|
+
const ext = path48.extname(fullPath).toLowerCase();
|
|
58155
59042
|
if (SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
58156
59043
|
files.push(fullPath);
|
|
58157
59044
|
}
|
|
@@ -58208,8 +59095,8 @@ var imports = createSwarmTool({
|
|
|
58208
59095
|
return JSON.stringify(errorResult, null, 2);
|
|
58209
59096
|
}
|
|
58210
59097
|
try {
|
|
58211
|
-
const targetFile =
|
|
58212
|
-
if (!
|
|
59098
|
+
const targetFile = path48.resolve(file3);
|
|
59099
|
+
if (!fs37.existsSync(targetFile)) {
|
|
58213
59100
|
const errorResult = {
|
|
58214
59101
|
error: `target file not found: ${file3}`,
|
|
58215
59102
|
target: file3,
|
|
@@ -58219,7 +59106,7 @@ var imports = createSwarmTool({
|
|
|
58219
59106
|
};
|
|
58220
59107
|
return JSON.stringify(errorResult, null, 2);
|
|
58221
59108
|
}
|
|
58222
|
-
const targetStat =
|
|
59109
|
+
const targetStat = fs37.statSync(targetFile);
|
|
58223
59110
|
if (!targetStat.isFile()) {
|
|
58224
59111
|
const errorResult = {
|
|
58225
59112
|
error: "target must be a file, not a directory",
|
|
@@ -58230,7 +59117,7 @@ var imports = createSwarmTool({
|
|
|
58230
59117
|
};
|
|
58231
59118
|
return JSON.stringify(errorResult, null, 2);
|
|
58232
59119
|
}
|
|
58233
|
-
const baseDir =
|
|
59120
|
+
const baseDir = path48.dirname(targetFile);
|
|
58234
59121
|
const scanStats = {
|
|
58235
59122
|
skippedDirs: [],
|
|
58236
59123
|
skippedFiles: 0,
|
|
@@ -58245,12 +59132,12 @@ var imports = createSwarmTool({
|
|
|
58245
59132
|
if (consumers.length >= MAX_CONSUMERS)
|
|
58246
59133
|
break;
|
|
58247
59134
|
try {
|
|
58248
|
-
const stat2 =
|
|
59135
|
+
const stat2 = fs37.statSync(filePath);
|
|
58249
59136
|
if (stat2.size > MAX_FILE_SIZE_BYTES4) {
|
|
58250
59137
|
skippedFileCount++;
|
|
58251
59138
|
continue;
|
|
58252
59139
|
}
|
|
58253
|
-
const buffer =
|
|
59140
|
+
const buffer = fs37.readFileSync(filePath);
|
|
58254
59141
|
if (isBinaryFile2(filePath, buffer)) {
|
|
58255
59142
|
skippedFileCount++;
|
|
58256
59143
|
continue;
|
|
@@ -58805,8 +59692,8 @@ init_dist();
|
|
|
58805
59692
|
init_config();
|
|
58806
59693
|
init_schema();
|
|
58807
59694
|
init_manager();
|
|
58808
|
-
import * as
|
|
58809
|
-
import * as
|
|
59695
|
+
import * as fs38 from "fs";
|
|
59696
|
+
import * as path49 from "path";
|
|
58810
59697
|
init_utils2();
|
|
58811
59698
|
init_telemetry();
|
|
58812
59699
|
init_create_tool();
|
|
@@ -59026,11 +59913,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
59026
59913
|
safeWarn(`[phase_complete] Completion verify error (non-blocking):`, completionError);
|
|
59027
59914
|
}
|
|
59028
59915
|
try {
|
|
59029
|
-
const driftEvidencePath =
|
|
59916
|
+
const driftEvidencePath = path49.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
|
|
59030
59917
|
let driftVerdictFound = false;
|
|
59031
59918
|
let driftVerdictApproved = false;
|
|
59032
59919
|
try {
|
|
59033
|
-
const driftEvidenceContent =
|
|
59920
|
+
const driftEvidenceContent = fs38.readFileSync(driftEvidencePath, "utf-8");
|
|
59034
59921
|
const driftEvidence = JSON.parse(driftEvidenceContent);
|
|
59035
59922
|
const entries = driftEvidence.entries ?? [];
|
|
59036
59923
|
for (const entry of entries) {
|
|
@@ -59060,14 +59947,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
59060
59947
|
driftVerdictFound = false;
|
|
59061
59948
|
}
|
|
59062
59949
|
if (!driftVerdictFound) {
|
|
59063
|
-
const specPath =
|
|
59064
|
-
const specExists =
|
|
59950
|
+
const specPath = path49.join(dir, ".swarm", "spec.md");
|
|
59951
|
+
const specExists = fs38.existsSync(specPath);
|
|
59065
59952
|
if (!specExists) {
|
|
59066
59953
|
let incompleteTaskCount = 0;
|
|
59067
59954
|
let planPhaseFound = false;
|
|
59068
59955
|
try {
|
|
59069
59956
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
59070
|
-
const planRaw =
|
|
59957
|
+
const planRaw = fs38.readFileSync(planPath, "utf-8");
|
|
59071
59958
|
const plan = JSON.parse(planRaw);
|
|
59072
59959
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
59073
59960
|
if (targetPhase) {
|
|
@@ -59134,7 +60021,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
59134
60021
|
};
|
|
59135
60022
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
59136
60023
|
try {
|
|
59137
|
-
const projectName =
|
|
60024
|
+
const projectName = path49.basename(dir);
|
|
59138
60025
|
await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
|
|
59139
60026
|
} catch (error93) {
|
|
59140
60027
|
safeWarn("[phase_complete] Failed to curate lessons from retrospective:", error93);
|
|
@@ -59177,7 +60064,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
59177
60064
|
if (agentsMissing.length > 0) {
|
|
59178
60065
|
try {
|
|
59179
60066
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
59180
|
-
const planRaw =
|
|
60067
|
+
const planRaw = fs38.readFileSync(planPath, "utf-8");
|
|
59181
60068
|
const plan = JSON.parse(planRaw);
|
|
59182
60069
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
59183
60070
|
if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
|
|
@@ -59208,7 +60095,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
59208
60095
|
if (phaseCompleteConfig.regression_sweep?.enforce) {
|
|
59209
60096
|
try {
|
|
59210
60097
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
59211
|
-
const planRaw =
|
|
60098
|
+
const planRaw = fs38.readFileSync(planPath, "utf-8");
|
|
59212
60099
|
const plan = JSON.parse(planRaw);
|
|
59213
60100
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
59214
60101
|
if (targetPhase) {
|
|
@@ -59246,7 +60133,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
59246
60133
|
};
|
|
59247
60134
|
try {
|
|
59248
60135
|
const eventsPath = validateSwarmPath(dir, "events.jsonl");
|
|
59249
|
-
|
|
60136
|
+
fs38.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
59250
60137
|
`, "utf-8");
|
|
59251
60138
|
} catch (writeError) {
|
|
59252
60139
|
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -59267,12 +60154,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
59267
60154
|
}
|
|
59268
60155
|
try {
|
|
59269
60156
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
59270
|
-
const planJson =
|
|
60157
|
+
const planJson = fs38.readFileSync(planPath, "utf-8");
|
|
59271
60158
|
const plan = JSON.parse(planJson);
|
|
59272
60159
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
59273
60160
|
if (phaseObj) {
|
|
59274
60161
|
phaseObj.status = "completed";
|
|
59275
|
-
|
|
60162
|
+
fs38.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
|
|
59276
60163
|
`, "utf-8");
|
|
59277
60164
|
}
|
|
59278
60165
|
} catch (error93) {
|
|
@@ -59326,8 +60213,8 @@ init_dist();
|
|
|
59326
60213
|
init_discovery();
|
|
59327
60214
|
init_utils();
|
|
59328
60215
|
init_create_tool();
|
|
59329
|
-
import * as
|
|
59330
|
-
import * as
|
|
60216
|
+
import * as fs39 from "fs";
|
|
60217
|
+
import * as path50 from "path";
|
|
59331
60218
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
59332
60219
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
59333
60220
|
function isValidEcosystem(value) {
|
|
@@ -59345,28 +60232,28 @@ function validateArgs3(args2) {
|
|
|
59345
60232
|
function detectEcosystems(directory) {
|
|
59346
60233
|
const ecosystems = [];
|
|
59347
60234
|
const cwd = directory;
|
|
59348
|
-
if (
|
|
60235
|
+
if (fs39.existsSync(path50.join(cwd, "package.json"))) {
|
|
59349
60236
|
ecosystems.push("npm");
|
|
59350
60237
|
}
|
|
59351
|
-
if (
|
|
60238
|
+
if (fs39.existsSync(path50.join(cwd, "pyproject.toml")) || fs39.existsSync(path50.join(cwd, "requirements.txt"))) {
|
|
59352
60239
|
ecosystems.push("pip");
|
|
59353
60240
|
}
|
|
59354
|
-
if (
|
|
60241
|
+
if (fs39.existsSync(path50.join(cwd, "Cargo.toml"))) {
|
|
59355
60242
|
ecosystems.push("cargo");
|
|
59356
60243
|
}
|
|
59357
|
-
if (
|
|
60244
|
+
if (fs39.existsSync(path50.join(cwd, "go.mod"))) {
|
|
59358
60245
|
ecosystems.push("go");
|
|
59359
60246
|
}
|
|
59360
60247
|
try {
|
|
59361
|
-
const files =
|
|
60248
|
+
const files = fs39.readdirSync(cwd);
|
|
59362
60249
|
if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
59363
60250
|
ecosystems.push("dotnet");
|
|
59364
60251
|
}
|
|
59365
60252
|
} catch {}
|
|
59366
|
-
if (
|
|
60253
|
+
if (fs39.existsSync(path50.join(cwd, "Gemfile")) || fs39.existsSync(path50.join(cwd, "Gemfile.lock"))) {
|
|
59367
60254
|
ecosystems.push("ruby");
|
|
59368
60255
|
}
|
|
59369
|
-
if (
|
|
60256
|
+
if (fs39.existsSync(path50.join(cwd, "pubspec.yaml"))) {
|
|
59370
60257
|
ecosystems.push("dart");
|
|
59371
60258
|
}
|
|
59372
60259
|
return ecosystems;
|
|
@@ -60366,47 +61253,6 @@ var pkg_audit = createSwarmTool({
|
|
|
60366
61253
|
});
|
|
60367
61254
|
// src/tools/placeholder-scan.ts
|
|
60368
61255
|
init_manager();
|
|
60369
|
-
|
|
60370
|
-
// src/lang/registry.ts
|
|
60371
|
-
init_runtime();
|
|
60372
|
-
var languageDefinitions = [
|
|
60373
|
-
{
|
|
60374
|
-
id: "javascript",
|
|
60375
|
-
extensions: [".js", ".jsx"],
|
|
60376
|
-
commentNodes: ["comment", "line_comment", "block_comment"]
|
|
60377
|
-
},
|
|
60378
|
-
{
|
|
60379
|
-
id: "typescript",
|
|
60380
|
-
extensions: [".ts", ".tsx"],
|
|
60381
|
-
commentNodes: ["comment", "line_comment", "block_comment"]
|
|
60382
|
-
},
|
|
60383
|
-
{
|
|
60384
|
-
id: "python",
|
|
60385
|
-
extensions: [".py"],
|
|
60386
|
-
commentNodes: ["comment"]
|
|
60387
|
-
},
|
|
60388
|
-
{
|
|
60389
|
-
id: "go",
|
|
60390
|
-
extensions: [".go"],
|
|
60391
|
-
commentNodes: ["comment"]
|
|
60392
|
-
},
|
|
60393
|
-
{
|
|
60394
|
-
id: "rust",
|
|
60395
|
-
extensions: [".rs"],
|
|
60396
|
-
commentNodes: ["line_comment", "block_comment"]
|
|
60397
|
-
}
|
|
60398
|
-
];
|
|
60399
|
-
var extensionMap = new Map;
|
|
60400
|
-
for (const definition of languageDefinitions) {
|
|
60401
|
-
for (const extension of definition.extensions) {
|
|
60402
|
-
extensionMap.set(extension, definition);
|
|
60403
|
-
}
|
|
60404
|
-
}
|
|
60405
|
-
function getLanguageForExtension(extension) {
|
|
60406
|
-
return extensionMap.get(extension.toLowerCase());
|
|
60407
|
-
}
|
|
60408
|
-
|
|
60409
|
-
// src/tools/placeholder-scan.ts
|
|
60410
61256
|
init_utils();
|
|
60411
61257
|
var MAX_FILE_SIZE = 1024 * 1024;
|
|
60412
61258
|
var SUPPORTED_PARSER_EXTENSIONS = new Set([
|
|
@@ -60428,8 +61274,8 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
|
|
|
60428
61274
|
]);
|
|
60429
61275
|
// src/tools/pre-check-batch.ts
|
|
60430
61276
|
init_dist();
|
|
60431
|
-
import * as
|
|
60432
|
-
import * as
|
|
61277
|
+
import * as fs42 from "fs";
|
|
61278
|
+
import * as path53 from "path";
|
|
60433
61279
|
|
|
60434
61280
|
// node_modules/yocto-queue/index.js
|
|
60435
61281
|
class Node2 {
|
|
@@ -60597,8 +61443,8 @@ init_lint();
|
|
|
60597
61443
|
init_manager();
|
|
60598
61444
|
|
|
60599
61445
|
// src/quality/metrics.ts
|
|
60600
|
-
import * as
|
|
60601
|
-
import * as
|
|
61446
|
+
import * as fs40 from "fs";
|
|
61447
|
+
import * as path51 from "path";
|
|
60602
61448
|
var MAX_FILE_SIZE_BYTES5 = 256 * 1024;
|
|
60603
61449
|
var MIN_DUPLICATION_LINES = 10;
|
|
60604
61450
|
function estimateCyclomaticComplexity(content) {
|
|
@@ -60636,11 +61482,11 @@ function estimateCyclomaticComplexity(content) {
|
|
|
60636
61482
|
}
|
|
60637
61483
|
function getComplexityForFile2(filePath) {
|
|
60638
61484
|
try {
|
|
60639
|
-
const stat2 =
|
|
61485
|
+
const stat2 = fs40.statSync(filePath);
|
|
60640
61486
|
if (stat2.size > MAX_FILE_SIZE_BYTES5) {
|
|
60641
61487
|
return null;
|
|
60642
61488
|
}
|
|
60643
|
-
const content =
|
|
61489
|
+
const content = fs40.readFileSync(filePath, "utf-8");
|
|
60644
61490
|
return estimateCyclomaticComplexity(content);
|
|
60645
61491
|
} catch {
|
|
60646
61492
|
return null;
|
|
@@ -60650,8 +61496,8 @@ async function computeComplexityDelta(files, workingDir) {
|
|
|
60650
61496
|
let totalComplexity = 0;
|
|
60651
61497
|
const analyzedFiles = [];
|
|
60652
61498
|
for (const file3 of files) {
|
|
60653
|
-
const fullPath =
|
|
60654
|
-
if (!
|
|
61499
|
+
const fullPath = path51.isAbsolute(file3) ? file3 : path51.join(workingDir, file3);
|
|
61500
|
+
if (!fs40.existsSync(fullPath)) {
|
|
60655
61501
|
continue;
|
|
60656
61502
|
}
|
|
60657
61503
|
const complexity = getComplexityForFile2(fullPath);
|
|
@@ -60772,8 +61618,8 @@ function countGoExports(content) {
|
|
|
60772
61618
|
}
|
|
60773
61619
|
function getExportCountForFile(filePath) {
|
|
60774
61620
|
try {
|
|
60775
|
-
const content =
|
|
60776
|
-
const ext =
|
|
61621
|
+
const content = fs40.readFileSync(filePath, "utf-8");
|
|
61622
|
+
const ext = path51.extname(filePath).toLowerCase();
|
|
60777
61623
|
switch (ext) {
|
|
60778
61624
|
case ".ts":
|
|
60779
61625
|
case ".tsx":
|
|
@@ -60799,8 +61645,8 @@ async function computePublicApiDelta(files, workingDir) {
|
|
|
60799
61645
|
let totalExports = 0;
|
|
60800
61646
|
const analyzedFiles = [];
|
|
60801
61647
|
for (const file3 of files) {
|
|
60802
|
-
const fullPath =
|
|
60803
|
-
if (!
|
|
61648
|
+
const fullPath = path51.isAbsolute(file3) ? file3 : path51.join(workingDir, file3);
|
|
61649
|
+
if (!fs40.existsSync(fullPath)) {
|
|
60804
61650
|
continue;
|
|
60805
61651
|
}
|
|
60806
61652
|
const exports = getExportCountForFile(fullPath);
|
|
@@ -60833,16 +61679,16 @@ async function computeDuplicationRatio(files, workingDir) {
|
|
|
60833
61679
|
let duplicateLines = 0;
|
|
60834
61680
|
const analyzedFiles = [];
|
|
60835
61681
|
for (const file3 of files) {
|
|
60836
|
-
const fullPath =
|
|
60837
|
-
if (!
|
|
61682
|
+
const fullPath = path51.isAbsolute(file3) ? file3 : path51.join(workingDir, file3);
|
|
61683
|
+
if (!fs40.existsSync(fullPath)) {
|
|
60838
61684
|
continue;
|
|
60839
61685
|
}
|
|
60840
61686
|
try {
|
|
60841
|
-
const stat2 =
|
|
61687
|
+
const stat2 = fs40.statSync(fullPath);
|
|
60842
61688
|
if (stat2.size > MAX_FILE_SIZE_BYTES5) {
|
|
60843
61689
|
continue;
|
|
60844
61690
|
}
|
|
60845
|
-
const content =
|
|
61691
|
+
const content = fs40.readFileSync(fullPath, "utf-8");
|
|
60846
61692
|
const lines = content.split(`
|
|
60847
61693
|
`).filter((line) => line.trim().length > 0);
|
|
60848
61694
|
if (lines.length < MIN_DUPLICATION_LINES) {
|
|
@@ -60866,8 +61712,8 @@ function countCodeLines(content) {
|
|
|
60866
61712
|
return lines.length;
|
|
60867
61713
|
}
|
|
60868
61714
|
function isTestFile(filePath) {
|
|
60869
|
-
const basename9 =
|
|
60870
|
-
const _ext =
|
|
61715
|
+
const basename9 = path51.basename(filePath);
|
|
61716
|
+
const _ext = path51.extname(filePath).toLowerCase();
|
|
60871
61717
|
const testPatterns = [
|
|
60872
61718
|
".test.",
|
|
60873
61719
|
".spec.",
|
|
@@ -60948,8 +61794,8 @@ function matchGlobSegment(globSegments, pathSegments) {
|
|
|
60948
61794
|
}
|
|
60949
61795
|
return gIndex === globSegments.length && pIndex === pathSegments.length;
|
|
60950
61796
|
}
|
|
60951
|
-
function matchesGlobSegment(
|
|
60952
|
-
const normalizedPath =
|
|
61797
|
+
function matchesGlobSegment(path52, glob) {
|
|
61798
|
+
const normalizedPath = path52.replace(/\\/g, "/");
|
|
60953
61799
|
const normalizedGlob = glob.replace(/\\/g, "/");
|
|
60954
61800
|
if (normalizedPath.includes("//")) {
|
|
60955
61801
|
return false;
|
|
@@ -60980,8 +61826,8 @@ function simpleGlobToRegex2(glob) {
|
|
|
60980
61826
|
function hasGlobstar(glob) {
|
|
60981
61827
|
return glob.includes("**");
|
|
60982
61828
|
}
|
|
60983
|
-
function globMatches(
|
|
60984
|
-
const normalizedPath =
|
|
61829
|
+
function globMatches(path52, glob) {
|
|
61830
|
+
const normalizedPath = path52.replace(/\\/g, "/");
|
|
60985
61831
|
if (!glob || glob === "") {
|
|
60986
61832
|
if (normalizedPath.includes("//")) {
|
|
60987
61833
|
return false;
|
|
@@ -61017,31 +61863,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
|
|
|
61017
61863
|
async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
61018
61864
|
let testLines = 0;
|
|
61019
61865
|
let codeLines = 0;
|
|
61020
|
-
const srcDir =
|
|
61021
|
-
if (
|
|
61866
|
+
const srcDir = path51.join(workingDir, "src");
|
|
61867
|
+
if (fs40.existsSync(srcDir)) {
|
|
61022
61868
|
await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
61023
61869
|
codeLines += lines;
|
|
61024
61870
|
});
|
|
61025
61871
|
}
|
|
61026
61872
|
const possibleSrcDirs = ["lib", "app", "source", "core"];
|
|
61027
61873
|
for (const dir of possibleSrcDirs) {
|
|
61028
|
-
const dirPath =
|
|
61029
|
-
if (
|
|
61874
|
+
const dirPath = path51.join(workingDir, dir);
|
|
61875
|
+
if (fs40.existsSync(dirPath)) {
|
|
61030
61876
|
await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
61031
61877
|
codeLines += lines;
|
|
61032
61878
|
});
|
|
61033
61879
|
}
|
|
61034
61880
|
}
|
|
61035
|
-
const testsDir =
|
|
61036
|
-
if (
|
|
61881
|
+
const testsDir = path51.join(workingDir, "tests");
|
|
61882
|
+
if (fs40.existsSync(testsDir)) {
|
|
61037
61883
|
await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
61038
61884
|
testLines += lines;
|
|
61039
61885
|
});
|
|
61040
61886
|
}
|
|
61041
61887
|
const possibleTestDirs = ["test", "__tests__", "specs"];
|
|
61042
61888
|
for (const dir of possibleTestDirs) {
|
|
61043
|
-
const dirPath =
|
|
61044
|
-
if (
|
|
61889
|
+
const dirPath = path51.join(workingDir, dir);
|
|
61890
|
+
if (fs40.existsSync(dirPath) && dirPath !== testsDir) {
|
|
61045
61891
|
await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
61046
61892
|
testLines += lines;
|
|
61047
61893
|
});
|
|
@@ -61053,9 +61899,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
61053
61899
|
}
|
|
61054
61900
|
async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
|
|
61055
61901
|
try {
|
|
61056
|
-
const entries =
|
|
61902
|
+
const entries = fs40.readdirSync(dirPath, { withFileTypes: true });
|
|
61057
61903
|
for (const entry of entries) {
|
|
61058
|
-
const fullPath =
|
|
61904
|
+
const fullPath = path51.join(dirPath, entry.name);
|
|
61059
61905
|
if (entry.isDirectory()) {
|
|
61060
61906
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
|
|
61061
61907
|
continue;
|
|
@@ -61063,7 +61909,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
61063
61909
|
await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
|
|
61064
61910
|
} else if (entry.isFile()) {
|
|
61065
61911
|
const relativePath = fullPath.replace(`${dirPath}/`, "");
|
|
61066
|
-
const ext =
|
|
61912
|
+
const ext = path51.extname(entry.name).toLowerCase();
|
|
61067
61913
|
const validExts = [
|
|
61068
61914
|
".ts",
|
|
61069
61915
|
".tsx",
|
|
@@ -61099,7 +61945,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
61099
61945
|
continue;
|
|
61100
61946
|
}
|
|
61101
61947
|
try {
|
|
61102
|
-
const content =
|
|
61948
|
+
const content = fs40.readFileSync(fullPath, "utf-8");
|
|
61103
61949
|
const lines = countCodeLines(content);
|
|
61104
61950
|
callback(lines);
|
|
61105
61951
|
} catch {}
|
|
@@ -61313,9 +62159,9 @@ async function qualityBudget(input, directory) {
|
|
|
61313
62159
|
init_dist();
|
|
61314
62160
|
init_manager();
|
|
61315
62161
|
init_detector();
|
|
61316
|
-
import * as
|
|
61317
|
-
import * as
|
|
61318
|
-
import { extname as
|
|
62162
|
+
import * as fs41 from "fs";
|
|
62163
|
+
import * as path52 from "path";
|
|
62164
|
+
import { extname as extname10 } from "path";
|
|
61319
62165
|
|
|
61320
62166
|
// src/sast/rules/c.ts
|
|
61321
62167
|
var cRules = [
|
|
@@ -62181,17 +63027,17 @@ var SEVERITY_ORDER = {
|
|
|
62181
63027
|
};
|
|
62182
63028
|
function shouldSkipFile(filePath) {
|
|
62183
63029
|
try {
|
|
62184
|
-
const stats =
|
|
63030
|
+
const stats = fs41.statSync(filePath);
|
|
62185
63031
|
if (stats.size > MAX_FILE_SIZE_BYTES6) {
|
|
62186
63032
|
return { skip: true, reason: "file too large" };
|
|
62187
63033
|
}
|
|
62188
63034
|
if (stats.size === 0) {
|
|
62189
63035
|
return { skip: true, reason: "empty file" };
|
|
62190
63036
|
}
|
|
62191
|
-
const fd =
|
|
63037
|
+
const fd = fs41.openSync(filePath, "r");
|
|
62192
63038
|
const buffer = Buffer.alloc(8192);
|
|
62193
|
-
const bytesRead =
|
|
62194
|
-
|
|
63039
|
+
const bytesRead = fs41.readSync(fd, buffer, 0, 8192, 0);
|
|
63040
|
+
fs41.closeSync(fd);
|
|
62195
63041
|
if (bytesRead > 0) {
|
|
62196
63042
|
let nullCount = 0;
|
|
62197
63043
|
for (let i2 = 0;i2 < bytesRead; i2++) {
|
|
@@ -62230,7 +63076,7 @@ function countBySeverity(findings) {
|
|
|
62230
63076
|
}
|
|
62231
63077
|
function scanFileWithTierA(filePath, language) {
|
|
62232
63078
|
try {
|
|
62233
|
-
const content =
|
|
63079
|
+
const content = fs41.readFileSync(filePath, "utf-8");
|
|
62234
63080
|
const findings = executeRulesSync(filePath, content, language);
|
|
62235
63081
|
return findings.map((f) => ({
|
|
62236
63082
|
rule_id: f.rule_id,
|
|
@@ -62277,8 +63123,8 @@ async function sastScan(input, directory, config3) {
|
|
|
62277
63123
|
_filesSkipped++;
|
|
62278
63124
|
continue;
|
|
62279
63125
|
}
|
|
62280
|
-
const resolvedPath =
|
|
62281
|
-
if (!
|
|
63126
|
+
const resolvedPath = path52.isAbsolute(filePath) ? filePath : path52.resolve(directory, filePath);
|
|
63127
|
+
if (!fs41.existsSync(resolvedPath)) {
|
|
62282
63128
|
_filesSkipped++;
|
|
62283
63129
|
continue;
|
|
62284
63130
|
}
|
|
@@ -62287,7 +63133,7 @@ async function sastScan(input, directory, config3) {
|
|
|
62287
63133
|
_filesSkipped++;
|
|
62288
63134
|
continue;
|
|
62289
63135
|
}
|
|
62290
|
-
const ext =
|
|
63136
|
+
const ext = extname10(resolvedPath).toLowerCase();
|
|
62291
63137
|
const profile = getProfileForFile(resolvedPath);
|
|
62292
63138
|
const langDef = getLanguageForExtension(ext);
|
|
62293
63139
|
if (!profile && !langDef) {
|
|
@@ -62476,18 +63322,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
62476
63322
|
let resolved;
|
|
62477
63323
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
62478
63324
|
if (isWinAbs) {
|
|
62479
|
-
resolved =
|
|
62480
|
-
} else if (
|
|
62481
|
-
resolved =
|
|
63325
|
+
resolved = path53.win32.resolve(inputPath);
|
|
63326
|
+
} else if (path53.isAbsolute(inputPath)) {
|
|
63327
|
+
resolved = path53.resolve(inputPath);
|
|
62482
63328
|
} else {
|
|
62483
|
-
resolved =
|
|
63329
|
+
resolved = path53.resolve(baseDir, inputPath);
|
|
62484
63330
|
}
|
|
62485
|
-
const workspaceResolved =
|
|
63331
|
+
const workspaceResolved = path53.resolve(workspaceDir);
|
|
62486
63332
|
let relative6;
|
|
62487
63333
|
if (isWinAbs) {
|
|
62488
|
-
relative6 =
|
|
63334
|
+
relative6 = path53.win32.relative(workspaceResolved, resolved);
|
|
62489
63335
|
} else {
|
|
62490
|
-
relative6 =
|
|
63336
|
+
relative6 = path53.relative(workspaceResolved, resolved);
|
|
62491
63337
|
}
|
|
62492
63338
|
if (relative6.startsWith("..")) {
|
|
62493
63339
|
return "path traversal detected";
|
|
@@ -62548,13 +63394,13 @@ async function runLintWrapped(files, directory, _config) {
|
|
|
62548
63394
|
}
|
|
62549
63395
|
async function runLintOnFiles(linter, files, workspaceDir) {
|
|
62550
63396
|
const isWindows = process.platform === "win32";
|
|
62551
|
-
const binDir =
|
|
63397
|
+
const binDir = path53.join(workspaceDir, "node_modules", ".bin");
|
|
62552
63398
|
const validatedFiles = [];
|
|
62553
63399
|
for (const file3 of files) {
|
|
62554
63400
|
if (typeof file3 !== "string") {
|
|
62555
63401
|
continue;
|
|
62556
63402
|
}
|
|
62557
|
-
const resolvedPath =
|
|
63403
|
+
const resolvedPath = path53.resolve(file3);
|
|
62558
63404
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
62559
63405
|
if (validationError) {
|
|
62560
63406
|
continue;
|
|
@@ -62572,10 +63418,10 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
62572
63418
|
}
|
|
62573
63419
|
let command;
|
|
62574
63420
|
if (linter === "biome") {
|
|
62575
|
-
const biomeBin = isWindows ?
|
|
63421
|
+
const biomeBin = isWindows ? path53.join(binDir, "biome.EXE") : path53.join(binDir, "biome");
|
|
62576
63422
|
command = [biomeBin, "check", ...validatedFiles];
|
|
62577
63423
|
} else {
|
|
62578
|
-
const eslintBin = isWindows ?
|
|
63424
|
+
const eslintBin = isWindows ? path53.join(binDir, "eslint.cmd") : path53.join(binDir, "eslint");
|
|
62579
63425
|
command = [eslintBin, ...validatedFiles];
|
|
62580
63426
|
}
|
|
62581
63427
|
try {
|
|
@@ -62712,7 +63558,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
62712
63558
|
skippedFiles++;
|
|
62713
63559
|
continue;
|
|
62714
63560
|
}
|
|
62715
|
-
const resolvedPath =
|
|
63561
|
+
const resolvedPath = path53.resolve(file3);
|
|
62716
63562
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
62717
63563
|
if (validationError) {
|
|
62718
63564
|
skippedFiles++;
|
|
@@ -62730,14 +63576,14 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
62730
63576
|
};
|
|
62731
63577
|
}
|
|
62732
63578
|
for (const file3 of validatedFiles) {
|
|
62733
|
-
const ext =
|
|
63579
|
+
const ext = path53.extname(file3).toLowerCase();
|
|
62734
63580
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
62735
63581
|
skippedFiles++;
|
|
62736
63582
|
continue;
|
|
62737
63583
|
}
|
|
62738
63584
|
let stat2;
|
|
62739
63585
|
try {
|
|
62740
|
-
stat2 =
|
|
63586
|
+
stat2 = fs42.statSync(file3);
|
|
62741
63587
|
} catch {
|
|
62742
63588
|
skippedFiles++;
|
|
62743
63589
|
continue;
|
|
@@ -62748,7 +63594,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
62748
63594
|
}
|
|
62749
63595
|
let content;
|
|
62750
63596
|
try {
|
|
62751
|
-
const buffer =
|
|
63597
|
+
const buffer = fs42.readFileSync(file3);
|
|
62752
63598
|
if (buffer.includes(0)) {
|
|
62753
63599
|
skippedFiles++;
|
|
62754
63600
|
continue;
|
|
@@ -62889,7 +63735,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
|
|
|
62889
63735
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
62890
63736
|
continue;
|
|
62891
63737
|
}
|
|
62892
|
-
changedFiles.push(
|
|
63738
|
+
changedFiles.push(path53.resolve(directory, file3));
|
|
62893
63739
|
}
|
|
62894
63740
|
if (changedFiles.length === 0) {
|
|
62895
63741
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -63060,7 +63906,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
63060
63906
|
};
|
|
63061
63907
|
return JSON.stringify(errorResult, null, 2);
|
|
63062
63908
|
}
|
|
63063
|
-
const resolvedDirectory =
|
|
63909
|
+
const resolvedDirectory = path53.resolve(typedArgs.directory);
|
|
63064
63910
|
const workspaceAnchor = resolvedDirectory;
|
|
63065
63911
|
const dirError = validateDirectory3(resolvedDirectory, workspaceAnchor);
|
|
63066
63912
|
if (dirError) {
|
|
@@ -63166,10 +64012,72 @@ ${paginatedContent}`;
|
|
|
63166
64012
|
});
|
|
63167
64013
|
// src/tools/save-plan.ts
|
|
63168
64014
|
init_tool();
|
|
64015
|
+
import * as fs44 from "fs";
|
|
64016
|
+
import * as path55 from "path";
|
|
64017
|
+
|
|
64018
|
+
// src/parallel/file-locks.ts
|
|
64019
|
+
import * as fs43 from "fs";
|
|
64020
|
+
import * as path54 from "path";
|
|
64021
|
+
var LOCKS_DIR = ".swarm/locks";
|
|
64022
|
+
var LOCK_TIMEOUT_MS = 5 * 60 * 1000;
|
|
64023
|
+
function getLockFilePath(directory, filePath) {
|
|
64024
|
+
if (filePath.includes("..")) {
|
|
64025
|
+
throw new Error("Invalid file path: path traversal not allowed");
|
|
64026
|
+
}
|
|
64027
|
+
const hash3 = Buffer.from(filePath).toString("base64").replace(/[/+=]/g, "_");
|
|
64028
|
+
return path54.join(directory, LOCKS_DIR, `${hash3}.lock`);
|
|
64029
|
+
}
|
|
64030
|
+
function tryAcquireLock(directory, filePath, agent, taskId) {
|
|
64031
|
+
const lockPath = getLockFilePath(directory, filePath);
|
|
64032
|
+
const locksDir = path54.dirname(lockPath);
|
|
64033
|
+
if (!fs43.existsSync(locksDir)) {
|
|
64034
|
+
fs43.mkdirSync(locksDir, { recursive: true });
|
|
64035
|
+
}
|
|
64036
|
+
if (fs43.existsSync(lockPath)) {
|
|
64037
|
+
try {
|
|
64038
|
+
const existingLock = JSON.parse(fs43.readFileSync(lockPath, "utf-8"));
|
|
64039
|
+
if (Date.now() > existingLock.expiresAt) {
|
|
64040
|
+
fs43.unlinkSync(lockPath);
|
|
64041
|
+
} else {
|
|
64042
|
+
return { acquired: false, existing: existingLock };
|
|
64043
|
+
}
|
|
64044
|
+
} catch {
|
|
64045
|
+
fs43.unlinkSync(lockPath);
|
|
64046
|
+
}
|
|
64047
|
+
}
|
|
64048
|
+
const lock = {
|
|
64049
|
+
filePath,
|
|
64050
|
+
agent,
|
|
64051
|
+
taskId,
|
|
64052
|
+
timestamp: new Date().toISOString(),
|
|
64053
|
+
expiresAt: Date.now() + LOCK_TIMEOUT_MS
|
|
64054
|
+
};
|
|
64055
|
+
const tempPath = `${lockPath}.tmp`;
|
|
64056
|
+
fs43.writeFileSync(tempPath, JSON.stringify(lock, null, 2), "utf-8");
|
|
64057
|
+
fs43.renameSync(tempPath, lockPath);
|
|
64058
|
+
return { acquired: true, lock };
|
|
64059
|
+
}
|
|
64060
|
+
function releaseLock(directory, filePath, taskId) {
|
|
64061
|
+
const lockPath = getLockFilePath(directory, filePath);
|
|
64062
|
+
if (!fs43.existsSync(lockPath)) {
|
|
64063
|
+
return true;
|
|
64064
|
+
}
|
|
64065
|
+
try {
|
|
64066
|
+
const lock = JSON.parse(fs43.readFileSync(lockPath, "utf-8"));
|
|
64067
|
+
if (lock.taskId === taskId) {
|
|
64068
|
+
fs43.unlinkSync(lockPath);
|
|
64069
|
+
return true;
|
|
64070
|
+
}
|
|
64071
|
+
return false;
|
|
64072
|
+
} catch {
|
|
64073
|
+
fs43.unlinkSync(lockPath);
|
|
64074
|
+
return true;
|
|
64075
|
+
}
|
|
64076
|
+
}
|
|
64077
|
+
|
|
64078
|
+
// src/tools/save-plan.ts
|
|
63169
64079
|
init_manager2();
|
|
63170
64080
|
init_create_tool();
|
|
63171
|
-
import * as fs42 from "fs";
|
|
63172
|
-
import * as path53 from "path";
|
|
63173
64081
|
function detectPlaceholderContent(args2) {
|
|
63174
64082
|
const issues = [];
|
|
63175
64083
|
const placeholderPattern = /^\[\w[\w\s]*\]$/;
|
|
@@ -63270,25 +64178,42 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
63270
64178
|
};
|
|
63271
64179
|
const tasksCount = plan.phases.reduce((acc, phase) => acc + phase.tasks.length, 0);
|
|
63272
64180
|
const dir = targetWorkspace;
|
|
64181
|
+
const lockTaskId = `save-plan-${Date.now()}`;
|
|
64182
|
+
const planFilePath = "plan.json";
|
|
63273
64183
|
try {
|
|
63274
|
-
|
|
64184
|
+
const lockResult = tryAcquireLock(dir, planFilePath, "architect", lockTaskId);
|
|
64185
|
+
if (!lockResult.acquired) {
|
|
64186
|
+
return {
|
|
64187
|
+
success: false,
|
|
64188
|
+
message: `Plan write blocked: file is locked by ${lockResult.existing?.agent ?? "another agent"} (task: ${lockResult.existing?.taskId ?? "unknown"})`,
|
|
64189
|
+
errors: [
|
|
64190
|
+
"Concurrent plan write detected \u2014 retry after the current write completes"
|
|
64191
|
+
],
|
|
64192
|
+
recovery_guidance: "Wait a moment and retry save_plan. The lock will expire automatically if the holding agent fails."
|
|
64193
|
+
};
|
|
64194
|
+
}
|
|
63275
64195
|
try {
|
|
63276
|
-
|
|
63277
|
-
|
|
63278
|
-
|
|
63279
|
-
|
|
64196
|
+
await savePlan(dir, plan);
|
|
64197
|
+
try {
|
|
64198
|
+
const markerPath = path55.join(dir, ".swarm", ".plan-write-marker");
|
|
64199
|
+
const marker = JSON.stringify({
|
|
64200
|
+
source: "save_plan",
|
|
64201
|
+
timestamp: new Date().toISOString(),
|
|
64202
|
+
phases_count: plan.phases.length,
|
|
64203
|
+
tasks_count: tasksCount
|
|
64204
|
+
});
|
|
64205
|
+
await fs44.promises.writeFile(markerPath, marker, "utf8");
|
|
64206
|
+
} catch {}
|
|
64207
|
+
return {
|
|
64208
|
+
success: true,
|
|
64209
|
+
message: "Plan saved successfully",
|
|
64210
|
+
plan_path: path55.join(dir, ".swarm", "plan.json"),
|
|
63280
64211
|
phases_count: plan.phases.length,
|
|
63281
64212
|
tasks_count: tasksCount
|
|
63282
|
-
}
|
|
63283
|
-
|
|
63284
|
-
|
|
63285
|
-
|
|
63286
|
-
success: true,
|
|
63287
|
-
message: "Plan saved successfully",
|
|
63288
|
-
plan_path: path53.join(dir, ".swarm", "plan.json"),
|
|
63289
|
-
phases_count: plan.phases.length,
|
|
63290
|
-
tasks_count: tasksCount
|
|
63291
|
-
};
|
|
64213
|
+
};
|
|
64214
|
+
} finally {
|
|
64215
|
+
releaseLock(dir, planFilePath, lockTaskId);
|
|
64216
|
+
}
|
|
63292
64217
|
} catch (error93) {
|
|
63293
64218
|
return {
|
|
63294
64219
|
success: false,
|
|
@@ -63323,8 +64248,8 @@ var save_plan = createSwarmTool({
|
|
|
63323
64248
|
// src/tools/sbom-generate.ts
|
|
63324
64249
|
init_dist();
|
|
63325
64250
|
init_manager();
|
|
63326
|
-
import * as
|
|
63327
|
-
import * as
|
|
64251
|
+
import * as fs45 from "fs";
|
|
64252
|
+
import * as path56 from "path";
|
|
63328
64253
|
|
|
63329
64254
|
// src/sbom/detectors/index.ts
|
|
63330
64255
|
init_utils();
|
|
@@ -64170,9 +65095,9 @@ function findManifestFiles(rootDir) {
|
|
|
64170
65095
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
64171
65096
|
function searchDir(dir) {
|
|
64172
65097
|
try {
|
|
64173
|
-
const entries =
|
|
65098
|
+
const entries = fs45.readdirSync(dir, { withFileTypes: true });
|
|
64174
65099
|
for (const entry of entries) {
|
|
64175
|
-
const fullPath =
|
|
65100
|
+
const fullPath = path56.join(dir, entry.name);
|
|
64176
65101
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
64177
65102
|
continue;
|
|
64178
65103
|
}
|
|
@@ -64181,7 +65106,7 @@ function findManifestFiles(rootDir) {
|
|
|
64181
65106
|
} else if (entry.isFile()) {
|
|
64182
65107
|
for (const pattern of patterns) {
|
|
64183
65108
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
64184
|
-
manifestFiles.push(
|
|
65109
|
+
manifestFiles.push(path56.relative(rootDir, fullPath));
|
|
64185
65110
|
break;
|
|
64186
65111
|
}
|
|
64187
65112
|
}
|
|
@@ -64197,13 +65122,13 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
64197
65122
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
64198
65123
|
for (const dir of directories) {
|
|
64199
65124
|
try {
|
|
64200
|
-
const entries =
|
|
65125
|
+
const entries = fs45.readdirSync(dir, { withFileTypes: true });
|
|
64201
65126
|
for (const entry of entries) {
|
|
64202
|
-
const fullPath =
|
|
65127
|
+
const fullPath = path56.join(dir, entry.name);
|
|
64203
65128
|
if (entry.isFile()) {
|
|
64204
65129
|
for (const pattern of patterns) {
|
|
64205
65130
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
64206
|
-
found.push(
|
|
65131
|
+
found.push(path56.relative(workingDir, fullPath));
|
|
64207
65132
|
break;
|
|
64208
65133
|
}
|
|
64209
65134
|
}
|
|
@@ -64216,11 +65141,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
64216
65141
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
64217
65142
|
const dirs = new Set;
|
|
64218
65143
|
for (const file3 of changedFiles) {
|
|
64219
|
-
let currentDir =
|
|
65144
|
+
let currentDir = path56.dirname(file3);
|
|
64220
65145
|
while (true) {
|
|
64221
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
64222
|
-
dirs.add(
|
|
64223
|
-
const parent =
|
|
65146
|
+
if (currentDir && currentDir !== "." && currentDir !== path56.sep) {
|
|
65147
|
+
dirs.add(path56.join(workingDir, currentDir));
|
|
65148
|
+
const parent = path56.dirname(currentDir);
|
|
64224
65149
|
if (parent === currentDir)
|
|
64225
65150
|
break;
|
|
64226
65151
|
currentDir = parent;
|
|
@@ -64234,7 +65159,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
64234
65159
|
}
|
|
64235
65160
|
function ensureOutputDir(outputDir) {
|
|
64236
65161
|
try {
|
|
64237
|
-
|
|
65162
|
+
fs45.mkdirSync(outputDir, { recursive: true });
|
|
64238
65163
|
} catch (error93) {
|
|
64239
65164
|
if (!error93 || error93.code !== "EEXIST") {
|
|
64240
65165
|
throw error93;
|
|
@@ -64304,7 +65229,7 @@ var sbom_generate = createSwarmTool({
|
|
|
64304
65229
|
const changedFiles = obj.changed_files;
|
|
64305
65230
|
const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
|
|
64306
65231
|
const workingDir = directory;
|
|
64307
|
-
const outputDir =
|
|
65232
|
+
const outputDir = path56.isAbsolute(relativeOutputDir) ? relativeOutputDir : path56.join(workingDir, relativeOutputDir);
|
|
64308
65233
|
let manifestFiles = [];
|
|
64309
65234
|
if (scope === "all") {
|
|
64310
65235
|
manifestFiles = findManifestFiles(workingDir);
|
|
@@ -64327,11 +65252,11 @@ var sbom_generate = createSwarmTool({
|
|
|
64327
65252
|
const processedFiles = [];
|
|
64328
65253
|
for (const manifestFile of manifestFiles) {
|
|
64329
65254
|
try {
|
|
64330
|
-
const fullPath =
|
|
64331
|
-
if (!
|
|
65255
|
+
const fullPath = path56.isAbsolute(manifestFile) ? manifestFile : path56.join(workingDir, manifestFile);
|
|
65256
|
+
if (!fs45.existsSync(fullPath)) {
|
|
64332
65257
|
continue;
|
|
64333
65258
|
}
|
|
64334
|
-
const content =
|
|
65259
|
+
const content = fs45.readFileSync(fullPath, "utf-8");
|
|
64335
65260
|
const components = detectComponents(manifestFile, content);
|
|
64336
65261
|
processedFiles.push(manifestFile);
|
|
64337
65262
|
if (components.length > 0) {
|
|
@@ -64344,8 +65269,8 @@ var sbom_generate = createSwarmTool({
|
|
|
64344
65269
|
const bom = generateCycloneDX(allComponents);
|
|
64345
65270
|
const bomJson = serializeCycloneDX(bom);
|
|
64346
65271
|
const filename = generateSbomFilename();
|
|
64347
|
-
const outputPath =
|
|
64348
|
-
|
|
65272
|
+
const outputPath = path56.join(outputDir, filename);
|
|
65273
|
+
fs45.writeFileSync(outputPath, bomJson, "utf-8");
|
|
64349
65274
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
64350
65275
|
try {
|
|
64351
65276
|
const timestamp = new Date().toISOString();
|
|
@@ -64387,8 +65312,8 @@ var sbom_generate = createSwarmTool({
|
|
|
64387
65312
|
// src/tools/schema-drift.ts
|
|
64388
65313
|
init_dist();
|
|
64389
65314
|
init_create_tool();
|
|
64390
|
-
import * as
|
|
64391
|
-
import * as
|
|
65315
|
+
import * as fs46 from "fs";
|
|
65316
|
+
import * as path57 from "path";
|
|
64392
65317
|
var SPEC_CANDIDATES = [
|
|
64393
65318
|
"openapi.json",
|
|
64394
65319
|
"openapi.yaml",
|
|
@@ -64420,28 +65345,28 @@ function normalizePath2(p) {
|
|
|
64420
65345
|
}
|
|
64421
65346
|
function discoverSpecFile(cwd, specFileArg) {
|
|
64422
65347
|
if (specFileArg) {
|
|
64423
|
-
const resolvedPath =
|
|
64424
|
-
const normalizedCwd = cwd.endsWith(
|
|
65348
|
+
const resolvedPath = path57.resolve(cwd, specFileArg);
|
|
65349
|
+
const normalizedCwd = cwd.endsWith(path57.sep) ? cwd : cwd + path57.sep;
|
|
64425
65350
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
64426
65351
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
64427
65352
|
}
|
|
64428
|
-
const ext =
|
|
65353
|
+
const ext = path57.extname(resolvedPath).toLowerCase();
|
|
64429
65354
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
64430
65355
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
64431
65356
|
}
|
|
64432
|
-
const stats =
|
|
65357
|
+
const stats = fs46.statSync(resolvedPath);
|
|
64433
65358
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
64434
65359
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
64435
65360
|
}
|
|
64436
|
-
if (!
|
|
65361
|
+
if (!fs46.existsSync(resolvedPath)) {
|
|
64437
65362
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
64438
65363
|
}
|
|
64439
65364
|
return resolvedPath;
|
|
64440
65365
|
}
|
|
64441
65366
|
for (const candidate of SPEC_CANDIDATES) {
|
|
64442
|
-
const candidatePath =
|
|
64443
|
-
if (
|
|
64444
|
-
const stats =
|
|
65367
|
+
const candidatePath = path57.resolve(cwd, candidate);
|
|
65368
|
+
if (fs46.existsSync(candidatePath)) {
|
|
65369
|
+
const stats = fs46.statSync(candidatePath);
|
|
64445
65370
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
64446
65371
|
return candidatePath;
|
|
64447
65372
|
}
|
|
@@ -64450,8 +65375,8 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
64450
65375
|
return null;
|
|
64451
65376
|
}
|
|
64452
65377
|
function parseSpec(specFile) {
|
|
64453
|
-
const content =
|
|
64454
|
-
const ext =
|
|
65378
|
+
const content = fs46.readFileSync(specFile, "utf-8");
|
|
65379
|
+
const ext = path57.extname(specFile).toLowerCase();
|
|
64455
65380
|
if (ext === ".json") {
|
|
64456
65381
|
return parseJsonSpec(content);
|
|
64457
65382
|
}
|
|
@@ -64522,12 +65447,12 @@ function extractRoutes(cwd) {
|
|
|
64522
65447
|
function walkDir(dir) {
|
|
64523
65448
|
let entries;
|
|
64524
65449
|
try {
|
|
64525
|
-
entries =
|
|
65450
|
+
entries = fs46.readdirSync(dir, { withFileTypes: true });
|
|
64526
65451
|
} catch {
|
|
64527
65452
|
return;
|
|
64528
65453
|
}
|
|
64529
65454
|
for (const entry of entries) {
|
|
64530
|
-
const fullPath =
|
|
65455
|
+
const fullPath = path57.join(dir, entry.name);
|
|
64531
65456
|
if (entry.isSymbolicLink()) {
|
|
64532
65457
|
continue;
|
|
64533
65458
|
}
|
|
@@ -64537,7 +65462,7 @@ function extractRoutes(cwd) {
|
|
|
64537
65462
|
}
|
|
64538
65463
|
walkDir(fullPath);
|
|
64539
65464
|
} else if (entry.isFile()) {
|
|
64540
|
-
const ext =
|
|
65465
|
+
const ext = path57.extname(entry.name).toLowerCase();
|
|
64541
65466
|
const baseName = entry.name.toLowerCase();
|
|
64542
65467
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
64543
65468
|
continue;
|
|
@@ -64555,7 +65480,7 @@ function extractRoutes(cwd) {
|
|
|
64555
65480
|
}
|
|
64556
65481
|
function extractRoutesFromFile(filePath) {
|
|
64557
65482
|
const routes = [];
|
|
64558
|
-
const content =
|
|
65483
|
+
const content = fs46.readFileSync(filePath, "utf-8");
|
|
64559
65484
|
const lines = content.split(/\r?\n/);
|
|
64560
65485
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
64561
65486
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -64706,8 +65631,8 @@ init_secretscan();
|
|
|
64706
65631
|
// src/tools/symbols.ts
|
|
64707
65632
|
init_tool();
|
|
64708
65633
|
init_create_tool();
|
|
64709
|
-
import * as
|
|
64710
|
-
import * as
|
|
65634
|
+
import * as fs47 from "fs";
|
|
65635
|
+
import * as path58 from "path";
|
|
64711
65636
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
64712
65637
|
var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
64713
65638
|
function containsControlCharacters(str) {
|
|
@@ -64736,11 +65661,11 @@ function containsWindowsAttacks(str) {
|
|
|
64736
65661
|
}
|
|
64737
65662
|
function isPathInWorkspace(filePath, workspace) {
|
|
64738
65663
|
try {
|
|
64739
|
-
const resolvedPath =
|
|
64740
|
-
const realWorkspace =
|
|
64741
|
-
const realResolvedPath =
|
|
64742
|
-
const relativePath =
|
|
64743
|
-
if (relativePath.startsWith("..") ||
|
|
65664
|
+
const resolvedPath = path58.resolve(workspace, filePath);
|
|
65665
|
+
const realWorkspace = fs47.realpathSync(workspace);
|
|
65666
|
+
const realResolvedPath = fs47.realpathSync(resolvedPath);
|
|
65667
|
+
const relativePath = path58.relative(realWorkspace, realResolvedPath);
|
|
65668
|
+
if (relativePath.startsWith("..") || path58.isAbsolute(relativePath)) {
|
|
64744
65669
|
return false;
|
|
64745
65670
|
}
|
|
64746
65671
|
return true;
|
|
@@ -64752,17 +65677,17 @@ function validatePathForRead(filePath, workspace) {
|
|
|
64752
65677
|
return isPathInWorkspace(filePath, workspace);
|
|
64753
65678
|
}
|
|
64754
65679
|
function extractTSSymbols(filePath, cwd) {
|
|
64755
|
-
const fullPath =
|
|
65680
|
+
const fullPath = path58.join(cwd, filePath);
|
|
64756
65681
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
64757
65682
|
return [];
|
|
64758
65683
|
}
|
|
64759
65684
|
let content;
|
|
64760
65685
|
try {
|
|
64761
|
-
const stats =
|
|
65686
|
+
const stats = fs47.statSync(fullPath);
|
|
64762
65687
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
64763
65688
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
64764
65689
|
}
|
|
64765
|
-
content =
|
|
65690
|
+
content = fs47.readFileSync(fullPath, "utf-8");
|
|
64766
65691
|
} catch {
|
|
64767
65692
|
return [];
|
|
64768
65693
|
}
|
|
@@ -64904,17 +65829,17 @@ function extractTSSymbols(filePath, cwd) {
|
|
|
64904
65829
|
});
|
|
64905
65830
|
}
|
|
64906
65831
|
function extractPythonSymbols(filePath, cwd) {
|
|
64907
|
-
const fullPath =
|
|
65832
|
+
const fullPath = path58.join(cwd, filePath);
|
|
64908
65833
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
64909
65834
|
return [];
|
|
64910
65835
|
}
|
|
64911
65836
|
let content;
|
|
64912
65837
|
try {
|
|
64913
|
-
const stats =
|
|
65838
|
+
const stats = fs47.statSync(fullPath);
|
|
64914
65839
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
64915
65840
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
64916
65841
|
}
|
|
64917
|
-
content =
|
|
65842
|
+
content = fs47.readFileSync(fullPath, "utf-8");
|
|
64918
65843
|
} catch {
|
|
64919
65844
|
return [];
|
|
64920
65845
|
}
|
|
@@ -64987,7 +65912,7 @@ var symbols = createSwarmTool({
|
|
|
64987
65912
|
}, null, 2);
|
|
64988
65913
|
}
|
|
64989
65914
|
const cwd = directory;
|
|
64990
|
-
const ext =
|
|
65915
|
+
const ext = path58.extname(file3);
|
|
64991
65916
|
if (containsControlCharacters(file3)) {
|
|
64992
65917
|
return JSON.stringify({
|
|
64993
65918
|
file: file3,
|
|
@@ -65058,8 +65983,8 @@ init_test_runner();
|
|
|
65058
65983
|
init_dist();
|
|
65059
65984
|
init_utils();
|
|
65060
65985
|
init_create_tool();
|
|
65061
|
-
import * as
|
|
65062
|
-
import * as
|
|
65986
|
+
import * as fs48 from "fs";
|
|
65987
|
+
import * as path59 from "path";
|
|
65063
65988
|
var MAX_TEXT_LENGTH = 200;
|
|
65064
65989
|
var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
|
|
65065
65990
|
var SUPPORTED_EXTENSIONS2 = new Set([
|
|
@@ -65130,9 +66055,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
65130
66055
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
65131
66056
|
}
|
|
65132
66057
|
try {
|
|
65133
|
-
const resolvedPath =
|
|
65134
|
-
const normalizedCwd =
|
|
65135
|
-
const normalizedResolved =
|
|
66058
|
+
const resolvedPath = path59.resolve(paths);
|
|
66059
|
+
const normalizedCwd = path59.resolve(cwd);
|
|
66060
|
+
const normalizedResolved = path59.resolve(resolvedPath);
|
|
65136
66061
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
65137
66062
|
return {
|
|
65138
66063
|
error: "paths must be within the current working directory",
|
|
@@ -65148,13 +66073,13 @@ function validatePathsInput(paths, cwd) {
|
|
|
65148
66073
|
}
|
|
65149
66074
|
}
|
|
65150
66075
|
function isSupportedExtension(filePath) {
|
|
65151
|
-
const ext =
|
|
66076
|
+
const ext = path59.extname(filePath).toLowerCase();
|
|
65152
66077
|
return SUPPORTED_EXTENSIONS2.has(ext);
|
|
65153
66078
|
}
|
|
65154
66079
|
function findSourceFiles2(dir, files = []) {
|
|
65155
66080
|
let entries;
|
|
65156
66081
|
try {
|
|
65157
|
-
entries =
|
|
66082
|
+
entries = fs48.readdirSync(dir);
|
|
65158
66083
|
} catch {
|
|
65159
66084
|
return files;
|
|
65160
66085
|
}
|
|
@@ -65163,10 +66088,10 @@ function findSourceFiles2(dir, files = []) {
|
|
|
65163
66088
|
if (SKIP_DIRECTORIES4.has(entry)) {
|
|
65164
66089
|
continue;
|
|
65165
66090
|
}
|
|
65166
|
-
const fullPath =
|
|
66091
|
+
const fullPath = path59.join(dir, entry);
|
|
65167
66092
|
let stat2;
|
|
65168
66093
|
try {
|
|
65169
|
-
stat2 =
|
|
66094
|
+
stat2 = fs48.statSync(fullPath);
|
|
65170
66095
|
} catch {
|
|
65171
66096
|
continue;
|
|
65172
66097
|
}
|
|
@@ -65259,7 +66184,7 @@ var todo_extract = createSwarmTool({
|
|
|
65259
66184
|
return JSON.stringify(errorResult, null, 2);
|
|
65260
66185
|
}
|
|
65261
66186
|
const scanPath = resolvedPath;
|
|
65262
|
-
if (!
|
|
66187
|
+
if (!fs48.existsSync(scanPath)) {
|
|
65263
66188
|
const errorResult = {
|
|
65264
66189
|
error: `path not found: ${pathsInput}`,
|
|
65265
66190
|
total: 0,
|
|
@@ -65269,13 +66194,13 @@ var todo_extract = createSwarmTool({
|
|
|
65269
66194
|
return JSON.stringify(errorResult, null, 2);
|
|
65270
66195
|
}
|
|
65271
66196
|
const filesToScan = [];
|
|
65272
|
-
const stat2 =
|
|
66197
|
+
const stat2 = fs48.statSync(scanPath);
|
|
65273
66198
|
if (stat2.isFile()) {
|
|
65274
66199
|
if (isSupportedExtension(scanPath)) {
|
|
65275
66200
|
filesToScan.push(scanPath);
|
|
65276
66201
|
} else {
|
|
65277
66202
|
const errorResult = {
|
|
65278
|
-
error: `unsupported file extension: ${
|
|
66203
|
+
error: `unsupported file extension: ${path59.extname(scanPath)}`,
|
|
65279
66204
|
total: 0,
|
|
65280
66205
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
65281
66206
|
entries: []
|
|
@@ -65288,11 +66213,11 @@ var todo_extract = createSwarmTool({
|
|
|
65288
66213
|
const allEntries = [];
|
|
65289
66214
|
for (const filePath of filesToScan) {
|
|
65290
66215
|
try {
|
|
65291
|
-
const fileStat =
|
|
66216
|
+
const fileStat = fs48.statSync(filePath);
|
|
65292
66217
|
if (fileStat.size > MAX_FILE_SIZE_BYTES8) {
|
|
65293
66218
|
continue;
|
|
65294
66219
|
}
|
|
65295
|
-
const content =
|
|
66220
|
+
const content = fs48.readFileSync(filePath, "utf-8");
|
|
65296
66221
|
const entries = parseTodoComments(content, filePath, tagsSet);
|
|
65297
66222
|
allEntries.push(...entries);
|
|
65298
66223
|
} catch {}
|
|
@@ -65321,18 +66246,18 @@ var todo_extract = createSwarmTool({
|
|
|
65321
66246
|
init_tool();
|
|
65322
66247
|
init_schema();
|
|
65323
66248
|
init_gate_evidence();
|
|
65324
|
-
import * as
|
|
65325
|
-
import * as
|
|
66249
|
+
import * as fs50 from "fs";
|
|
66250
|
+
import * as path61 from "path";
|
|
65326
66251
|
|
|
65327
66252
|
// src/hooks/diff-scope.ts
|
|
65328
|
-
import * as
|
|
65329
|
-
import * as
|
|
66253
|
+
import * as fs49 from "fs";
|
|
66254
|
+
import * as path60 from "path";
|
|
65330
66255
|
function getDeclaredScope(taskId, directory) {
|
|
65331
66256
|
try {
|
|
65332
|
-
const planPath =
|
|
65333
|
-
if (!
|
|
66257
|
+
const planPath = path60.join(directory, ".swarm", "plan.json");
|
|
66258
|
+
if (!fs49.existsSync(planPath))
|
|
65334
66259
|
return null;
|
|
65335
|
-
const raw =
|
|
66260
|
+
const raw = fs49.readFileSync(planPath, "utf-8");
|
|
65336
66261
|
const plan = JSON.parse(raw);
|
|
65337
66262
|
for (const phase of plan.phases ?? []) {
|
|
65338
66263
|
for (const task of phase.tasks ?? []) {
|
|
@@ -65445,7 +66370,7 @@ var TIER_3_PATTERNS = [
|
|
|
65445
66370
|
];
|
|
65446
66371
|
function matchesTier3Pattern(files) {
|
|
65447
66372
|
for (const file3 of files) {
|
|
65448
|
-
const fileName =
|
|
66373
|
+
const fileName = path61.basename(file3);
|
|
65449
66374
|
for (const pattern of TIER_3_PATTERNS) {
|
|
65450
66375
|
if (pattern.test(fileName)) {
|
|
65451
66376
|
return true;
|
|
@@ -65459,8 +66384,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
65459
66384
|
if (hasActiveTurboMode()) {
|
|
65460
66385
|
const resolvedDir2 = workingDirectory;
|
|
65461
66386
|
try {
|
|
65462
|
-
const planPath =
|
|
65463
|
-
const planRaw =
|
|
66387
|
+
const planPath = path61.join(resolvedDir2, ".swarm", "plan.json");
|
|
66388
|
+
const planRaw = fs50.readFileSync(planPath, "utf-8");
|
|
65464
66389
|
const plan = JSON.parse(planRaw);
|
|
65465
66390
|
for (const planPhase of plan.phases ?? []) {
|
|
65466
66391
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -65526,8 +66451,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
65526
66451
|
}
|
|
65527
66452
|
try {
|
|
65528
66453
|
const resolvedDir2 = workingDirectory;
|
|
65529
|
-
const planPath =
|
|
65530
|
-
const planRaw =
|
|
66454
|
+
const planPath = path61.join(resolvedDir2, ".swarm", "plan.json");
|
|
66455
|
+
const planRaw = fs50.readFileSync(planPath, "utf-8");
|
|
65531
66456
|
const plan = JSON.parse(planRaw);
|
|
65532
66457
|
for (const planPhase of plan.phases ?? []) {
|
|
65533
66458
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -65709,8 +66634,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
65709
66634
|
};
|
|
65710
66635
|
}
|
|
65711
66636
|
}
|
|
65712
|
-
normalizedDir =
|
|
65713
|
-
const pathParts = normalizedDir.split(
|
|
66637
|
+
normalizedDir = path61.normalize(args2.working_directory);
|
|
66638
|
+
const pathParts = normalizedDir.split(path61.sep);
|
|
65714
66639
|
if (pathParts.includes("..")) {
|
|
65715
66640
|
return {
|
|
65716
66641
|
success: false,
|
|
@@ -65720,11 +66645,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
65720
66645
|
]
|
|
65721
66646
|
};
|
|
65722
66647
|
}
|
|
65723
|
-
const resolvedDir =
|
|
66648
|
+
const resolvedDir = path61.resolve(normalizedDir);
|
|
65724
66649
|
try {
|
|
65725
|
-
const realPath =
|
|
65726
|
-
const planPath =
|
|
65727
|
-
if (!
|
|
66650
|
+
const realPath = fs50.realpathSync(resolvedDir);
|
|
66651
|
+
const planPath = path61.join(realPath, ".swarm", "plan.json");
|
|
66652
|
+
if (!fs50.existsSync(planPath)) {
|
|
65728
66653
|
return {
|
|
65729
66654
|
success: false,
|
|
65730
66655
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -65945,10 +66870,11 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
65945
66870
|
let statusArtifact;
|
|
65946
66871
|
if (automationConfig.mode !== "manual") {
|
|
65947
66872
|
automationManager = createAutomationManager(automationConfig);
|
|
66873
|
+
automationManager.start();
|
|
65948
66874
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
65949
66875
|
preflightTriggerManager = new PTM(automationConfig);
|
|
65950
66876
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
65951
|
-
const swarmDir =
|
|
66877
|
+
const swarmDir = path62.resolve(ctx.directory, ".swarm");
|
|
65952
66878
|
statusArtifact = new ASA(swarmDir);
|
|
65953
66879
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
65954
66880
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|
|
@@ -65992,9 +66918,16 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
65992
66918
|
});
|
|
65993
66919
|
}
|
|
65994
66920
|
}
|
|
66921
|
+
const cleanupAutomation = () => {
|
|
66922
|
+
automationManager?.stop();
|
|
66923
|
+
};
|
|
66924
|
+
process.on("exit", cleanupAutomation);
|
|
66925
|
+
process.on("SIGINT", cleanupAutomation);
|
|
66926
|
+
process.on("SIGTERM", cleanupAutomation);
|
|
65995
66927
|
log("Automation framework initialized", {
|
|
65996
66928
|
mode: automationConfig.mode,
|
|
65997
66929
|
enabled: automationManager?.isEnabled(),
|
|
66930
|
+
running: automationManager?.isActive(),
|
|
65998
66931
|
preflightEnabled: preflightTriggerManager?.isEnabled()
|
|
65999
66932
|
});
|
|
66000
66933
|
}
|
|
@@ -66293,6 +67226,37 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
66293
67226
|
await safeHook(delegationGateHooks.toolAfter)(input, output);
|
|
66294
67227
|
if (_dbg)
|
|
66295
67228
|
console.error(`[DIAG] toolAfter delegationGate done tool=${_toolName}`);
|
|
67229
|
+
if (isTaskTool && typeof output.output === "string") {
|
|
67230
|
+
try {
|
|
67231
|
+
const adversarialMatches = detectAdversarialPatterns(output.output);
|
|
67232
|
+
if (adversarialMatches.length > 0) {
|
|
67233
|
+
const sessionId = input.sessionID;
|
|
67234
|
+
const session = swarmState.agentSessions.get(sessionId);
|
|
67235
|
+
if (session) {
|
|
67236
|
+
session.pendingAdvisoryMessages ??= [];
|
|
67237
|
+
session.pendingAdvisoryMessages.push(`ADVERSARIAL PATTERN DETECTED: ${adversarialMatches.map((p) => p.pattern).join(", ")}. Review agent output for potential prompt injection or gate bypass.`);
|
|
67238
|
+
}
|
|
67239
|
+
if ("adversarialPatternDetected" in telemetry) {
|
|
67240
|
+
telemetry.adversarialPatternDetected(input.sessionID, adversarialMatches);
|
|
67241
|
+
}
|
|
67242
|
+
}
|
|
67243
|
+
} catch {}
|
|
67244
|
+
}
|
|
67245
|
+
try {
|
|
67246
|
+
recordToolCall(normalizedTool, input.args);
|
|
67247
|
+
} catch {}
|
|
67248
|
+
try {
|
|
67249
|
+
const spiralMatch = await detectDebuggingSpiral(ctx.directory);
|
|
67250
|
+
if (spiralMatch) {
|
|
67251
|
+
const taskId = swarmState.agentSessions.get(input.sessionID)?.currentTaskId ?? "unknown";
|
|
67252
|
+
const spiralResult = await handleDebuggingSpiral(spiralMatch, taskId, ctx.directory);
|
|
67253
|
+
const session = swarmState.agentSessions.get(input.sessionID);
|
|
67254
|
+
if (session) {
|
|
67255
|
+
session.pendingAdvisoryMessages ??= [];
|
|
67256
|
+
session.pendingAdvisoryMessages.push(spiralResult.message);
|
|
67257
|
+
}
|
|
67258
|
+
}
|
|
67259
|
+
} catch {}
|
|
66296
67260
|
if (knowledgeCuratorHook)
|
|
66297
67261
|
await safeHook(knowledgeCuratorHook)(input, output);
|
|
66298
67262
|
if (hivePromoterHook)
|
|
@@ -66314,8 +67278,9 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
66314
67278
|
await slopDetectorHook.toolAfter(input, output);
|
|
66315
67279
|
if (incrementalVerifyHook)
|
|
66316
67280
|
await incrementalVerifyHook.toolAfter(input, output);
|
|
66317
|
-
|
|
66318
|
-
|
|
67281
|
+
}
|
|
67282
|
+
if (execMode !== "fast" && compactionServiceHook) {
|
|
67283
|
+
await compactionServiceHook.toolAfter(input, output);
|
|
66319
67284
|
}
|
|
66320
67285
|
const toolOutputConfig = config3.tool_output;
|
|
66321
67286
|
if (toolOutputConfig && toolOutputConfig.truncation_enabled !== false && typeof output.output === "string") {
|