opencode-swarm 6.36.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 +2 -2
- package/dist/hooks/adversarial-detector.d.ts +9 -0
- package/dist/hooks/curator.d.ts +24 -5
- package/dist/hooks/delegation-gate.d.ts +7 -0
- package/dist/hooks/phase-monitor.d.ts +2 -1
- package/dist/index.js +1418 -414
- package/dist/state.session-restart.test.d.ts +1 -1
- 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";
|
|
@@ -34195,7 +34199,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
34195
34199
|
return false;
|
|
34196
34200
|
}
|
|
34197
34201
|
function containsControlChars(str) {
|
|
34198
|
-
return /[\0\r]/.test(str);
|
|
34202
|
+
return /[\0\t\r\n]/.test(str);
|
|
34199
34203
|
}
|
|
34200
34204
|
function validateDirectoryInput(dir) {
|
|
34201
34205
|
if (!dir || dir.length === 0) {
|
|
@@ -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();
|
|
@@ -40386,7 +40471,7 @@ async function readPlanFromDisk(directory) {
|
|
|
40386
40471
|
return null;
|
|
40387
40472
|
}
|
|
40388
40473
|
}
|
|
40389
|
-
async function
|
|
40474
|
+
async function readGateEvidenceFromDisk(directory) {
|
|
40390
40475
|
const evidenceMap = new Map;
|
|
40391
40476
|
try {
|
|
40392
40477
|
const evidenceDir = path3.join(directory, ".swarm", "evidence");
|
|
@@ -40421,7 +40506,7 @@ async function buildRehydrationCache(directory) {
|
|
|
40421
40506
|
}
|
|
40422
40507
|
}
|
|
40423
40508
|
}
|
|
40424
|
-
const evidenceMap = await
|
|
40509
|
+
const evidenceMap = await readGateEvidenceFromDisk(directory);
|
|
40425
40510
|
_rehydrationCache = { planTaskStates, evidenceMap };
|
|
40426
40511
|
}
|
|
40427
40512
|
function applyRehydrationCache(session) {
|
|
@@ -40530,7 +40615,9 @@ Do not re-trigger DISCOVER or CONSULT because you noticed a project phase bounda
|
|
|
40530
40615
|
Output to .swarm/plan.md MUST use "## Phase N" headers. Do not write MODE labels into plan.md.
|
|
40531
40616
|
|
|
40532
40617
|
1. DELEGATE all coding to {{AGENT_PREFIX}}coder. You do NOT write code.
|
|
40533
|
-
|
|
40618
|
+
// IMPORTANT: This list MUST match AGENT_TOOL_MAP['architect'] in src/config/constants.ts
|
|
40619
|
+
// If you add a tool to the map, add it here. If you remove it from the map, remove it here.
|
|
40620
|
+
YOUR TOOLS: Task (delegation), checkpoint, check_gate_status, complexity_hotspots, declare_scope, detect_domains, diff, evidence_check, extract_code_blocks, gitingest, imports, knowledge_query, lint, pkg_audit, pre_check_batch, retrieve_summary, save_plan, schema_drift, secretscan, symbols, test_runner, todo_extract, update_task_status, write_retro.
|
|
40534
40621
|
CODER'S TOOLS: write, edit, patch, apply_patch, create_file, insert, replace \u2014 any tool that modifies file contents.
|
|
40535
40622
|
If a tool modifies a file, it is a CODER tool. Delegate.
|
|
40536
40623
|
2. ONE agent per message. Send, STOP, wait for response.
|
|
@@ -42364,6 +42451,82 @@ RULES:
|
|
|
42364
42451
|
- Do NOT rephrase or summarize doc content with your own words \u2014 use the actual text from the file
|
|
42365
42452
|
- Full doc content is only loaded when relevant to the current task, never preloaded
|
|
42366
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
|
+
`;
|
|
42367
42530
|
function createExplorerAgent(model, customPrompt, customAppendPrompt) {
|
|
42368
42531
|
let prompt = EXPLORER_PROMPT;
|
|
42369
42532
|
if (customPrompt) {
|
|
@@ -42388,6 +42551,26 @@ ${customAppendPrompt}`;
|
|
|
42388
42551
|
}
|
|
42389
42552
|
};
|
|
42390
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
|
+
}
|
|
42391
42574
|
|
|
42392
42575
|
// src/agents/reviewer.ts
|
|
42393
42576
|
var REVIEWER_PROMPT = `## PRESSURE IMMUNITY
|
|
@@ -44543,9 +44726,9 @@ init_schema();
|
|
|
44543
44726
|
import path15 from "path";
|
|
44544
44727
|
|
|
44545
44728
|
// src/hooks/curator.ts
|
|
44546
|
-
init_event_bus();
|
|
44547
44729
|
import * as fs9 from "fs";
|
|
44548
44730
|
import * as path13 from "path";
|
|
44731
|
+
init_event_bus();
|
|
44549
44732
|
|
|
44550
44733
|
// src/hooks/knowledge-store.ts
|
|
44551
44734
|
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
@@ -44703,6 +44886,33 @@ function inferTags(lesson) {
|
|
|
44703
44886
|
|
|
44704
44887
|
// src/hooks/curator.ts
|
|
44705
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
|
+
}
|
|
44706
44916
|
async function readCuratorSummary(directory) {
|
|
44707
44917
|
const content = await readSwarmFileAsync(directory, "curator-summary.json");
|
|
44708
44918
|
if (content === null) {
|
|
@@ -44861,7 +45071,7 @@ function checkPhaseCompliance(phaseEvents, agentsDispatched, requiredAgents, pha
|
|
|
44861
45071
|
}
|
|
44862
45072
|
return observations;
|
|
44863
45073
|
}
|
|
44864
|
-
async function runCuratorInit(directory, config3) {
|
|
45074
|
+
async function runCuratorInit(directory, config3, llmDelegate) {
|
|
44865
45075
|
try {
|
|
44866
45076
|
const priorSummary = await readCuratorSummary(directory);
|
|
44867
45077
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
@@ -44905,9 +45115,41 @@ async function runCuratorInit(directory, config3) {
|
|
|
44905
45115
|
briefingParts.push(contextMd.slice(0, maxContextChars));
|
|
44906
45116
|
}
|
|
44907
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
|
+
}
|
|
44908
45151
|
const result = {
|
|
44909
|
-
briefing:
|
|
44910
|
-
`),
|
|
45152
|
+
briefing: briefingText,
|
|
44911
45153
|
contradictions,
|
|
44912
45154
|
knowledge_entries_reviewed: allEntries.length,
|
|
44913
45155
|
prior_phases_covered: priorSummary ? priorSummary.last_phase_covered : 0
|
|
@@ -44932,7 +45174,7 @@ Could not load prior session context.`,
|
|
|
44932
45174
|
};
|
|
44933
45175
|
}
|
|
44934
45176
|
}
|
|
44935
|
-
async function runCuratorPhase(directory, phase, agentsDispatched, _config, _knowledgeConfig) {
|
|
45177
|
+
async function runCuratorPhase(directory, phase, agentsDispatched, _config, _knowledgeConfig, llmDelegate) {
|
|
44936
45178
|
try {
|
|
44937
45179
|
const priorSummary = await readCuratorSummary(directory);
|
|
44938
45180
|
const eventsJsonlContent = await readSwarmFileAsync(directory, "events.jsonl");
|
|
@@ -44965,7 +45207,40 @@ async function runCuratorPhase(directory, phase, agentsDispatched, _config, _kno
|
|
|
44965
45207
|
key_decisions: keyDecisions.slice(0, 5),
|
|
44966
45208
|
blockers_resolved: []
|
|
44967
45209
|
};
|
|
44968
|
-
|
|
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
|
+
}
|
|
44969
45244
|
const sessionId = `session-${Date.now()}`;
|
|
44970
45245
|
const now = new Date().toISOString();
|
|
44971
45246
|
let updatedSummary;
|
|
@@ -50506,6 +50781,68 @@ function maskToolOutput(msg, _threshold) {
|
|
|
50506
50781
|
init_schema();
|
|
50507
50782
|
import * as fs21 from "fs";
|
|
50508
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
|
|
50509
50846
|
init_telemetry();
|
|
50510
50847
|
|
|
50511
50848
|
// src/hooks/guardrails.ts
|
|
@@ -51144,15 +51481,19 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
|
|
|
51144
51481
|
const errorContent = output.error ?? outputStr;
|
|
51145
51482
|
if (typeof errorContent === "string" && TRANSIENT_MODEL_ERROR_PATTERN.test(errorContent) && !session.modelFallbackExhausted) {
|
|
51146
51483
|
session.model_fallback_index++;
|
|
51147
|
-
session.modelFallbackExhausted = true;
|
|
51148
51484
|
const baseAgentName = session.agentName ? session.agentName.replace(/^[^_]+[_]/, "") : "";
|
|
51149
|
-
const
|
|
51485
|
+
const swarmAgents = getSwarmAgents();
|
|
51486
|
+
const fallbackModels = swarmAgents?.[baseAgentName]?.fallback_models;
|
|
51487
|
+
session.modelFallbackExhausted = !fallbackModels || session.model_fallback_index > fallbackModels.length;
|
|
51488
|
+
const fallbackModel = resolveFallbackModel(baseAgentName, session.model_fallback_index, swarmAgents);
|
|
51150
51489
|
if (fallbackModel) {
|
|
51151
|
-
const swarmAgents = getSwarmAgents();
|
|
51152
51490
|
const primaryModel = swarmAgents?.[baseAgentName]?.model ?? "default";
|
|
51491
|
+
if (swarmAgents?.[baseAgentName]) {
|
|
51492
|
+
swarmAgents[baseAgentName].model = fallbackModel;
|
|
51493
|
+
}
|
|
51153
51494
|
telemetry.modelFallback(input.sessionID, session.agentName, primaryModel, fallbackModel, "transient_model_error");
|
|
51154
51495
|
session.pendingAdvisoryMessages ??= [];
|
|
51155
|
-
session.pendingAdvisoryMessages.push(`MODEL FALLBACK:
|
|
51496
|
+
session.pendingAdvisoryMessages.push(`MODEL FALLBACK: Applied fallback model "${fallbackModel}" (attempt ${session.model_fallback_index}). ` + `Using /swarm handoff to reset to primary model.`);
|
|
51156
51497
|
} else {
|
|
51157
51498
|
session.pendingAdvisoryMessages ??= [];
|
|
51158
51499
|
session.pendingAdvisoryMessages.push(`MODEL FALLBACK: Transient model error detected (attempt ${session.model_fallback_index}). ` + `No fallback models configured for this agent. Add "fallback_models": ["model-a", "model-b"] ` + `to the agent's config in opencode-swarm.json.`);
|
|
@@ -51558,9 +51899,55 @@ function createDelegationGateHook(config3, directory) {
|
|
|
51558
51899
|
if (!enabled) {
|
|
51559
51900
|
return {
|
|
51560
51901
|
messagesTransform: async (_input, _output) => {},
|
|
51902
|
+
toolBefore: async () => {},
|
|
51561
51903
|
toolAfter: async () => {}
|
|
51562
51904
|
};
|
|
51563
51905
|
}
|
|
51906
|
+
const toolBefore = async (input, output) => {
|
|
51907
|
+
if (!input.sessionID)
|
|
51908
|
+
return;
|
|
51909
|
+
const normalized = input.tool.replace(/^[^:]+[:.]/, "");
|
|
51910
|
+
if (normalized !== "Task" && normalized !== "task")
|
|
51911
|
+
return;
|
|
51912
|
+
const args2 = output.args;
|
|
51913
|
+
if (!args2)
|
|
51914
|
+
return;
|
|
51915
|
+
const subagentType = args2.subagent_type;
|
|
51916
|
+
if (typeof subagentType !== "string")
|
|
51917
|
+
return;
|
|
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
|
+
}
|
|
51934
|
+
if (targetAgent !== "coder")
|
|
51935
|
+
return;
|
|
51936
|
+
const session = swarmState.agentSessions.get(input.sessionID);
|
|
51937
|
+
if (!session || !session.taskWorkflowStates)
|
|
51938
|
+
return;
|
|
51939
|
+
for (const [taskId, state2] of session.taskWorkflowStates) {
|
|
51940
|
+
if (state2 !== "coder_delegated")
|
|
51941
|
+
continue;
|
|
51942
|
+
const turbo = hasActiveTurboMode(input.sessionID);
|
|
51943
|
+
if (turbo) {
|
|
51944
|
+
const isTier3 = taskId.startsWith("3.");
|
|
51945
|
+
if (!isTier3)
|
|
51946
|
+
continue;
|
|
51947
|
+
}
|
|
51948
|
+
throw new Error(`REVIEWER_GATE_VIOLATION: Cannot re-delegate to coder without reviewer delegation. ` + `Task ${taskId} state: coder_delegated. Delegate to reviewer first.`);
|
|
51949
|
+
}
|
|
51950
|
+
};
|
|
51564
51951
|
const toolAfter = async (input, _output) => {
|
|
51565
51952
|
if (!input.sessionID)
|
|
51566
51953
|
return;
|
|
@@ -51782,6 +52169,7 @@ function createDelegationGateHook(config3, directory) {
|
|
|
51782
52169
|
}
|
|
51783
52170
|
};
|
|
51784
52171
|
return {
|
|
52172
|
+
toolBefore,
|
|
51785
52173
|
messagesTransform: async (_input, output) => {
|
|
51786
52174
|
const messages = output.messages;
|
|
51787
52175
|
if (!messages || messages.length === 0)
|
|
@@ -52332,7 +52720,7 @@ init_schema();
|
|
|
52332
52720
|
init_manager();
|
|
52333
52721
|
init_detector();
|
|
52334
52722
|
init_manager2();
|
|
52335
|
-
import * as
|
|
52723
|
+
import * as fs25 from "fs";
|
|
52336
52724
|
|
|
52337
52725
|
// src/services/decision-drift-analyzer.ts
|
|
52338
52726
|
init_utils2();
|
|
@@ -52615,6 +53003,8 @@ init_utils();
|
|
|
52615
53003
|
// src/hooks/adversarial-detector.ts
|
|
52616
53004
|
init_constants();
|
|
52617
53005
|
init_schema();
|
|
53006
|
+
import * as fs24 from "fs/promises";
|
|
53007
|
+
import * as path35 from "path";
|
|
52618
53008
|
function safeGet(obj, key) {
|
|
52619
53009
|
if (!obj || !Object.hasOwn(obj, key))
|
|
52620
53010
|
return;
|
|
@@ -52646,6 +53036,248 @@ function formatAdversarialWarning(agentA, agentB, sharedModel, policy) {
|
|
|
52646
53036
|
}
|
|
52647
53037
|
return `\u26A0\uFE0F Same-model adversarial pair detected. Agent ${agentA} and checker ${agentB} both use model ${sharedModel}. Review may lack independence.`;
|
|
52648
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
|
+
}
|
|
52649
53281
|
|
|
52650
53282
|
// src/hooks/context-scoring.ts
|
|
52651
53283
|
function calculateAgeFactor(ageHours, config3) {
|
|
@@ -52991,11 +53623,11 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
52991
53623
|
if (handoffContent) {
|
|
52992
53624
|
const handoffPath = validateSwarmPath(directory, "handoff.md");
|
|
52993
53625
|
const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
|
|
52994
|
-
if (
|
|
53626
|
+
if (fs25.existsSync(consumedPath)) {
|
|
52995
53627
|
warn("Duplicate handoff detected: handoff-consumed.md already exists");
|
|
52996
|
-
|
|
53628
|
+
fs25.unlinkSync(consumedPath);
|
|
52997
53629
|
}
|
|
52998
|
-
|
|
53630
|
+
fs25.renameSync(handoffPath, consumedPath);
|
|
52999
53631
|
const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
|
|
53000
53632
|
The previous model's session ended. Here is your starting context:
|
|
53001
53633
|
|
|
@@ -53276,11 +53908,11 @@ ${budgetWarning}`);
|
|
|
53276
53908
|
if (handoffContent) {
|
|
53277
53909
|
const handoffPath = validateSwarmPath(directory, "handoff.md");
|
|
53278
53910
|
const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
|
|
53279
|
-
if (
|
|
53911
|
+
if (fs25.existsSync(consumedPath)) {
|
|
53280
53912
|
warn("Duplicate handoff detected: handoff-consumed.md already exists");
|
|
53281
|
-
|
|
53913
|
+
fs25.unlinkSync(consumedPath);
|
|
53282
53914
|
}
|
|
53283
|
-
|
|
53915
|
+
fs25.renameSync(handoffPath, consumedPath);
|
|
53284
53916
|
const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
|
|
53285
53917
|
The previous model's session ended. Here is your starting context:
|
|
53286
53918
|
|
|
@@ -54050,8 +54682,8 @@ function isReadTool(toolName) {
|
|
|
54050
54682
|
}
|
|
54051
54683
|
|
|
54052
54684
|
// src/hooks/incremental-verify.ts
|
|
54053
|
-
import * as
|
|
54054
|
-
import * as
|
|
54685
|
+
import * as fs26 from "fs";
|
|
54686
|
+
import * as path36 from "path";
|
|
54055
54687
|
|
|
54056
54688
|
// src/hooks/spawn-helper.ts
|
|
54057
54689
|
import { spawn } from "child_process";
|
|
@@ -54126,21 +54758,21 @@ function spawnAsync(command, cwd, timeoutMs) {
|
|
|
54126
54758
|
// src/hooks/incremental-verify.ts
|
|
54127
54759
|
var emittedSkipAdvisories = new Set;
|
|
54128
54760
|
function detectPackageManager(projectDir) {
|
|
54129
|
-
if (
|
|
54761
|
+
if (fs26.existsSync(path36.join(projectDir, "bun.lockb")))
|
|
54130
54762
|
return "bun";
|
|
54131
|
-
if (
|
|
54763
|
+
if (fs26.existsSync(path36.join(projectDir, "pnpm-lock.yaml")))
|
|
54132
54764
|
return "pnpm";
|
|
54133
|
-
if (
|
|
54765
|
+
if (fs26.existsSync(path36.join(projectDir, "yarn.lock")))
|
|
54134
54766
|
return "yarn";
|
|
54135
|
-
if (
|
|
54767
|
+
if (fs26.existsSync(path36.join(projectDir, "package-lock.json")))
|
|
54136
54768
|
return "npm";
|
|
54137
54769
|
return "bun";
|
|
54138
54770
|
}
|
|
54139
54771
|
function detectTypecheckCommand(projectDir) {
|
|
54140
|
-
const pkgPath =
|
|
54141
|
-
if (
|
|
54772
|
+
const pkgPath = path36.join(projectDir, "package.json");
|
|
54773
|
+
if (fs26.existsSync(pkgPath)) {
|
|
54142
54774
|
try {
|
|
54143
|
-
const pkg = JSON.parse(
|
|
54775
|
+
const pkg = JSON.parse(fs26.readFileSync(pkgPath, "utf8"));
|
|
54144
54776
|
const scripts = pkg.scripts;
|
|
54145
54777
|
if (scripts?.typecheck) {
|
|
54146
54778
|
const pm = detectPackageManager(projectDir);
|
|
@@ -54154,8 +54786,8 @@ function detectTypecheckCommand(projectDir) {
|
|
|
54154
54786
|
...pkg.dependencies,
|
|
54155
54787
|
...pkg.devDependencies
|
|
54156
54788
|
};
|
|
54157
|
-
if (!deps?.typescript && !
|
|
54158
|
-
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"));
|
|
54159
54791
|
if (hasTSMarkers) {
|
|
54160
54792
|
return { command: ["npx", "tsc", "--noEmit"], language: "typescript" };
|
|
54161
54793
|
}
|
|
@@ -54163,17 +54795,17 @@ function detectTypecheckCommand(projectDir) {
|
|
|
54163
54795
|
return null;
|
|
54164
54796
|
}
|
|
54165
54797
|
}
|
|
54166
|
-
if (
|
|
54798
|
+
if (fs26.existsSync(path36.join(projectDir, "go.mod"))) {
|
|
54167
54799
|
return { command: ["go", "vet", "./..."], language: "go" };
|
|
54168
54800
|
}
|
|
54169
|
-
if (
|
|
54801
|
+
if (fs26.existsSync(path36.join(projectDir, "Cargo.toml"))) {
|
|
54170
54802
|
return { command: ["cargo", "check"], language: "rust" };
|
|
54171
54803
|
}
|
|
54172
|
-
if (
|
|
54804
|
+
if (fs26.existsSync(path36.join(projectDir, "pyproject.toml")) || fs26.existsSync(path36.join(projectDir, "requirements.txt")) || fs26.existsSync(path36.join(projectDir, "setup.py"))) {
|
|
54173
54805
|
return { command: null, language: "python" };
|
|
54174
54806
|
}
|
|
54175
54807
|
try {
|
|
54176
|
-
const entries =
|
|
54808
|
+
const entries = fs26.readdirSync(projectDir);
|
|
54177
54809
|
if (entries.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
54178
54810
|
return {
|
|
54179
54811
|
command: ["dotnet", "build", "--no-restore"],
|
|
@@ -54243,8 +54875,8 @@ ${errorSummary}`);
|
|
|
54243
54875
|
|
|
54244
54876
|
// src/hooks/knowledge-reader.ts
|
|
54245
54877
|
import { existsSync as existsSync22 } from "fs";
|
|
54246
|
-
import { mkdir as
|
|
54247
|
-
import * as
|
|
54878
|
+
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
|
|
54879
|
+
import * as path37 from "path";
|
|
54248
54880
|
var JACCARD_THRESHOLD = 0.6;
|
|
54249
54881
|
var HIVE_TIER_BOOST = 0.05;
|
|
54250
54882
|
var SAME_PROJECT_PENALTY = -0.05;
|
|
@@ -54292,7 +54924,7 @@ function inferCategoriesFromPhase(phaseDescription) {
|
|
|
54292
54924
|
return ["process", "tooling"];
|
|
54293
54925
|
}
|
|
54294
54926
|
async function recordLessonsShown(directory, lessonIds, currentPhase) {
|
|
54295
|
-
const shownFile =
|
|
54927
|
+
const shownFile = path37.join(directory, ".swarm", ".knowledge-shown.json");
|
|
54296
54928
|
try {
|
|
54297
54929
|
let shownData = {};
|
|
54298
54930
|
if (existsSync22(shownFile)) {
|
|
@@ -54300,7 +54932,7 @@ async function recordLessonsShown(directory, lessonIds, currentPhase) {
|
|
|
54300
54932
|
shownData = JSON.parse(content);
|
|
54301
54933
|
}
|
|
54302
54934
|
shownData[currentPhase] = lessonIds;
|
|
54303
|
-
await
|
|
54935
|
+
await mkdir5(path37.dirname(shownFile), { recursive: true });
|
|
54304
54936
|
await writeFile4(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
|
|
54305
54937
|
} catch {
|
|
54306
54938
|
console.warn("[swarm] Knowledge: failed to record shown lessons");
|
|
@@ -54397,7 +55029,7 @@ async function readMergedKnowledge(directory, config3, context) {
|
|
|
54397
55029
|
return topN;
|
|
54398
55030
|
}
|
|
54399
55031
|
async function updateRetrievalOutcome(directory, phaseInfo, phaseSucceeded) {
|
|
54400
|
-
const shownFile =
|
|
55032
|
+
const shownFile = path37.join(directory, ".swarm", ".knowledge-shown.json");
|
|
54401
55033
|
try {
|
|
54402
55034
|
if (!existsSync22(shownFile)) {
|
|
54403
55035
|
return;
|
|
@@ -55032,7 +55664,7 @@ ${injectionText}`;
|
|
|
55032
55664
|
// src/hooks/scope-guard.ts
|
|
55033
55665
|
init_constants();
|
|
55034
55666
|
init_schema();
|
|
55035
|
-
import * as
|
|
55667
|
+
import * as path39 from "path";
|
|
55036
55668
|
var WRITE_TOOLS = new Set([
|
|
55037
55669
|
"write",
|
|
55038
55670
|
"edit",
|
|
@@ -55094,13 +55726,13 @@ function createScopeGuardHook(config3, directory, injectAdvisory) {
|
|
|
55094
55726
|
}
|
|
55095
55727
|
function isFileInScope(filePath, scopeEntries, directory) {
|
|
55096
55728
|
const dir = directory ?? process.cwd();
|
|
55097
|
-
const resolvedFile =
|
|
55729
|
+
const resolvedFile = path39.resolve(dir, filePath);
|
|
55098
55730
|
return scopeEntries.some((scope) => {
|
|
55099
|
-
const resolvedScope =
|
|
55731
|
+
const resolvedScope = path39.resolve(dir, scope);
|
|
55100
55732
|
if (resolvedFile === resolvedScope)
|
|
55101
55733
|
return true;
|
|
55102
|
-
const rel =
|
|
55103
|
-
return rel.length > 0 && !rel.startsWith("..") && !
|
|
55734
|
+
const rel = path39.relative(resolvedScope, resolvedFile);
|
|
55735
|
+
return rel.length > 0 && !rel.startsWith("..") && !path39.isAbsolute(rel);
|
|
55104
55736
|
});
|
|
55105
55737
|
}
|
|
55106
55738
|
|
|
@@ -55149,8 +55781,8 @@ function createSelfReviewHook(config3, injectAdvisory) {
|
|
|
55149
55781
|
}
|
|
55150
55782
|
|
|
55151
55783
|
// src/hooks/slop-detector.ts
|
|
55152
|
-
import * as
|
|
55153
|
-
import * as
|
|
55784
|
+
import * as fs28 from "fs";
|
|
55785
|
+
import * as path40 from "path";
|
|
55154
55786
|
var WRITE_EDIT_TOOLS = new Set([
|
|
55155
55787
|
"write",
|
|
55156
55788
|
"edit",
|
|
@@ -55195,12 +55827,12 @@ function checkBoilerplateExplosion(content, taskDescription, threshold) {
|
|
|
55195
55827
|
function walkFiles(dir, exts, deadline) {
|
|
55196
55828
|
const results = [];
|
|
55197
55829
|
try {
|
|
55198
|
-
for (const entry of
|
|
55830
|
+
for (const entry of fs28.readdirSync(dir, { withFileTypes: true })) {
|
|
55199
55831
|
if (deadline !== undefined && Date.now() > deadline)
|
|
55200
55832
|
break;
|
|
55201
55833
|
if (entry.isSymbolicLink())
|
|
55202
55834
|
continue;
|
|
55203
|
-
const full =
|
|
55835
|
+
const full = path40.join(dir, entry.name);
|
|
55204
55836
|
if (entry.isDirectory()) {
|
|
55205
55837
|
if (entry.name === "node_modules" || entry.name === ".git")
|
|
55206
55838
|
continue;
|
|
@@ -55215,7 +55847,7 @@ function walkFiles(dir, exts, deadline) {
|
|
|
55215
55847
|
return results;
|
|
55216
55848
|
}
|
|
55217
55849
|
function checkDeadExports(content, projectDir, startTime) {
|
|
55218
|
-
const hasPackageJson =
|
|
55850
|
+
const hasPackageJson = fs28.existsSync(path40.join(projectDir, "package.json"));
|
|
55219
55851
|
if (!hasPackageJson)
|
|
55220
55852
|
return null;
|
|
55221
55853
|
const exportMatches = content.matchAll(/^\+(?:export)\s+(?:function|class|const|type|interface)\s+(\w{3,})/gm);
|
|
@@ -55238,7 +55870,7 @@ function checkDeadExports(content, projectDir, startTime) {
|
|
|
55238
55870
|
if (found || Date.now() - startTime > 480)
|
|
55239
55871
|
break;
|
|
55240
55872
|
try {
|
|
55241
|
-
const text =
|
|
55873
|
+
const text = fs28.readFileSync(file3, "utf-8");
|
|
55242
55874
|
if (importPattern.test(text))
|
|
55243
55875
|
found = true;
|
|
55244
55876
|
importPattern.lastIndex = 0;
|
|
@@ -55371,7 +56003,7 @@ Review before proceeding.`;
|
|
|
55371
56003
|
|
|
55372
56004
|
// src/hooks/steering-consumed.ts
|
|
55373
56005
|
init_utils2();
|
|
55374
|
-
import * as
|
|
56006
|
+
import * as fs29 from "fs";
|
|
55375
56007
|
function recordSteeringConsumed(directory, directiveId) {
|
|
55376
56008
|
try {
|
|
55377
56009
|
const eventsPath = validateSwarmPath(directory, "events.jsonl");
|
|
@@ -55380,7 +56012,7 @@ function recordSteeringConsumed(directory, directiveId) {
|
|
|
55380
56012
|
directiveId,
|
|
55381
56013
|
timestamp: new Date().toISOString()
|
|
55382
56014
|
};
|
|
55383
|
-
|
|
56015
|
+
fs29.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
55384
56016
|
`, "utf-8");
|
|
55385
56017
|
} catch {}
|
|
55386
56018
|
}
|
|
@@ -55777,8 +56409,8 @@ var build_check = createSwarmTool({
|
|
|
55777
56409
|
init_dist();
|
|
55778
56410
|
init_manager();
|
|
55779
56411
|
init_create_tool();
|
|
55780
|
-
import * as
|
|
55781
|
-
import * as
|
|
56412
|
+
import * as fs30 from "fs";
|
|
56413
|
+
import * as path41 from "path";
|
|
55782
56414
|
var EVIDENCE_DIR = ".swarm/evidence";
|
|
55783
56415
|
var TASK_ID_PATTERN2 = /^\d+\.\d+(\.\d+)*$/;
|
|
55784
56416
|
function isValidTaskId3(taskId) {
|
|
@@ -55795,18 +56427,18 @@ function isValidTaskId3(taskId) {
|
|
|
55795
56427
|
return TASK_ID_PATTERN2.test(taskId);
|
|
55796
56428
|
}
|
|
55797
56429
|
function isPathWithinSwarm(filePath, workspaceRoot) {
|
|
55798
|
-
const normalizedWorkspace =
|
|
55799
|
-
const swarmPath =
|
|
55800
|
-
const normalizedPath =
|
|
56430
|
+
const normalizedWorkspace = path41.resolve(workspaceRoot);
|
|
56431
|
+
const swarmPath = path41.join(normalizedWorkspace, ".swarm", "evidence");
|
|
56432
|
+
const normalizedPath = path41.resolve(filePath);
|
|
55801
56433
|
return normalizedPath.startsWith(swarmPath);
|
|
55802
56434
|
}
|
|
55803
56435
|
function readEvidenceFile(evidencePath) {
|
|
55804
|
-
if (!
|
|
56436
|
+
if (!fs30.existsSync(evidencePath)) {
|
|
55805
56437
|
return null;
|
|
55806
56438
|
}
|
|
55807
56439
|
let content;
|
|
55808
56440
|
try {
|
|
55809
|
-
content =
|
|
56441
|
+
content = fs30.readFileSync(evidencePath, "utf-8");
|
|
55810
56442
|
} catch {
|
|
55811
56443
|
return null;
|
|
55812
56444
|
}
|
|
@@ -55860,7 +56492,7 @@ var check_gate_status = createSwarmTool({
|
|
|
55860
56492
|
};
|
|
55861
56493
|
return JSON.stringify(errorResult, null, 2);
|
|
55862
56494
|
}
|
|
55863
|
-
const evidencePath =
|
|
56495
|
+
const evidencePath = path41.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
|
|
55864
56496
|
if (!isPathWithinSwarm(evidencePath, directory)) {
|
|
55865
56497
|
const errorResult = {
|
|
55866
56498
|
taskId: taskIdInput,
|
|
@@ -55952,8 +56584,8 @@ init_checkpoint();
|
|
|
55952
56584
|
// src/tools/completion-verify.ts
|
|
55953
56585
|
init_dist();
|
|
55954
56586
|
init_utils2();
|
|
55955
|
-
import * as
|
|
55956
|
-
import * as
|
|
56587
|
+
import * as fs31 from "fs";
|
|
56588
|
+
import * as path42 from "path";
|
|
55957
56589
|
init_create_tool();
|
|
55958
56590
|
function extractMatches(regex, text) {
|
|
55959
56591
|
return Array.from(text.matchAll(regex));
|
|
@@ -56035,7 +56667,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
56035
56667
|
let plan;
|
|
56036
56668
|
try {
|
|
56037
56669
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
56038
|
-
const planRaw =
|
|
56670
|
+
const planRaw = fs31.readFileSync(planPath, "utf-8");
|
|
56039
56671
|
plan = JSON.parse(planRaw);
|
|
56040
56672
|
} catch {
|
|
56041
56673
|
const result2 = {
|
|
@@ -56086,10 +56718,10 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
56086
56718
|
let foundCount = 0;
|
|
56087
56719
|
let hasFileReadFailure = false;
|
|
56088
56720
|
for (const filePath of fileTargets) {
|
|
56089
|
-
const resolvedPath =
|
|
56721
|
+
const resolvedPath = path42.resolve(directory, filePath);
|
|
56090
56722
|
let fileContent;
|
|
56091
56723
|
try {
|
|
56092
|
-
fileContent =
|
|
56724
|
+
fileContent = fs31.readFileSync(resolvedPath, "utf-8");
|
|
56093
56725
|
} catch {
|
|
56094
56726
|
blockedTasks.push({
|
|
56095
56727
|
task_id: task.id,
|
|
@@ -56131,9 +56763,9 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
56131
56763
|
blockedTasks
|
|
56132
56764
|
};
|
|
56133
56765
|
try {
|
|
56134
|
-
const evidenceDir =
|
|
56135
|
-
const evidencePath =
|
|
56136
|
-
|
|
56766
|
+
const evidenceDir = path42.join(directory, ".swarm", "evidence", `${phase}`);
|
|
56767
|
+
const evidencePath = path42.join(evidenceDir, "completion-verify.json");
|
|
56768
|
+
fs31.mkdirSync(evidenceDir, { recursive: true });
|
|
56137
56769
|
const evidenceBundle = {
|
|
56138
56770
|
schema_version: "1.0.0",
|
|
56139
56771
|
task_id: "completion-verify",
|
|
@@ -56154,7 +56786,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
56154
56786
|
}
|
|
56155
56787
|
]
|
|
56156
56788
|
};
|
|
56157
|
-
|
|
56789
|
+
fs31.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
|
|
56158
56790
|
} catch {}
|
|
56159
56791
|
return JSON.stringify(result, null, 2);
|
|
56160
56792
|
}
|
|
@@ -56194,8 +56826,8 @@ var completion_verify = createSwarmTool({
|
|
|
56194
56826
|
// src/tools/complexity-hotspots.ts
|
|
56195
56827
|
init_dist();
|
|
56196
56828
|
init_create_tool();
|
|
56197
|
-
import * as
|
|
56198
|
-
import * as
|
|
56829
|
+
import * as fs32 from "fs";
|
|
56830
|
+
import * as path43 from "path";
|
|
56199
56831
|
var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
|
|
56200
56832
|
var DEFAULT_DAYS = 90;
|
|
56201
56833
|
var DEFAULT_TOP_N = 20;
|
|
@@ -56324,11 +56956,11 @@ function estimateComplexity(content) {
|
|
|
56324
56956
|
}
|
|
56325
56957
|
function getComplexityForFile(filePath) {
|
|
56326
56958
|
try {
|
|
56327
|
-
const stat2 =
|
|
56959
|
+
const stat2 = fs32.statSync(filePath);
|
|
56328
56960
|
if (stat2.size > MAX_FILE_SIZE_BYTES2) {
|
|
56329
56961
|
return null;
|
|
56330
56962
|
}
|
|
56331
|
-
const content =
|
|
56963
|
+
const content = fs32.readFileSync(filePath, "utf-8");
|
|
56332
56964
|
return estimateComplexity(content);
|
|
56333
56965
|
} catch {
|
|
56334
56966
|
return null;
|
|
@@ -56339,7 +56971,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
56339
56971
|
const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
|
|
56340
56972
|
const filteredChurn = new Map;
|
|
56341
56973
|
for (const [file3, count] of churnMap) {
|
|
56342
|
-
const ext =
|
|
56974
|
+
const ext = path43.extname(file3).toLowerCase();
|
|
56343
56975
|
if (extSet.has(ext)) {
|
|
56344
56976
|
filteredChurn.set(file3, count);
|
|
56345
56977
|
}
|
|
@@ -56349,8 +56981,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
56349
56981
|
let analyzedFiles = 0;
|
|
56350
56982
|
for (const [file3, churnCount] of filteredChurn) {
|
|
56351
56983
|
let fullPath = file3;
|
|
56352
|
-
if (!
|
|
56353
|
-
fullPath =
|
|
56984
|
+
if (!fs32.existsSync(fullPath)) {
|
|
56985
|
+
fullPath = path43.join(cwd, file3);
|
|
56354
56986
|
}
|
|
56355
56987
|
const complexity = getComplexityForFile(fullPath);
|
|
56356
56988
|
if (complexity !== null) {
|
|
@@ -56558,8 +57190,8 @@ var curator_analyze = createSwarmTool({
|
|
|
56558
57190
|
});
|
|
56559
57191
|
// src/tools/declare-scope.ts
|
|
56560
57192
|
init_tool();
|
|
56561
|
-
import * as
|
|
56562
|
-
import * as
|
|
57193
|
+
import * as fs33 from "fs";
|
|
57194
|
+
import * as path44 from "path";
|
|
56563
57195
|
init_create_tool();
|
|
56564
57196
|
function validateTaskIdFormat(taskId) {
|
|
56565
57197
|
const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
|
|
@@ -56638,8 +57270,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
56638
57270
|
};
|
|
56639
57271
|
}
|
|
56640
57272
|
}
|
|
56641
|
-
normalizedDir =
|
|
56642
|
-
const pathParts = normalizedDir.split(
|
|
57273
|
+
normalizedDir = path44.normalize(args2.working_directory);
|
|
57274
|
+
const pathParts = normalizedDir.split(path44.sep);
|
|
56643
57275
|
if (pathParts.includes("..")) {
|
|
56644
57276
|
return {
|
|
56645
57277
|
success: false,
|
|
@@ -56649,11 +57281,11 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
56649
57281
|
]
|
|
56650
57282
|
};
|
|
56651
57283
|
}
|
|
56652
|
-
const resolvedDir =
|
|
57284
|
+
const resolvedDir = path44.resolve(normalizedDir);
|
|
56653
57285
|
try {
|
|
56654
|
-
const realPath =
|
|
56655
|
-
const planPath2 =
|
|
56656
|
-
if (!
|
|
57286
|
+
const realPath = fs33.realpathSync(resolvedDir);
|
|
57287
|
+
const planPath2 = path44.join(realPath, ".swarm", "plan.json");
|
|
57288
|
+
if (!fs33.existsSync(planPath2)) {
|
|
56657
57289
|
return {
|
|
56658
57290
|
success: false,
|
|
56659
57291
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -56676,8 +57308,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
56676
57308
|
console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
|
|
56677
57309
|
}
|
|
56678
57310
|
const directory = normalizedDir || fallbackDir;
|
|
56679
|
-
const planPath =
|
|
56680
|
-
if (!
|
|
57311
|
+
const planPath = path44.resolve(directory, ".swarm", "plan.json");
|
|
57312
|
+
if (!fs33.existsSync(planPath)) {
|
|
56681
57313
|
return {
|
|
56682
57314
|
success: false,
|
|
56683
57315
|
message: "No plan found",
|
|
@@ -56686,7 +57318,7 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
56686
57318
|
}
|
|
56687
57319
|
let planContent;
|
|
56688
57320
|
try {
|
|
56689
|
-
planContent = JSON.parse(
|
|
57321
|
+
planContent = JSON.parse(fs33.readFileSync(planPath, "utf-8"));
|
|
56690
57322
|
} catch {
|
|
56691
57323
|
return {
|
|
56692
57324
|
success: false,
|
|
@@ -56739,8 +57371,252 @@ var declare_scope = createSwarmTool({
|
|
|
56739
57371
|
});
|
|
56740
57372
|
// src/tools/diff.ts
|
|
56741
57373
|
init_dist();
|
|
56742
|
-
init_create_tool();
|
|
56743
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();
|
|
56744
57620
|
var MAX_DIFF_LINES = 500;
|
|
56745
57621
|
var DIFF_TIMEOUT_MS = 30000;
|
|
56746
57622
|
var MAX_BUFFER_BYTES = 5 * 1024 * 1024;
|
|
@@ -56767,20 +57643,20 @@ function validateBase(base) {
|
|
|
56767
57643
|
function validatePaths(paths) {
|
|
56768
57644
|
if (!paths)
|
|
56769
57645
|
return null;
|
|
56770
|
-
for (const
|
|
56771
|
-
if (!
|
|
57646
|
+
for (const path45 of paths) {
|
|
57647
|
+
if (!path45 || path45.length === 0) {
|
|
56772
57648
|
return "empty path not allowed";
|
|
56773
57649
|
}
|
|
56774
|
-
if (
|
|
57650
|
+
if (path45.length > MAX_PATH_LENGTH) {
|
|
56775
57651
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
56776
57652
|
}
|
|
56777
|
-
if (SHELL_METACHARACTERS2.test(
|
|
57653
|
+
if (SHELL_METACHARACTERS2.test(path45)) {
|
|
56778
57654
|
return "path contains shell metacharacters";
|
|
56779
57655
|
}
|
|
56780
|
-
if (
|
|
57656
|
+
if (path45.startsWith("-")) {
|
|
56781
57657
|
return 'path cannot start with "-" (option-like arguments not allowed)';
|
|
56782
57658
|
}
|
|
56783
|
-
if (CONTROL_CHAR_PATTERN2.test(
|
|
57659
|
+
if (CONTROL_CHAR_PATTERN2.test(path45)) {
|
|
56784
57660
|
return "path contains control characters";
|
|
56785
57661
|
}
|
|
56786
57662
|
}
|
|
@@ -56861,8 +57737,8 @@ var diff = createSwarmTool({
|
|
|
56861
57737
|
if (parts2.length >= 3) {
|
|
56862
57738
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
56863
57739
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
56864
|
-
const
|
|
56865
|
-
files.push({ path:
|
|
57740
|
+
const path45 = parts2[2];
|
|
57741
|
+
files.push({ path: path45, additions, deletions });
|
|
56866
57742
|
}
|
|
56867
57743
|
}
|
|
56868
57744
|
const contractChanges = [];
|
|
@@ -56888,13 +57764,62 @@ var diff = createSwarmTool({
|
|
|
56888
57764
|
}
|
|
56889
57765
|
const hasContractChanges = contractChanges.length > 0;
|
|
56890
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
|
+
}
|
|
56891
57815
|
const truncated = diffLines.length > MAX_DIFF_LINES;
|
|
56892
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"}`;
|
|
56893
57817
|
const result = {
|
|
56894
57818
|
files,
|
|
56895
57819
|
contractChanges,
|
|
56896
57820
|
hasContractChanges,
|
|
56897
|
-
summary
|
|
57821
|
+
summary,
|
|
57822
|
+
...astDiffs.length > 0 ? { astDiffs } : {}
|
|
56898
57823
|
};
|
|
56899
57824
|
return JSON.stringify(result, null, 2);
|
|
56900
57825
|
} catch (e) {
|
|
@@ -56912,9 +57837,9 @@ var diff = createSwarmTool({
|
|
|
56912
57837
|
init_dist();
|
|
56913
57838
|
init_schema();
|
|
56914
57839
|
import * as crypto4 from "crypto";
|
|
56915
|
-
import * as
|
|
56916
|
-
import { mkdir as
|
|
56917
|
-
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";
|
|
56918
57843
|
init_create_tool();
|
|
56919
57844
|
var SKIP_DIRECTORIES2 = new Set([
|
|
56920
57845
|
"node_modules",
|
|
@@ -56939,7 +57864,7 @@ function normalizeSeparators(filePath) {
|
|
|
56939
57864
|
}
|
|
56940
57865
|
function matchesDocPattern(filePath, patterns) {
|
|
56941
57866
|
const normalizedPath = normalizeSeparators(filePath);
|
|
56942
|
-
const basename5 =
|
|
57867
|
+
const basename5 = path45.basename(filePath);
|
|
56943
57868
|
for (const pattern of patterns) {
|
|
56944
57869
|
if (!pattern.includes("/") && !pattern.includes("\\")) {
|
|
56945
57870
|
if (basename5 === pattern) {
|
|
@@ -56995,7 +57920,7 @@ function stripMarkdown(text) {
|
|
|
56995
57920
|
return text.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/^\s*[-*\u2022]\s+/gm, "").replace(/^\s*\d+\.\s+/gm, "").trim();
|
|
56996
57921
|
}
|
|
56997
57922
|
async function scanDocIndex(directory) {
|
|
56998
|
-
const manifestPath =
|
|
57923
|
+
const manifestPath = path45.join(directory, ".swarm", "doc-manifest.json");
|
|
56999
57924
|
const defaultPatterns = DocsConfigSchema.parse({}).doc_patterns;
|
|
57000
57925
|
const extraPatterns = [
|
|
57001
57926
|
"ARCHITECTURE.md",
|
|
@@ -57012,8 +57937,8 @@ async function scanDocIndex(directory) {
|
|
|
57012
57937
|
let cacheValid = true;
|
|
57013
57938
|
for (const file3 of existingManifest.files) {
|
|
57014
57939
|
try {
|
|
57015
|
-
const fullPath =
|
|
57016
|
-
const stat2 =
|
|
57940
|
+
const fullPath = path45.join(directory, file3.path);
|
|
57941
|
+
const stat2 = fs34.statSync(fullPath);
|
|
57017
57942
|
if (stat2.mtimeMs > new Date(existingManifest.scanned_at).getTime()) {
|
|
57018
57943
|
cacheValid = false;
|
|
57019
57944
|
break;
|
|
@@ -57031,7 +57956,7 @@ async function scanDocIndex(directory) {
|
|
|
57031
57956
|
const discoveredFiles = [];
|
|
57032
57957
|
let rawEntries;
|
|
57033
57958
|
try {
|
|
57034
|
-
rawEntries =
|
|
57959
|
+
rawEntries = fs34.readdirSync(directory, { recursive: true });
|
|
57035
57960
|
} catch {
|
|
57036
57961
|
const manifest2 = {
|
|
57037
57962
|
schema_version: 1,
|
|
@@ -57042,10 +57967,10 @@ async function scanDocIndex(directory) {
|
|
|
57042
57967
|
}
|
|
57043
57968
|
const entries = rawEntries.filter((e) => typeof e === "string");
|
|
57044
57969
|
for (const entry of entries) {
|
|
57045
|
-
const fullPath =
|
|
57970
|
+
const fullPath = path45.join(directory, entry);
|
|
57046
57971
|
let stat2;
|
|
57047
57972
|
try {
|
|
57048
|
-
stat2 =
|
|
57973
|
+
stat2 = fs34.statSync(fullPath);
|
|
57049
57974
|
} catch {
|
|
57050
57975
|
continue;
|
|
57051
57976
|
}
|
|
@@ -57074,11 +57999,11 @@ async function scanDocIndex(directory) {
|
|
|
57074
57999
|
}
|
|
57075
58000
|
let content;
|
|
57076
58001
|
try {
|
|
57077
|
-
content =
|
|
58002
|
+
content = fs34.readFileSync(fullPath, "utf-8");
|
|
57078
58003
|
} catch {
|
|
57079
58004
|
continue;
|
|
57080
58005
|
}
|
|
57081
|
-
const { title, summary } = extractTitleAndSummary(content,
|
|
58006
|
+
const { title, summary } = extractTitleAndSummary(content, path45.basename(entry));
|
|
57082
58007
|
const lineCount = content.split(`
|
|
57083
58008
|
`).length;
|
|
57084
58009
|
discoveredFiles.push({
|
|
@@ -57104,7 +58029,7 @@ async function scanDocIndex(directory) {
|
|
|
57104
58029
|
files: discoveredFiles
|
|
57105
58030
|
};
|
|
57106
58031
|
try {
|
|
57107
|
-
await
|
|
58032
|
+
await mkdir6(path45.dirname(manifestPath), { recursive: true });
|
|
57108
58033
|
await writeFile5(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
57109
58034
|
} catch {}
|
|
57110
58035
|
return { manifest, cached: false };
|
|
@@ -57154,7 +58079,7 @@ function extractConstraintsFromContent(content) {
|
|
|
57154
58079
|
return constraints;
|
|
57155
58080
|
}
|
|
57156
58081
|
async function extractDocConstraints(directory, taskFiles, taskDescription) {
|
|
57157
|
-
const manifestPath =
|
|
58082
|
+
const manifestPath = path45.join(directory, ".swarm", "doc-manifest.json");
|
|
57158
58083
|
let manifest;
|
|
57159
58084
|
try {
|
|
57160
58085
|
const content = await readFile6(manifestPath, "utf-8");
|
|
@@ -57180,7 +58105,7 @@ async function extractDocConstraints(directory, taskFiles, taskDescription) {
|
|
|
57180
58105
|
}
|
|
57181
58106
|
let fullContent;
|
|
57182
58107
|
try {
|
|
57183
|
-
fullContent = await readFile6(
|
|
58108
|
+
fullContent = await readFile6(path45.join(directory, docFile.path), "utf-8");
|
|
57184
58109
|
} catch {
|
|
57185
58110
|
skippedCount++;
|
|
57186
58111
|
continue;
|
|
@@ -57203,7 +58128,7 @@ async function extractDocConstraints(directory, taskFiles, taskDescription) {
|
|
|
57203
58128
|
tier: "swarm",
|
|
57204
58129
|
lesson: constraint,
|
|
57205
58130
|
category: "architecture",
|
|
57206
|
-
tags: ["doc-scan",
|
|
58131
|
+
tags: ["doc-scan", path45.basename(docFile.path)],
|
|
57207
58132
|
scope: "global",
|
|
57208
58133
|
confidence: 0.5,
|
|
57209
58134
|
status: "candidate",
|
|
@@ -57249,9 +58174,9 @@ var doc_scan = createSwarmTool({
|
|
|
57249
58174
|
}
|
|
57250
58175
|
} catch {}
|
|
57251
58176
|
if (force) {
|
|
57252
|
-
const manifestPath =
|
|
58177
|
+
const manifestPath = path45.join(directory, ".swarm", "doc-manifest.json");
|
|
57253
58178
|
try {
|
|
57254
|
-
|
|
58179
|
+
fs34.unlinkSync(manifestPath);
|
|
57255
58180
|
} catch {}
|
|
57256
58181
|
}
|
|
57257
58182
|
const { manifest, cached: cached3 } = await scanDocIndex(directory);
|
|
@@ -57476,8 +58401,8 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
57476
58401
|
// src/tools/evidence-check.ts
|
|
57477
58402
|
init_dist();
|
|
57478
58403
|
init_create_tool();
|
|
57479
|
-
import * as
|
|
57480
|
-
import * as
|
|
58404
|
+
import * as fs35 from "fs";
|
|
58405
|
+
import * as path46 from "path";
|
|
57481
58406
|
var MAX_FILE_SIZE_BYTES3 = 1024 * 1024;
|
|
57482
58407
|
var MAX_EVIDENCE_FILES = 1000;
|
|
57483
58408
|
var EVIDENCE_DIR2 = ".swarm/evidence";
|
|
@@ -57507,9 +58432,9 @@ function validateRequiredTypes(input) {
|
|
|
57507
58432
|
return null;
|
|
57508
58433
|
}
|
|
57509
58434
|
function isPathWithinSwarm2(filePath, cwd) {
|
|
57510
|
-
const normalizedCwd =
|
|
57511
|
-
const swarmPath =
|
|
57512
|
-
const normalizedPath =
|
|
58435
|
+
const normalizedCwd = path46.resolve(cwd);
|
|
58436
|
+
const swarmPath = path46.join(normalizedCwd, ".swarm");
|
|
58437
|
+
const normalizedPath = path46.resolve(filePath);
|
|
57513
58438
|
return normalizedPath.startsWith(swarmPath);
|
|
57514
58439
|
}
|
|
57515
58440
|
function parseCompletedTasks(planContent) {
|
|
@@ -57525,12 +58450,12 @@ function parseCompletedTasks(planContent) {
|
|
|
57525
58450
|
}
|
|
57526
58451
|
function readEvidenceFiles(evidenceDir, _cwd) {
|
|
57527
58452
|
const evidence = [];
|
|
57528
|
-
if (!
|
|
58453
|
+
if (!fs35.existsSync(evidenceDir) || !fs35.statSync(evidenceDir).isDirectory()) {
|
|
57529
58454
|
return evidence;
|
|
57530
58455
|
}
|
|
57531
58456
|
let files;
|
|
57532
58457
|
try {
|
|
57533
|
-
files =
|
|
58458
|
+
files = fs35.readdirSync(evidenceDir);
|
|
57534
58459
|
} catch {
|
|
57535
58460
|
return evidence;
|
|
57536
58461
|
}
|
|
@@ -57539,14 +58464,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
57539
58464
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
57540
58465
|
continue;
|
|
57541
58466
|
}
|
|
57542
|
-
const filePath =
|
|
58467
|
+
const filePath = path46.join(evidenceDir, filename);
|
|
57543
58468
|
try {
|
|
57544
|
-
const resolvedPath =
|
|
57545
|
-
const evidenceDirResolved =
|
|
58469
|
+
const resolvedPath = path46.resolve(filePath);
|
|
58470
|
+
const evidenceDirResolved = path46.resolve(evidenceDir);
|
|
57546
58471
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
57547
58472
|
continue;
|
|
57548
58473
|
}
|
|
57549
|
-
const stat2 =
|
|
58474
|
+
const stat2 = fs35.lstatSync(filePath);
|
|
57550
58475
|
if (!stat2.isFile()) {
|
|
57551
58476
|
continue;
|
|
57552
58477
|
}
|
|
@@ -57555,7 +58480,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
57555
58480
|
}
|
|
57556
58481
|
let fileStat;
|
|
57557
58482
|
try {
|
|
57558
|
-
fileStat =
|
|
58483
|
+
fileStat = fs35.statSync(filePath);
|
|
57559
58484
|
if (fileStat.size > MAX_FILE_SIZE_BYTES3) {
|
|
57560
58485
|
continue;
|
|
57561
58486
|
}
|
|
@@ -57564,7 +58489,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
57564
58489
|
}
|
|
57565
58490
|
let content;
|
|
57566
58491
|
try {
|
|
57567
|
-
content =
|
|
58492
|
+
content = fs35.readFileSync(filePath, "utf-8");
|
|
57568
58493
|
} catch {
|
|
57569
58494
|
continue;
|
|
57570
58495
|
}
|
|
@@ -57660,7 +58585,7 @@ var evidence_check = createSwarmTool({
|
|
|
57660
58585
|
return JSON.stringify(errorResult, null, 2);
|
|
57661
58586
|
}
|
|
57662
58587
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
|
|
57663
|
-
const planPath =
|
|
58588
|
+
const planPath = path46.join(cwd, PLAN_FILE);
|
|
57664
58589
|
if (!isPathWithinSwarm2(planPath, cwd)) {
|
|
57665
58590
|
const errorResult = {
|
|
57666
58591
|
error: "plan file path validation failed",
|
|
@@ -57674,7 +58599,7 @@ var evidence_check = createSwarmTool({
|
|
|
57674
58599
|
}
|
|
57675
58600
|
let planContent;
|
|
57676
58601
|
try {
|
|
57677
|
-
planContent =
|
|
58602
|
+
planContent = fs35.readFileSync(planPath, "utf-8");
|
|
57678
58603
|
} catch {
|
|
57679
58604
|
const result2 = {
|
|
57680
58605
|
message: "No completed tasks found in plan.",
|
|
@@ -57692,7 +58617,7 @@ var evidence_check = createSwarmTool({
|
|
|
57692
58617
|
};
|
|
57693
58618
|
return JSON.stringify(result2, null, 2);
|
|
57694
58619
|
}
|
|
57695
|
-
const evidenceDir =
|
|
58620
|
+
const evidenceDir = path46.join(cwd, EVIDENCE_DIR2);
|
|
57696
58621
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
57697
58622
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
57698
58623
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -57709,8 +58634,8 @@ var evidence_check = createSwarmTool({
|
|
|
57709
58634
|
// src/tools/file-extractor.ts
|
|
57710
58635
|
init_tool();
|
|
57711
58636
|
init_create_tool();
|
|
57712
|
-
import * as
|
|
57713
|
-
import * as
|
|
58637
|
+
import * as fs36 from "fs";
|
|
58638
|
+
import * as path47 from "path";
|
|
57714
58639
|
var EXT_MAP = {
|
|
57715
58640
|
python: ".py",
|
|
57716
58641
|
py: ".py",
|
|
@@ -57772,8 +58697,8 @@ var extract_code_blocks = createSwarmTool({
|
|
|
57772
58697
|
execute: async (args2, directory) => {
|
|
57773
58698
|
const { content, output_dir, prefix } = args2;
|
|
57774
58699
|
const targetDir = output_dir || directory;
|
|
57775
|
-
if (!
|
|
57776
|
-
|
|
58700
|
+
if (!fs36.existsSync(targetDir)) {
|
|
58701
|
+
fs36.mkdirSync(targetDir, { recursive: true });
|
|
57777
58702
|
}
|
|
57778
58703
|
if (!content) {
|
|
57779
58704
|
return "Error: content is required";
|
|
@@ -57791,16 +58716,16 @@ var extract_code_blocks = createSwarmTool({
|
|
|
57791
58716
|
if (prefix) {
|
|
57792
58717
|
filename = `${prefix}_${filename}`;
|
|
57793
58718
|
}
|
|
57794
|
-
let filepath =
|
|
57795
|
-
const base =
|
|
57796
|
-
const ext =
|
|
58719
|
+
let filepath = path47.join(targetDir, filename);
|
|
58720
|
+
const base = path47.basename(filepath, path47.extname(filepath));
|
|
58721
|
+
const ext = path47.extname(filepath);
|
|
57797
58722
|
let counter = 1;
|
|
57798
|
-
while (
|
|
57799
|
-
filepath =
|
|
58723
|
+
while (fs36.existsSync(filepath)) {
|
|
58724
|
+
filepath = path47.join(targetDir, `${base}_${counter}${ext}`);
|
|
57800
58725
|
counter++;
|
|
57801
58726
|
}
|
|
57802
58727
|
try {
|
|
57803
|
-
|
|
58728
|
+
fs36.writeFileSync(filepath, code.trim(), "utf-8");
|
|
57804
58729
|
savedFiles.push(filepath);
|
|
57805
58730
|
} catch (error93) {
|
|
57806
58731
|
errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
@@ -57916,8 +58841,8 @@ var gitingest = createSwarmTool({
|
|
|
57916
58841
|
// src/tools/imports.ts
|
|
57917
58842
|
init_dist();
|
|
57918
58843
|
init_create_tool();
|
|
57919
|
-
import * as
|
|
57920
|
-
import * as
|
|
58844
|
+
import * as fs37 from "fs";
|
|
58845
|
+
import * as path48 from "path";
|
|
57921
58846
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
57922
58847
|
var MAX_SYMBOL_LENGTH = 256;
|
|
57923
58848
|
var MAX_FILE_SIZE_BYTES4 = 1024 * 1024;
|
|
@@ -57971,7 +58896,7 @@ function validateSymbolInput(symbol3) {
|
|
|
57971
58896
|
return null;
|
|
57972
58897
|
}
|
|
57973
58898
|
function isBinaryFile2(filePath, buffer) {
|
|
57974
|
-
const ext =
|
|
58899
|
+
const ext = path48.extname(filePath).toLowerCase();
|
|
57975
58900
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
57976
58901
|
return false;
|
|
57977
58902
|
}
|
|
@@ -57995,15 +58920,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
57995
58920
|
const imports = [];
|
|
57996
58921
|
let _resolvedTarget;
|
|
57997
58922
|
try {
|
|
57998
|
-
_resolvedTarget =
|
|
58923
|
+
_resolvedTarget = path48.resolve(targetFile);
|
|
57999
58924
|
} catch {
|
|
58000
58925
|
_resolvedTarget = targetFile;
|
|
58001
58926
|
}
|
|
58002
|
-
const targetBasename =
|
|
58927
|
+
const targetBasename = path48.basename(targetFile, path48.extname(targetFile));
|
|
58003
58928
|
const targetWithExt = targetFile;
|
|
58004
58929
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
58005
|
-
const normalizedTargetWithExt =
|
|
58006
|
-
const normalizedTargetWithoutExt =
|
|
58930
|
+
const normalizedTargetWithExt = path48.normalize(targetWithExt).replace(/\\/g, "/");
|
|
58931
|
+
const normalizedTargetWithoutExt = path48.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
58007
58932
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
58008
58933
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
58009
58934
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -58026,9 +58951,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
58026
58951
|
}
|
|
58027
58952
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
58028
58953
|
let isMatch = false;
|
|
58029
|
-
const _targetDir =
|
|
58030
|
-
const targetExt =
|
|
58031
|
-
const targetBasenameNoExt =
|
|
58954
|
+
const _targetDir = path48.dirname(targetFile);
|
|
58955
|
+
const targetExt = path48.extname(targetFile);
|
|
58956
|
+
const targetBasenameNoExt = path48.basename(targetFile, targetExt);
|
|
58032
58957
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
58033
58958
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
58034
58959
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -58085,7 +59010,7 @@ var SKIP_DIRECTORIES3 = new Set([
|
|
|
58085
59010
|
function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
|
|
58086
59011
|
let entries;
|
|
58087
59012
|
try {
|
|
58088
|
-
entries =
|
|
59013
|
+
entries = fs37.readdirSync(dir);
|
|
58089
59014
|
} catch (e) {
|
|
58090
59015
|
stats.fileErrors.push({
|
|
58091
59016
|
path: dir,
|
|
@@ -58096,13 +59021,13 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
|
|
|
58096
59021
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
58097
59022
|
for (const entry of entries) {
|
|
58098
59023
|
if (SKIP_DIRECTORIES3.has(entry)) {
|
|
58099
|
-
stats.skippedDirs.push(
|
|
59024
|
+
stats.skippedDirs.push(path48.join(dir, entry));
|
|
58100
59025
|
continue;
|
|
58101
59026
|
}
|
|
58102
|
-
const fullPath =
|
|
59027
|
+
const fullPath = path48.join(dir, entry);
|
|
58103
59028
|
let stat2;
|
|
58104
59029
|
try {
|
|
58105
|
-
stat2 =
|
|
59030
|
+
stat2 = fs37.statSync(fullPath);
|
|
58106
59031
|
} catch (e) {
|
|
58107
59032
|
stats.fileErrors.push({
|
|
58108
59033
|
path: fullPath,
|
|
@@ -58113,7 +59038,7 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
|
|
|
58113
59038
|
if (stat2.isDirectory()) {
|
|
58114
59039
|
findSourceFiles(fullPath, files, stats);
|
|
58115
59040
|
} else if (stat2.isFile()) {
|
|
58116
|
-
const ext =
|
|
59041
|
+
const ext = path48.extname(fullPath).toLowerCase();
|
|
58117
59042
|
if (SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
58118
59043
|
files.push(fullPath);
|
|
58119
59044
|
}
|
|
@@ -58170,8 +59095,8 @@ var imports = createSwarmTool({
|
|
|
58170
59095
|
return JSON.stringify(errorResult, null, 2);
|
|
58171
59096
|
}
|
|
58172
59097
|
try {
|
|
58173
|
-
const targetFile =
|
|
58174
|
-
if (!
|
|
59098
|
+
const targetFile = path48.resolve(file3);
|
|
59099
|
+
if (!fs37.existsSync(targetFile)) {
|
|
58175
59100
|
const errorResult = {
|
|
58176
59101
|
error: `target file not found: ${file3}`,
|
|
58177
59102
|
target: file3,
|
|
@@ -58181,7 +59106,7 @@ var imports = createSwarmTool({
|
|
|
58181
59106
|
};
|
|
58182
59107
|
return JSON.stringify(errorResult, null, 2);
|
|
58183
59108
|
}
|
|
58184
|
-
const targetStat =
|
|
59109
|
+
const targetStat = fs37.statSync(targetFile);
|
|
58185
59110
|
if (!targetStat.isFile()) {
|
|
58186
59111
|
const errorResult = {
|
|
58187
59112
|
error: "target must be a file, not a directory",
|
|
@@ -58192,7 +59117,7 @@ var imports = createSwarmTool({
|
|
|
58192
59117
|
};
|
|
58193
59118
|
return JSON.stringify(errorResult, null, 2);
|
|
58194
59119
|
}
|
|
58195
|
-
const baseDir =
|
|
59120
|
+
const baseDir = path48.dirname(targetFile);
|
|
58196
59121
|
const scanStats = {
|
|
58197
59122
|
skippedDirs: [],
|
|
58198
59123
|
skippedFiles: 0,
|
|
@@ -58207,12 +59132,12 @@ var imports = createSwarmTool({
|
|
|
58207
59132
|
if (consumers.length >= MAX_CONSUMERS)
|
|
58208
59133
|
break;
|
|
58209
59134
|
try {
|
|
58210
|
-
const stat2 =
|
|
59135
|
+
const stat2 = fs37.statSync(filePath);
|
|
58211
59136
|
if (stat2.size > MAX_FILE_SIZE_BYTES4) {
|
|
58212
59137
|
skippedFileCount++;
|
|
58213
59138
|
continue;
|
|
58214
59139
|
}
|
|
58215
|
-
const buffer =
|
|
59140
|
+
const buffer = fs37.readFileSync(filePath);
|
|
58216
59141
|
if (isBinaryFile2(filePath, buffer)) {
|
|
58217
59142
|
skippedFileCount++;
|
|
58218
59143
|
continue;
|
|
@@ -58767,8 +59692,8 @@ init_dist();
|
|
|
58767
59692
|
init_config();
|
|
58768
59693
|
init_schema();
|
|
58769
59694
|
init_manager();
|
|
58770
|
-
import * as
|
|
58771
|
-
import * as
|
|
59695
|
+
import * as fs38 from "fs";
|
|
59696
|
+
import * as path49 from "path";
|
|
58772
59697
|
init_utils2();
|
|
58773
59698
|
init_telemetry();
|
|
58774
59699
|
init_create_tool();
|
|
@@ -58988,11 +59913,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
58988
59913
|
safeWarn(`[phase_complete] Completion verify error (non-blocking):`, completionError);
|
|
58989
59914
|
}
|
|
58990
59915
|
try {
|
|
58991
|
-
const driftEvidencePath =
|
|
59916
|
+
const driftEvidencePath = path49.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
|
|
58992
59917
|
let driftVerdictFound = false;
|
|
58993
59918
|
let driftVerdictApproved = false;
|
|
58994
59919
|
try {
|
|
58995
|
-
const driftEvidenceContent =
|
|
59920
|
+
const driftEvidenceContent = fs38.readFileSync(driftEvidencePath, "utf-8");
|
|
58996
59921
|
const driftEvidence = JSON.parse(driftEvidenceContent);
|
|
58997
59922
|
const entries = driftEvidence.entries ?? [];
|
|
58998
59923
|
for (const entry of entries) {
|
|
@@ -59022,14 +59947,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
59022
59947
|
driftVerdictFound = false;
|
|
59023
59948
|
}
|
|
59024
59949
|
if (!driftVerdictFound) {
|
|
59025
|
-
const specPath =
|
|
59026
|
-
const specExists =
|
|
59950
|
+
const specPath = path49.join(dir, ".swarm", "spec.md");
|
|
59951
|
+
const specExists = fs38.existsSync(specPath);
|
|
59027
59952
|
if (!specExists) {
|
|
59028
59953
|
let incompleteTaskCount = 0;
|
|
59029
59954
|
let planPhaseFound = false;
|
|
59030
59955
|
try {
|
|
59031
59956
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
59032
|
-
const planRaw =
|
|
59957
|
+
const planRaw = fs38.readFileSync(planPath, "utf-8");
|
|
59033
59958
|
const plan = JSON.parse(planRaw);
|
|
59034
59959
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
59035
59960
|
if (targetPhase) {
|
|
@@ -59096,7 +60021,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
59096
60021
|
};
|
|
59097
60022
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
59098
60023
|
try {
|
|
59099
|
-
const projectName =
|
|
60024
|
+
const projectName = path49.basename(dir);
|
|
59100
60025
|
await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
|
|
59101
60026
|
} catch (error93) {
|
|
59102
60027
|
safeWarn("[phase_complete] Failed to curate lessons from retrospective:", error93);
|
|
@@ -59139,7 +60064,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
59139
60064
|
if (agentsMissing.length > 0) {
|
|
59140
60065
|
try {
|
|
59141
60066
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
59142
|
-
const planRaw =
|
|
60067
|
+
const planRaw = fs38.readFileSync(planPath, "utf-8");
|
|
59143
60068
|
const plan = JSON.parse(planRaw);
|
|
59144
60069
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
59145
60070
|
if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
|
|
@@ -59170,7 +60095,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
59170
60095
|
if (phaseCompleteConfig.regression_sweep?.enforce) {
|
|
59171
60096
|
try {
|
|
59172
60097
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
59173
|
-
const planRaw =
|
|
60098
|
+
const planRaw = fs38.readFileSync(planPath, "utf-8");
|
|
59174
60099
|
const plan = JSON.parse(planRaw);
|
|
59175
60100
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
59176
60101
|
if (targetPhase) {
|
|
@@ -59208,7 +60133,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
59208
60133
|
};
|
|
59209
60134
|
try {
|
|
59210
60135
|
const eventsPath = validateSwarmPath(dir, "events.jsonl");
|
|
59211
|
-
|
|
60136
|
+
fs38.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
59212
60137
|
`, "utf-8");
|
|
59213
60138
|
} catch (writeError) {
|
|
59214
60139
|
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -59229,12 +60154,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
59229
60154
|
}
|
|
59230
60155
|
try {
|
|
59231
60156
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
59232
|
-
const planJson =
|
|
60157
|
+
const planJson = fs38.readFileSync(planPath, "utf-8");
|
|
59233
60158
|
const plan = JSON.parse(planJson);
|
|
59234
60159
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
59235
60160
|
if (phaseObj) {
|
|
59236
60161
|
phaseObj.status = "completed";
|
|
59237
|
-
|
|
60162
|
+
fs38.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
|
|
59238
60163
|
`, "utf-8");
|
|
59239
60164
|
}
|
|
59240
60165
|
} catch (error93) {
|
|
@@ -59288,8 +60213,8 @@ init_dist();
|
|
|
59288
60213
|
init_discovery();
|
|
59289
60214
|
init_utils();
|
|
59290
60215
|
init_create_tool();
|
|
59291
|
-
import * as
|
|
59292
|
-
import * as
|
|
60216
|
+
import * as fs39 from "fs";
|
|
60217
|
+
import * as path50 from "path";
|
|
59293
60218
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
59294
60219
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
59295
60220
|
function isValidEcosystem(value) {
|
|
@@ -59307,28 +60232,28 @@ function validateArgs3(args2) {
|
|
|
59307
60232
|
function detectEcosystems(directory) {
|
|
59308
60233
|
const ecosystems = [];
|
|
59309
60234
|
const cwd = directory;
|
|
59310
|
-
if (
|
|
60235
|
+
if (fs39.existsSync(path50.join(cwd, "package.json"))) {
|
|
59311
60236
|
ecosystems.push("npm");
|
|
59312
60237
|
}
|
|
59313
|
-
if (
|
|
60238
|
+
if (fs39.existsSync(path50.join(cwd, "pyproject.toml")) || fs39.existsSync(path50.join(cwd, "requirements.txt"))) {
|
|
59314
60239
|
ecosystems.push("pip");
|
|
59315
60240
|
}
|
|
59316
|
-
if (
|
|
60241
|
+
if (fs39.existsSync(path50.join(cwd, "Cargo.toml"))) {
|
|
59317
60242
|
ecosystems.push("cargo");
|
|
59318
60243
|
}
|
|
59319
|
-
if (
|
|
60244
|
+
if (fs39.existsSync(path50.join(cwd, "go.mod"))) {
|
|
59320
60245
|
ecosystems.push("go");
|
|
59321
60246
|
}
|
|
59322
60247
|
try {
|
|
59323
|
-
const files =
|
|
60248
|
+
const files = fs39.readdirSync(cwd);
|
|
59324
60249
|
if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
59325
60250
|
ecosystems.push("dotnet");
|
|
59326
60251
|
}
|
|
59327
60252
|
} catch {}
|
|
59328
|
-
if (
|
|
60253
|
+
if (fs39.existsSync(path50.join(cwd, "Gemfile")) || fs39.existsSync(path50.join(cwd, "Gemfile.lock"))) {
|
|
59329
60254
|
ecosystems.push("ruby");
|
|
59330
60255
|
}
|
|
59331
|
-
if (
|
|
60256
|
+
if (fs39.existsSync(path50.join(cwd, "pubspec.yaml"))) {
|
|
59332
60257
|
ecosystems.push("dart");
|
|
59333
60258
|
}
|
|
59334
60259
|
return ecosystems;
|
|
@@ -60328,47 +61253,6 @@ var pkg_audit = createSwarmTool({
|
|
|
60328
61253
|
});
|
|
60329
61254
|
// src/tools/placeholder-scan.ts
|
|
60330
61255
|
init_manager();
|
|
60331
|
-
|
|
60332
|
-
// src/lang/registry.ts
|
|
60333
|
-
init_runtime();
|
|
60334
|
-
var languageDefinitions = [
|
|
60335
|
-
{
|
|
60336
|
-
id: "javascript",
|
|
60337
|
-
extensions: [".js", ".jsx"],
|
|
60338
|
-
commentNodes: ["comment", "line_comment", "block_comment"]
|
|
60339
|
-
},
|
|
60340
|
-
{
|
|
60341
|
-
id: "typescript",
|
|
60342
|
-
extensions: [".ts", ".tsx"],
|
|
60343
|
-
commentNodes: ["comment", "line_comment", "block_comment"]
|
|
60344
|
-
},
|
|
60345
|
-
{
|
|
60346
|
-
id: "python",
|
|
60347
|
-
extensions: [".py"],
|
|
60348
|
-
commentNodes: ["comment"]
|
|
60349
|
-
},
|
|
60350
|
-
{
|
|
60351
|
-
id: "go",
|
|
60352
|
-
extensions: [".go"],
|
|
60353
|
-
commentNodes: ["comment"]
|
|
60354
|
-
},
|
|
60355
|
-
{
|
|
60356
|
-
id: "rust",
|
|
60357
|
-
extensions: [".rs"],
|
|
60358
|
-
commentNodes: ["line_comment", "block_comment"]
|
|
60359
|
-
}
|
|
60360
|
-
];
|
|
60361
|
-
var extensionMap = new Map;
|
|
60362
|
-
for (const definition of languageDefinitions) {
|
|
60363
|
-
for (const extension of definition.extensions) {
|
|
60364
|
-
extensionMap.set(extension, definition);
|
|
60365
|
-
}
|
|
60366
|
-
}
|
|
60367
|
-
function getLanguageForExtension(extension) {
|
|
60368
|
-
return extensionMap.get(extension.toLowerCase());
|
|
60369
|
-
}
|
|
60370
|
-
|
|
60371
|
-
// src/tools/placeholder-scan.ts
|
|
60372
61256
|
init_utils();
|
|
60373
61257
|
var MAX_FILE_SIZE = 1024 * 1024;
|
|
60374
61258
|
var SUPPORTED_PARSER_EXTENSIONS = new Set([
|
|
@@ -60390,8 +61274,8 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
|
|
|
60390
61274
|
]);
|
|
60391
61275
|
// src/tools/pre-check-batch.ts
|
|
60392
61276
|
init_dist();
|
|
60393
|
-
import * as
|
|
60394
|
-
import * as
|
|
61277
|
+
import * as fs42 from "fs";
|
|
61278
|
+
import * as path53 from "path";
|
|
60395
61279
|
|
|
60396
61280
|
// node_modules/yocto-queue/index.js
|
|
60397
61281
|
class Node2 {
|
|
@@ -60559,8 +61443,8 @@ init_lint();
|
|
|
60559
61443
|
init_manager();
|
|
60560
61444
|
|
|
60561
61445
|
// src/quality/metrics.ts
|
|
60562
|
-
import * as
|
|
60563
|
-
import * as
|
|
61446
|
+
import * as fs40 from "fs";
|
|
61447
|
+
import * as path51 from "path";
|
|
60564
61448
|
var MAX_FILE_SIZE_BYTES5 = 256 * 1024;
|
|
60565
61449
|
var MIN_DUPLICATION_LINES = 10;
|
|
60566
61450
|
function estimateCyclomaticComplexity(content) {
|
|
@@ -60598,11 +61482,11 @@ function estimateCyclomaticComplexity(content) {
|
|
|
60598
61482
|
}
|
|
60599
61483
|
function getComplexityForFile2(filePath) {
|
|
60600
61484
|
try {
|
|
60601
|
-
const stat2 =
|
|
61485
|
+
const stat2 = fs40.statSync(filePath);
|
|
60602
61486
|
if (stat2.size > MAX_FILE_SIZE_BYTES5) {
|
|
60603
61487
|
return null;
|
|
60604
61488
|
}
|
|
60605
|
-
const content =
|
|
61489
|
+
const content = fs40.readFileSync(filePath, "utf-8");
|
|
60606
61490
|
return estimateCyclomaticComplexity(content);
|
|
60607
61491
|
} catch {
|
|
60608
61492
|
return null;
|
|
@@ -60612,8 +61496,8 @@ async function computeComplexityDelta(files, workingDir) {
|
|
|
60612
61496
|
let totalComplexity = 0;
|
|
60613
61497
|
const analyzedFiles = [];
|
|
60614
61498
|
for (const file3 of files) {
|
|
60615
|
-
const fullPath =
|
|
60616
|
-
if (!
|
|
61499
|
+
const fullPath = path51.isAbsolute(file3) ? file3 : path51.join(workingDir, file3);
|
|
61500
|
+
if (!fs40.existsSync(fullPath)) {
|
|
60617
61501
|
continue;
|
|
60618
61502
|
}
|
|
60619
61503
|
const complexity = getComplexityForFile2(fullPath);
|
|
@@ -60734,8 +61618,8 @@ function countGoExports(content) {
|
|
|
60734
61618
|
}
|
|
60735
61619
|
function getExportCountForFile(filePath) {
|
|
60736
61620
|
try {
|
|
60737
|
-
const content =
|
|
60738
|
-
const ext =
|
|
61621
|
+
const content = fs40.readFileSync(filePath, "utf-8");
|
|
61622
|
+
const ext = path51.extname(filePath).toLowerCase();
|
|
60739
61623
|
switch (ext) {
|
|
60740
61624
|
case ".ts":
|
|
60741
61625
|
case ".tsx":
|
|
@@ -60761,8 +61645,8 @@ async function computePublicApiDelta(files, workingDir) {
|
|
|
60761
61645
|
let totalExports = 0;
|
|
60762
61646
|
const analyzedFiles = [];
|
|
60763
61647
|
for (const file3 of files) {
|
|
60764
|
-
const fullPath =
|
|
60765
|
-
if (!
|
|
61648
|
+
const fullPath = path51.isAbsolute(file3) ? file3 : path51.join(workingDir, file3);
|
|
61649
|
+
if (!fs40.existsSync(fullPath)) {
|
|
60766
61650
|
continue;
|
|
60767
61651
|
}
|
|
60768
61652
|
const exports = getExportCountForFile(fullPath);
|
|
@@ -60795,16 +61679,16 @@ async function computeDuplicationRatio(files, workingDir) {
|
|
|
60795
61679
|
let duplicateLines = 0;
|
|
60796
61680
|
const analyzedFiles = [];
|
|
60797
61681
|
for (const file3 of files) {
|
|
60798
|
-
const fullPath =
|
|
60799
|
-
if (!
|
|
61682
|
+
const fullPath = path51.isAbsolute(file3) ? file3 : path51.join(workingDir, file3);
|
|
61683
|
+
if (!fs40.existsSync(fullPath)) {
|
|
60800
61684
|
continue;
|
|
60801
61685
|
}
|
|
60802
61686
|
try {
|
|
60803
|
-
const stat2 =
|
|
61687
|
+
const stat2 = fs40.statSync(fullPath);
|
|
60804
61688
|
if (stat2.size > MAX_FILE_SIZE_BYTES5) {
|
|
60805
61689
|
continue;
|
|
60806
61690
|
}
|
|
60807
|
-
const content =
|
|
61691
|
+
const content = fs40.readFileSync(fullPath, "utf-8");
|
|
60808
61692
|
const lines = content.split(`
|
|
60809
61693
|
`).filter((line) => line.trim().length > 0);
|
|
60810
61694
|
if (lines.length < MIN_DUPLICATION_LINES) {
|
|
@@ -60828,8 +61712,8 @@ function countCodeLines(content) {
|
|
|
60828
61712
|
return lines.length;
|
|
60829
61713
|
}
|
|
60830
61714
|
function isTestFile(filePath) {
|
|
60831
|
-
const basename9 =
|
|
60832
|
-
const _ext =
|
|
61715
|
+
const basename9 = path51.basename(filePath);
|
|
61716
|
+
const _ext = path51.extname(filePath).toLowerCase();
|
|
60833
61717
|
const testPatterns = [
|
|
60834
61718
|
".test.",
|
|
60835
61719
|
".spec.",
|
|
@@ -60910,8 +61794,8 @@ function matchGlobSegment(globSegments, pathSegments) {
|
|
|
60910
61794
|
}
|
|
60911
61795
|
return gIndex === globSegments.length && pIndex === pathSegments.length;
|
|
60912
61796
|
}
|
|
60913
|
-
function matchesGlobSegment(
|
|
60914
|
-
const normalizedPath =
|
|
61797
|
+
function matchesGlobSegment(path52, glob) {
|
|
61798
|
+
const normalizedPath = path52.replace(/\\/g, "/");
|
|
60915
61799
|
const normalizedGlob = glob.replace(/\\/g, "/");
|
|
60916
61800
|
if (normalizedPath.includes("//")) {
|
|
60917
61801
|
return false;
|
|
@@ -60942,8 +61826,8 @@ function simpleGlobToRegex2(glob) {
|
|
|
60942
61826
|
function hasGlobstar(glob) {
|
|
60943
61827
|
return glob.includes("**");
|
|
60944
61828
|
}
|
|
60945
|
-
function globMatches(
|
|
60946
|
-
const normalizedPath =
|
|
61829
|
+
function globMatches(path52, glob) {
|
|
61830
|
+
const normalizedPath = path52.replace(/\\/g, "/");
|
|
60947
61831
|
if (!glob || glob === "") {
|
|
60948
61832
|
if (normalizedPath.includes("//")) {
|
|
60949
61833
|
return false;
|
|
@@ -60979,31 +61863,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
|
|
|
60979
61863
|
async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
60980
61864
|
let testLines = 0;
|
|
60981
61865
|
let codeLines = 0;
|
|
60982
|
-
const srcDir =
|
|
60983
|
-
if (
|
|
61866
|
+
const srcDir = path51.join(workingDir, "src");
|
|
61867
|
+
if (fs40.existsSync(srcDir)) {
|
|
60984
61868
|
await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
60985
61869
|
codeLines += lines;
|
|
60986
61870
|
});
|
|
60987
61871
|
}
|
|
60988
61872
|
const possibleSrcDirs = ["lib", "app", "source", "core"];
|
|
60989
61873
|
for (const dir of possibleSrcDirs) {
|
|
60990
|
-
const dirPath =
|
|
60991
|
-
if (
|
|
61874
|
+
const dirPath = path51.join(workingDir, dir);
|
|
61875
|
+
if (fs40.existsSync(dirPath)) {
|
|
60992
61876
|
await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
60993
61877
|
codeLines += lines;
|
|
60994
61878
|
});
|
|
60995
61879
|
}
|
|
60996
61880
|
}
|
|
60997
|
-
const testsDir =
|
|
60998
|
-
if (
|
|
61881
|
+
const testsDir = path51.join(workingDir, "tests");
|
|
61882
|
+
if (fs40.existsSync(testsDir)) {
|
|
60999
61883
|
await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
61000
61884
|
testLines += lines;
|
|
61001
61885
|
});
|
|
61002
61886
|
}
|
|
61003
61887
|
const possibleTestDirs = ["test", "__tests__", "specs"];
|
|
61004
61888
|
for (const dir of possibleTestDirs) {
|
|
61005
|
-
const dirPath =
|
|
61006
|
-
if (
|
|
61889
|
+
const dirPath = path51.join(workingDir, dir);
|
|
61890
|
+
if (fs40.existsSync(dirPath) && dirPath !== testsDir) {
|
|
61007
61891
|
await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
61008
61892
|
testLines += lines;
|
|
61009
61893
|
});
|
|
@@ -61015,9 +61899,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
61015
61899
|
}
|
|
61016
61900
|
async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
|
|
61017
61901
|
try {
|
|
61018
|
-
const entries =
|
|
61902
|
+
const entries = fs40.readdirSync(dirPath, { withFileTypes: true });
|
|
61019
61903
|
for (const entry of entries) {
|
|
61020
|
-
const fullPath =
|
|
61904
|
+
const fullPath = path51.join(dirPath, entry.name);
|
|
61021
61905
|
if (entry.isDirectory()) {
|
|
61022
61906
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
|
|
61023
61907
|
continue;
|
|
@@ -61025,7 +61909,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
61025
61909
|
await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
|
|
61026
61910
|
} else if (entry.isFile()) {
|
|
61027
61911
|
const relativePath = fullPath.replace(`${dirPath}/`, "");
|
|
61028
|
-
const ext =
|
|
61912
|
+
const ext = path51.extname(entry.name).toLowerCase();
|
|
61029
61913
|
const validExts = [
|
|
61030
61914
|
".ts",
|
|
61031
61915
|
".tsx",
|
|
@@ -61061,7 +61945,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
61061
61945
|
continue;
|
|
61062
61946
|
}
|
|
61063
61947
|
try {
|
|
61064
|
-
const content =
|
|
61948
|
+
const content = fs40.readFileSync(fullPath, "utf-8");
|
|
61065
61949
|
const lines = countCodeLines(content);
|
|
61066
61950
|
callback(lines);
|
|
61067
61951
|
} catch {}
|
|
@@ -61275,9 +62159,9 @@ async function qualityBudget(input, directory) {
|
|
|
61275
62159
|
init_dist();
|
|
61276
62160
|
init_manager();
|
|
61277
62161
|
init_detector();
|
|
61278
|
-
import * as
|
|
61279
|
-
import * as
|
|
61280
|
-
import { extname as
|
|
62162
|
+
import * as fs41 from "fs";
|
|
62163
|
+
import * as path52 from "path";
|
|
62164
|
+
import { extname as extname10 } from "path";
|
|
61281
62165
|
|
|
61282
62166
|
// src/sast/rules/c.ts
|
|
61283
62167
|
var cRules = [
|
|
@@ -62143,17 +63027,17 @@ var SEVERITY_ORDER = {
|
|
|
62143
63027
|
};
|
|
62144
63028
|
function shouldSkipFile(filePath) {
|
|
62145
63029
|
try {
|
|
62146
|
-
const stats =
|
|
63030
|
+
const stats = fs41.statSync(filePath);
|
|
62147
63031
|
if (stats.size > MAX_FILE_SIZE_BYTES6) {
|
|
62148
63032
|
return { skip: true, reason: "file too large" };
|
|
62149
63033
|
}
|
|
62150
63034
|
if (stats.size === 0) {
|
|
62151
63035
|
return { skip: true, reason: "empty file" };
|
|
62152
63036
|
}
|
|
62153
|
-
const fd =
|
|
63037
|
+
const fd = fs41.openSync(filePath, "r");
|
|
62154
63038
|
const buffer = Buffer.alloc(8192);
|
|
62155
|
-
const bytesRead =
|
|
62156
|
-
|
|
63039
|
+
const bytesRead = fs41.readSync(fd, buffer, 0, 8192, 0);
|
|
63040
|
+
fs41.closeSync(fd);
|
|
62157
63041
|
if (bytesRead > 0) {
|
|
62158
63042
|
let nullCount = 0;
|
|
62159
63043
|
for (let i2 = 0;i2 < bytesRead; i2++) {
|
|
@@ -62192,7 +63076,7 @@ function countBySeverity(findings) {
|
|
|
62192
63076
|
}
|
|
62193
63077
|
function scanFileWithTierA(filePath, language) {
|
|
62194
63078
|
try {
|
|
62195
|
-
const content =
|
|
63079
|
+
const content = fs41.readFileSync(filePath, "utf-8");
|
|
62196
63080
|
const findings = executeRulesSync(filePath, content, language);
|
|
62197
63081
|
return findings.map((f) => ({
|
|
62198
63082
|
rule_id: f.rule_id,
|
|
@@ -62239,8 +63123,8 @@ async function sastScan(input, directory, config3) {
|
|
|
62239
63123
|
_filesSkipped++;
|
|
62240
63124
|
continue;
|
|
62241
63125
|
}
|
|
62242
|
-
const resolvedPath =
|
|
62243
|
-
if (!
|
|
63126
|
+
const resolvedPath = path52.isAbsolute(filePath) ? filePath : path52.resolve(directory, filePath);
|
|
63127
|
+
if (!fs41.existsSync(resolvedPath)) {
|
|
62244
63128
|
_filesSkipped++;
|
|
62245
63129
|
continue;
|
|
62246
63130
|
}
|
|
@@ -62249,7 +63133,7 @@ async function sastScan(input, directory, config3) {
|
|
|
62249
63133
|
_filesSkipped++;
|
|
62250
63134
|
continue;
|
|
62251
63135
|
}
|
|
62252
|
-
const ext =
|
|
63136
|
+
const ext = extname10(resolvedPath).toLowerCase();
|
|
62253
63137
|
const profile = getProfileForFile(resolvedPath);
|
|
62254
63138
|
const langDef = getLanguageForExtension(ext);
|
|
62255
63139
|
if (!profile && !langDef) {
|
|
@@ -62438,18 +63322,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
62438
63322
|
let resolved;
|
|
62439
63323
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
62440
63324
|
if (isWinAbs) {
|
|
62441
|
-
resolved =
|
|
62442
|
-
} else if (
|
|
62443
|
-
resolved =
|
|
63325
|
+
resolved = path53.win32.resolve(inputPath);
|
|
63326
|
+
} else if (path53.isAbsolute(inputPath)) {
|
|
63327
|
+
resolved = path53.resolve(inputPath);
|
|
62444
63328
|
} else {
|
|
62445
|
-
resolved =
|
|
63329
|
+
resolved = path53.resolve(baseDir, inputPath);
|
|
62446
63330
|
}
|
|
62447
|
-
const workspaceResolved =
|
|
63331
|
+
const workspaceResolved = path53.resolve(workspaceDir);
|
|
62448
63332
|
let relative6;
|
|
62449
63333
|
if (isWinAbs) {
|
|
62450
|
-
relative6 =
|
|
63334
|
+
relative6 = path53.win32.relative(workspaceResolved, resolved);
|
|
62451
63335
|
} else {
|
|
62452
|
-
relative6 =
|
|
63336
|
+
relative6 = path53.relative(workspaceResolved, resolved);
|
|
62453
63337
|
}
|
|
62454
63338
|
if (relative6.startsWith("..")) {
|
|
62455
63339
|
return "path traversal detected";
|
|
@@ -62510,13 +63394,13 @@ async function runLintWrapped(files, directory, _config) {
|
|
|
62510
63394
|
}
|
|
62511
63395
|
async function runLintOnFiles(linter, files, workspaceDir) {
|
|
62512
63396
|
const isWindows = process.platform === "win32";
|
|
62513
|
-
const binDir =
|
|
63397
|
+
const binDir = path53.join(workspaceDir, "node_modules", ".bin");
|
|
62514
63398
|
const validatedFiles = [];
|
|
62515
63399
|
for (const file3 of files) {
|
|
62516
63400
|
if (typeof file3 !== "string") {
|
|
62517
63401
|
continue;
|
|
62518
63402
|
}
|
|
62519
|
-
const resolvedPath =
|
|
63403
|
+
const resolvedPath = path53.resolve(file3);
|
|
62520
63404
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
62521
63405
|
if (validationError) {
|
|
62522
63406
|
continue;
|
|
@@ -62534,10 +63418,10 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
62534
63418
|
}
|
|
62535
63419
|
let command;
|
|
62536
63420
|
if (linter === "biome") {
|
|
62537
|
-
const biomeBin = isWindows ?
|
|
63421
|
+
const biomeBin = isWindows ? path53.join(binDir, "biome.EXE") : path53.join(binDir, "biome");
|
|
62538
63422
|
command = [biomeBin, "check", ...validatedFiles];
|
|
62539
63423
|
} else {
|
|
62540
|
-
const eslintBin = isWindows ?
|
|
63424
|
+
const eslintBin = isWindows ? path53.join(binDir, "eslint.cmd") : path53.join(binDir, "eslint");
|
|
62541
63425
|
command = [eslintBin, ...validatedFiles];
|
|
62542
63426
|
}
|
|
62543
63427
|
try {
|
|
@@ -62674,7 +63558,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
62674
63558
|
skippedFiles++;
|
|
62675
63559
|
continue;
|
|
62676
63560
|
}
|
|
62677
|
-
const resolvedPath =
|
|
63561
|
+
const resolvedPath = path53.resolve(file3);
|
|
62678
63562
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
62679
63563
|
if (validationError) {
|
|
62680
63564
|
skippedFiles++;
|
|
@@ -62692,14 +63576,14 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
62692
63576
|
};
|
|
62693
63577
|
}
|
|
62694
63578
|
for (const file3 of validatedFiles) {
|
|
62695
|
-
const ext =
|
|
63579
|
+
const ext = path53.extname(file3).toLowerCase();
|
|
62696
63580
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
62697
63581
|
skippedFiles++;
|
|
62698
63582
|
continue;
|
|
62699
63583
|
}
|
|
62700
63584
|
let stat2;
|
|
62701
63585
|
try {
|
|
62702
|
-
stat2 =
|
|
63586
|
+
stat2 = fs42.statSync(file3);
|
|
62703
63587
|
} catch {
|
|
62704
63588
|
skippedFiles++;
|
|
62705
63589
|
continue;
|
|
@@ -62710,7 +63594,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
62710
63594
|
}
|
|
62711
63595
|
let content;
|
|
62712
63596
|
try {
|
|
62713
|
-
const buffer =
|
|
63597
|
+
const buffer = fs42.readFileSync(file3);
|
|
62714
63598
|
if (buffer.includes(0)) {
|
|
62715
63599
|
skippedFiles++;
|
|
62716
63600
|
continue;
|
|
@@ -62851,7 +63735,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
|
|
|
62851
63735
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
62852
63736
|
continue;
|
|
62853
63737
|
}
|
|
62854
|
-
changedFiles.push(
|
|
63738
|
+
changedFiles.push(path53.resolve(directory, file3));
|
|
62855
63739
|
}
|
|
62856
63740
|
if (changedFiles.length === 0) {
|
|
62857
63741
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -63022,7 +63906,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
63022
63906
|
};
|
|
63023
63907
|
return JSON.stringify(errorResult, null, 2);
|
|
63024
63908
|
}
|
|
63025
|
-
const resolvedDirectory =
|
|
63909
|
+
const resolvedDirectory = path53.resolve(typedArgs.directory);
|
|
63026
63910
|
const workspaceAnchor = resolvedDirectory;
|
|
63027
63911
|
const dirError = validateDirectory3(resolvedDirectory, workspaceAnchor);
|
|
63028
63912
|
if (dirError) {
|
|
@@ -63128,10 +64012,72 @@ ${paginatedContent}`;
|
|
|
63128
64012
|
});
|
|
63129
64013
|
// src/tools/save-plan.ts
|
|
63130
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
|
|
63131
64079
|
init_manager2();
|
|
63132
64080
|
init_create_tool();
|
|
63133
|
-
import * as fs42 from "fs";
|
|
63134
|
-
import * as path53 from "path";
|
|
63135
64081
|
function detectPlaceholderContent(args2) {
|
|
63136
64082
|
const issues = [];
|
|
63137
64083
|
const placeholderPattern = /^\[\w[\w\s]*\]$/;
|
|
@@ -63232,25 +64178,42 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
63232
64178
|
};
|
|
63233
64179
|
const tasksCount = plan.phases.reduce((acc, phase) => acc + phase.tasks.length, 0);
|
|
63234
64180
|
const dir = targetWorkspace;
|
|
64181
|
+
const lockTaskId = `save-plan-${Date.now()}`;
|
|
64182
|
+
const planFilePath = "plan.json";
|
|
63235
64183
|
try {
|
|
63236
|
-
|
|
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
|
+
}
|
|
63237
64195
|
try {
|
|
63238
|
-
|
|
63239
|
-
|
|
63240
|
-
|
|
63241
|
-
|
|
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"),
|
|
63242
64211
|
phases_count: plan.phases.length,
|
|
63243
64212
|
tasks_count: tasksCount
|
|
63244
|
-
}
|
|
63245
|
-
|
|
63246
|
-
|
|
63247
|
-
|
|
63248
|
-
success: true,
|
|
63249
|
-
message: "Plan saved successfully",
|
|
63250
|
-
plan_path: path53.join(dir, ".swarm", "plan.json"),
|
|
63251
|
-
phases_count: plan.phases.length,
|
|
63252
|
-
tasks_count: tasksCount
|
|
63253
|
-
};
|
|
64213
|
+
};
|
|
64214
|
+
} finally {
|
|
64215
|
+
releaseLock(dir, planFilePath, lockTaskId);
|
|
64216
|
+
}
|
|
63254
64217
|
} catch (error93) {
|
|
63255
64218
|
return {
|
|
63256
64219
|
success: false,
|
|
@@ -63285,8 +64248,8 @@ var save_plan = createSwarmTool({
|
|
|
63285
64248
|
// src/tools/sbom-generate.ts
|
|
63286
64249
|
init_dist();
|
|
63287
64250
|
init_manager();
|
|
63288
|
-
import * as
|
|
63289
|
-
import * as
|
|
64251
|
+
import * as fs45 from "fs";
|
|
64252
|
+
import * as path56 from "path";
|
|
63290
64253
|
|
|
63291
64254
|
// src/sbom/detectors/index.ts
|
|
63292
64255
|
init_utils();
|
|
@@ -64132,9 +65095,9 @@ function findManifestFiles(rootDir) {
|
|
|
64132
65095
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
64133
65096
|
function searchDir(dir) {
|
|
64134
65097
|
try {
|
|
64135
|
-
const entries =
|
|
65098
|
+
const entries = fs45.readdirSync(dir, { withFileTypes: true });
|
|
64136
65099
|
for (const entry of entries) {
|
|
64137
|
-
const fullPath =
|
|
65100
|
+
const fullPath = path56.join(dir, entry.name);
|
|
64138
65101
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
64139
65102
|
continue;
|
|
64140
65103
|
}
|
|
@@ -64143,7 +65106,7 @@ function findManifestFiles(rootDir) {
|
|
|
64143
65106
|
} else if (entry.isFile()) {
|
|
64144
65107
|
for (const pattern of patterns) {
|
|
64145
65108
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
64146
|
-
manifestFiles.push(
|
|
65109
|
+
manifestFiles.push(path56.relative(rootDir, fullPath));
|
|
64147
65110
|
break;
|
|
64148
65111
|
}
|
|
64149
65112
|
}
|
|
@@ -64159,13 +65122,13 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
64159
65122
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
64160
65123
|
for (const dir of directories) {
|
|
64161
65124
|
try {
|
|
64162
|
-
const entries =
|
|
65125
|
+
const entries = fs45.readdirSync(dir, { withFileTypes: true });
|
|
64163
65126
|
for (const entry of entries) {
|
|
64164
|
-
const fullPath =
|
|
65127
|
+
const fullPath = path56.join(dir, entry.name);
|
|
64165
65128
|
if (entry.isFile()) {
|
|
64166
65129
|
for (const pattern of patterns) {
|
|
64167
65130
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
64168
|
-
found.push(
|
|
65131
|
+
found.push(path56.relative(workingDir, fullPath));
|
|
64169
65132
|
break;
|
|
64170
65133
|
}
|
|
64171
65134
|
}
|
|
@@ -64178,11 +65141,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
64178
65141
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
64179
65142
|
const dirs = new Set;
|
|
64180
65143
|
for (const file3 of changedFiles) {
|
|
64181
|
-
let currentDir =
|
|
65144
|
+
let currentDir = path56.dirname(file3);
|
|
64182
65145
|
while (true) {
|
|
64183
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
64184
|
-
dirs.add(
|
|
64185
|
-
const parent =
|
|
65146
|
+
if (currentDir && currentDir !== "." && currentDir !== path56.sep) {
|
|
65147
|
+
dirs.add(path56.join(workingDir, currentDir));
|
|
65148
|
+
const parent = path56.dirname(currentDir);
|
|
64186
65149
|
if (parent === currentDir)
|
|
64187
65150
|
break;
|
|
64188
65151
|
currentDir = parent;
|
|
@@ -64196,7 +65159,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
64196
65159
|
}
|
|
64197
65160
|
function ensureOutputDir(outputDir) {
|
|
64198
65161
|
try {
|
|
64199
|
-
|
|
65162
|
+
fs45.mkdirSync(outputDir, { recursive: true });
|
|
64200
65163
|
} catch (error93) {
|
|
64201
65164
|
if (!error93 || error93.code !== "EEXIST") {
|
|
64202
65165
|
throw error93;
|
|
@@ -64266,7 +65229,7 @@ var sbom_generate = createSwarmTool({
|
|
|
64266
65229
|
const changedFiles = obj.changed_files;
|
|
64267
65230
|
const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
|
|
64268
65231
|
const workingDir = directory;
|
|
64269
|
-
const outputDir =
|
|
65232
|
+
const outputDir = path56.isAbsolute(relativeOutputDir) ? relativeOutputDir : path56.join(workingDir, relativeOutputDir);
|
|
64270
65233
|
let manifestFiles = [];
|
|
64271
65234
|
if (scope === "all") {
|
|
64272
65235
|
manifestFiles = findManifestFiles(workingDir);
|
|
@@ -64289,11 +65252,11 @@ var sbom_generate = createSwarmTool({
|
|
|
64289
65252
|
const processedFiles = [];
|
|
64290
65253
|
for (const manifestFile of manifestFiles) {
|
|
64291
65254
|
try {
|
|
64292
|
-
const fullPath =
|
|
64293
|
-
if (!
|
|
65255
|
+
const fullPath = path56.isAbsolute(manifestFile) ? manifestFile : path56.join(workingDir, manifestFile);
|
|
65256
|
+
if (!fs45.existsSync(fullPath)) {
|
|
64294
65257
|
continue;
|
|
64295
65258
|
}
|
|
64296
|
-
const content =
|
|
65259
|
+
const content = fs45.readFileSync(fullPath, "utf-8");
|
|
64297
65260
|
const components = detectComponents(manifestFile, content);
|
|
64298
65261
|
processedFiles.push(manifestFile);
|
|
64299
65262
|
if (components.length > 0) {
|
|
@@ -64306,8 +65269,8 @@ var sbom_generate = createSwarmTool({
|
|
|
64306
65269
|
const bom = generateCycloneDX(allComponents);
|
|
64307
65270
|
const bomJson = serializeCycloneDX(bom);
|
|
64308
65271
|
const filename = generateSbomFilename();
|
|
64309
|
-
const outputPath =
|
|
64310
|
-
|
|
65272
|
+
const outputPath = path56.join(outputDir, filename);
|
|
65273
|
+
fs45.writeFileSync(outputPath, bomJson, "utf-8");
|
|
64311
65274
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
64312
65275
|
try {
|
|
64313
65276
|
const timestamp = new Date().toISOString();
|
|
@@ -64349,8 +65312,8 @@ var sbom_generate = createSwarmTool({
|
|
|
64349
65312
|
// src/tools/schema-drift.ts
|
|
64350
65313
|
init_dist();
|
|
64351
65314
|
init_create_tool();
|
|
64352
|
-
import * as
|
|
64353
|
-
import * as
|
|
65315
|
+
import * as fs46 from "fs";
|
|
65316
|
+
import * as path57 from "path";
|
|
64354
65317
|
var SPEC_CANDIDATES = [
|
|
64355
65318
|
"openapi.json",
|
|
64356
65319
|
"openapi.yaml",
|
|
@@ -64382,28 +65345,28 @@ function normalizePath2(p) {
|
|
|
64382
65345
|
}
|
|
64383
65346
|
function discoverSpecFile(cwd, specFileArg) {
|
|
64384
65347
|
if (specFileArg) {
|
|
64385
|
-
const resolvedPath =
|
|
64386
|
-
const normalizedCwd = cwd.endsWith(
|
|
65348
|
+
const resolvedPath = path57.resolve(cwd, specFileArg);
|
|
65349
|
+
const normalizedCwd = cwd.endsWith(path57.sep) ? cwd : cwd + path57.sep;
|
|
64387
65350
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
64388
65351
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
64389
65352
|
}
|
|
64390
|
-
const ext =
|
|
65353
|
+
const ext = path57.extname(resolvedPath).toLowerCase();
|
|
64391
65354
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
64392
65355
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
64393
65356
|
}
|
|
64394
|
-
const stats =
|
|
65357
|
+
const stats = fs46.statSync(resolvedPath);
|
|
64395
65358
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
64396
65359
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
64397
65360
|
}
|
|
64398
|
-
if (!
|
|
65361
|
+
if (!fs46.existsSync(resolvedPath)) {
|
|
64399
65362
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
64400
65363
|
}
|
|
64401
65364
|
return resolvedPath;
|
|
64402
65365
|
}
|
|
64403
65366
|
for (const candidate of SPEC_CANDIDATES) {
|
|
64404
|
-
const candidatePath =
|
|
64405
|
-
if (
|
|
64406
|
-
const stats =
|
|
65367
|
+
const candidatePath = path57.resolve(cwd, candidate);
|
|
65368
|
+
if (fs46.existsSync(candidatePath)) {
|
|
65369
|
+
const stats = fs46.statSync(candidatePath);
|
|
64407
65370
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
64408
65371
|
return candidatePath;
|
|
64409
65372
|
}
|
|
@@ -64412,8 +65375,8 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
64412
65375
|
return null;
|
|
64413
65376
|
}
|
|
64414
65377
|
function parseSpec(specFile) {
|
|
64415
|
-
const content =
|
|
64416
|
-
const ext =
|
|
65378
|
+
const content = fs46.readFileSync(specFile, "utf-8");
|
|
65379
|
+
const ext = path57.extname(specFile).toLowerCase();
|
|
64417
65380
|
if (ext === ".json") {
|
|
64418
65381
|
return parseJsonSpec(content);
|
|
64419
65382
|
}
|
|
@@ -64484,12 +65447,12 @@ function extractRoutes(cwd) {
|
|
|
64484
65447
|
function walkDir(dir) {
|
|
64485
65448
|
let entries;
|
|
64486
65449
|
try {
|
|
64487
|
-
entries =
|
|
65450
|
+
entries = fs46.readdirSync(dir, { withFileTypes: true });
|
|
64488
65451
|
} catch {
|
|
64489
65452
|
return;
|
|
64490
65453
|
}
|
|
64491
65454
|
for (const entry of entries) {
|
|
64492
|
-
const fullPath =
|
|
65455
|
+
const fullPath = path57.join(dir, entry.name);
|
|
64493
65456
|
if (entry.isSymbolicLink()) {
|
|
64494
65457
|
continue;
|
|
64495
65458
|
}
|
|
@@ -64499,7 +65462,7 @@ function extractRoutes(cwd) {
|
|
|
64499
65462
|
}
|
|
64500
65463
|
walkDir(fullPath);
|
|
64501
65464
|
} else if (entry.isFile()) {
|
|
64502
|
-
const ext =
|
|
65465
|
+
const ext = path57.extname(entry.name).toLowerCase();
|
|
64503
65466
|
const baseName = entry.name.toLowerCase();
|
|
64504
65467
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
64505
65468
|
continue;
|
|
@@ -64517,7 +65480,7 @@ function extractRoutes(cwd) {
|
|
|
64517
65480
|
}
|
|
64518
65481
|
function extractRoutesFromFile(filePath) {
|
|
64519
65482
|
const routes = [];
|
|
64520
|
-
const content =
|
|
65483
|
+
const content = fs46.readFileSync(filePath, "utf-8");
|
|
64521
65484
|
const lines = content.split(/\r?\n/);
|
|
64522
65485
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
64523
65486
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -64668,8 +65631,8 @@ init_secretscan();
|
|
|
64668
65631
|
// src/tools/symbols.ts
|
|
64669
65632
|
init_tool();
|
|
64670
65633
|
init_create_tool();
|
|
64671
|
-
import * as
|
|
64672
|
-
import * as
|
|
65634
|
+
import * as fs47 from "fs";
|
|
65635
|
+
import * as path58 from "path";
|
|
64673
65636
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
64674
65637
|
var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
64675
65638
|
function containsControlCharacters(str) {
|
|
@@ -64698,11 +65661,11 @@ function containsWindowsAttacks(str) {
|
|
|
64698
65661
|
}
|
|
64699
65662
|
function isPathInWorkspace(filePath, workspace) {
|
|
64700
65663
|
try {
|
|
64701
|
-
const resolvedPath =
|
|
64702
|
-
const realWorkspace =
|
|
64703
|
-
const realResolvedPath =
|
|
64704
|
-
const relativePath =
|
|
64705
|
-
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)) {
|
|
64706
65669
|
return false;
|
|
64707
65670
|
}
|
|
64708
65671
|
return true;
|
|
@@ -64714,17 +65677,17 @@ function validatePathForRead(filePath, workspace) {
|
|
|
64714
65677
|
return isPathInWorkspace(filePath, workspace);
|
|
64715
65678
|
}
|
|
64716
65679
|
function extractTSSymbols(filePath, cwd) {
|
|
64717
|
-
const fullPath =
|
|
65680
|
+
const fullPath = path58.join(cwd, filePath);
|
|
64718
65681
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
64719
65682
|
return [];
|
|
64720
65683
|
}
|
|
64721
65684
|
let content;
|
|
64722
65685
|
try {
|
|
64723
|
-
const stats =
|
|
65686
|
+
const stats = fs47.statSync(fullPath);
|
|
64724
65687
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
64725
65688
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
64726
65689
|
}
|
|
64727
|
-
content =
|
|
65690
|
+
content = fs47.readFileSync(fullPath, "utf-8");
|
|
64728
65691
|
} catch {
|
|
64729
65692
|
return [];
|
|
64730
65693
|
}
|
|
@@ -64866,17 +65829,17 @@ function extractTSSymbols(filePath, cwd) {
|
|
|
64866
65829
|
});
|
|
64867
65830
|
}
|
|
64868
65831
|
function extractPythonSymbols(filePath, cwd) {
|
|
64869
|
-
const fullPath =
|
|
65832
|
+
const fullPath = path58.join(cwd, filePath);
|
|
64870
65833
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
64871
65834
|
return [];
|
|
64872
65835
|
}
|
|
64873
65836
|
let content;
|
|
64874
65837
|
try {
|
|
64875
|
-
const stats =
|
|
65838
|
+
const stats = fs47.statSync(fullPath);
|
|
64876
65839
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
64877
65840
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
64878
65841
|
}
|
|
64879
|
-
content =
|
|
65842
|
+
content = fs47.readFileSync(fullPath, "utf-8");
|
|
64880
65843
|
} catch {
|
|
64881
65844
|
return [];
|
|
64882
65845
|
}
|
|
@@ -64949,7 +65912,7 @@ var symbols = createSwarmTool({
|
|
|
64949
65912
|
}, null, 2);
|
|
64950
65913
|
}
|
|
64951
65914
|
const cwd = directory;
|
|
64952
|
-
const ext =
|
|
65915
|
+
const ext = path58.extname(file3);
|
|
64953
65916
|
if (containsControlCharacters(file3)) {
|
|
64954
65917
|
return JSON.stringify({
|
|
64955
65918
|
file: file3,
|
|
@@ -65020,8 +65983,8 @@ init_test_runner();
|
|
|
65020
65983
|
init_dist();
|
|
65021
65984
|
init_utils();
|
|
65022
65985
|
init_create_tool();
|
|
65023
|
-
import * as
|
|
65024
|
-
import * as
|
|
65986
|
+
import * as fs48 from "fs";
|
|
65987
|
+
import * as path59 from "path";
|
|
65025
65988
|
var MAX_TEXT_LENGTH = 200;
|
|
65026
65989
|
var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
|
|
65027
65990
|
var SUPPORTED_EXTENSIONS2 = new Set([
|
|
@@ -65092,9 +66055,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
65092
66055
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
65093
66056
|
}
|
|
65094
66057
|
try {
|
|
65095
|
-
const resolvedPath =
|
|
65096
|
-
const normalizedCwd =
|
|
65097
|
-
const normalizedResolved =
|
|
66058
|
+
const resolvedPath = path59.resolve(paths);
|
|
66059
|
+
const normalizedCwd = path59.resolve(cwd);
|
|
66060
|
+
const normalizedResolved = path59.resolve(resolvedPath);
|
|
65098
66061
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
65099
66062
|
return {
|
|
65100
66063
|
error: "paths must be within the current working directory",
|
|
@@ -65110,13 +66073,13 @@ function validatePathsInput(paths, cwd) {
|
|
|
65110
66073
|
}
|
|
65111
66074
|
}
|
|
65112
66075
|
function isSupportedExtension(filePath) {
|
|
65113
|
-
const ext =
|
|
66076
|
+
const ext = path59.extname(filePath).toLowerCase();
|
|
65114
66077
|
return SUPPORTED_EXTENSIONS2.has(ext);
|
|
65115
66078
|
}
|
|
65116
66079
|
function findSourceFiles2(dir, files = []) {
|
|
65117
66080
|
let entries;
|
|
65118
66081
|
try {
|
|
65119
|
-
entries =
|
|
66082
|
+
entries = fs48.readdirSync(dir);
|
|
65120
66083
|
} catch {
|
|
65121
66084
|
return files;
|
|
65122
66085
|
}
|
|
@@ -65125,10 +66088,10 @@ function findSourceFiles2(dir, files = []) {
|
|
|
65125
66088
|
if (SKIP_DIRECTORIES4.has(entry)) {
|
|
65126
66089
|
continue;
|
|
65127
66090
|
}
|
|
65128
|
-
const fullPath =
|
|
66091
|
+
const fullPath = path59.join(dir, entry);
|
|
65129
66092
|
let stat2;
|
|
65130
66093
|
try {
|
|
65131
|
-
stat2 =
|
|
66094
|
+
stat2 = fs48.statSync(fullPath);
|
|
65132
66095
|
} catch {
|
|
65133
66096
|
continue;
|
|
65134
66097
|
}
|
|
@@ -65221,7 +66184,7 @@ var todo_extract = createSwarmTool({
|
|
|
65221
66184
|
return JSON.stringify(errorResult, null, 2);
|
|
65222
66185
|
}
|
|
65223
66186
|
const scanPath = resolvedPath;
|
|
65224
|
-
if (!
|
|
66187
|
+
if (!fs48.existsSync(scanPath)) {
|
|
65225
66188
|
const errorResult = {
|
|
65226
66189
|
error: `path not found: ${pathsInput}`,
|
|
65227
66190
|
total: 0,
|
|
@@ -65231,13 +66194,13 @@ var todo_extract = createSwarmTool({
|
|
|
65231
66194
|
return JSON.stringify(errorResult, null, 2);
|
|
65232
66195
|
}
|
|
65233
66196
|
const filesToScan = [];
|
|
65234
|
-
const stat2 =
|
|
66197
|
+
const stat2 = fs48.statSync(scanPath);
|
|
65235
66198
|
if (stat2.isFile()) {
|
|
65236
66199
|
if (isSupportedExtension(scanPath)) {
|
|
65237
66200
|
filesToScan.push(scanPath);
|
|
65238
66201
|
} else {
|
|
65239
66202
|
const errorResult = {
|
|
65240
|
-
error: `unsupported file extension: ${
|
|
66203
|
+
error: `unsupported file extension: ${path59.extname(scanPath)}`,
|
|
65241
66204
|
total: 0,
|
|
65242
66205
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
65243
66206
|
entries: []
|
|
@@ -65250,11 +66213,11 @@ var todo_extract = createSwarmTool({
|
|
|
65250
66213
|
const allEntries = [];
|
|
65251
66214
|
for (const filePath of filesToScan) {
|
|
65252
66215
|
try {
|
|
65253
|
-
const fileStat =
|
|
66216
|
+
const fileStat = fs48.statSync(filePath);
|
|
65254
66217
|
if (fileStat.size > MAX_FILE_SIZE_BYTES8) {
|
|
65255
66218
|
continue;
|
|
65256
66219
|
}
|
|
65257
|
-
const content =
|
|
66220
|
+
const content = fs48.readFileSync(filePath, "utf-8");
|
|
65258
66221
|
const entries = parseTodoComments(content, filePath, tagsSet);
|
|
65259
66222
|
allEntries.push(...entries);
|
|
65260
66223
|
} catch {}
|
|
@@ -65283,18 +66246,18 @@ var todo_extract = createSwarmTool({
|
|
|
65283
66246
|
init_tool();
|
|
65284
66247
|
init_schema();
|
|
65285
66248
|
init_gate_evidence();
|
|
65286
|
-
import * as
|
|
65287
|
-
import * as
|
|
66249
|
+
import * as fs50 from "fs";
|
|
66250
|
+
import * as path61 from "path";
|
|
65288
66251
|
|
|
65289
66252
|
// src/hooks/diff-scope.ts
|
|
65290
|
-
import * as
|
|
65291
|
-
import * as
|
|
66253
|
+
import * as fs49 from "fs";
|
|
66254
|
+
import * as path60 from "path";
|
|
65292
66255
|
function getDeclaredScope(taskId, directory) {
|
|
65293
66256
|
try {
|
|
65294
|
-
const planPath =
|
|
65295
|
-
if (!
|
|
66257
|
+
const planPath = path60.join(directory, ".swarm", "plan.json");
|
|
66258
|
+
if (!fs49.existsSync(planPath))
|
|
65296
66259
|
return null;
|
|
65297
|
-
const raw =
|
|
66260
|
+
const raw = fs49.readFileSync(planPath, "utf-8");
|
|
65298
66261
|
const plan = JSON.parse(raw);
|
|
65299
66262
|
for (const phase of plan.phases ?? []) {
|
|
65300
66263
|
for (const task of phase.tasks ?? []) {
|
|
@@ -65407,7 +66370,7 @@ var TIER_3_PATTERNS = [
|
|
|
65407
66370
|
];
|
|
65408
66371
|
function matchesTier3Pattern(files) {
|
|
65409
66372
|
for (const file3 of files) {
|
|
65410
|
-
const fileName =
|
|
66373
|
+
const fileName = path61.basename(file3);
|
|
65411
66374
|
for (const pattern of TIER_3_PATTERNS) {
|
|
65412
66375
|
if (pattern.test(fileName)) {
|
|
65413
66376
|
return true;
|
|
@@ -65421,8 +66384,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
65421
66384
|
if (hasActiveTurboMode()) {
|
|
65422
66385
|
const resolvedDir2 = workingDirectory;
|
|
65423
66386
|
try {
|
|
65424
|
-
const planPath =
|
|
65425
|
-
const planRaw =
|
|
66387
|
+
const planPath = path61.join(resolvedDir2, ".swarm", "plan.json");
|
|
66388
|
+
const planRaw = fs50.readFileSync(planPath, "utf-8");
|
|
65426
66389
|
const plan = JSON.parse(planRaw);
|
|
65427
66390
|
for (const planPhase of plan.phases ?? []) {
|
|
65428
66391
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -65488,8 +66451,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
65488
66451
|
}
|
|
65489
66452
|
try {
|
|
65490
66453
|
const resolvedDir2 = workingDirectory;
|
|
65491
|
-
const planPath =
|
|
65492
|
-
const planRaw =
|
|
66454
|
+
const planPath = path61.join(resolvedDir2, ".swarm", "plan.json");
|
|
66455
|
+
const planRaw = fs50.readFileSync(planPath, "utf-8");
|
|
65493
66456
|
const plan = JSON.parse(planRaw);
|
|
65494
66457
|
for (const planPhase of plan.phases ?? []) {
|
|
65495
66458
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -65671,8 +66634,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
65671
66634
|
};
|
|
65672
66635
|
}
|
|
65673
66636
|
}
|
|
65674
|
-
normalizedDir =
|
|
65675
|
-
const pathParts = normalizedDir.split(
|
|
66637
|
+
normalizedDir = path61.normalize(args2.working_directory);
|
|
66638
|
+
const pathParts = normalizedDir.split(path61.sep);
|
|
65676
66639
|
if (pathParts.includes("..")) {
|
|
65677
66640
|
return {
|
|
65678
66641
|
success: false,
|
|
@@ -65682,11 +66645,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
65682
66645
|
]
|
|
65683
66646
|
};
|
|
65684
66647
|
}
|
|
65685
|
-
const resolvedDir =
|
|
66648
|
+
const resolvedDir = path61.resolve(normalizedDir);
|
|
65686
66649
|
try {
|
|
65687
|
-
const realPath =
|
|
65688
|
-
const planPath =
|
|
65689
|
-
if (!
|
|
66650
|
+
const realPath = fs50.realpathSync(resolvedDir);
|
|
66651
|
+
const planPath = path61.join(realPath, ".swarm", "plan.json");
|
|
66652
|
+
if (!fs50.existsSync(planPath)) {
|
|
65690
66653
|
return {
|
|
65691
66654
|
success: false,
|
|
65692
66655
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -65907,10 +66870,11 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
65907
66870
|
let statusArtifact;
|
|
65908
66871
|
if (automationConfig.mode !== "manual") {
|
|
65909
66872
|
automationManager = createAutomationManager(automationConfig);
|
|
66873
|
+
automationManager.start();
|
|
65910
66874
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
65911
66875
|
preflightTriggerManager = new PTM(automationConfig);
|
|
65912
66876
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
65913
|
-
const swarmDir =
|
|
66877
|
+
const swarmDir = path62.resolve(ctx.directory, ".swarm");
|
|
65914
66878
|
statusArtifact = new ASA(swarmDir);
|
|
65915
66879
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
65916
66880
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|
|
@@ -65954,9 +66918,16 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
65954
66918
|
});
|
|
65955
66919
|
}
|
|
65956
66920
|
}
|
|
66921
|
+
const cleanupAutomation = () => {
|
|
66922
|
+
automationManager?.stop();
|
|
66923
|
+
};
|
|
66924
|
+
process.on("exit", cleanupAutomation);
|
|
66925
|
+
process.on("SIGINT", cleanupAutomation);
|
|
66926
|
+
process.on("SIGTERM", cleanupAutomation);
|
|
65957
66927
|
log("Automation framework initialized", {
|
|
65958
66928
|
mode: automationConfig.mode,
|
|
65959
66929
|
enabled: automationManager?.isEnabled(),
|
|
66930
|
+
running: automationManager?.isActive(),
|
|
65960
66931
|
preflightEnabled: preflightTriggerManager?.isEnabled()
|
|
65961
66932
|
});
|
|
65962
66933
|
}
|
|
@@ -66221,6 +67192,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
66221
67192
|
}
|
|
66222
67193
|
await guardrailsHooks.toolBefore(input, output);
|
|
66223
67194
|
await scopeGuardHook.toolBefore(input, output);
|
|
67195
|
+
await delegationGateHooks.toolBefore(input, output);
|
|
66224
67196
|
if (swarmState.lastBudgetPct >= 50) {
|
|
66225
67197
|
const pressureSession = ensureAgentSession(input.sessionID, swarmState.activeAgent.get(input.sessionID) ?? ORCHESTRATOR_NAME);
|
|
66226
67198
|
if (!pressureSession.contextPressureWarningSent) {
|
|
@@ -66254,6 +67226,37 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
66254
67226
|
await safeHook(delegationGateHooks.toolAfter)(input, output);
|
|
66255
67227
|
if (_dbg)
|
|
66256
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 {}
|
|
66257
67260
|
if (knowledgeCuratorHook)
|
|
66258
67261
|
await safeHook(knowledgeCuratorHook)(input, output);
|
|
66259
67262
|
if (hivePromoterHook)
|
|
@@ -66275,8 +67278,9 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
66275
67278
|
await slopDetectorHook.toolAfter(input, output);
|
|
66276
67279
|
if (incrementalVerifyHook)
|
|
66277
67280
|
await incrementalVerifyHook.toolAfter(input, output);
|
|
66278
|
-
|
|
66279
|
-
|
|
67281
|
+
}
|
|
67282
|
+
if (execMode !== "fast" && compactionServiceHook) {
|
|
67283
|
+
await compactionServiceHook.toolAfter(input, output);
|
|
66280
67284
|
}
|
|
66281
67285
|
const toolOutputConfig = config3.tool_output;
|
|
66282
67286
|
if (toolOutputConfig && toolOutputConfig.truncation_enabled !== false && typeof output.output === "string") {
|