opencode-swarm 6.44.3 → 6.45.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/cli/index.js +17 -4
- package/dist/hooks/normalize-tool-name.d.ts +25 -0
- package/dist/index.js +1589 -634
- package/dist/tools/batch-symbols.d.ts +24 -0
- package/dist/tools/batch-symbols.test.d.ts +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/search.adversarial.test.d.ts +1 -0
- package/dist/tools/search.d.ts +29 -0
- package/dist/tools/search.test.d.ts +1 -0
- package/dist/tools/suggest-patch.adversarial.test.d.ts +1 -0
- package/dist/tools/suggest-patch.d.ts +37 -0
- package/dist/tools/suggest-patch.test.d.ts +1 -0
- package/dist/tools/symbols.d.ts +19 -0
- package/dist/tools/tool-names.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -70,7 +70,10 @@ var init_tool_names = __esm(() => {
|
|
|
70
70
|
"knowledgeAdd",
|
|
71
71
|
"knowledgeRecall",
|
|
72
72
|
"knowledgeRemove",
|
|
73
|
-
"co_change_analyzer"
|
|
73
|
+
"co_change_analyzer",
|
|
74
|
+
"search",
|
|
75
|
+
"batch_symbols",
|
|
76
|
+
"suggest_patch"
|
|
74
77
|
];
|
|
75
78
|
TOOL_NAME_SET = new Set(TOOL_NAMES);
|
|
76
79
|
});
|
|
@@ -153,6 +156,8 @@ var init_constants = __esm(() => {
|
|
|
153
156
|
"quality_budget",
|
|
154
157
|
"retrieve_summary",
|
|
155
158
|
"save_plan",
|
|
159
|
+
"search",
|
|
160
|
+
"batch_symbols",
|
|
156
161
|
"schema_drift",
|
|
157
162
|
"secretscan",
|
|
158
163
|
"symbols",
|
|
@@ -174,7 +179,8 @@ var init_constants = __esm(() => {
|
|
|
174
179
|
"knowledgeAdd",
|
|
175
180
|
"knowledgeRecall",
|
|
176
181
|
"knowledgeRemove",
|
|
177
|
-
"co_change_analyzer"
|
|
182
|
+
"co_change_analyzer",
|
|
183
|
+
"suggest_patch"
|
|
178
184
|
],
|
|
179
185
|
explorer: [
|
|
180
186
|
"complexity_hotspots",
|
|
@@ -184,6 +190,8 @@ var init_constants = __esm(() => {
|
|
|
184
190
|
"imports",
|
|
185
191
|
"retrieve_summary",
|
|
186
192
|
"schema_drift",
|
|
193
|
+
"search",
|
|
194
|
+
"batch_symbols",
|
|
187
195
|
"symbols",
|
|
188
196
|
"todo_extract",
|
|
189
197
|
"doc_scan",
|
|
@@ -196,6 +204,7 @@ var init_constants = __esm(() => {
|
|
|
196
204
|
"symbols",
|
|
197
205
|
"extract_code_blocks",
|
|
198
206
|
"retrieve_summary",
|
|
207
|
+
"search",
|
|
199
208
|
"build_check",
|
|
200
209
|
"syntax_check",
|
|
201
210
|
"knowledgeAdd",
|
|
@@ -211,7 +220,8 @@ var init_constants = __esm(() => {
|
|
|
211
220
|
"complexity_hotspots",
|
|
212
221
|
"pkg_audit",
|
|
213
222
|
"build_check",
|
|
214
|
-
"syntax_check"
|
|
223
|
+
"syntax_check",
|
|
224
|
+
"search"
|
|
215
225
|
],
|
|
216
226
|
sme: [
|
|
217
227
|
"complexity_hotspots",
|
|
@@ -237,7 +247,10 @@ var init_constants = __esm(() => {
|
|
|
237
247
|
"test_runner",
|
|
238
248
|
"sast_scan",
|
|
239
249
|
"placeholder_scan",
|
|
240
|
-
"knowledgeRecall"
|
|
250
|
+
"knowledgeRecall",
|
|
251
|
+
"search",
|
|
252
|
+
"batch_symbols",
|
|
253
|
+
"suggest_patch"
|
|
241
254
|
],
|
|
242
255
|
critic: [
|
|
243
256
|
"complexity_hotspots",
|
|
@@ -333,7 +346,10 @@ var init_constants = __esm(() => {
|
|
|
333
346
|
detect_domains: "detect which SME domains are relevant for a given text",
|
|
334
347
|
extract_code_blocks: "extract code blocks from text content and save them to files",
|
|
335
348
|
gitingest: "fetch a GitHub repository full content via gitingest.com",
|
|
336
|
-
retrieve_summary: "retrieve the full content of a stored tool output summary"
|
|
349
|
+
retrieve_summary: "retrieve the full content of a stored tool output summary",
|
|
350
|
+
search: "Workspace-scoped ripgrep-style text search with structured JSON output. Supports literal and regex modes, glob filtering, and result limits. NOTE: This is text search, not structural AST search \u2014 use symbols and imports tools for structural queries.",
|
|
351
|
+
batch_symbols: "Batched symbol extraction across multiple files. Returns per-file symbol summaries with isolated error handling.",
|
|
352
|
+
suggest_patch: "Reviewer-safe structured patch suggestion tool. Produces context-anchored patch artifacts without file modification. Returns structured diagnostics on context mismatch."
|
|
337
353
|
};
|
|
338
354
|
for (const [agentName, tools] of Object.entries(AGENT_TOOL_MAP)) {
|
|
339
355
|
const invalidTools = tools.filter((tool) => !TOOL_NAME_SET.has(tool));
|
|
@@ -39385,24 +39401,24 @@ var init_tree_sitter = __esm(() => {
|
|
|
39385
39401
|
descendantsOfType(types, startPosition = ZERO_POINT, endPosition = ZERO_POINT) {
|
|
39386
39402
|
if (!Array.isArray(types))
|
|
39387
39403
|
types = [types];
|
|
39388
|
-
const
|
|
39404
|
+
const symbols2 = [];
|
|
39389
39405
|
const typesBySymbol = this.tree.language.types;
|
|
39390
39406
|
for (const node_type of types) {
|
|
39391
39407
|
if (node_type == "ERROR") {
|
|
39392
|
-
|
|
39408
|
+
symbols2.push(65535);
|
|
39393
39409
|
}
|
|
39394
39410
|
}
|
|
39395
39411
|
for (let i2 = 0, n = typesBySymbol.length;i2 < n; i2++) {
|
|
39396
39412
|
if (types.includes(typesBySymbol[i2])) {
|
|
39397
|
-
|
|
39413
|
+
symbols2.push(i2);
|
|
39398
39414
|
}
|
|
39399
39415
|
}
|
|
39400
|
-
const symbolsAddress = C._malloc(SIZE_OF_INT *
|
|
39401
|
-
for (let i2 = 0, n =
|
|
39402
|
-
C.setValue(symbolsAddress + i2 * SIZE_OF_INT,
|
|
39416
|
+
const symbolsAddress = C._malloc(SIZE_OF_INT * symbols2.length);
|
|
39417
|
+
for (let i2 = 0, n = symbols2.length;i2 < n; i2++) {
|
|
39418
|
+
C.setValue(symbolsAddress + i2 * SIZE_OF_INT, symbols2[i2], "i32");
|
|
39403
39419
|
}
|
|
39404
39420
|
marshalNode(this);
|
|
39405
|
-
C._ts_node_descendants_of_type_wasm(this.tree[0], symbolsAddress,
|
|
39421
|
+
C._ts_node_descendants_of_type_wasm(this.tree[0], symbolsAddress, symbols2.length, startPosition.row, startPosition.column, endPosition.row, endPosition.column);
|
|
39406
39422
|
const descendantCount = C.getValue(TRANSFER_BUFFER, "i32");
|
|
39407
39423
|
const descendantAddress = C.getValue(TRANSFER_BUFFER + SIZE_OF_INT, "i32");
|
|
39408
39424
|
const result = new Array(descendantCount);
|
|
@@ -40018,8 +40034,8 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
40018
40034
|
var moduleRtn;
|
|
40019
40035
|
var Module = moduleArg;
|
|
40020
40036
|
var readyPromiseResolve, readyPromiseReject;
|
|
40021
|
-
var readyPromise = new Promise((
|
|
40022
|
-
readyPromiseResolve =
|
|
40037
|
+
var readyPromise = new Promise((resolve19, reject) => {
|
|
40038
|
+
readyPromiseResolve = resolve19;
|
|
40023
40039
|
readyPromiseReject = reject;
|
|
40024
40040
|
});
|
|
40025
40041
|
var ENVIRONMENT_IS_WEB = typeof window == "object";
|
|
@@ -40041,11 +40057,11 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
40041
40057
|
throw toThrow;
|
|
40042
40058
|
}, "quit_");
|
|
40043
40059
|
var scriptDirectory = "";
|
|
40044
|
-
function locateFile(
|
|
40060
|
+
function locateFile(path55) {
|
|
40045
40061
|
if (Module["locateFile"]) {
|
|
40046
|
-
return Module["locateFile"](
|
|
40062
|
+
return Module["locateFile"](path55, scriptDirectory);
|
|
40047
40063
|
}
|
|
40048
|
-
return scriptDirectory +
|
|
40064
|
+
return scriptDirectory + path55;
|
|
40049
40065
|
}
|
|
40050
40066
|
__name(locateFile, "locateFile");
|
|
40051
40067
|
var readAsync, readBinary;
|
|
@@ -40099,13 +40115,13 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
40099
40115
|
}
|
|
40100
40116
|
readAsync = /* @__PURE__ */ __name(async (url3) => {
|
|
40101
40117
|
if (isFileURI(url3)) {
|
|
40102
|
-
return new Promise((
|
|
40118
|
+
return new Promise((resolve19, reject) => {
|
|
40103
40119
|
var xhr = new XMLHttpRequest;
|
|
40104
40120
|
xhr.open("GET", url3, true);
|
|
40105
40121
|
xhr.responseType = "arraybuffer";
|
|
40106
40122
|
xhr.onload = () => {
|
|
40107
40123
|
if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
|
|
40108
|
-
|
|
40124
|
+
resolve19(xhr.response);
|
|
40109
40125
|
return;
|
|
40110
40126
|
}
|
|
40111
40127
|
reject(xhr.status);
|
|
@@ -40325,10 +40341,10 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
40325
40341
|
__name(receiveInstantiationResult, "receiveInstantiationResult");
|
|
40326
40342
|
var info2 = getWasmImports();
|
|
40327
40343
|
if (Module["instantiateWasm"]) {
|
|
40328
|
-
return new Promise((
|
|
40344
|
+
return new Promise((resolve19, reject) => {
|
|
40329
40345
|
Module["instantiateWasm"](info2, (mod, inst) => {
|
|
40330
40346
|
receiveInstance(mod, inst);
|
|
40331
|
-
|
|
40347
|
+
resolve19(mod.exports);
|
|
40332
40348
|
});
|
|
40333
40349
|
});
|
|
40334
40350
|
}
|
|
@@ -41785,13 +41801,13 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
41785
41801
|
});
|
|
41786
41802
|
|
|
41787
41803
|
// src/lang/runtime.ts
|
|
41788
|
-
import * as
|
|
41804
|
+
import * as path55 from "path";
|
|
41789
41805
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
41790
41806
|
async function initTreeSitter() {
|
|
41791
41807
|
if (treeSitterInitialized) {
|
|
41792
41808
|
return;
|
|
41793
41809
|
}
|
|
41794
|
-
const thisDir =
|
|
41810
|
+
const thisDir = path55.dirname(fileURLToPath2(import.meta.url));
|
|
41795
41811
|
const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/lang");
|
|
41796
41812
|
if (isSource) {
|
|
41797
41813
|
await Parser.init();
|
|
@@ -41799,7 +41815,7 @@ async function initTreeSitter() {
|
|
|
41799
41815
|
const grammarsDir = getGrammarsDirAbsolute();
|
|
41800
41816
|
await Parser.init({
|
|
41801
41817
|
locateFile(scriptName) {
|
|
41802
|
-
return
|
|
41818
|
+
return path55.join(grammarsDir, scriptName);
|
|
41803
41819
|
}
|
|
41804
41820
|
});
|
|
41805
41821
|
}
|
|
@@ -41820,9 +41836,9 @@ function getWasmFileName(languageId) {
|
|
|
41820
41836
|
return `tree-sitter-${sanitized}.wasm`;
|
|
41821
41837
|
}
|
|
41822
41838
|
function getGrammarsDirAbsolute() {
|
|
41823
|
-
const thisDir =
|
|
41839
|
+
const thisDir = path55.dirname(fileURLToPath2(import.meta.url));
|
|
41824
41840
|
const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/lang");
|
|
41825
|
-
return isSource ?
|
|
41841
|
+
return isSource ? path55.join(thisDir, "grammars") : path55.join(thisDir, "lang", "grammars");
|
|
41826
41842
|
}
|
|
41827
41843
|
async function loadGrammar(languageId) {
|
|
41828
41844
|
if (typeof languageId !== "string" || languageId.length > 100) {
|
|
@@ -41838,9 +41854,9 @@ async function loadGrammar(languageId) {
|
|
|
41838
41854
|
await initTreeSitter();
|
|
41839
41855
|
const parser = new Parser;
|
|
41840
41856
|
const wasmFileName = getWasmFileName(normalizedId);
|
|
41841
|
-
const wasmPath =
|
|
41842
|
-
const { existsSync:
|
|
41843
|
-
if (!
|
|
41857
|
+
const wasmPath = path55.join(getGrammarsDirAbsolute(), wasmFileName);
|
|
41858
|
+
const { existsSync: existsSync33 } = await import("fs");
|
|
41859
|
+
if (!existsSync33(wasmPath)) {
|
|
41844
41860
|
throw new Error(`Grammar file not found for ${languageId}: ${wasmPath}
|
|
41845
41861
|
Make sure to run 'bun run build' to copy grammar files to dist/lang/grammars/`);
|
|
41846
41862
|
}
|
|
@@ -41885,7 +41901,7 @@ var init_runtime = __esm(() => {
|
|
|
41885
41901
|
});
|
|
41886
41902
|
|
|
41887
41903
|
// src/index.ts
|
|
41888
|
-
import * as
|
|
41904
|
+
import * as path73 from "path";
|
|
41889
41905
|
|
|
41890
41906
|
// src/agents/index.ts
|
|
41891
41907
|
init_config();
|
|
@@ -42751,7 +42767,7 @@ OUTPUT: Test file + VERDICT: PASS/FAIL
|
|
|
42751
42767
|
TASK: Integration impact analysis
|
|
42752
42768
|
INPUT: Contract changes detected: [list from diff tool]
|
|
42753
42769
|
OUTPUT: BREAKING_CHANGES + COMPATIBLE_CHANGES + CONSUMERS_AFFECTED + VERDICT: BREAKING/COMPATIBLE + MIGRATION_NEEDED
|
|
42754
|
-
CONSTRAINT: Read-only.
|
|
42770
|
+
CONSTRAINT: Read-only. use search to find imports/usages of changed exports.
|
|
42755
42771
|
|
|
42756
42772
|
{{AGENT_PREFIX}}docs
|
|
42757
42773
|
TASK: Update documentation for Phase 2 changes
|
|
@@ -42904,6 +42920,7 @@ For complex tasks, make a second explorer call focused on risk/gap analysis:
|
|
|
42904
42920
|
- Existing patterns that the implementation must follow
|
|
42905
42921
|
After explorer returns:
|
|
42906
42922
|
- Run \`symbols\` tool on key files identified by explorer to understand public API surfaces
|
|
42923
|
+
- For multi-file module surveys: prefer \`batch_symbols\` over sequential single-file symbols calls
|
|
42907
42924
|
- Run \`complexity_hotspots\` if not already run in Phase 0 (check context.md for existing analysis). Note modules with recommendation "security_review" or "full_gates" in context.md.
|
|
42908
42925
|
- Check for project governance files using the \`glob\` tool with patterns \`project-instructions.md\`, \`docs/project-instructions.md\`, \`CONTRIBUTING.md\`, and \`INSTRUCTIONS.md\` (checked in that priority order \u2014 first match wins). If a file is found: read it and extract all MUST (mandatory constraints) and SHOULD (recommended practices) rules. Write the extracted rules as a summary to \`.swarm/context.md\` under a \`## Project Governance\` section \u2014 append if the section already exists, create it if not. If no MUST or SHOULD rules are found in the file, skip writing. If no governance file is found: skip silently. Existing DISCOVER steps are unchanged.
|
|
42909
42926
|
|
|
@@ -43179,6 +43196,23 @@ Treating pre_check_batch as a substitute for {{AGENT_PREFIX}}reviewer is a PROCE
|
|
|
43179
43196
|
IMPORTANT: The regression sweep runs test_runner DIRECTLY (architect calls the tool). Do NOT delegate to test_engineer for this \u2014 the test_engineer's EXECUTION BOUNDARY restricts it to its own test files. The architect has unrestricted test_runner access.
|
|
43180
43197
|
\u2192 REQUIRED: Print "regression-sweep: [PASS N additional tests | SKIPPED \u2014 no related tests beyond task scope | SKIPPED \u2014 test_runner error | FAIL \u2014 REGRESSION DETECTED in files]"
|
|
43181
43198
|
|
|
43199
|
+
5l-ter. TEST DRIFT CHECK (conditional): Run this step if the change involves any drift-prone area:
|
|
43200
|
+
- Command/CLI behavior changed (shell command wrappers, CLI interfaces)
|
|
43201
|
+
- Parsing or routing logic changed (argument parsing, route matching, file resolution)
|
|
43202
|
+
- User-visible output changed (formatted output, error messages, JSON response structure)
|
|
43203
|
+
- Public contracts or schemas changed (API types, tool argument schemas, return types)
|
|
43204
|
+
- Assertion-heavy areas where output strings are tested (command/help output tests, error message tests)
|
|
43205
|
+
- Helper behavior or lifecycle semantics changed (state machines, lifecycle hooks, initialization)
|
|
43206
|
+
|
|
43207
|
+
If NOT triggered: Print "test-drift: NOT TRIGGERED \u2014 no drift-prone change detected"
|
|
43208
|
+
If TRIGGERED:
|
|
43209
|
+
- Use grep/search to find test files that cover the affected functionality
|
|
43210
|
+
- Run those tests via test_runner with scope:"convention" on the related test files
|
|
43211
|
+
- If any FAIL \u2192 print "test-drift: DRIFT DETECTED in [N] tests" and escalate to reviewer/test_engineer
|
|
43212
|
+
- If all PASS \u2192 print "test-drift: [N] related tests verified"
|
|
43213
|
+
- If no related tests found \u2192 print "test-drift: NO RELATED TESTS FOUND" (not a failure)
|
|
43214
|
+
\u2192 REQUIRED: Print "test-drift: [TRIGGERED | NOT TRIGGERED \u2014 reason]" and "[DRIFT DETECTED in N tests | N related tests verified | NO RELATED TESTS FOUND | NOT TRIGGERED]"
|
|
43215
|
+
|
|
43182
43216
|
5n. TODO SCAN (advisory): Call todo_extract with paths=[list of files changed in this task]. If any results have priority HIGH \u2192 print "todo-scan: WARN \u2014 N high-priority TODOs in changed files: [list of TODO texts]". If no high-priority results \u2192 print "todo-scan: CLEAN". This is advisory only and does NOT block the pipeline.
|
|
43183
43217
|
\u2192 REQUIRED: Print "todo-scan: [WARN \u2014 N high-priority TODOs | CLEAN]"
|
|
43184
43218
|
|
|
@@ -43192,6 +43226,7 @@ PRE-COMMIT RULE \u2014 Before ANY commit or push:
|
|
|
43192
43226
|
[ ] Did pre_check_batch run with gates_passed true?
|
|
43193
43227
|
[ ] Did the diff step run?
|
|
43194
43228
|
[ ] Did regression-sweep run (or SKIP with no related tests or test_runner error)?
|
|
43229
|
+
[ ] Did test-drift check run (or NOT TRIGGERED)?
|
|
43195
43230
|
|
|
43196
43231
|
If ANY box is unchecked: DO NOT COMMIT. Return to step 5b.
|
|
43197
43232
|
There is no override. A commit without a completed QA gate is a workflow violation.
|
|
@@ -43208,6 +43243,7 @@ PRE-COMMIT RULE \u2014 Before ANY commit or push:
|
|
|
43208
43243
|
[GATE] security-reviewer: APPROVED / SKIPPED \u2014 value: ___
|
|
43209
43244
|
[GATE] test_engineer-verification: PASS \u2014 value: ___
|
|
43210
43245
|
[GATE] regression-sweep: PASS / SKIPPED \u2014 value: ___
|
|
43246
|
+
[GATE] test-drift: TRIGGERED / NOT TRIGGERED \u2014 value: ___
|
|
43211
43247
|
{{ADVERSARIAL_TEST_CHECKLIST}}
|
|
43212
43248
|
[GATE] coverage: \u226570% / soft-skip \u2014 value: ___
|
|
43213
43249
|
|
|
@@ -43421,22 +43457,22 @@ RULES:
|
|
|
43421
43457
|
- Read target file before editing
|
|
43422
43458
|
- Implement exactly what TASK specifies
|
|
43423
43459
|
- Respect CONSTRAINT
|
|
43424
|
-
- No web searches or documentation lookups \u2014 but DO
|
|
43460
|
+
- No web searches or documentation lookups \u2014 but DO use the search tool for cross-codebase pattern lookup before using any function
|
|
43425
43461
|
- Verify all import paths exist before using them
|
|
43426
43462
|
|
|
43427
43463
|
## ANTI-HALLUCINATION PROTOCOL (MANDATORY)
|
|
43428
43464
|
Before importing ANY function, type, or class from an existing project module:
|
|
43429
|
-
1. Run
|
|
43465
|
+
1. Run search to find the exact export using the search tool with appropriate query pattern
|
|
43430
43466
|
2. Read the file that contains the export to verify its signature
|
|
43431
43467
|
3. Use the EXACT function name and import path you found \u2014 do not guess or abbreviate
|
|
43432
43468
|
|
|
43433
|
-
If
|
|
43469
|
+
If search returns zero results, the function does not exist. Do NOT:
|
|
43434
43470
|
- Import it anyway hoping it exists somewhere
|
|
43435
43471
|
- Create a similar-sounding function name
|
|
43436
43472
|
- Assume an export exists based on naming conventions
|
|
43437
43473
|
|
|
43438
43474
|
WRONG: import { saveEvidence } from '../evidence/manager' (guessed path)
|
|
43439
|
-
RIGHT: [
|
|
43475
|
+
RIGHT: [search first, then] import { saveEvidence } from '../evidence/manager' (verified path)
|
|
43440
43476
|
|
|
43441
43477
|
If available_symbols was provided in your scope declaration, you MUST only call functions from that list when importing from existing project modules. Do not invent function names that are not in the list.
|
|
43442
43478
|
|
|
@@ -43906,7 +43942,7 @@ INPUT: [focus areas/paths]
|
|
|
43906
43942
|
ACTIONS:
|
|
43907
43943
|
- Scan structure (tree, ls, glob)
|
|
43908
43944
|
- Read key files (README, configs, entry points)
|
|
43909
|
-
- Search patterns
|
|
43945
|
+
- Search patterns using the search tool
|
|
43910
43946
|
|
|
43911
43947
|
RULES:
|
|
43912
43948
|
- Be fast: scan broadly, read selectively
|
|
@@ -43919,6 +43955,7 @@ When exploring a codebase area, systematically report all four dimensions:
|
|
|
43919
43955
|
### STRUCTURE
|
|
43920
43956
|
- Entry points and their call chains (max 3 levels deep)
|
|
43921
43957
|
- Public API surface: exported functions/classes/types with signatures
|
|
43958
|
+
- For multi-file symbol surveys: use batch_symbols to extract symbols from multiple files in one call
|
|
43922
43959
|
- Internal dependencies: what this module imports and from where
|
|
43923
43960
|
- External dependencies: third-party packages used
|
|
43924
43961
|
|
|
@@ -43966,7 +44003,7 @@ Activates when delegated with "Integration impact analysis" or INPUT lists contr
|
|
|
43966
44003
|
INPUT: List of contract changes (from diff tool output \u2014 changed exports, signatures, types)
|
|
43967
44004
|
|
|
43968
44005
|
STEPS:
|
|
43969
|
-
1. For each changed export:
|
|
44006
|
+
1. For each changed export: use search to find imports and usages of that symbol
|
|
43970
44007
|
2. Classify each change: BREAKING (callers must update) or COMPATIBLE (callers unaffected)
|
|
43971
44008
|
3. List all files that import or use the changed exports
|
|
43972
44009
|
|
|
@@ -44490,9 +44527,10 @@ Your unique value is catching LOGIC ERRORS, EDGE CASES, and SECURITY FLAWS that
|
|
|
44490
44527
|
|
|
44491
44528
|
DO (explicitly):
|
|
44492
44529
|
- READ the changed files yourself \u2014 do not rely on the coder's self-report
|
|
44493
|
-
- VERIFY imports exist: if the coder added a new import,
|
|
44530
|
+
- VERIFY imports exist: if the coder added a new import, use search to verify the export exists in the source
|
|
44494
44531
|
- CHECK test files were updated: if the coder changed a function signature, the tests should reflect it
|
|
44495
44532
|
- VERIFY platform compatibility: path.join() used for all paths, no hardcoded separators
|
|
44533
|
+
- For confirmed issues requiring a concrete fix: use suggest_patch to produce a structured patch artifact for the coder
|
|
44496
44534
|
|
|
44497
44535
|
## REVIEW REASONING
|
|
44498
44536
|
For each changed function or method, answer these before formulating issues:
|
|
@@ -53344,6 +53382,17 @@ function detectLoop(sessionId, toolName, args2) {
|
|
|
53344
53382
|
};
|
|
53345
53383
|
}
|
|
53346
53384
|
|
|
53385
|
+
// src/hooks/normalize-tool-name.ts
|
|
53386
|
+
var NAMESPACE_PREFIX_PATTERN = /^[^:]+[:.]/;
|
|
53387
|
+
function normalizeToolName(toolName) {
|
|
53388
|
+
if (!toolName)
|
|
53389
|
+
return;
|
|
53390
|
+
return toolName.replace(NAMESPACE_PREFIX_PATTERN, "");
|
|
53391
|
+
}
|
|
53392
|
+
function normalizeToolNameLowerCase(toolName) {
|
|
53393
|
+
return toolName.replace(NAMESPACE_PREFIX_PATTERN, "").toLowerCase();
|
|
53394
|
+
}
|
|
53395
|
+
|
|
53347
53396
|
// src/hooks/guardrails.ts
|
|
53348
53397
|
var storedInputArgs = new Map;
|
|
53349
53398
|
var TRANSIENT_MODEL_ERROR_PATTERN = /rate.?limit|429|503|timeout|overloaded|model.?not.?found|temporarily unavailable|server error/i;
|
|
@@ -53366,7 +53415,7 @@ function extractPhaseNumber(phaseString) {
|
|
|
53366
53415
|
return match ? parseInt(match[1], 10) : 1;
|
|
53367
53416
|
}
|
|
53368
53417
|
function isWriteTool(toolName) {
|
|
53369
|
-
const normalized = toolName
|
|
53418
|
+
const normalized = normalizeToolName(toolName);
|
|
53370
53419
|
return WRITE_TOOL_NAMES.includes(normalized);
|
|
53371
53420
|
}
|
|
53372
53421
|
function isArchitect(sessionId) {
|
|
@@ -53421,7 +53470,7 @@ function hasTraversalSegments(filePath) {
|
|
|
53421
53470
|
return normalized.startsWith("..") || normalized.includes("/../") || normalized.endsWith("/..");
|
|
53422
53471
|
}
|
|
53423
53472
|
function isGateTool(toolName) {
|
|
53424
|
-
const normalized = toolName
|
|
53473
|
+
const normalized = normalizeToolName(toolName);
|
|
53425
53474
|
const gateTools = [
|
|
53426
53475
|
"diff",
|
|
53427
53476
|
"syntax_check",
|
|
@@ -53437,7 +53486,7 @@ function isGateTool(toolName) {
|
|
|
53437
53486
|
return gateTools.includes(normalized);
|
|
53438
53487
|
}
|
|
53439
53488
|
function isAgentDelegation(toolName, args2) {
|
|
53440
|
-
const normalized = toolName
|
|
53489
|
+
const normalized = normalizeToolName(toolName);
|
|
53441
53490
|
if (normalized !== "Task" && normalized !== "task") {
|
|
53442
53491
|
return { isDelegation: false, targetAgent: null };
|
|
53443
53492
|
}
|
|
@@ -53932,7 +53981,7 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
|
|
|
53932
53981
|
}
|
|
53933
53982
|
}
|
|
53934
53983
|
const sessionId = input.sessionID;
|
|
53935
|
-
const normalizedToolName = input.tool
|
|
53984
|
+
const normalizedToolName = normalizeToolName(input.tool);
|
|
53936
53985
|
if (isWriteTool(normalizedToolName)) {
|
|
53937
53986
|
toolCallsSinceLastWrite.set(sessionId, 0);
|
|
53938
53987
|
noOpWarningIssued.delete(sessionId);
|
|
@@ -54490,7 +54539,7 @@ function createDelegationGateHook(config3, directory) {
|
|
|
54490
54539
|
const toolBefore = async (input, output) => {
|
|
54491
54540
|
if (!input.sessionID)
|
|
54492
54541
|
return;
|
|
54493
|
-
const normalized = input.tool
|
|
54542
|
+
const normalized = normalizeToolName(input.tool);
|
|
54494
54543
|
if (normalized !== "Task" && normalized !== "task")
|
|
54495
54544
|
return;
|
|
54496
54545
|
const args2 = output.args;
|
|
@@ -54546,7 +54595,7 @@ function createDelegationGateHook(config3, directory) {
|
|
|
54546
54595
|
const session = swarmState.agentSessions.get(input.sessionID);
|
|
54547
54596
|
if (!session)
|
|
54548
54597
|
return;
|
|
54549
|
-
const normalized = input.tool
|
|
54598
|
+
const normalized = normalizeToolName(input.tool);
|
|
54550
54599
|
if (normalized === "Task" || normalized === "task") {
|
|
54551
54600
|
const directArgs = input.args;
|
|
54552
54601
|
const storedArgs = getStoredInputArgs(input.callID);
|
|
@@ -57354,12 +57403,12 @@ var WRITE_TOOL_PATTERNS = [
|
|
|
57354
57403
|
"prepend"
|
|
57355
57404
|
];
|
|
57356
57405
|
function isWriteTool2(toolName) {
|
|
57357
|
-
const normalized = toolName
|
|
57406
|
+
const normalized = normalizeToolNameLowerCase(toolName);
|
|
57358
57407
|
return WRITE_TOOL_PATTERNS.some((p) => normalized.includes(p));
|
|
57359
57408
|
}
|
|
57360
57409
|
var READ_TOOL_PATTERNS = ["read", "cat", "view", "fetch", "get"];
|
|
57361
57410
|
function isReadTool(toolName) {
|
|
57362
|
-
const normalized = toolName
|
|
57411
|
+
const normalized = normalizeToolNameLowerCase(toolName);
|
|
57363
57412
|
return READ_TOOL_PATTERNS.some((p) => normalized.includes(p));
|
|
57364
57413
|
}
|
|
57365
57414
|
|
|
@@ -57796,7 +57845,7 @@ function createScopeGuardHook(config3, directory, injectAdvisory) {
|
|
|
57796
57845
|
toolBefore: async (input, output) => {
|
|
57797
57846
|
if (!enabled)
|
|
57798
57847
|
return;
|
|
57799
|
-
const toolName = input.tool
|
|
57848
|
+
const toolName = normalizeToolName(input.tool);
|
|
57800
57849
|
if (!WRITE_TOOLS.has(toolName))
|
|
57801
57850
|
return;
|
|
57802
57851
|
const sessionId = input.sessionID;
|
|
@@ -57859,7 +57908,7 @@ function createSelfReviewHook(config3, injectAdvisory) {
|
|
|
57859
57908
|
toolAfter: async (input, output) => {
|
|
57860
57909
|
if (!enabled)
|
|
57861
57910
|
return;
|
|
57862
|
-
const toolName = input.tool
|
|
57911
|
+
const toolName = normalizeToolName(input.tool);
|
|
57863
57912
|
if (toolName !== "update_task_status")
|
|
57864
57913
|
return;
|
|
57865
57914
|
const args2 = output.args;
|
|
@@ -58359,6 +58408,520 @@ async function loadSnapshot(directory) {
|
|
|
58359
58408
|
// src/index.ts
|
|
58360
58409
|
init_telemetry();
|
|
58361
58410
|
|
|
58411
|
+
// src/tools/batch-symbols.ts
|
|
58412
|
+
init_tool();
|
|
58413
|
+
init_create_tool();
|
|
58414
|
+
import * as fs38 from "fs";
|
|
58415
|
+
import * as path49 from "path";
|
|
58416
|
+
|
|
58417
|
+
// src/tools/symbols.ts
|
|
58418
|
+
init_tool();
|
|
58419
|
+
init_create_tool();
|
|
58420
|
+
import * as fs37 from "fs";
|
|
58421
|
+
import * as path48 from "path";
|
|
58422
|
+
var MAX_FILE_SIZE_BYTES2 = 1024 * 1024;
|
|
58423
|
+
var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
58424
|
+
function containsWindowsAttacks(str) {
|
|
58425
|
+
if (/:[^\\/]/.test(str)) {
|
|
58426
|
+
return true;
|
|
58427
|
+
}
|
|
58428
|
+
const parts2 = str.split(/[/\\]/);
|
|
58429
|
+
for (const part of parts2) {
|
|
58430
|
+
if (WINDOWS_RESERVED_NAMES.test(part)) {
|
|
58431
|
+
return true;
|
|
58432
|
+
}
|
|
58433
|
+
}
|
|
58434
|
+
return false;
|
|
58435
|
+
}
|
|
58436
|
+
function isPathInWorkspace(filePath, workspace) {
|
|
58437
|
+
try {
|
|
58438
|
+
const resolvedPath = path48.resolve(workspace, filePath);
|
|
58439
|
+
const realWorkspace = fs37.realpathSync(workspace);
|
|
58440
|
+
const realResolvedPath = fs37.realpathSync(resolvedPath);
|
|
58441
|
+
const relativePath = path48.relative(realWorkspace, realResolvedPath);
|
|
58442
|
+
if (relativePath.startsWith("..") || path48.isAbsolute(relativePath)) {
|
|
58443
|
+
return false;
|
|
58444
|
+
}
|
|
58445
|
+
return true;
|
|
58446
|
+
} catch {
|
|
58447
|
+
return false;
|
|
58448
|
+
}
|
|
58449
|
+
}
|
|
58450
|
+
function validatePathForRead(filePath, workspace) {
|
|
58451
|
+
return isPathInWorkspace(filePath, workspace);
|
|
58452
|
+
}
|
|
58453
|
+
function extractTSSymbols(filePath, cwd) {
|
|
58454
|
+
const fullPath = path48.join(cwd, filePath);
|
|
58455
|
+
if (!validatePathForRead(fullPath, cwd)) {
|
|
58456
|
+
return [];
|
|
58457
|
+
}
|
|
58458
|
+
let content;
|
|
58459
|
+
try {
|
|
58460
|
+
const stats = fs37.statSync(fullPath);
|
|
58461
|
+
if (stats.size > MAX_FILE_SIZE_BYTES2) {
|
|
58462
|
+
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES2})`);
|
|
58463
|
+
}
|
|
58464
|
+
content = fs37.readFileSync(fullPath, "utf-8");
|
|
58465
|
+
} catch {
|
|
58466
|
+
return [];
|
|
58467
|
+
}
|
|
58468
|
+
const lines = content.split(`
|
|
58469
|
+
`);
|
|
58470
|
+
const symbols = [];
|
|
58471
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
58472
|
+
const line = lines[i2];
|
|
58473
|
+
const lineNum = i2 + 1;
|
|
58474
|
+
let jsdoc;
|
|
58475
|
+
if (i2 > 0 && lines[i2 - 1].trim().endsWith("*/")) {
|
|
58476
|
+
const jsdocLines = [];
|
|
58477
|
+
for (let j = i2 - 1;j >= 0; j--) {
|
|
58478
|
+
jsdocLines.unshift(lines[j]);
|
|
58479
|
+
if (lines[j].trim().startsWith("/**"))
|
|
58480
|
+
break;
|
|
58481
|
+
}
|
|
58482
|
+
jsdoc = jsdocLines.join(`
|
|
58483
|
+
`).trim();
|
|
58484
|
+
if (jsdoc.length > 300)
|
|
58485
|
+
jsdoc = `${jsdoc.substring(0, 300)}...`;
|
|
58486
|
+
}
|
|
58487
|
+
const fnMatch = line.match(/^export\s+(?:async\s+)?function\s+(\w+)\s*(<[^>]*>)?\s*\(([^)]*)\)(?:\s*:\s*(.+?))?(?:\s*\{|$)/);
|
|
58488
|
+
if (fnMatch) {
|
|
58489
|
+
symbols.push({
|
|
58490
|
+
name: fnMatch[1],
|
|
58491
|
+
kind: "function",
|
|
58492
|
+
exported: true,
|
|
58493
|
+
signature: `function ${fnMatch[1]}${fnMatch[2] || ""}(${fnMatch[3].trim()})${fnMatch[4] ? `: ${fnMatch[4].trim()}` : ""}`,
|
|
58494
|
+
line: lineNum,
|
|
58495
|
+
jsdoc
|
|
58496
|
+
});
|
|
58497
|
+
continue;
|
|
58498
|
+
}
|
|
58499
|
+
const constMatch = line.match(/^export\s+const\s+(\w+)(?:\s*:\s*(.+?))?\s*=/);
|
|
58500
|
+
if (constMatch) {
|
|
58501
|
+
const restOfLine = line.substring(line.indexOf("=") + 1).trim();
|
|
58502
|
+
const isArrow = restOfLine.startsWith("(") || restOfLine.startsWith("async (") || restOfLine.match(/^\w+\s*=>/);
|
|
58503
|
+
symbols.push({
|
|
58504
|
+
name: constMatch[1],
|
|
58505
|
+
kind: isArrow ? "function" : "const",
|
|
58506
|
+
exported: true,
|
|
58507
|
+
signature: `const ${constMatch[1]}${constMatch[2] ? `: ${constMatch[2].trim()}` : ""}`,
|
|
58508
|
+
line: lineNum,
|
|
58509
|
+
jsdoc
|
|
58510
|
+
});
|
|
58511
|
+
continue;
|
|
58512
|
+
}
|
|
58513
|
+
const classMatch = line.match(/^export\s+(?:abstract\s+)?class\s+(\w+)(?:\s+(?:extends|implements)\s+(.+?))?(?:\s*\{|$)/);
|
|
58514
|
+
if (classMatch) {
|
|
58515
|
+
symbols.push({
|
|
58516
|
+
name: classMatch[1],
|
|
58517
|
+
kind: "class",
|
|
58518
|
+
exported: true,
|
|
58519
|
+
signature: `class ${classMatch[1]}${classMatch[2] ? ` extends/implements ${classMatch[2].trim()}` : ""}`,
|
|
58520
|
+
line: lineNum,
|
|
58521
|
+
jsdoc
|
|
58522
|
+
});
|
|
58523
|
+
let braceDepth = (line.match(/\{/g) || []).length - (line.match(/\}/g) || []).length;
|
|
58524
|
+
for (let j = i2 + 1;j < lines.length && braceDepth > 0; j++) {
|
|
58525
|
+
const memberLine = lines[j];
|
|
58526
|
+
braceDepth += (memberLine.match(/\{/g) || []).length - (memberLine.match(/\}/g) || []).length;
|
|
58527
|
+
const methodMatch = memberLine.match(/^\s+(?:public\s+)?(?:async\s+)?(\w+)\s*\(([^)]*)\)(?:\s*:\s*(.+?))?(?:\s*\{|;|$)/);
|
|
58528
|
+
if (methodMatch && !memberLine.includes("private") && !memberLine.includes("protected") && !memberLine.trim().startsWith("//")) {
|
|
58529
|
+
symbols.push({
|
|
58530
|
+
name: `${classMatch[1]}.${methodMatch[1]}`,
|
|
58531
|
+
kind: "method",
|
|
58532
|
+
exported: true,
|
|
58533
|
+
signature: `${methodMatch[1]}(${methodMatch[2].trim()})${methodMatch[3] ? `: ${methodMatch[3].trim()}` : ""}`,
|
|
58534
|
+
line: j + 1
|
|
58535
|
+
});
|
|
58536
|
+
}
|
|
58537
|
+
const propMatch = memberLine.match(/^\s+(?:public\s+)?(?:readonly\s+)?(\w+)(?:\?)?:\s*(.+?)(?:\s*[;=]|$)/);
|
|
58538
|
+
if (propMatch && !memberLine.includes("private") && !memberLine.includes("protected") && !memberLine.trim().startsWith("//")) {
|
|
58539
|
+
symbols.push({
|
|
58540
|
+
name: `${classMatch[1]}.${propMatch[1]}`,
|
|
58541
|
+
kind: "property",
|
|
58542
|
+
exported: true,
|
|
58543
|
+
signature: `${propMatch[1]}: ${propMatch[2].trim()}`,
|
|
58544
|
+
line: j + 1
|
|
58545
|
+
});
|
|
58546
|
+
}
|
|
58547
|
+
}
|
|
58548
|
+
continue;
|
|
58549
|
+
}
|
|
58550
|
+
const ifaceMatch = line.match(/^export\s+interface\s+(\w+)(?:\s*<([^>]+)>)?(?:\s+extends\s+(.+?))?(?:\s*\{|$)/);
|
|
58551
|
+
if (ifaceMatch) {
|
|
58552
|
+
symbols.push({
|
|
58553
|
+
name: ifaceMatch[1],
|
|
58554
|
+
kind: "interface",
|
|
58555
|
+
exported: true,
|
|
58556
|
+
signature: `interface ${ifaceMatch[1]}${ifaceMatch[2] ? `<${ifaceMatch[2]}>` : ""}${ifaceMatch[3] ? ` extends ${ifaceMatch[3].trim()}` : ""}`,
|
|
58557
|
+
line: lineNum,
|
|
58558
|
+
jsdoc
|
|
58559
|
+
});
|
|
58560
|
+
continue;
|
|
58561
|
+
}
|
|
58562
|
+
const typeMatch = line.match(/^export\s+type\s+(\w+)(?:\s*<([^>]+)>)?\s*=/);
|
|
58563
|
+
if (typeMatch) {
|
|
58564
|
+
const typeValue = line.substring(line.indexOf("=") + 1).trim().substring(0, 100);
|
|
58565
|
+
symbols.push({
|
|
58566
|
+
name: typeMatch[1],
|
|
58567
|
+
kind: "type",
|
|
58568
|
+
exported: true,
|
|
58569
|
+
signature: `type ${typeMatch[1]}${typeMatch[2] ? `<${typeMatch[2]}>` : ""} = ${typeValue}`,
|
|
58570
|
+
line: lineNum,
|
|
58571
|
+
jsdoc
|
|
58572
|
+
});
|
|
58573
|
+
continue;
|
|
58574
|
+
}
|
|
58575
|
+
const enumMatch = line.match(/^export\s+(?:const\s+)?enum\s+(\w+)/);
|
|
58576
|
+
if (enumMatch) {
|
|
58577
|
+
symbols.push({
|
|
58578
|
+
name: enumMatch[1],
|
|
58579
|
+
kind: "enum",
|
|
58580
|
+
exported: true,
|
|
58581
|
+
signature: `enum ${enumMatch[1]}`,
|
|
58582
|
+
line: lineNum,
|
|
58583
|
+
jsdoc
|
|
58584
|
+
});
|
|
58585
|
+
continue;
|
|
58586
|
+
}
|
|
58587
|
+
const defaultMatch = line.match(/^export\s+default\s+(?:function\s+)?(\w+)/);
|
|
58588
|
+
if (defaultMatch) {
|
|
58589
|
+
symbols.push({
|
|
58590
|
+
name: defaultMatch[1],
|
|
58591
|
+
kind: "function",
|
|
58592
|
+
exported: true,
|
|
58593
|
+
signature: `default ${defaultMatch[1]}`,
|
|
58594
|
+
line: lineNum,
|
|
58595
|
+
jsdoc
|
|
58596
|
+
});
|
|
58597
|
+
}
|
|
58598
|
+
}
|
|
58599
|
+
return symbols.sort((a, b) => {
|
|
58600
|
+
if (a.line !== b.line)
|
|
58601
|
+
return a.line - b.line;
|
|
58602
|
+
return a.name.localeCompare(b.name);
|
|
58603
|
+
});
|
|
58604
|
+
}
|
|
58605
|
+
function extractPythonSymbols(filePath, cwd) {
|
|
58606
|
+
const fullPath = path48.join(cwd, filePath);
|
|
58607
|
+
if (!validatePathForRead(fullPath, cwd)) {
|
|
58608
|
+
return [];
|
|
58609
|
+
}
|
|
58610
|
+
let content;
|
|
58611
|
+
try {
|
|
58612
|
+
const stats = fs37.statSync(fullPath);
|
|
58613
|
+
if (stats.size > MAX_FILE_SIZE_BYTES2) {
|
|
58614
|
+
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES2})`);
|
|
58615
|
+
}
|
|
58616
|
+
content = fs37.readFileSync(fullPath, "utf-8");
|
|
58617
|
+
} catch {
|
|
58618
|
+
return [];
|
|
58619
|
+
}
|
|
58620
|
+
const lines = content.split(`
|
|
58621
|
+
`);
|
|
58622
|
+
const symbols = [];
|
|
58623
|
+
const allMatch = content.match(/__all__\s*=\s*\[([^\]]+)\]/);
|
|
58624
|
+
const explicitExports = allMatch ? allMatch[1].split(",").map((s) => s.trim().replace(/['"]/g, "")) : null;
|
|
58625
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
58626
|
+
const line = lines[i2];
|
|
58627
|
+
if (line.startsWith(" ") || line.startsWith("\t"))
|
|
58628
|
+
continue;
|
|
58629
|
+
const fnMatch = line.match(/^(?:async\s+)?def\s+(\w+)\s*\(([^)]*)\)(?:\s*->\s*(.+?))?:/);
|
|
58630
|
+
if (fnMatch && !fnMatch[1].startsWith("_")) {
|
|
58631
|
+
const exported = !explicitExports || explicitExports.includes(fnMatch[1]);
|
|
58632
|
+
symbols.push({
|
|
58633
|
+
name: fnMatch[1],
|
|
58634
|
+
kind: "function",
|
|
58635
|
+
exported,
|
|
58636
|
+
signature: `def ${fnMatch[1]}(${fnMatch[2].trim()})${fnMatch[3] ? ` -> ${fnMatch[3].trim()}` : ""}`,
|
|
58637
|
+
line: i2 + 1
|
|
58638
|
+
});
|
|
58639
|
+
}
|
|
58640
|
+
const classMatch = line.match(/^class\s+(\w+)(?:\(([^)]*)\))?:/);
|
|
58641
|
+
if (classMatch && !classMatch[1].startsWith("_")) {
|
|
58642
|
+
const exported = !explicitExports || explicitExports.includes(classMatch[1]);
|
|
58643
|
+
symbols.push({
|
|
58644
|
+
name: classMatch[1],
|
|
58645
|
+
kind: "class",
|
|
58646
|
+
exported,
|
|
58647
|
+
signature: `class ${classMatch[1]}${classMatch[2] ? `(${classMatch[2].trim()})` : ""}`,
|
|
58648
|
+
line: i2 + 1
|
|
58649
|
+
});
|
|
58650
|
+
}
|
|
58651
|
+
const constMatch = line.match(/^([A-Z][A-Z0-9_]+)\s*[:=]/);
|
|
58652
|
+
if (constMatch) {
|
|
58653
|
+
symbols.push({
|
|
58654
|
+
name: constMatch[1],
|
|
58655
|
+
kind: "const",
|
|
58656
|
+
exported: true,
|
|
58657
|
+
signature: line.trim().substring(0, 100),
|
|
58658
|
+
line: i2 + 1
|
|
58659
|
+
});
|
|
58660
|
+
}
|
|
58661
|
+
}
|
|
58662
|
+
return symbols.sort((a, b) => {
|
|
58663
|
+
if (a.line !== b.line)
|
|
58664
|
+
return a.line - b.line;
|
|
58665
|
+
return a.name.localeCompare(b.name);
|
|
58666
|
+
});
|
|
58667
|
+
}
|
|
58668
|
+
var symbols = createSwarmTool({
|
|
58669
|
+
description: "Extract all exported symbols from a source file: functions with signatures, " + "classes with public members, interfaces, types, enums, constants. " + "Supports TypeScript/JavaScript and Python. Use for architect planning, " + "designer scaffolding, and understanding module public API surface.",
|
|
58670
|
+
args: {
|
|
58671
|
+
file: tool.schema.string().describe('File path to extract symbols from (e.g., "src/auth/login.ts")'),
|
|
58672
|
+
exported_only: tool.schema.boolean().default(true).describe("If true, only return exported/public symbols. If false, include all top-level symbols.")
|
|
58673
|
+
},
|
|
58674
|
+
execute: async (args2, directory) => {
|
|
58675
|
+
let file3;
|
|
58676
|
+
let exportedOnly = true;
|
|
58677
|
+
try {
|
|
58678
|
+
const obj = args2;
|
|
58679
|
+
file3 = String(obj.file);
|
|
58680
|
+
exportedOnly = obj.exported_only === true;
|
|
58681
|
+
} catch {
|
|
58682
|
+
return JSON.stringify({
|
|
58683
|
+
file: "<unknown>",
|
|
58684
|
+
error: "Invalid arguments: could not extract file path",
|
|
58685
|
+
symbols: []
|
|
58686
|
+
}, null, 2);
|
|
58687
|
+
}
|
|
58688
|
+
const cwd = directory;
|
|
58689
|
+
const ext = path48.extname(file3);
|
|
58690
|
+
if (containsControlChars(file3)) {
|
|
58691
|
+
return JSON.stringify({
|
|
58692
|
+
file: file3,
|
|
58693
|
+
error: "Path contains invalid control characters",
|
|
58694
|
+
symbols: []
|
|
58695
|
+
}, null, 2);
|
|
58696
|
+
}
|
|
58697
|
+
if (containsPathTraversal(file3)) {
|
|
58698
|
+
return JSON.stringify({
|
|
58699
|
+
file: file3,
|
|
58700
|
+
error: "Path contains path traversal sequence",
|
|
58701
|
+
symbols: []
|
|
58702
|
+
}, null, 2);
|
|
58703
|
+
}
|
|
58704
|
+
if (containsWindowsAttacks(file3)) {
|
|
58705
|
+
return JSON.stringify({
|
|
58706
|
+
file: file3,
|
|
58707
|
+
error: "Path contains invalid Windows-specific sequence",
|
|
58708
|
+
symbols: []
|
|
58709
|
+
}, null, 2);
|
|
58710
|
+
}
|
|
58711
|
+
if (!isPathInWorkspace(file3, cwd)) {
|
|
58712
|
+
return JSON.stringify({
|
|
58713
|
+
file: file3,
|
|
58714
|
+
error: "Path is outside workspace",
|
|
58715
|
+
symbols: []
|
|
58716
|
+
}, null, 2);
|
|
58717
|
+
}
|
|
58718
|
+
let syms;
|
|
58719
|
+
switch (ext) {
|
|
58720
|
+
case ".ts":
|
|
58721
|
+
case ".tsx":
|
|
58722
|
+
case ".js":
|
|
58723
|
+
case ".jsx":
|
|
58724
|
+
case ".mjs":
|
|
58725
|
+
case ".cjs":
|
|
58726
|
+
syms = extractTSSymbols(file3, cwd);
|
|
58727
|
+
break;
|
|
58728
|
+
case ".py":
|
|
58729
|
+
syms = extractPythonSymbols(file3, cwd);
|
|
58730
|
+
break;
|
|
58731
|
+
default:
|
|
58732
|
+
return JSON.stringify({
|
|
58733
|
+
file: file3,
|
|
58734
|
+
error: `Unsupported file extension: ${ext}. Supported: .ts, .tsx, .js, .jsx, .mjs, .cjs, .py`,
|
|
58735
|
+
symbols: []
|
|
58736
|
+
}, null, 2);
|
|
58737
|
+
}
|
|
58738
|
+
if (exportedOnly) {
|
|
58739
|
+
syms = syms.filter((s) => s.exported);
|
|
58740
|
+
}
|
|
58741
|
+
return JSON.stringify({
|
|
58742
|
+
file: file3,
|
|
58743
|
+
symbolCount: syms.length,
|
|
58744
|
+
symbols: syms
|
|
58745
|
+
}, null, 2);
|
|
58746
|
+
}
|
|
58747
|
+
});
|
|
58748
|
+
|
|
58749
|
+
// src/tools/batch-symbols.ts
|
|
58750
|
+
var WINDOWS_RESERVED_NAMES2 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
58751
|
+
function containsWindowsAttacks2(str) {
|
|
58752
|
+
if (/:[^\\/]/.test(str)) {
|
|
58753
|
+
return true;
|
|
58754
|
+
}
|
|
58755
|
+
const parts2 = str.split(/[/\\]/);
|
|
58756
|
+
for (const part of parts2) {
|
|
58757
|
+
if (WINDOWS_RESERVED_NAMES2.test(part)) {
|
|
58758
|
+
return true;
|
|
58759
|
+
}
|
|
58760
|
+
}
|
|
58761
|
+
return false;
|
|
58762
|
+
}
|
|
58763
|
+
function isPathInWorkspace2(filePath, workspace) {
|
|
58764
|
+
try {
|
|
58765
|
+
const resolvedPath = path49.resolve(workspace, filePath);
|
|
58766
|
+
if (!fs38.existsSync(resolvedPath)) {
|
|
58767
|
+
return true;
|
|
58768
|
+
}
|
|
58769
|
+
const realWorkspace = fs38.realpathSync(workspace);
|
|
58770
|
+
const realResolvedPath = fs38.realpathSync(resolvedPath);
|
|
58771
|
+
const relativePath = path49.relative(realWorkspace, realResolvedPath);
|
|
58772
|
+
if (relativePath.startsWith("..") || path49.isAbsolute(relativePath)) {
|
|
58773
|
+
return false;
|
|
58774
|
+
}
|
|
58775
|
+
return true;
|
|
58776
|
+
} catch {
|
|
58777
|
+
return false;
|
|
58778
|
+
}
|
|
58779
|
+
}
|
|
58780
|
+
function processFile(file3, cwd, exportedOnly) {
|
|
58781
|
+
const ext = path49.extname(file3);
|
|
58782
|
+
if (containsControlChars(file3)) {
|
|
58783
|
+
return {
|
|
58784
|
+
file: file3,
|
|
58785
|
+
success: false,
|
|
58786
|
+
error: "Path contains invalid control characters",
|
|
58787
|
+
errorType: "invalid-path"
|
|
58788
|
+
};
|
|
58789
|
+
}
|
|
58790
|
+
if (containsPathTraversal(file3)) {
|
|
58791
|
+
return {
|
|
58792
|
+
file: file3,
|
|
58793
|
+
success: false,
|
|
58794
|
+
error: "Path contains path traversal sequence",
|
|
58795
|
+
errorType: "path-traversal"
|
|
58796
|
+
};
|
|
58797
|
+
}
|
|
58798
|
+
if (containsWindowsAttacks2(file3)) {
|
|
58799
|
+
return {
|
|
58800
|
+
file: file3,
|
|
58801
|
+
success: false,
|
|
58802
|
+
error: "Path contains invalid Windows-specific sequence",
|
|
58803
|
+
errorType: "invalid-path"
|
|
58804
|
+
};
|
|
58805
|
+
}
|
|
58806
|
+
if (!isPathInWorkspace2(file3, cwd)) {
|
|
58807
|
+
return {
|
|
58808
|
+
file: file3,
|
|
58809
|
+
success: false,
|
|
58810
|
+
error: "Path is outside workspace",
|
|
58811
|
+
errorType: "path-outside-workspace"
|
|
58812
|
+
};
|
|
58813
|
+
}
|
|
58814
|
+
const fullPath = path49.join(cwd, file3);
|
|
58815
|
+
if (!fs38.existsSync(fullPath)) {
|
|
58816
|
+
return {
|
|
58817
|
+
file: file3,
|
|
58818
|
+
success: false,
|
|
58819
|
+
error: `File not found: ${file3}`,
|
|
58820
|
+
errorType: "file-not-found"
|
|
58821
|
+
};
|
|
58822
|
+
}
|
|
58823
|
+
let syms;
|
|
58824
|
+
switch (ext) {
|
|
58825
|
+
case ".ts":
|
|
58826
|
+
case ".tsx":
|
|
58827
|
+
case ".js":
|
|
58828
|
+
case ".jsx":
|
|
58829
|
+
case ".mjs":
|
|
58830
|
+
case ".cjs":
|
|
58831
|
+
syms = extractTSSymbols(file3, cwd);
|
|
58832
|
+
break;
|
|
58833
|
+
case ".py":
|
|
58834
|
+
syms = extractPythonSymbols(file3, cwd);
|
|
58835
|
+
break;
|
|
58836
|
+
default:
|
|
58837
|
+
return {
|
|
58838
|
+
file: file3,
|
|
58839
|
+
success: false,
|
|
58840
|
+
error: `Unsupported file extension: ${ext}. Supported: .ts, .tsx, .js, .jsx, .mjs, .cjs, .py`,
|
|
58841
|
+
errorType: "unsupported-language"
|
|
58842
|
+
};
|
|
58843
|
+
}
|
|
58844
|
+
let isEmptyFile = false;
|
|
58845
|
+
try {
|
|
58846
|
+
const stats = fs38.statSync(fullPath);
|
|
58847
|
+
if (stats.size === 0) {
|
|
58848
|
+
isEmptyFile = true;
|
|
58849
|
+
}
|
|
58850
|
+
} catch {}
|
|
58851
|
+
if (syms.length === 0) {
|
|
58852
|
+
try {
|
|
58853
|
+
const content = fs38.readFileSync(fullPath, "utf-8");
|
|
58854
|
+
if (content.trim().length === 0) {
|
|
58855
|
+
isEmptyFile = true;
|
|
58856
|
+
}
|
|
58857
|
+
} catch {}
|
|
58858
|
+
}
|
|
58859
|
+
if (isEmptyFile) {
|
|
58860
|
+
return {
|
|
58861
|
+
file: file3,
|
|
58862
|
+
success: true,
|
|
58863
|
+
symbols: [],
|
|
58864
|
+
error: "empty-file",
|
|
58865
|
+
errorType: "empty-file"
|
|
58866
|
+
};
|
|
58867
|
+
}
|
|
58868
|
+
if (exportedOnly) {
|
|
58869
|
+
syms = syms.filter((s) => s.exported);
|
|
58870
|
+
}
|
|
58871
|
+
return {
|
|
58872
|
+
file: file3,
|
|
58873
|
+
success: true,
|
|
58874
|
+
symbols: syms
|
|
58875
|
+
};
|
|
58876
|
+
}
|
|
58877
|
+
var batch_symbols = createSwarmTool({
|
|
58878
|
+
description: "Extract symbols from multiple files in a single batch call. " + "Accepts an array of file paths and returns per-file symbol summaries. " + "One bad file does not crash the batch. Use for surveying a module " + "when you need symbol information from multiple files at once.",
|
|
58879
|
+
args: {
|
|
58880
|
+
files: tool.schema.array(tool.schema.string()).describe("Array of file paths to extract symbols from"),
|
|
58881
|
+
exported_only: tool.schema.boolean().default(true).describe("If true, only return exported/public symbols. If false, include all top-level symbols.")
|
|
58882
|
+
},
|
|
58883
|
+
execute: async (args2, directory) => {
|
|
58884
|
+
let files;
|
|
58885
|
+
let exportedOnly = true;
|
|
58886
|
+
try {
|
|
58887
|
+
const obj = args2;
|
|
58888
|
+
if (!Array.isArray(obj.files)) {
|
|
58889
|
+
return JSON.stringify({
|
|
58890
|
+
results: [],
|
|
58891
|
+
totalFiles: 0,
|
|
58892
|
+
successCount: 0,
|
|
58893
|
+
failureCount: 0,
|
|
58894
|
+
error: "Invalid arguments: files must be an array"
|
|
58895
|
+
}, null, 2);
|
|
58896
|
+
}
|
|
58897
|
+
files = obj.files.map((f) => String(f));
|
|
58898
|
+
exportedOnly = obj.exported_only === true;
|
|
58899
|
+
} catch {
|
|
58900
|
+
return JSON.stringify({
|
|
58901
|
+
results: [],
|
|
58902
|
+
totalFiles: 0,
|
|
58903
|
+
successCount: 0,
|
|
58904
|
+
failureCount: 0,
|
|
58905
|
+
error: "Invalid arguments: could not extract files array"
|
|
58906
|
+
}, null, 2);
|
|
58907
|
+
}
|
|
58908
|
+
const cwd = directory;
|
|
58909
|
+
const results = [];
|
|
58910
|
+
for (const file3 of files) {
|
|
58911
|
+
const result = processFile(file3, cwd, exportedOnly);
|
|
58912
|
+
results.push(result);
|
|
58913
|
+
}
|
|
58914
|
+
const successCount = results.filter((r) => r.success).length;
|
|
58915
|
+
const failureCount = results.filter((r) => !r.success).length;
|
|
58916
|
+
const batchResult = {
|
|
58917
|
+
results,
|
|
58918
|
+
totalFiles: files.length,
|
|
58919
|
+
successCount,
|
|
58920
|
+
failureCount
|
|
58921
|
+
};
|
|
58922
|
+
return JSON.stringify(batchResult, null, 2);
|
|
58923
|
+
}
|
|
58924
|
+
});
|
|
58362
58925
|
// src/tools/build-check.ts
|
|
58363
58926
|
init_dist();
|
|
58364
58927
|
init_discovery();
|
|
@@ -58538,8 +59101,8 @@ init_dist();
|
|
|
58538
59101
|
init_manager();
|
|
58539
59102
|
init_create_tool();
|
|
58540
59103
|
init_resolve_working_directory();
|
|
58541
|
-
import * as
|
|
58542
|
-
import * as
|
|
59104
|
+
import * as fs39 from "fs";
|
|
59105
|
+
import * as path50 from "path";
|
|
58543
59106
|
var EVIDENCE_DIR = ".swarm/evidence";
|
|
58544
59107
|
var TASK_ID_PATTERN2 = /^\d+\.\d+(\.\d+)*$/;
|
|
58545
59108
|
function isValidTaskId3(taskId) {
|
|
@@ -58556,18 +59119,18 @@ function isValidTaskId3(taskId) {
|
|
|
58556
59119
|
return TASK_ID_PATTERN2.test(taskId);
|
|
58557
59120
|
}
|
|
58558
59121
|
function isPathWithinSwarm(filePath, workspaceRoot) {
|
|
58559
|
-
const normalizedWorkspace =
|
|
58560
|
-
const swarmPath =
|
|
58561
|
-
const normalizedPath =
|
|
59122
|
+
const normalizedWorkspace = path50.resolve(workspaceRoot);
|
|
59123
|
+
const swarmPath = path50.join(normalizedWorkspace, ".swarm", "evidence");
|
|
59124
|
+
const normalizedPath = path50.resolve(filePath);
|
|
58562
59125
|
return normalizedPath.startsWith(swarmPath);
|
|
58563
59126
|
}
|
|
58564
59127
|
function readEvidenceFile(evidencePath) {
|
|
58565
|
-
if (!
|
|
59128
|
+
if (!fs39.existsSync(evidencePath)) {
|
|
58566
59129
|
return null;
|
|
58567
59130
|
}
|
|
58568
59131
|
let content;
|
|
58569
59132
|
try {
|
|
58570
|
-
content =
|
|
59133
|
+
content = fs39.readFileSync(evidencePath, "utf-8");
|
|
58571
59134
|
} catch {
|
|
58572
59135
|
return null;
|
|
58573
59136
|
}
|
|
@@ -58639,7 +59202,7 @@ var check_gate_status = createSwarmTool({
|
|
|
58639
59202
|
};
|
|
58640
59203
|
return JSON.stringify(errorResult, null, 2);
|
|
58641
59204
|
}
|
|
58642
|
-
const evidencePath =
|
|
59205
|
+
const evidencePath = path50.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
|
|
58643
59206
|
if (!isPathWithinSwarm(evidencePath, directory)) {
|
|
58644
59207
|
const errorResult = {
|
|
58645
59208
|
taskId: taskIdInput,
|
|
@@ -58732,8 +59295,8 @@ init_co_change_analyzer();
|
|
|
58732
59295
|
// src/tools/completion-verify.ts
|
|
58733
59296
|
init_dist();
|
|
58734
59297
|
init_utils2();
|
|
58735
|
-
import * as
|
|
58736
|
-
import * as
|
|
59298
|
+
import * as fs40 from "fs";
|
|
59299
|
+
import * as path51 from "path";
|
|
58737
59300
|
init_create_tool();
|
|
58738
59301
|
init_resolve_working_directory();
|
|
58739
59302
|
function extractMatches(regex, text) {
|
|
@@ -58829,7 +59392,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
58829
59392
|
let plan;
|
|
58830
59393
|
try {
|
|
58831
59394
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
58832
|
-
const planRaw =
|
|
59395
|
+
const planRaw = fs40.readFileSync(planPath, "utf-8");
|
|
58833
59396
|
plan = JSON.parse(planRaw);
|
|
58834
59397
|
} catch {
|
|
58835
59398
|
const result2 = {
|
|
@@ -58887,10 +59450,10 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
58887
59450
|
let hasFileReadFailure = false;
|
|
58888
59451
|
for (const filePath of fileTargets) {
|
|
58889
59452
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
58890
|
-
const resolvedPath =
|
|
58891
|
-
const projectRoot =
|
|
58892
|
-
const
|
|
58893
|
-
const withinProject =
|
|
59453
|
+
const resolvedPath = path51.resolve(directory, normalizedPath);
|
|
59454
|
+
const projectRoot = path51.resolve(directory);
|
|
59455
|
+
const relative9 = path51.relative(projectRoot, resolvedPath);
|
|
59456
|
+
const withinProject = relative9 === "" || !relative9.startsWith("..") && !path51.isAbsolute(relative9);
|
|
58894
59457
|
if (!withinProject) {
|
|
58895
59458
|
blockedTasks.push({
|
|
58896
59459
|
task_id: task.id,
|
|
@@ -58903,7 +59466,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
58903
59466
|
}
|
|
58904
59467
|
let fileContent;
|
|
58905
59468
|
try {
|
|
58906
|
-
fileContent =
|
|
59469
|
+
fileContent = fs40.readFileSync(resolvedPath, "utf-8");
|
|
58907
59470
|
} catch {
|
|
58908
59471
|
blockedTasks.push({
|
|
58909
59472
|
task_id: task.id,
|
|
@@ -58945,9 +59508,9 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
58945
59508
|
blockedTasks
|
|
58946
59509
|
};
|
|
58947
59510
|
try {
|
|
58948
|
-
const evidenceDir =
|
|
58949
|
-
const evidencePath =
|
|
58950
|
-
|
|
59511
|
+
const evidenceDir = path51.join(directory, ".swarm", "evidence", `${phase}`);
|
|
59512
|
+
const evidencePath = path51.join(evidenceDir, "completion-verify.json");
|
|
59513
|
+
fs40.mkdirSync(evidenceDir, { recursive: true });
|
|
58951
59514
|
const evidenceBundle = {
|
|
58952
59515
|
schema_version: "1.0.0",
|
|
58953
59516
|
task_id: "completion-verify",
|
|
@@ -58968,7 +59531,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
58968
59531
|
}
|
|
58969
59532
|
]
|
|
58970
59533
|
};
|
|
58971
|
-
|
|
59534
|
+
fs40.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
|
|
58972
59535
|
} catch {}
|
|
58973
59536
|
return JSON.stringify(result, null, 2);
|
|
58974
59537
|
}
|
|
@@ -59022,13 +59585,13 @@ var completion_verify = createSwarmTool({
|
|
|
59022
59585
|
});
|
|
59023
59586
|
// src/tools/complexity-hotspots.ts
|
|
59024
59587
|
init_dist();
|
|
59025
|
-
import * as
|
|
59026
|
-
import * as
|
|
59588
|
+
import * as fs42 from "fs";
|
|
59589
|
+
import * as path53 from "path";
|
|
59027
59590
|
|
|
59028
59591
|
// src/quality/metrics.ts
|
|
59029
|
-
import * as
|
|
59030
|
-
import * as
|
|
59031
|
-
var
|
|
59592
|
+
import * as fs41 from "fs";
|
|
59593
|
+
import * as path52 from "path";
|
|
59594
|
+
var MAX_FILE_SIZE_BYTES3 = 256 * 1024;
|
|
59032
59595
|
var MIN_DUPLICATION_LINES = 10;
|
|
59033
59596
|
function estimateCyclomaticComplexity(content) {
|
|
59034
59597
|
let processed = content.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
@@ -59065,11 +59628,11 @@ function estimateCyclomaticComplexity(content) {
|
|
|
59065
59628
|
}
|
|
59066
59629
|
function getComplexityForFile(filePath) {
|
|
59067
59630
|
try {
|
|
59068
|
-
const stat2 =
|
|
59069
|
-
if (stat2.size >
|
|
59631
|
+
const stat2 = fs41.statSync(filePath);
|
|
59632
|
+
if (stat2.size > MAX_FILE_SIZE_BYTES3) {
|
|
59070
59633
|
return null;
|
|
59071
59634
|
}
|
|
59072
|
-
const content =
|
|
59635
|
+
const content = fs41.readFileSync(filePath, "utf-8");
|
|
59073
59636
|
return estimateCyclomaticComplexity(content);
|
|
59074
59637
|
} catch {
|
|
59075
59638
|
return null;
|
|
@@ -59079,8 +59642,8 @@ async function computeComplexityDelta(files, workingDir) {
|
|
|
59079
59642
|
let totalComplexity = 0;
|
|
59080
59643
|
const analyzedFiles = [];
|
|
59081
59644
|
for (const file3 of files) {
|
|
59082
|
-
const fullPath =
|
|
59083
|
-
if (!
|
|
59645
|
+
const fullPath = path52.isAbsolute(file3) ? file3 : path52.join(workingDir, file3);
|
|
59646
|
+
if (!fs41.existsSync(fullPath)) {
|
|
59084
59647
|
continue;
|
|
59085
59648
|
}
|
|
59086
59649
|
const complexity = getComplexityForFile(fullPath);
|
|
@@ -59201,8 +59764,8 @@ function countGoExports(content) {
|
|
|
59201
59764
|
}
|
|
59202
59765
|
function getExportCountForFile(filePath) {
|
|
59203
59766
|
try {
|
|
59204
|
-
const content =
|
|
59205
|
-
const ext =
|
|
59767
|
+
const content = fs41.readFileSync(filePath, "utf-8");
|
|
59768
|
+
const ext = path52.extname(filePath).toLowerCase();
|
|
59206
59769
|
switch (ext) {
|
|
59207
59770
|
case ".ts":
|
|
59208
59771
|
case ".tsx":
|
|
@@ -59228,8 +59791,8 @@ async function computePublicApiDelta(files, workingDir) {
|
|
|
59228
59791
|
let totalExports = 0;
|
|
59229
59792
|
const analyzedFiles = [];
|
|
59230
59793
|
for (const file3 of files) {
|
|
59231
|
-
const fullPath =
|
|
59232
|
-
if (!
|
|
59794
|
+
const fullPath = path52.isAbsolute(file3) ? file3 : path52.join(workingDir, file3);
|
|
59795
|
+
if (!fs41.existsSync(fullPath)) {
|
|
59233
59796
|
continue;
|
|
59234
59797
|
}
|
|
59235
59798
|
const exports = getExportCountForFile(fullPath);
|
|
@@ -59262,16 +59825,16 @@ async function computeDuplicationRatio(files, workingDir) {
|
|
|
59262
59825
|
let duplicateLines = 0;
|
|
59263
59826
|
const analyzedFiles = [];
|
|
59264
59827
|
for (const file3 of files) {
|
|
59265
|
-
const fullPath =
|
|
59266
|
-
if (!
|
|
59828
|
+
const fullPath = path52.isAbsolute(file3) ? file3 : path52.join(workingDir, file3);
|
|
59829
|
+
if (!fs41.existsSync(fullPath)) {
|
|
59267
59830
|
continue;
|
|
59268
59831
|
}
|
|
59269
59832
|
try {
|
|
59270
|
-
const stat2 =
|
|
59271
|
-
if (stat2.size >
|
|
59833
|
+
const stat2 = fs41.statSync(fullPath);
|
|
59834
|
+
if (stat2.size > MAX_FILE_SIZE_BYTES3) {
|
|
59272
59835
|
continue;
|
|
59273
59836
|
}
|
|
59274
|
-
const content =
|
|
59837
|
+
const content = fs41.readFileSync(fullPath, "utf-8");
|
|
59275
59838
|
const lines = content.split(`
|
|
59276
59839
|
`).filter((line) => line.trim().length > 0);
|
|
59277
59840
|
if (lines.length < MIN_DUPLICATION_LINES) {
|
|
@@ -59295,8 +59858,8 @@ function countCodeLines(content) {
|
|
|
59295
59858
|
return lines.length;
|
|
59296
59859
|
}
|
|
59297
59860
|
function isTestFile(filePath) {
|
|
59298
|
-
const basename7 =
|
|
59299
|
-
const _ext =
|
|
59861
|
+
const basename7 = path52.basename(filePath);
|
|
59862
|
+
const _ext = path52.extname(filePath).toLowerCase();
|
|
59300
59863
|
const testPatterns = [
|
|
59301
59864
|
".test.",
|
|
59302
59865
|
".spec.",
|
|
@@ -59377,8 +59940,8 @@ function matchGlobSegment(globSegments, pathSegments) {
|
|
|
59377
59940
|
}
|
|
59378
59941
|
return gIndex === globSegments.length && pIndex === pathSegments.length;
|
|
59379
59942
|
}
|
|
59380
|
-
function matchesGlobSegment(
|
|
59381
|
-
const normalizedPath =
|
|
59943
|
+
function matchesGlobSegment(path53, glob) {
|
|
59944
|
+
const normalizedPath = path53.replace(/\\/g, "/");
|
|
59382
59945
|
const normalizedGlob = glob.replace(/\\/g, "/");
|
|
59383
59946
|
if (normalizedPath.includes("//")) {
|
|
59384
59947
|
return false;
|
|
@@ -59409,8 +59972,8 @@ function simpleGlobToRegex2(glob) {
|
|
|
59409
59972
|
function hasGlobstar(glob) {
|
|
59410
59973
|
return glob.includes("**");
|
|
59411
59974
|
}
|
|
59412
|
-
function globMatches(
|
|
59413
|
-
const normalizedPath =
|
|
59975
|
+
function globMatches(path53, glob) {
|
|
59976
|
+
const normalizedPath = path53.replace(/\\/g, "/");
|
|
59414
59977
|
if (!glob || glob === "") {
|
|
59415
59978
|
if (normalizedPath.includes("//")) {
|
|
59416
59979
|
return false;
|
|
@@ -59446,31 +60009,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
|
|
|
59446
60009
|
async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
59447
60010
|
let testLines = 0;
|
|
59448
60011
|
let codeLines = 0;
|
|
59449
|
-
const srcDir =
|
|
59450
|
-
if (
|
|
60012
|
+
const srcDir = path52.join(workingDir, "src");
|
|
60013
|
+
if (fs41.existsSync(srcDir)) {
|
|
59451
60014
|
await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
59452
60015
|
codeLines += lines;
|
|
59453
60016
|
});
|
|
59454
60017
|
}
|
|
59455
60018
|
const possibleSrcDirs = ["lib", "app", "source", "core"];
|
|
59456
60019
|
for (const dir of possibleSrcDirs) {
|
|
59457
|
-
const dirPath =
|
|
59458
|
-
if (
|
|
60020
|
+
const dirPath = path52.join(workingDir, dir);
|
|
60021
|
+
if (fs41.existsSync(dirPath)) {
|
|
59459
60022
|
await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
59460
60023
|
codeLines += lines;
|
|
59461
60024
|
});
|
|
59462
60025
|
}
|
|
59463
60026
|
}
|
|
59464
|
-
const testsDir =
|
|
59465
|
-
if (
|
|
60027
|
+
const testsDir = path52.join(workingDir, "tests");
|
|
60028
|
+
if (fs41.existsSync(testsDir)) {
|
|
59466
60029
|
await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
59467
60030
|
testLines += lines;
|
|
59468
60031
|
});
|
|
59469
60032
|
}
|
|
59470
60033
|
const possibleTestDirs = ["test", "__tests__", "specs"];
|
|
59471
60034
|
for (const dir of possibleTestDirs) {
|
|
59472
|
-
const dirPath =
|
|
59473
|
-
if (
|
|
60035
|
+
const dirPath = path52.join(workingDir, dir);
|
|
60036
|
+
if (fs41.existsSync(dirPath) && dirPath !== testsDir) {
|
|
59474
60037
|
await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
59475
60038
|
testLines += lines;
|
|
59476
60039
|
});
|
|
@@ -59482,9 +60045,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
59482
60045
|
}
|
|
59483
60046
|
async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
|
|
59484
60047
|
try {
|
|
59485
|
-
const entries =
|
|
60048
|
+
const entries = fs41.readdirSync(dirPath, { withFileTypes: true });
|
|
59486
60049
|
for (const entry of entries) {
|
|
59487
|
-
const fullPath =
|
|
60050
|
+
const fullPath = path52.join(dirPath, entry.name);
|
|
59488
60051
|
if (entry.isDirectory()) {
|
|
59489
60052
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
|
|
59490
60053
|
continue;
|
|
@@ -59492,7 +60055,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
59492
60055
|
await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
|
|
59493
60056
|
} else if (entry.isFile()) {
|
|
59494
60057
|
const relativePath = fullPath.replace(`${dirPath}/`, "");
|
|
59495
|
-
const ext =
|
|
60058
|
+
const ext = path52.extname(entry.name).toLowerCase();
|
|
59496
60059
|
const validExts = [
|
|
59497
60060
|
".ts",
|
|
59498
60061
|
".tsx",
|
|
@@ -59528,7 +60091,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
59528
60091
|
continue;
|
|
59529
60092
|
}
|
|
59530
60093
|
try {
|
|
59531
|
-
const content =
|
|
60094
|
+
const content = fs41.readFileSync(fullPath, "utf-8");
|
|
59532
60095
|
const lines = countCodeLines(content);
|
|
59533
60096
|
callback(lines);
|
|
59534
60097
|
} catch {}
|
|
@@ -59635,7 +60198,7 @@ async function computeQualityMetrics(changedFiles, thresholds, workingDir) {
|
|
|
59635
60198
|
|
|
59636
60199
|
// src/tools/complexity-hotspots.ts
|
|
59637
60200
|
init_create_tool();
|
|
59638
|
-
var
|
|
60201
|
+
var MAX_FILE_SIZE_BYTES4 = 256 * 1024;
|
|
59639
60202
|
var DEFAULT_DAYS = 90;
|
|
59640
60203
|
var DEFAULT_TOP_N = 20;
|
|
59641
60204
|
var DEFAULT_EXTENSIONS = "ts,tsx,js,jsx,py,rs,ps1";
|
|
@@ -59729,11 +60292,11 @@ async function getGitChurn(days, directory) {
|
|
|
59729
60292
|
}
|
|
59730
60293
|
function getComplexityForFile2(filePath) {
|
|
59731
60294
|
try {
|
|
59732
|
-
const stat2 =
|
|
59733
|
-
if (stat2.size >
|
|
60295
|
+
const stat2 = fs42.statSync(filePath);
|
|
60296
|
+
if (stat2.size > MAX_FILE_SIZE_BYTES4) {
|
|
59734
60297
|
return null;
|
|
59735
60298
|
}
|
|
59736
|
-
const content =
|
|
60299
|
+
const content = fs42.readFileSync(filePath, "utf-8");
|
|
59737
60300
|
return estimateCyclomaticComplexity(content);
|
|
59738
60301
|
} catch {
|
|
59739
60302
|
return null;
|
|
@@ -59744,7 +60307,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
59744
60307
|
const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
|
|
59745
60308
|
const filteredChurn = new Map;
|
|
59746
60309
|
for (const [file3, count] of churnMap) {
|
|
59747
|
-
const ext =
|
|
60310
|
+
const ext = path53.extname(file3).toLowerCase();
|
|
59748
60311
|
if (extSet.has(ext)) {
|
|
59749
60312
|
filteredChurn.set(file3, count);
|
|
59750
60313
|
}
|
|
@@ -59754,8 +60317,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
59754
60317
|
let analyzedFiles = 0;
|
|
59755
60318
|
for (const [file3, churnCount] of filteredChurn) {
|
|
59756
60319
|
let fullPath = file3;
|
|
59757
|
-
if (!
|
|
59758
|
-
fullPath =
|
|
60320
|
+
if (!fs42.existsSync(fullPath)) {
|
|
60321
|
+
fullPath = path53.join(cwd, file3);
|
|
59759
60322
|
}
|
|
59760
60323
|
const complexity = getComplexityForFile2(fullPath);
|
|
59761
60324
|
if (complexity !== null) {
|
|
@@ -59997,8 +60560,8 @@ var curator_analyze = createSwarmTool({
|
|
|
59997
60560
|
});
|
|
59998
60561
|
// src/tools/declare-scope.ts
|
|
59999
60562
|
init_tool();
|
|
60000
|
-
import * as
|
|
60001
|
-
import * as
|
|
60563
|
+
import * as fs43 from "fs";
|
|
60564
|
+
import * as path54 from "path";
|
|
60002
60565
|
init_create_tool();
|
|
60003
60566
|
function validateTaskIdFormat(taskId) {
|
|
60004
60567
|
const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
|
|
@@ -60077,8 +60640,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
60077
60640
|
};
|
|
60078
60641
|
}
|
|
60079
60642
|
}
|
|
60080
|
-
normalizedDir =
|
|
60081
|
-
const pathParts = normalizedDir.split(
|
|
60643
|
+
normalizedDir = path54.normalize(args2.working_directory);
|
|
60644
|
+
const pathParts = normalizedDir.split(path54.sep);
|
|
60082
60645
|
if (pathParts.includes("..")) {
|
|
60083
60646
|
return {
|
|
60084
60647
|
success: false,
|
|
@@ -60088,11 +60651,11 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
60088
60651
|
]
|
|
60089
60652
|
};
|
|
60090
60653
|
}
|
|
60091
|
-
const resolvedDir =
|
|
60654
|
+
const resolvedDir = path54.resolve(normalizedDir);
|
|
60092
60655
|
try {
|
|
60093
|
-
const realPath =
|
|
60094
|
-
const planPath2 =
|
|
60095
|
-
if (!
|
|
60656
|
+
const realPath = fs43.realpathSync(resolvedDir);
|
|
60657
|
+
const planPath2 = path54.join(realPath, ".swarm", "plan.json");
|
|
60658
|
+
if (!fs43.existsSync(planPath2)) {
|
|
60096
60659
|
return {
|
|
60097
60660
|
success: false,
|
|
60098
60661
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -60115,8 +60678,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
60115
60678
|
console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
|
|
60116
60679
|
}
|
|
60117
60680
|
const directory = normalizedDir || fallbackDir;
|
|
60118
|
-
const planPath =
|
|
60119
|
-
if (!
|
|
60681
|
+
const planPath = path54.resolve(directory, ".swarm", "plan.json");
|
|
60682
|
+
if (!fs43.existsSync(planPath)) {
|
|
60120
60683
|
return {
|
|
60121
60684
|
success: false,
|
|
60122
60685
|
message: "No plan found",
|
|
@@ -60125,7 +60688,7 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
60125
60688
|
}
|
|
60126
60689
|
let planContent;
|
|
60127
60690
|
try {
|
|
60128
|
-
planContent = JSON.parse(
|
|
60691
|
+
planContent = JSON.parse(fs43.readFileSync(planPath, "utf-8"));
|
|
60129
60692
|
} catch {
|
|
60130
60693
|
return {
|
|
60131
60694
|
success: false,
|
|
@@ -60157,8 +60720,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
60157
60720
|
const normalizeErrors = [];
|
|
60158
60721
|
const dir = normalizedDir || fallbackDir || process.cwd();
|
|
60159
60722
|
const mergedFiles = rawMergedFiles.map((file3) => {
|
|
60160
|
-
if (
|
|
60161
|
-
const relativePath =
|
|
60723
|
+
if (path54.isAbsolute(file3)) {
|
|
60724
|
+
const relativePath = path54.relative(dir, file3).replace(/\\/g, "/");
|
|
60162
60725
|
if (relativePath.startsWith("..")) {
|
|
60163
60726
|
normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
|
|
60164
60727
|
return file3;
|
|
@@ -60205,7 +60768,7 @@ import * as child_process5 from "child_process";
|
|
|
60205
60768
|
|
|
60206
60769
|
// src/diff/ast-diff.ts
|
|
60207
60770
|
init_tree_sitter();
|
|
60208
|
-
import { extname as
|
|
60771
|
+
import { extname as extname9 } from "path";
|
|
60209
60772
|
|
|
60210
60773
|
// src/lang/registry.ts
|
|
60211
60774
|
init_runtime();
|
|
@@ -60290,7 +60853,7 @@ var QUERIES = {
|
|
|
60290
60853
|
var AST_TIMEOUT_MS = 500;
|
|
60291
60854
|
async function computeASTDiff(filePath, oldContent, newContent) {
|
|
60292
60855
|
const startTime = Date.now();
|
|
60293
|
-
const extension =
|
|
60856
|
+
const extension = extname9(filePath).toLowerCase();
|
|
60294
60857
|
const language = getLanguageForExtension(extension);
|
|
60295
60858
|
if (!language) {
|
|
60296
60859
|
return {
|
|
@@ -60352,26 +60915,26 @@ async function computeASTDiff(filePath, oldContent, newContent) {
|
|
|
60352
60915
|
}
|
|
60353
60916
|
}
|
|
60354
60917
|
function extractSymbols(tree, language) {
|
|
60355
|
-
const
|
|
60918
|
+
const symbols2 = [];
|
|
60356
60919
|
const queryStr = QUERIES[language.id];
|
|
60357
60920
|
if (!queryStr) {
|
|
60358
|
-
return
|
|
60921
|
+
return symbols2;
|
|
60359
60922
|
}
|
|
60360
60923
|
try {
|
|
60361
60924
|
const lang = tree.language;
|
|
60362
60925
|
if (!lang) {
|
|
60363
|
-
return
|
|
60926
|
+
return symbols2;
|
|
60364
60927
|
}
|
|
60365
60928
|
const query = new Query(lang, queryStr);
|
|
60366
60929
|
const matches = query.matches(tree.rootNode);
|
|
60367
60930
|
for (const match of matches) {
|
|
60368
60931
|
const symbol3 = parseMatch(match, language.id);
|
|
60369
60932
|
if (symbol3) {
|
|
60370
|
-
|
|
60933
|
+
symbols2.push(symbol3);
|
|
60371
60934
|
}
|
|
60372
60935
|
}
|
|
60373
60936
|
} catch {}
|
|
60374
|
-
return
|
|
60937
|
+
return symbols2;
|
|
60375
60938
|
}
|
|
60376
60939
|
function parseMatch(match, languageId) {
|
|
60377
60940
|
const captures = match.captures;
|
|
@@ -60484,20 +61047,20 @@ function validateBase(base) {
|
|
|
60484
61047
|
function validatePaths(paths) {
|
|
60485
61048
|
if (!paths)
|
|
60486
61049
|
return null;
|
|
60487
|
-
for (const
|
|
60488
|
-
if (!
|
|
61050
|
+
for (const path56 of paths) {
|
|
61051
|
+
if (!path56 || path56.length === 0) {
|
|
60489
61052
|
return "empty path not allowed";
|
|
60490
61053
|
}
|
|
60491
|
-
if (
|
|
61054
|
+
if (path56.length > MAX_PATH_LENGTH) {
|
|
60492
61055
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
60493
61056
|
}
|
|
60494
|
-
if (SHELL_METACHARACTERS2.test(
|
|
61057
|
+
if (SHELL_METACHARACTERS2.test(path56)) {
|
|
60495
61058
|
return "path contains shell metacharacters";
|
|
60496
61059
|
}
|
|
60497
|
-
if (
|
|
61060
|
+
if (path56.startsWith("-")) {
|
|
60498
61061
|
return 'path cannot start with "-" (option-like arguments not allowed)';
|
|
60499
61062
|
}
|
|
60500
|
-
if (CONTROL_CHAR_PATTERN2.test(
|
|
61063
|
+
if (CONTROL_CHAR_PATTERN2.test(path56)) {
|
|
60501
61064
|
return "path contains control characters";
|
|
60502
61065
|
}
|
|
60503
61066
|
}
|
|
@@ -60578,8 +61141,8 @@ var diff = createSwarmTool({
|
|
|
60578
61141
|
if (parts2.length >= 3) {
|
|
60579
61142
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
60580
61143
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
60581
|
-
const
|
|
60582
|
-
files.push({ path:
|
|
61144
|
+
const path56 = parts2[2];
|
|
61145
|
+
files.push({ path: path56, additions, deletions });
|
|
60583
61146
|
}
|
|
60584
61147
|
}
|
|
60585
61148
|
const contractChanges = [];
|
|
@@ -60861,9 +61424,9 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
60861
61424
|
// src/tools/evidence-check.ts
|
|
60862
61425
|
init_dist();
|
|
60863
61426
|
init_create_tool();
|
|
60864
|
-
import * as
|
|
60865
|
-
import * as
|
|
60866
|
-
var
|
|
61427
|
+
import * as fs44 from "fs";
|
|
61428
|
+
import * as path56 from "path";
|
|
61429
|
+
var MAX_FILE_SIZE_BYTES5 = 1024 * 1024;
|
|
60867
61430
|
var MAX_EVIDENCE_FILES = 1000;
|
|
60868
61431
|
var EVIDENCE_DIR2 = ".swarm/evidence";
|
|
60869
61432
|
var PLAN_FILE = ".swarm/plan.md";
|
|
@@ -60889,9 +61452,9 @@ function validateRequiredTypes(input) {
|
|
|
60889
61452
|
return null;
|
|
60890
61453
|
}
|
|
60891
61454
|
function isPathWithinSwarm2(filePath, cwd) {
|
|
60892
|
-
const normalizedCwd =
|
|
60893
|
-
const swarmPath =
|
|
60894
|
-
const normalizedPath =
|
|
61455
|
+
const normalizedCwd = path56.resolve(cwd);
|
|
61456
|
+
const swarmPath = path56.join(normalizedCwd, ".swarm");
|
|
61457
|
+
const normalizedPath = path56.resolve(filePath);
|
|
60895
61458
|
return normalizedPath.startsWith(swarmPath);
|
|
60896
61459
|
}
|
|
60897
61460
|
function parseCompletedTasks(planContent) {
|
|
@@ -60907,12 +61470,12 @@ function parseCompletedTasks(planContent) {
|
|
|
60907
61470
|
}
|
|
60908
61471
|
function readEvidenceFiles(evidenceDir, _cwd) {
|
|
60909
61472
|
const evidence = [];
|
|
60910
|
-
if (!
|
|
61473
|
+
if (!fs44.existsSync(evidenceDir) || !fs44.statSync(evidenceDir).isDirectory()) {
|
|
60911
61474
|
return evidence;
|
|
60912
61475
|
}
|
|
60913
61476
|
let files;
|
|
60914
61477
|
try {
|
|
60915
|
-
files =
|
|
61478
|
+
files = fs44.readdirSync(evidenceDir);
|
|
60916
61479
|
} catch {
|
|
60917
61480
|
return evidence;
|
|
60918
61481
|
}
|
|
@@ -60921,14 +61484,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
60921
61484
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
60922
61485
|
continue;
|
|
60923
61486
|
}
|
|
60924
|
-
const filePath =
|
|
61487
|
+
const filePath = path56.join(evidenceDir, filename);
|
|
60925
61488
|
try {
|
|
60926
|
-
const resolvedPath =
|
|
60927
|
-
const evidenceDirResolved =
|
|
61489
|
+
const resolvedPath = path56.resolve(filePath);
|
|
61490
|
+
const evidenceDirResolved = path56.resolve(evidenceDir);
|
|
60928
61491
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
60929
61492
|
continue;
|
|
60930
61493
|
}
|
|
60931
|
-
const stat2 =
|
|
61494
|
+
const stat2 = fs44.lstatSync(filePath);
|
|
60932
61495
|
if (!stat2.isFile()) {
|
|
60933
61496
|
continue;
|
|
60934
61497
|
}
|
|
@@ -60937,8 +61500,8 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
60937
61500
|
}
|
|
60938
61501
|
let fileStat;
|
|
60939
61502
|
try {
|
|
60940
|
-
fileStat =
|
|
60941
|
-
if (fileStat.size >
|
|
61503
|
+
fileStat = fs44.statSync(filePath);
|
|
61504
|
+
if (fileStat.size > MAX_FILE_SIZE_BYTES5) {
|
|
60942
61505
|
continue;
|
|
60943
61506
|
}
|
|
60944
61507
|
} catch {
|
|
@@ -60946,7 +61509,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
60946
61509
|
}
|
|
60947
61510
|
let content;
|
|
60948
61511
|
try {
|
|
60949
|
-
content =
|
|
61512
|
+
content = fs44.readFileSync(filePath, "utf-8");
|
|
60950
61513
|
} catch {
|
|
60951
61514
|
continue;
|
|
60952
61515
|
}
|
|
@@ -61042,7 +61605,7 @@ var evidence_check = createSwarmTool({
|
|
|
61042
61605
|
return JSON.stringify(errorResult, null, 2);
|
|
61043
61606
|
}
|
|
61044
61607
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
|
|
61045
|
-
const planPath =
|
|
61608
|
+
const planPath = path56.join(cwd, PLAN_FILE);
|
|
61046
61609
|
if (!isPathWithinSwarm2(planPath, cwd)) {
|
|
61047
61610
|
const errorResult = {
|
|
61048
61611
|
error: "plan file path validation failed",
|
|
@@ -61056,7 +61619,7 @@ var evidence_check = createSwarmTool({
|
|
|
61056
61619
|
}
|
|
61057
61620
|
let planContent;
|
|
61058
61621
|
try {
|
|
61059
|
-
planContent =
|
|
61622
|
+
planContent = fs44.readFileSync(planPath, "utf-8");
|
|
61060
61623
|
} catch {
|
|
61061
61624
|
const result2 = {
|
|
61062
61625
|
message: "No completed tasks found in plan.",
|
|
@@ -61074,7 +61637,7 @@ var evidence_check = createSwarmTool({
|
|
|
61074
61637
|
};
|
|
61075
61638
|
return JSON.stringify(result2, null, 2);
|
|
61076
61639
|
}
|
|
61077
|
-
const evidenceDir =
|
|
61640
|
+
const evidenceDir = path56.join(cwd, EVIDENCE_DIR2);
|
|
61078
61641
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
61079
61642
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
61080
61643
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -61091,8 +61654,8 @@ var evidence_check = createSwarmTool({
|
|
|
61091
61654
|
// src/tools/file-extractor.ts
|
|
61092
61655
|
init_tool();
|
|
61093
61656
|
init_create_tool();
|
|
61094
|
-
import * as
|
|
61095
|
-
import * as
|
|
61657
|
+
import * as fs45 from "fs";
|
|
61658
|
+
import * as path57 from "path";
|
|
61096
61659
|
var EXT_MAP = {
|
|
61097
61660
|
python: ".py",
|
|
61098
61661
|
py: ".py",
|
|
@@ -61154,8 +61717,8 @@ var extract_code_blocks = createSwarmTool({
|
|
|
61154
61717
|
execute: async (args2, directory) => {
|
|
61155
61718
|
const { content, output_dir, prefix } = args2;
|
|
61156
61719
|
const targetDir = output_dir || directory;
|
|
61157
|
-
if (!
|
|
61158
|
-
|
|
61720
|
+
if (!fs45.existsSync(targetDir)) {
|
|
61721
|
+
fs45.mkdirSync(targetDir, { recursive: true });
|
|
61159
61722
|
}
|
|
61160
61723
|
if (!content) {
|
|
61161
61724
|
return "Error: content is required";
|
|
@@ -61173,16 +61736,16 @@ var extract_code_blocks = createSwarmTool({
|
|
|
61173
61736
|
if (prefix) {
|
|
61174
61737
|
filename = `${prefix}_${filename}`;
|
|
61175
61738
|
}
|
|
61176
|
-
let filepath =
|
|
61177
|
-
const base =
|
|
61178
|
-
const ext =
|
|
61739
|
+
let filepath = path57.join(targetDir, filename);
|
|
61740
|
+
const base = path57.basename(filepath, path57.extname(filepath));
|
|
61741
|
+
const ext = path57.extname(filepath);
|
|
61179
61742
|
let counter = 1;
|
|
61180
|
-
while (
|
|
61181
|
-
filepath =
|
|
61743
|
+
while (fs45.existsSync(filepath)) {
|
|
61744
|
+
filepath = path57.join(targetDir, `${base}_${counter}${ext}`);
|
|
61182
61745
|
counter++;
|
|
61183
61746
|
}
|
|
61184
61747
|
try {
|
|
61185
|
-
|
|
61748
|
+
fs45.writeFileSync(filepath, code.trim(), "utf-8");
|
|
61186
61749
|
savedFiles.push(filepath);
|
|
61187
61750
|
} catch (error93) {
|
|
61188
61751
|
errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
@@ -61212,7 +61775,7 @@ init_create_tool();
|
|
|
61212
61775
|
var GITINGEST_TIMEOUT_MS = 1e4;
|
|
61213
61776
|
var GITINGEST_MAX_RESPONSE_BYTES = 5242880;
|
|
61214
61777
|
var GITINGEST_MAX_RETRIES = 2;
|
|
61215
|
-
var delay = (ms) => new Promise((
|
|
61778
|
+
var delay = (ms) => new Promise((resolve20) => setTimeout(resolve20, ms));
|
|
61216
61779
|
async function fetchGitingest(args2) {
|
|
61217
61780
|
for (let attempt = 0;attempt <= GITINGEST_MAX_RETRIES; attempt++) {
|
|
61218
61781
|
try {
|
|
@@ -61298,11 +61861,11 @@ var gitingest = createSwarmTool({
|
|
|
61298
61861
|
// src/tools/imports.ts
|
|
61299
61862
|
init_dist();
|
|
61300
61863
|
init_create_tool();
|
|
61301
|
-
import * as
|
|
61302
|
-
import * as
|
|
61864
|
+
import * as fs46 from "fs";
|
|
61865
|
+
import * as path58 from "path";
|
|
61303
61866
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
61304
61867
|
var MAX_SYMBOL_LENGTH = 256;
|
|
61305
|
-
var
|
|
61868
|
+
var MAX_FILE_SIZE_BYTES6 = 1024 * 1024;
|
|
61306
61869
|
var MAX_CONSUMERS = 100;
|
|
61307
61870
|
var SUPPORTED_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
61308
61871
|
var BINARY_SIGNATURES2 = [
|
|
@@ -61347,7 +61910,7 @@ function validateSymbolInput(symbol3) {
|
|
|
61347
61910
|
return null;
|
|
61348
61911
|
}
|
|
61349
61912
|
function isBinaryFile2(filePath, buffer) {
|
|
61350
|
-
const ext =
|
|
61913
|
+
const ext = path58.extname(filePath).toLowerCase();
|
|
61351
61914
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
61352
61915
|
return false;
|
|
61353
61916
|
}
|
|
@@ -61371,15 +61934,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
61371
61934
|
const imports = [];
|
|
61372
61935
|
let _resolvedTarget;
|
|
61373
61936
|
try {
|
|
61374
|
-
_resolvedTarget =
|
|
61937
|
+
_resolvedTarget = path58.resolve(targetFile);
|
|
61375
61938
|
} catch {
|
|
61376
61939
|
_resolvedTarget = targetFile;
|
|
61377
61940
|
}
|
|
61378
|
-
const targetBasename =
|
|
61941
|
+
const targetBasename = path58.basename(targetFile, path58.extname(targetFile));
|
|
61379
61942
|
const targetWithExt = targetFile;
|
|
61380
61943
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
61381
|
-
const normalizedTargetWithExt =
|
|
61382
|
-
const normalizedTargetWithoutExt =
|
|
61944
|
+
const normalizedTargetWithExt = path58.normalize(targetWithExt).replace(/\\/g, "/");
|
|
61945
|
+
const normalizedTargetWithoutExt = path58.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
61383
61946
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
61384
61947
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
61385
61948
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -61402,9 +61965,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
61402
61965
|
}
|
|
61403
61966
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
61404
61967
|
let isMatch = false;
|
|
61405
|
-
const _targetDir =
|
|
61406
|
-
const targetExt =
|
|
61407
|
-
const targetBasenameNoExt =
|
|
61968
|
+
const _targetDir = path58.dirname(targetFile);
|
|
61969
|
+
const targetExt = path58.extname(targetFile);
|
|
61970
|
+
const targetBasenameNoExt = path58.basename(targetFile, targetExt);
|
|
61408
61971
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
61409
61972
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
61410
61973
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -61461,7 +62024,7 @@ var SKIP_DIRECTORIES3 = new Set([
|
|
|
61461
62024
|
function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
|
|
61462
62025
|
let entries;
|
|
61463
62026
|
try {
|
|
61464
|
-
entries =
|
|
62027
|
+
entries = fs46.readdirSync(dir);
|
|
61465
62028
|
} catch (e) {
|
|
61466
62029
|
stats.fileErrors.push({
|
|
61467
62030
|
path: dir,
|
|
@@ -61472,13 +62035,13 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
|
|
|
61472
62035
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
61473
62036
|
for (const entry of entries) {
|
|
61474
62037
|
if (SKIP_DIRECTORIES3.has(entry)) {
|
|
61475
|
-
stats.skippedDirs.push(
|
|
62038
|
+
stats.skippedDirs.push(path58.join(dir, entry));
|
|
61476
62039
|
continue;
|
|
61477
62040
|
}
|
|
61478
|
-
const fullPath =
|
|
62041
|
+
const fullPath = path58.join(dir, entry);
|
|
61479
62042
|
let stat2;
|
|
61480
62043
|
try {
|
|
61481
|
-
stat2 =
|
|
62044
|
+
stat2 = fs46.statSync(fullPath);
|
|
61482
62045
|
} catch (e) {
|
|
61483
62046
|
stats.fileErrors.push({
|
|
61484
62047
|
path: fullPath,
|
|
@@ -61489,7 +62052,7 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
|
|
|
61489
62052
|
if (stat2.isDirectory()) {
|
|
61490
62053
|
findSourceFiles(fullPath, files, stats);
|
|
61491
62054
|
} else if (stat2.isFile()) {
|
|
61492
|
-
const ext =
|
|
62055
|
+
const ext = path58.extname(fullPath).toLowerCase();
|
|
61493
62056
|
if (SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
61494
62057
|
files.push(fullPath);
|
|
61495
62058
|
}
|
|
@@ -61546,8 +62109,8 @@ var imports = createSwarmTool({
|
|
|
61546
62109
|
return JSON.stringify(errorResult, null, 2);
|
|
61547
62110
|
}
|
|
61548
62111
|
try {
|
|
61549
|
-
const targetFile =
|
|
61550
|
-
if (!
|
|
62112
|
+
const targetFile = path58.resolve(file3);
|
|
62113
|
+
if (!fs46.existsSync(targetFile)) {
|
|
61551
62114
|
const errorResult = {
|
|
61552
62115
|
error: `target file not found: ${file3}`,
|
|
61553
62116
|
target: file3,
|
|
@@ -61557,7 +62120,7 @@ var imports = createSwarmTool({
|
|
|
61557
62120
|
};
|
|
61558
62121
|
return JSON.stringify(errorResult, null, 2);
|
|
61559
62122
|
}
|
|
61560
|
-
const targetStat =
|
|
62123
|
+
const targetStat = fs46.statSync(targetFile);
|
|
61561
62124
|
if (!targetStat.isFile()) {
|
|
61562
62125
|
const errorResult = {
|
|
61563
62126
|
error: "target must be a file, not a directory",
|
|
@@ -61568,7 +62131,7 @@ var imports = createSwarmTool({
|
|
|
61568
62131
|
};
|
|
61569
62132
|
return JSON.stringify(errorResult, null, 2);
|
|
61570
62133
|
}
|
|
61571
|
-
const baseDir =
|
|
62134
|
+
const baseDir = path58.dirname(targetFile);
|
|
61572
62135
|
const scanStats = {
|
|
61573
62136
|
skippedDirs: [],
|
|
61574
62137
|
skippedFiles: 0,
|
|
@@ -61583,12 +62146,12 @@ var imports = createSwarmTool({
|
|
|
61583
62146
|
if (consumers.length >= MAX_CONSUMERS)
|
|
61584
62147
|
break;
|
|
61585
62148
|
try {
|
|
61586
|
-
const stat2 =
|
|
61587
|
-
if (stat2.size >
|
|
62149
|
+
const stat2 = fs46.statSync(filePath);
|
|
62150
|
+
if (stat2.size > MAX_FILE_SIZE_BYTES6) {
|
|
61588
62151
|
skippedFileCount++;
|
|
61589
62152
|
continue;
|
|
61590
62153
|
}
|
|
61591
|
-
const buffer =
|
|
62154
|
+
const buffer = fs46.readFileSync(filePath);
|
|
61592
62155
|
if (isBinaryFile2(filePath, buffer)) {
|
|
61593
62156
|
skippedFileCount++;
|
|
61594
62157
|
continue;
|
|
@@ -61788,7 +62351,7 @@ init_dist();
|
|
|
61788
62351
|
init_config();
|
|
61789
62352
|
init_knowledge_store();
|
|
61790
62353
|
init_create_tool();
|
|
61791
|
-
import { existsSync as
|
|
62354
|
+
import { existsSync as existsSync36 } from "fs";
|
|
61792
62355
|
var DEFAULT_LIMIT = 10;
|
|
61793
62356
|
var MAX_LESSON_LENGTH = 200;
|
|
61794
62357
|
var VALID_CATEGORIES3 = [
|
|
@@ -61857,14 +62420,14 @@ function validateLimit(limit) {
|
|
|
61857
62420
|
}
|
|
61858
62421
|
async function readSwarmKnowledge(directory) {
|
|
61859
62422
|
const swarmPath = resolveSwarmKnowledgePath(directory);
|
|
61860
|
-
if (!
|
|
62423
|
+
if (!existsSync36(swarmPath)) {
|
|
61861
62424
|
return [];
|
|
61862
62425
|
}
|
|
61863
62426
|
return readKnowledge(swarmPath);
|
|
61864
62427
|
}
|
|
61865
62428
|
async function readHiveKnowledge() {
|
|
61866
62429
|
const hivePath = resolveHiveKnowledgePath();
|
|
61867
|
-
if (!
|
|
62430
|
+
if (!existsSync36(hivePath)) {
|
|
61868
62431
|
return [];
|
|
61869
62432
|
}
|
|
61870
62433
|
return readKnowledge(hivePath);
|
|
@@ -62177,8 +62740,8 @@ init_dist();
|
|
|
62177
62740
|
init_config();
|
|
62178
62741
|
init_schema();
|
|
62179
62742
|
init_manager();
|
|
62180
|
-
import * as
|
|
62181
|
-
import * as
|
|
62743
|
+
import * as fs47 from "fs";
|
|
62744
|
+
import * as path59 from "path";
|
|
62182
62745
|
init_review_receipt();
|
|
62183
62746
|
init_utils2();
|
|
62184
62747
|
init_ledger();
|
|
@@ -62402,11 +62965,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
62402
62965
|
safeWarn(`[phase_complete] Completion verify error (non-blocking):`, completionError);
|
|
62403
62966
|
}
|
|
62404
62967
|
try {
|
|
62405
|
-
const driftEvidencePath =
|
|
62968
|
+
const driftEvidencePath = path59.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
|
|
62406
62969
|
let driftVerdictFound = false;
|
|
62407
62970
|
let driftVerdictApproved = false;
|
|
62408
62971
|
try {
|
|
62409
|
-
const driftEvidenceContent =
|
|
62972
|
+
const driftEvidenceContent = fs47.readFileSync(driftEvidencePath, "utf-8");
|
|
62410
62973
|
const driftEvidence = JSON.parse(driftEvidenceContent);
|
|
62411
62974
|
const entries = driftEvidence.entries ?? [];
|
|
62412
62975
|
for (const entry of entries) {
|
|
@@ -62436,14 +62999,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
62436
62999
|
driftVerdictFound = false;
|
|
62437
63000
|
}
|
|
62438
63001
|
if (!driftVerdictFound) {
|
|
62439
|
-
const specPath =
|
|
62440
|
-
const specExists =
|
|
63002
|
+
const specPath = path59.join(dir, ".swarm", "spec.md");
|
|
63003
|
+
const specExists = fs47.existsSync(specPath);
|
|
62441
63004
|
if (!specExists) {
|
|
62442
63005
|
let incompleteTaskCount = 0;
|
|
62443
63006
|
let planPhaseFound = false;
|
|
62444
63007
|
try {
|
|
62445
63008
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
62446
|
-
const planRaw =
|
|
63009
|
+
const planRaw = fs47.readFileSync(planPath, "utf-8");
|
|
62447
63010
|
const plan = JSON.parse(planRaw);
|
|
62448
63011
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
62449
63012
|
if (targetPhase) {
|
|
@@ -62488,7 +63051,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
62488
63051
|
const knowledgeConfig = KnowledgeConfigSchema.parse(config3.knowledge ?? {});
|
|
62489
63052
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
62490
63053
|
try {
|
|
62491
|
-
const projectName =
|
|
63054
|
+
const projectName = path59.basename(dir);
|
|
62492
63055
|
const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
|
|
62493
63056
|
if (curationResult) {
|
|
62494
63057
|
const sessionState = swarmState.agentSessions.get(sessionID);
|
|
@@ -62568,7 +63131,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
62568
63131
|
let phaseRequiredAgents;
|
|
62569
63132
|
try {
|
|
62570
63133
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
62571
|
-
const planRaw =
|
|
63134
|
+
const planRaw = fs47.readFileSync(planPath, "utf-8");
|
|
62572
63135
|
const plan = JSON.parse(planRaw);
|
|
62573
63136
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
62574
63137
|
phaseRequiredAgents = phaseObj?.required_agents;
|
|
@@ -62583,7 +63146,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
62583
63146
|
if (agentsMissing.length > 0) {
|
|
62584
63147
|
try {
|
|
62585
63148
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
62586
|
-
const planRaw =
|
|
63149
|
+
const planRaw = fs47.readFileSync(planPath, "utf-8");
|
|
62587
63150
|
const plan = JSON.parse(planRaw);
|
|
62588
63151
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
62589
63152
|
if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
|
|
@@ -62623,7 +63186,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
62623
63186
|
if (phaseCompleteConfig.regression_sweep?.enforce) {
|
|
62624
63187
|
try {
|
|
62625
63188
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
62626
|
-
const planRaw =
|
|
63189
|
+
const planRaw = fs47.readFileSync(planPath, "utf-8");
|
|
62627
63190
|
const plan = JSON.parse(planRaw);
|
|
62628
63191
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
62629
63192
|
if (targetPhase) {
|
|
@@ -62661,7 +63224,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
62661
63224
|
};
|
|
62662
63225
|
try {
|
|
62663
63226
|
const eventsPath = validateSwarmPath(dir, "events.jsonl");
|
|
62664
|
-
|
|
63227
|
+
fs47.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
62665
63228
|
`, "utf-8");
|
|
62666
63229
|
} catch (writeError) {
|
|
62667
63230
|
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -62703,12 +63266,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
62703
63266
|
warnings.push(`Warning: failed to update plan.json phase status`);
|
|
62704
63267
|
try {
|
|
62705
63268
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
62706
|
-
const planRaw =
|
|
63269
|
+
const planRaw = fs47.readFileSync(planPath, "utf-8");
|
|
62707
63270
|
const plan2 = JSON.parse(planRaw);
|
|
62708
63271
|
const phaseObj = plan2.phases.find((p) => p.id === phase);
|
|
62709
63272
|
if (phaseObj) {
|
|
62710
63273
|
phaseObj.status = "complete";
|
|
62711
|
-
|
|
63274
|
+
fs47.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
|
|
62712
63275
|
}
|
|
62713
63276
|
} catch {}
|
|
62714
63277
|
} else if (plan) {
|
|
@@ -62745,12 +63308,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
62745
63308
|
warnings.push(`Warning: failed to update plan.json phase status`);
|
|
62746
63309
|
try {
|
|
62747
63310
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
62748
|
-
const planRaw =
|
|
63311
|
+
const planRaw = fs47.readFileSync(planPath, "utf-8");
|
|
62749
63312
|
const plan = JSON.parse(planRaw);
|
|
62750
63313
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
62751
63314
|
if (phaseObj) {
|
|
62752
63315
|
phaseObj.status = "complete";
|
|
62753
|
-
|
|
63316
|
+
fs47.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
|
|
62754
63317
|
}
|
|
62755
63318
|
} catch {}
|
|
62756
63319
|
}
|
|
@@ -62807,8 +63370,8 @@ init_dist();
|
|
|
62807
63370
|
init_discovery();
|
|
62808
63371
|
init_utils();
|
|
62809
63372
|
init_create_tool();
|
|
62810
|
-
import * as
|
|
62811
|
-
import * as
|
|
63373
|
+
import * as fs48 from "fs";
|
|
63374
|
+
import * as path60 from "path";
|
|
62812
63375
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
62813
63376
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
62814
63377
|
function isValidEcosystem(value) {
|
|
@@ -62826,28 +63389,28 @@ function validateArgs3(args2) {
|
|
|
62826
63389
|
function detectEcosystems(directory) {
|
|
62827
63390
|
const ecosystems = [];
|
|
62828
63391
|
const cwd = directory;
|
|
62829
|
-
if (
|
|
63392
|
+
if (fs48.existsSync(path60.join(cwd, "package.json"))) {
|
|
62830
63393
|
ecosystems.push("npm");
|
|
62831
63394
|
}
|
|
62832
|
-
if (
|
|
63395
|
+
if (fs48.existsSync(path60.join(cwd, "pyproject.toml")) || fs48.existsSync(path60.join(cwd, "requirements.txt"))) {
|
|
62833
63396
|
ecosystems.push("pip");
|
|
62834
63397
|
}
|
|
62835
|
-
if (
|
|
63398
|
+
if (fs48.existsSync(path60.join(cwd, "Cargo.toml"))) {
|
|
62836
63399
|
ecosystems.push("cargo");
|
|
62837
63400
|
}
|
|
62838
|
-
if (
|
|
63401
|
+
if (fs48.existsSync(path60.join(cwd, "go.mod"))) {
|
|
62839
63402
|
ecosystems.push("go");
|
|
62840
63403
|
}
|
|
62841
63404
|
try {
|
|
62842
|
-
const files =
|
|
63405
|
+
const files = fs48.readdirSync(cwd);
|
|
62843
63406
|
if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
62844
63407
|
ecosystems.push("dotnet");
|
|
62845
63408
|
}
|
|
62846
63409
|
} catch {}
|
|
62847
|
-
if (
|
|
63410
|
+
if (fs48.existsSync(path60.join(cwd, "Gemfile")) || fs48.existsSync(path60.join(cwd, "Gemfile.lock"))) {
|
|
62848
63411
|
ecosystems.push("ruby");
|
|
62849
63412
|
}
|
|
62850
|
-
if (
|
|
63413
|
+
if (fs48.existsSync(path60.join(cwd, "pubspec.yaml"))) {
|
|
62851
63414
|
ecosystems.push("dart");
|
|
62852
63415
|
}
|
|
62853
63416
|
return ecosystems;
|
|
@@ -62860,7 +63423,7 @@ async function runNpmAudit(directory) {
|
|
|
62860
63423
|
stderr: "pipe",
|
|
62861
63424
|
cwd: directory
|
|
62862
63425
|
});
|
|
62863
|
-
const timeoutPromise = new Promise((
|
|
63426
|
+
const timeoutPromise = new Promise((resolve21) => setTimeout(() => resolve21("timeout"), AUDIT_TIMEOUT_MS));
|
|
62864
63427
|
const result = await Promise.race([
|
|
62865
63428
|
Promise.all([
|
|
62866
63429
|
new Response(proc.stdout).text(),
|
|
@@ -62983,7 +63546,7 @@ async function runPipAudit(directory) {
|
|
|
62983
63546
|
stderr: "pipe",
|
|
62984
63547
|
cwd: directory
|
|
62985
63548
|
});
|
|
62986
|
-
const timeoutPromise = new Promise((
|
|
63549
|
+
const timeoutPromise = new Promise((resolve21) => setTimeout(() => resolve21("timeout"), AUDIT_TIMEOUT_MS));
|
|
62987
63550
|
const result = await Promise.race([
|
|
62988
63551
|
Promise.all([
|
|
62989
63552
|
new Response(proc.stdout).text(),
|
|
@@ -63114,7 +63677,7 @@ async function runCargoAudit(directory) {
|
|
|
63114
63677
|
stderr: "pipe",
|
|
63115
63678
|
cwd: directory
|
|
63116
63679
|
});
|
|
63117
|
-
const timeoutPromise = new Promise((
|
|
63680
|
+
const timeoutPromise = new Promise((resolve21) => setTimeout(() => resolve21("timeout"), AUDIT_TIMEOUT_MS));
|
|
63118
63681
|
const result = await Promise.race([
|
|
63119
63682
|
Promise.all([
|
|
63120
63683
|
new Response(proc.stdout).text(),
|
|
@@ -63241,7 +63804,7 @@ async function runGoAudit(directory) {
|
|
|
63241
63804
|
stderr: "pipe",
|
|
63242
63805
|
cwd: directory
|
|
63243
63806
|
});
|
|
63244
|
-
const timeoutPromise = new Promise((
|
|
63807
|
+
const timeoutPromise = new Promise((resolve21) => setTimeout(() => resolve21("timeout"), AUDIT_TIMEOUT_MS));
|
|
63245
63808
|
const result = await Promise.race([
|
|
63246
63809
|
Promise.all([
|
|
63247
63810
|
new Response(proc.stdout).text(),
|
|
@@ -63377,7 +63940,7 @@ async function runDotnetAudit(directory) {
|
|
|
63377
63940
|
stderr: "pipe",
|
|
63378
63941
|
cwd: directory
|
|
63379
63942
|
});
|
|
63380
|
-
const timeoutPromise = new Promise((
|
|
63943
|
+
const timeoutPromise = new Promise((resolve21) => setTimeout(() => resolve21("timeout"), AUDIT_TIMEOUT_MS));
|
|
63381
63944
|
const result = await Promise.race([
|
|
63382
63945
|
Promise.all([
|
|
63383
63946
|
new Response(proc.stdout).text(),
|
|
@@ -63496,7 +64059,7 @@ async function runBundleAudit(directory) {
|
|
|
63496
64059
|
stderr: "pipe",
|
|
63497
64060
|
cwd: directory
|
|
63498
64061
|
});
|
|
63499
|
-
const timeoutPromise = new Promise((
|
|
64062
|
+
const timeoutPromise = new Promise((resolve21) => setTimeout(() => resolve21("timeout"), AUDIT_TIMEOUT_MS));
|
|
63500
64063
|
const result = await Promise.race([
|
|
63501
64064
|
Promise.all([
|
|
63502
64065
|
new Response(proc.stdout).text(),
|
|
@@ -63644,7 +64207,7 @@ async function runDartAudit(directory) {
|
|
|
63644
64207
|
stderr: "pipe",
|
|
63645
64208
|
cwd: directory
|
|
63646
64209
|
});
|
|
63647
|
-
const timeoutPromise = new Promise((
|
|
64210
|
+
const timeoutPromise = new Promise((resolve21) => setTimeout(() => resolve21("timeout"), AUDIT_TIMEOUT_MS));
|
|
63648
64211
|
const result = await Promise.race([
|
|
63649
64212
|
Promise.all([
|
|
63650
64213
|
new Response(proc.stdout).text(),
|
|
@@ -63869,8 +64432,8 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
|
|
|
63869
64432
|
]);
|
|
63870
64433
|
// src/tools/pre-check-batch.ts
|
|
63871
64434
|
init_dist();
|
|
63872
|
-
import * as
|
|
63873
|
-
import * as
|
|
64435
|
+
import * as fs50 from "fs";
|
|
64436
|
+
import * as path62 from "path";
|
|
63874
64437
|
|
|
63875
64438
|
// node_modules/yocto-queue/index.js
|
|
63876
64439
|
class Node2 {
|
|
@@ -63961,26 +64524,26 @@ function pLimit(concurrency) {
|
|
|
63961
64524
|
activeCount--;
|
|
63962
64525
|
resumeNext();
|
|
63963
64526
|
};
|
|
63964
|
-
const run2 = async (function_,
|
|
64527
|
+
const run2 = async (function_, resolve21, arguments_2) => {
|
|
63965
64528
|
const result = (async () => function_(...arguments_2))();
|
|
63966
|
-
|
|
64529
|
+
resolve21(result);
|
|
63967
64530
|
try {
|
|
63968
64531
|
await result;
|
|
63969
64532
|
} catch {}
|
|
63970
64533
|
next();
|
|
63971
64534
|
};
|
|
63972
|
-
const enqueue = (function_,
|
|
64535
|
+
const enqueue = (function_, resolve21, reject, arguments_2) => {
|
|
63973
64536
|
const queueItem = { reject };
|
|
63974
64537
|
new Promise((internalResolve) => {
|
|
63975
64538
|
queueItem.run = internalResolve;
|
|
63976
64539
|
queue.enqueue(queueItem);
|
|
63977
|
-
}).then(run2.bind(undefined, function_,
|
|
64540
|
+
}).then(run2.bind(undefined, function_, resolve21, arguments_2));
|
|
63978
64541
|
if (activeCount < concurrency) {
|
|
63979
64542
|
resumeNext();
|
|
63980
64543
|
}
|
|
63981
64544
|
};
|
|
63982
|
-
const generator = (function_, ...arguments_2) => new Promise((
|
|
63983
|
-
enqueue(function_,
|
|
64545
|
+
const generator = (function_, ...arguments_2) => new Promise((resolve21, reject) => {
|
|
64546
|
+
enqueue(function_, resolve21, reject, arguments_2);
|
|
63984
64547
|
});
|
|
63985
64548
|
Object.defineProperties(generator, {
|
|
63986
64549
|
activeCount: {
|
|
@@ -64144,9 +64707,9 @@ async function qualityBudget(input, directory) {
|
|
|
64144
64707
|
init_dist();
|
|
64145
64708
|
init_manager();
|
|
64146
64709
|
init_detector();
|
|
64147
|
-
import * as
|
|
64148
|
-
import * as
|
|
64149
|
-
import { extname as
|
|
64710
|
+
import * as fs49 from "fs";
|
|
64711
|
+
import * as path61 from "path";
|
|
64712
|
+
import { extname as extname12 } from "path";
|
|
64150
64713
|
|
|
64151
64714
|
// src/sast/rules/c.ts
|
|
64152
64715
|
var cRules = [
|
|
@@ -64896,7 +65459,7 @@ function mapSemgrepSeverity(severity) {
|
|
|
64896
65459
|
}
|
|
64897
65460
|
}
|
|
64898
65461
|
async function executeWithTimeout(command, args2, options) {
|
|
64899
|
-
return new Promise((
|
|
65462
|
+
return new Promise((resolve21) => {
|
|
64900
65463
|
const child = child_process6.spawn(command, args2, {
|
|
64901
65464
|
shell: false,
|
|
64902
65465
|
cwd: options.cwd
|
|
@@ -64905,7 +65468,7 @@ async function executeWithTimeout(command, args2, options) {
|
|
|
64905
65468
|
let stderr = "";
|
|
64906
65469
|
const timeout = setTimeout(() => {
|
|
64907
65470
|
child.kill("SIGTERM");
|
|
64908
|
-
|
|
65471
|
+
resolve21({
|
|
64909
65472
|
stdout,
|
|
64910
65473
|
stderr: "Process timed out",
|
|
64911
65474
|
exitCode: 124
|
|
@@ -64919,7 +65482,7 @@ async function executeWithTimeout(command, args2, options) {
|
|
|
64919
65482
|
});
|
|
64920
65483
|
child.on("close", (code) => {
|
|
64921
65484
|
clearTimeout(timeout);
|
|
64922
|
-
|
|
65485
|
+
resolve21({
|
|
64923
65486
|
stdout,
|
|
64924
65487
|
stderr,
|
|
64925
65488
|
exitCode: code ?? 0
|
|
@@ -64927,7 +65490,7 @@ async function executeWithTimeout(command, args2, options) {
|
|
|
64927
65490
|
});
|
|
64928
65491
|
child.on("error", (err2) => {
|
|
64929
65492
|
clearTimeout(timeout);
|
|
64930
|
-
|
|
65493
|
+
resolve21({
|
|
64931
65494
|
stdout,
|
|
64932
65495
|
stderr: err2.message,
|
|
64933
65496
|
exitCode: 1
|
|
@@ -65004,7 +65567,7 @@ async function runSemgrep(options) {
|
|
|
65004
65567
|
// src/tools/sast-scan.ts
|
|
65005
65568
|
init_utils();
|
|
65006
65569
|
init_create_tool();
|
|
65007
|
-
var
|
|
65570
|
+
var MAX_FILE_SIZE_BYTES7 = 512 * 1024;
|
|
65008
65571
|
var MAX_FILES_SCANNED2 = 1000;
|
|
65009
65572
|
var MAX_FINDINGS2 = 100;
|
|
65010
65573
|
var SEVERITY_ORDER = {
|
|
@@ -65015,17 +65578,17 @@ var SEVERITY_ORDER = {
|
|
|
65015
65578
|
};
|
|
65016
65579
|
function shouldSkipFile(filePath) {
|
|
65017
65580
|
try {
|
|
65018
|
-
const stats =
|
|
65019
|
-
if (stats.size >
|
|
65581
|
+
const stats = fs49.statSync(filePath);
|
|
65582
|
+
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
65020
65583
|
return { skip: true, reason: "file too large" };
|
|
65021
65584
|
}
|
|
65022
65585
|
if (stats.size === 0) {
|
|
65023
65586
|
return { skip: true, reason: "empty file" };
|
|
65024
65587
|
}
|
|
65025
|
-
const fd =
|
|
65588
|
+
const fd = fs49.openSync(filePath, "r");
|
|
65026
65589
|
const buffer = Buffer.alloc(8192);
|
|
65027
|
-
const bytesRead =
|
|
65028
|
-
|
|
65590
|
+
const bytesRead = fs49.readSync(fd, buffer, 0, 8192, 0);
|
|
65591
|
+
fs49.closeSync(fd);
|
|
65029
65592
|
if (bytesRead > 0) {
|
|
65030
65593
|
let nullCount = 0;
|
|
65031
65594
|
for (let i2 = 0;i2 < bytesRead; i2++) {
|
|
@@ -65064,7 +65627,7 @@ function countBySeverity(findings) {
|
|
|
65064
65627
|
}
|
|
65065
65628
|
function scanFileWithTierA(filePath, language) {
|
|
65066
65629
|
try {
|
|
65067
|
-
const content =
|
|
65630
|
+
const content = fs49.readFileSync(filePath, "utf-8");
|
|
65068
65631
|
const findings = executeRulesSync(filePath, content, language);
|
|
65069
65632
|
return findings.map((f) => ({
|
|
65070
65633
|
rule_id: f.rule_id,
|
|
@@ -65111,13 +65674,13 @@ async function sastScan(input, directory, config3) {
|
|
|
65111
65674
|
_filesSkipped++;
|
|
65112
65675
|
continue;
|
|
65113
65676
|
}
|
|
65114
|
-
const resolvedPath =
|
|
65115
|
-
const resolvedDirectory =
|
|
65116
|
-
if (!resolvedPath.startsWith(resolvedDirectory +
|
|
65677
|
+
const resolvedPath = path61.isAbsolute(filePath) ? filePath : path61.resolve(directory, filePath);
|
|
65678
|
+
const resolvedDirectory = path61.resolve(directory);
|
|
65679
|
+
if (!resolvedPath.startsWith(resolvedDirectory + path61.sep) && resolvedPath !== resolvedDirectory) {
|
|
65117
65680
|
_filesSkipped++;
|
|
65118
65681
|
continue;
|
|
65119
65682
|
}
|
|
65120
|
-
if (!
|
|
65683
|
+
if (!fs49.existsSync(resolvedPath)) {
|
|
65121
65684
|
_filesSkipped++;
|
|
65122
65685
|
continue;
|
|
65123
65686
|
}
|
|
@@ -65126,7 +65689,7 @@ async function sastScan(input, directory, config3) {
|
|
|
65126
65689
|
_filesSkipped++;
|
|
65127
65690
|
continue;
|
|
65128
65691
|
}
|
|
65129
|
-
const ext =
|
|
65692
|
+
const ext = extname12(resolvedPath).toLowerCase();
|
|
65130
65693
|
const profile = getProfileForFile(resolvedPath);
|
|
65131
65694
|
const langDef = getLanguageForExtension(ext);
|
|
65132
65695
|
if (!profile && !langDef) {
|
|
@@ -65315,20 +65878,20 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
65315
65878
|
let resolved;
|
|
65316
65879
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
65317
65880
|
if (isWinAbs) {
|
|
65318
|
-
resolved =
|
|
65319
|
-
} else if (
|
|
65320
|
-
resolved =
|
|
65881
|
+
resolved = path62.win32.resolve(inputPath);
|
|
65882
|
+
} else if (path62.isAbsolute(inputPath)) {
|
|
65883
|
+
resolved = path62.resolve(inputPath);
|
|
65321
65884
|
} else {
|
|
65322
|
-
resolved =
|
|
65885
|
+
resolved = path62.resolve(baseDir, inputPath);
|
|
65323
65886
|
}
|
|
65324
|
-
const workspaceResolved =
|
|
65325
|
-
let
|
|
65887
|
+
const workspaceResolved = path62.resolve(workspaceDir);
|
|
65888
|
+
let relative11;
|
|
65326
65889
|
if (isWinAbs) {
|
|
65327
|
-
|
|
65890
|
+
relative11 = path62.win32.relative(workspaceResolved, resolved);
|
|
65328
65891
|
} else {
|
|
65329
|
-
|
|
65892
|
+
relative11 = path62.relative(workspaceResolved, resolved);
|
|
65330
65893
|
}
|
|
65331
|
-
if (
|
|
65894
|
+
if (relative11.startsWith("..")) {
|
|
65332
65895
|
return "path traversal detected";
|
|
65333
65896
|
}
|
|
65334
65897
|
return null;
|
|
@@ -65391,7 +65954,7 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
65391
65954
|
if (typeof file3 !== "string") {
|
|
65392
65955
|
continue;
|
|
65393
65956
|
}
|
|
65394
|
-
const resolvedPath =
|
|
65957
|
+
const resolvedPath = path62.resolve(file3);
|
|
65395
65958
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
65396
65959
|
if (validationError) {
|
|
65397
65960
|
continue;
|
|
@@ -65484,7 +66047,7 @@ async function runSecretscanWrapped(files, directory, _config) {
|
|
|
65484
66047
|
}
|
|
65485
66048
|
}
|
|
65486
66049
|
async function runSecretscanWithFiles(files, directory) {
|
|
65487
|
-
const
|
|
66050
|
+
const MAX_FILE_SIZE_BYTES8 = 512 * 1024;
|
|
65488
66051
|
const MAX_FINDINGS3 = 100;
|
|
65489
66052
|
const DEFAULT_EXCLUDE_EXTENSIONS2 = new Set([
|
|
65490
66053
|
".png",
|
|
@@ -65548,7 +66111,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
65548
66111
|
skippedFiles++;
|
|
65549
66112
|
continue;
|
|
65550
66113
|
}
|
|
65551
|
-
const resolvedPath =
|
|
66114
|
+
const resolvedPath = path62.resolve(file3);
|
|
65552
66115
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
65553
66116
|
if (validationError) {
|
|
65554
66117
|
skippedFiles++;
|
|
@@ -65566,25 +66129,25 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
65566
66129
|
};
|
|
65567
66130
|
}
|
|
65568
66131
|
for (const file3 of validatedFiles) {
|
|
65569
|
-
const ext =
|
|
66132
|
+
const ext = path62.extname(file3).toLowerCase();
|
|
65570
66133
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
65571
66134
|
skippedFiles++;
|
|
65572
66135
|
continue;
|
|
65573
66136
|
}
|
|
65574
66137
|
let stat2;
|
|
65575
66138
|
try {
|
|
65576
|
-
stat2 =
|
|
66139
|
+
stat2 = fs50.statSync(file3);
|
|
65577
66140
|
} catch {
|
|
65578
66141
|
skippedFiles++;
|
|
65579
66142
|
continue;
|
|
65580
66143
|
}
|
|
65581
|
-
if (stat2.size >
|
|
66144
|
+
if (stat2.size > MAX_FILE_SIZE_BYTES8) {
|
|
65582
66145
|
skippedFiles++;
|
|
65583
66146
|
continue;
|
|
65584
66147
|
}
|
|
65585
66148
|
let content;
|
|
65586
66149
|
try {
|
|
65587
|
-
const buffer =
|
|
66150
|
+
const buffer = fs50.readFileSync(file3);
|
|
65588
66151
|
if (buffer.includes(0)) {
|
|
65589
66152
|
skippedFiles++;
|
|
65590
66153
|
continue;
|
|
@@ -65772,7 +66335,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
|
|
|
65772
66335
|
const preexistingFindings = [];
|
|
65773
66336
|
for (const finding of findings) {
|
|
65774
66337
|
const filePath = finding.location.file;
|
|
65775
|
-
const normalised =
|
|
66338
|
+
const normalised = path62.relative(directory, filePath).replace(/\\/g, "/");
|
|
65776
66339
|
const changedLines = changedLineRanges.get(normalised);
|
|
65777
66340
|
if (changedLines && changedLines.has(finding.location.line)) {
|
|
65778
66341
|
newFindings.push(finding);
|
|
@@ -65823,7 +66386,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
|
|
|
65823
66386
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
65824
66387
|
continue;
|
|
65825
66388
|
}
|
|
65826
|
-
changedFiles.push(
|
|
66389
|
+
changedFiles.push(path62.resolve(directory, file3));
|
|
65827
66390
|
}
|
|
65828
66391
|
if (changedFiles.length === 0) {
|
|
65829
66392
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -66011,7 +66574,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
66011
66574
|
};
|
|
66012
66575
|
return JSON.stringify(errorResult, null, 2);
|
|
66013
66576
|
}
|
|
66014
|
-
const resolvedDirectory =
|
|
66577
|
+
const resolvedDirectory = path62.resolve(typedArgs.directory);
|
|
66015
66578
|
const workspaceAnchor = resolvedDirectory;
|
|
66016
66579
|
const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
|
|
66017
66580
|
if (dirError) {
|
|
@@ -66117,31 +66680,31 @@ ${paginatedContent}`;
|
|
|
66117
66680
|
});
|
|
66118
66681
|
// src/tools/save-plan.ts
|
|
66119
66682
|
init_tool();
|
|
66120
|
-
import * as
|
|
66121
|
-
import * as
|
|
66683
|
+
import * as fs52 from "fs";
|
|
66684
|
+
import * as path64 from "path";
|
|
66122
66685
|
|
|
66123
66686
|
// src/parallel/file-locks.ts
|
|
66124
66687
|
var import_proper_lockfile3 = __toESM(require_proper_lockfile(), 1);
|
|
66125
|
-
import * as
|
|
66126
|
-
import * as
|
|
66688
|
+
import * as fs51 from "fs";
|
|
66689
|
+
import * as path63 from "path";
|
|
66127
66690
|
var LOCKS_DIR = ".swarm/locks";
|
|
66128
66691
|
var LOCK_TIMEOUT_MS = 5 * 60 * 1000;
|
|
66129
66692
|
function getLockFilePath(directory, filePath) {
|
|
66130
|
-
const normalized =
|
|
66131
|
-
if (!normalized.startsWith(
|
|
66693
|
+
const normalized = path63.resolve(directory, filePath);
|
|
66694
|
+
if (!normalized.startsWith(path63.resolve(directory))) {
|
|
66132
66695
|
throw new Error("Invalid file path: path traversal not allowed");
|
|
66133
66696
|
}
|
|
66134
66697
|
const hash3 = Buffer.from(normalized).toString("base64").replace(/[/+=]/g, "_");
|
|
66135
|
-
return
|
|
66698
|
+
return path63.join(directory, LOCKS_DIR, `${hash3}.lock`);
|
|
66136
66699
|
}
|
|
66137
66700
|
async function tryAcquireLock(directory, filePath, agent, taskId) {
|
|
66138
66701
|
const lockPath = getLockFilePath(directory, filePath);
|
|
66139
|
-
const locksDir =
|
|
66140
|
-
if (!
|
|
66141
|
-
|
|
66702
|
+
const locksDir = path63.dirname(lockPath);
|
|
66703
|
+
if (!fs51.existsSync(locksDir)) {
|
|
66704
|
+
fs51.mkdirSync(locksDir, { recursive: true });
|
|
66142
66705
|
}
|
|
66143
|
-
if (!
|
|
66144
|
-
|
|
66706
|
+
if (!fs51.existsSync(lockPath)) {
|
|
66707
|
+
fs51.writeFileSync(lockPath, "", "utf-8");
|
|
66145
66708
|
}
|
|
66146
66709
|
let release;
|
|
66147
66710
|
try {
|
|
@@ -66289,14 +66852,14 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
66289
66852
|
await savePlan(dir, plan);
|
|
66290
66853
|
await writeCheckpoint(dir).catch(() => {});
|
|
66291
66854
|
try {
|
|
66292
|
-
const markerPath =
|
|
66855
|
+
const markerPath = path64.join(dir, ".swarm", ".plan-write-marker");
|
|
66293
66856
|
const marker = JSON.stringify({
|
|
66294
66857
|
source: "save_plan",
|
|
66295
66858
|
timestamp: new Date().toISOString(),
|
|
66296
66859
|
phases_count: plan.phases.length,
|
|
66297
66860
|
tasks_count: tasksCount
|
|
66298
66861
|
});
|
|
66299
|
-
await
|
|
66862
|
+
await fs52.promises.writeFile(markerPath, marker, "utf8");
|
|
66300
66863
|
} catch {}
|
|
66301
66864
|
const warnings = [];
|
|
66302
66865
|
let criticReviewFound = false;
|
|
@@ -66312,7 +66875,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
66312
66875
|
return {
|
|
66313
66876
|
success: true,
|
|
66314
66877
|
message: "Plan saved successfully",
|
|
66315
|
-
plan_path:
|
|
66878
|
+
plan_path: path64.join(dir, ".swarm", "plan.json"),
|
|
66316
66879
|
phases_count: plan.phases.length,
|
|
66317
66880
|
tasks_count: tasksCount,
|
|
66318
66881
|
...warnings.length > 0 ? { warnings } : {}
|
|
@@ -66356,8 +66919,8 @@ var save_plan = createSwarmTool({
|
|
|
66356
66919
|
// src/tools/sbom-generate.ts
|
|
66357
66920
|
init_dist();
|
|
66358
66921
|
init_manager();
|
|
66359
|
-
import * as
|
|
66360
|
-
import * as
|
|
66922
|
+
import * as fs53 from "fs";
|
|
66923
|
+
import * as path65 from "path";
|
|
66361
66924
|
|
|
66362
66925
|
// src/sbom/detectors/index.ts
|
|
66363
66926
|
init_utils();
|
|
@@ -67205,9 +67768,9 @@ function findManifestFiles(rootDir) {
|
|
|
67205
67768
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
67206
67769
|
function searchDir(dir) {
|
|
67207
67770
|
try {
|
|
67208
|
-
const entries =
|
|
67771
|
+
const entries = fs53.readdirSync(dir, { withFileTypes: true });
|
|
67209
67772
|
for (const entry of entries) {
|
|
67210
|
-
const fullPath =
|
|
67773
|
+
const fullPath = path65.join(dir, entry.name);
|
|
67211
67774
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
67212
67775
|
continue;
|
|
67213
67776
|
}
|
|
@@ -67216,7 +67779,7 @@ function findManifestFiles(rootDir) {
|
|
|
67216
67779
|
} else if (entry.isFile()) {
|
|
67217
67780
|
for (const pattern of patterns) {
|
|
67218
67781
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
67219
|
-
manifestFiles.push(
|
|
67782
|
+
manifestFiles.push(path65.relative(rootDir, fullPath));
|
|
67220
67783
|
break;
|
|
67221
67784
|
}
|
|
67222
67785
|
}
|
|
@@ -67232,13 +67795,13 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
67232
67795
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
67233
67796
|
for (const dir of directories) {
|
|
67234
67797
|
try {
|
|
67235
|
-
const entries =
|
|
67798
|
+
const entries = fs53.readdirSync(dir, { withFileTypes: true });
|
|
67236
67799
|
for (const entry of entries) {
|
|
67237
|
-
const fullPath =
|
|
67800
|
+
const fullPath = path65.join(dir, entry.name);
|
|
67238
67801
|
if (entry.isFile()) {
|
|
67239
67802
|
for (const pattern of patterns) {
|
|
67240
67803
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
67241
|
-
found.push(
|
|
67804
|
+
found.push(path65.relative(workingDir, fullPath));
|
|
67242
67805
|
break;
|
|
67243
67806
|
}
|
|
67244
67807
|
}
|
|
@@ -67251,11 +67814,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
67251
67814
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
67252
67815
|
const dirs = new Set;
|
|
67253
67816
|
for (const file3 of changedFiles) {
|
|
67254
|
-
let currentDir =
|
|
67817
|
+
let currentDir = path65.dirname(file3);
|
|
67255
67818
|
while (true) {
|
|
67256
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
67257
|
-
dirs.add(
|
|
67258
|
-
const parent =
|
|
67819
|
+
if (currentDir && currentDir !== "." && currentDir !== path65.sep) {
|
|
67820
|
+
dirs.add(path65.join(workingDir, currentDir));
|
|
67821
|
+
const parent = path65.dirname(currentDir);
|
|
67259
67822
|
if (parent === currentDir)
|
|
67260
67823
|
break;
|
|
67261
67824
|
currentDir = parent;
|
|
@@ -67269,7 +67832,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
67269
67832
|
}
|
|
67270
67833
|
function ensureOutputDir(outputDir) {
|
|
67271
67834
|
try {
|
|
67272
|
-
|
|
67835
|
+
fs53.mkdirSync(outputDir, { recursive: true });
|
|
67273
67836
|
} catch (error93) {
|
|
67274
67837
|
if (!error93 || error93.code !== "EEXIST") {
|
|
67275
67838
|
throw error93;
|
|
@@ -67339,7 +67902,7 @@ var sbom_generate = createSwarmTool({
|
|
|
67339
67902
|
const changedFiles = obj.changed_files;
|
|
67340
67903
|
const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
|
|
67341
67904
|
const workingDir = directory;
|
|
67342
|
-
const outputDir =
|
|
67905
|
+
const outputDir = path65.isAbsolute(relativeOutputDir) ? relativeOutputDir : path65.join(workingDir, relativeOutputDir);
|
|
67343
67906
|
let manifestFiles = [];
|
|
67344
67907
|
if (scope === "all") {
|
|
67345
67908
|
manifestFiles = findManifestFiles(workingDir);
|
|
@@ -67362,11 +67925,11 @@ var sbom_generate = createSwarmTool({
|
|
|
67362
67925
|
const processedFiles = [];
|
|
67363
67926
|
for (const manifestFile of manifestFiles) {
|
|
67364
67927
|
try {
|
|
67365
|
-
const fullPath =
|
|
67366
|
-
if (!
|
|
67928
|
+
const fullPath = path65.isAbsolute(manifestFile) ? manifestFile : path65.join(workingDir, manifestFile);
|
|
67929
|
+
if (!fs53.existsSync(fullPath)) {
|
|
67367
67930
|
continue;
|
|
67368
67931
|
}
|
|
67369
|
-
const content =
|
|
67932
|
+
const content = fs53.readFileSync(fullPath, "utf-8");
|
|
67370
67933
|
const components = detectComponents(manifestFile, content);
|
|
67371
67934
|
processedFiles.push(manifestFile);
|
|
67372
67935
|
if (components.length > 0) {
|
|
@@ -67379,8 +67942,8 @@ var sbom_generate = createSwarmTool({
|
|
|
67379
67942
|
const bom = generateCycloneDX(allComponents);
|
|
67380
67943
|
const bomJson = serializeCycloneDX(bom);
|
|
67381
67944
|
const filename = generateSbomFilename();
|
|
67382
|
-
const outputPath =
|
|
67383
|
-
|
|
67945
|
+
const outputPath = path65.join(outputDir, filename);
|
|
67946
|
+
fs53.writeFileSync(outputPath, bomJson, "utf-8");
|
|
67384
67947
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
67385
67948
|
try {
|
|
67386
67949
|
const timestamp = new Date().toISOString();
|
|
@@ -67422,8 +67985,8 @@ var sbom_generate = createSwarmTool({
|
|
|
67422
67985
|
// src/tools/schema-drift.ts
|
|
67423
67986
|
init_dist();
|
|
67424
67987
|
init_create_tool();
|
|
67425
|
-
import * as
|
|
67426
|
-
import * as
|
|
67988
|
+
import * as fs54 from "fs";
|
|
67989
|
+
import * as path66 from "path";
|
|
67427
67990
|
var SPEC_CANDIDATES = [
|
|
67428
67991
|
"openapi.json",
|
|
67429
67992
|
"openapi.yaml",
|
|
@@ -67455,28 +68018,28 @@ function normalizePath2(p) {
|
|
|
67455
68018
|
}
|
|
67456
68019
|
function discoverSpecFile(cwd, specFileArg) {
|
|
67457
68020
|
if (specFileArg) {
|
|
67458
|
-
const resolvedPath =
|
|
67459
|
-
const normalizedCwd = cwd.endsWith(
|
|
68021
|
+
const resolvedPath = path66.resolve(cwd, specFileArg);
|
|
68022
|
+
const normalizedCwd = cwd.endsWith(path66.sep) ? cwd : cwd + path66.sep;
|
|
67460
68023
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
67461
68024
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
67462
68025
|
}
|
|
67463
|
-
const ext =
|
|
68026
|
+
const ext = path66.extname(resolvedPath).toLowerCase();
|
|
67464
68027
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
67465
68028
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
67466
68029
|
}
|
|
67467
|
-
const stats =
|
|
68030
|
+
const stats = fs54.statSync(resolvedPath);
|
|
67468
68031
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
67469
68032
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
67470
68033
|
}
|
|
67471
|
-
if (!
|
|
68034
|
+
if (!fs54.existsSync(resolvedPath)) {
|
|
67472
68035
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
67473
68036
|
}
|
|
67474
68037
|
return resolvedPath;
|
|
67475
68038
|
}
|
|
67476
68039
|
for (const candidate of SPEC_CANDIDATES) {
|
|
67477
|
-
const candidatePath =
|
|
67478
|
-
if (
|
|
67479
|
-
const stats =
|
|
68040
|
+
const candidatePath = path66.resolve(cwd, candidate);
|
|
68041
|
+
if (fs54.existsSync(candidatePath)) {
|
|
68042
|
+
const stats = fs54.statSync(candidatePath);
|
|
67480
68043
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
67481
68044
|
return candidatePath;
|
|
67482
68045
|
}
|
|
@@ -67485,8 +68048,8 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
67485
68048
|
return null;
|
|
67486
68049
|
}
|
|
67487
68050
|
function parseSpec(specFile) {
|
|
67488
|
-
const content =
|
|
67489
|
-
const ext =
|
|
68051
|
+
const content = fs54.readFileSync(specFile, "utf-8");
|
|
68052
|
+
const ext = path66.extname(specFile).toLowerCase();
|
|
67490
68053
|
if (ext === ".json") {
|
|
67491
68054
|
return parseJsonSpec(content);
|
|
67492
68055
|
}
|
|
@@ -67557,12 +68120,12 @@ function extractRoutes(cwd) {
|
|
|
67557
68120
|
function walkDir(dir) {
|
|
67558
68121
|
let entries;
|
|
67559
68122
|
try {
|
|
67560
|
-
entries =
|
|
68123
|
+
entries = fs54.readdirSync(dir, { withFileTypes: true });
|
|
67561
68124
|
} catch {
|
|
67562
68125
|
return;
|
|
67563
68126
|
}
|
|
67564
68127
|
for (const entry of entries) {
|
|
67565
|
-
const fullPath =
|
|
68128
|
+
const fullPath = path66.join(dir, entry.name);
|
|
67566
68129
|
if (entry.isSymbolicLink()) {
|
|
67567
68130
|
continue;
|
|
67568
68131
|
}
|
|
@@ -67572,7 +68135,7 @@ function extractRoutes(cwd) {
|
|
|
67572
68135
|
}
|
|
67573
68136
|
walkDir(fullPath);
|
|
67574
68137
|
} else if (entry.isFile()) {
|
|
67575
|
-
const ext =
|
|
68138
|
+
const ext = path66.extname(entry.name).toLowerCase();
|
|
67576
68139
|
const baseName = entry.name.toLowerCase();
|
|
67577
68140
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
67578
68141
|
continue;
|
|
@@ -67590,7 +68153,7 @@ function extractRoutes(cwd) {
|
|
|
67590
68153
|
}
|
|
67591
68154
|
function extractRoutesFromFile(filePath) {
|
|
67592
68155
|
const routes = [];
|
|
67593
|
-
const content =
|
|
68156
|
+
const content = fs54.readFileSync(filePath, "utf-8");
|
|
67594
68157
|
const lines = content.split(/\r?\n/);
|
|
67595
68158
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
67596
68159
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -67734,36 +68297,51 @@ var schema_drift = createSwarmTool({
|
|
|
67734
68297
|
}
|
|
67735
68298
|
}
|
|
67736
68299
|
});
|
|
67737
|
-
|
|
67738
|
-
// src/tools/index.ts
|
|
67739
|
-
init_secretscan();
|
|
67740
|
-
|
|
67741
|
-
// src/tools/symbols.ts
|
|
68300
|
+
// src/tools/search.ts
|
|
67742
68301
|
init_tool();
|
|
67743
68302
|
init_create_tool();
|
|
67744
|
-
import * as
|
|
67745
|
-
import * as
|
|
67746
|
-
var
|
|
67747
|
-
var
|
|
67748
|
-
|
|
67749
|
-
|
|
67750
|
-
|
|
68303
|
+
import * as fs55 from "fs";
|
|
68304
|
+
import * as path67 from "path";
|
|
68305
|
+
var DEFAULT_MAX_RESULTS = 100;
|
|
68306
|
+
var DEFAULT_MAX_LINES = 200;
|
|
68307
|
+
var REGEX_TIMEOUT_MS = 5000;
|
|
68308
|
+
var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
|
|
68309
|
+
var HARD_CAP_RESULTS = 1e4;
|
|
68310
|
+
var HARD_CAP_LINES = 1e4;
|
|
68311
|
+
function globMatch(pattern, filePath) {
|
|
68312
|
+
const normalizedPattern = pattern.replace(/\\/g, "/");
|
|
68313
|
+
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
68314
|
+
const regexPattern = normalizedPattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{DOUBLESTAR}}").replace(/\*/g, "[^/]*").replace(/\?/g, ".").replace(/\{\{DOUBLESTAR\}\}/g, ".*");
|
|
68315
|
+
try {
|
|
68316
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
68317
|
+
return regex.test(normalizedPath);
|
|
68318
|
+
} catch {
|
|
68319
|
+
return false;
|
|
67751
68320
|
}
|
|
68321
|
+
}
|
|
68322
|
+
function matchesGlobs(filePath, globs) {
|
|
68323
|
+
if (globs.length === 0)
|
|
68324
|
+
return true;
|
|
68325
|
+
return globs.some((glob) => globMatch(glob, filePath));
|
|
68326
|
+
}
|
|
68327
|
+
var WINDOWS_RESERVED_NAMES3 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
68328
|
+
function containsWindowsAttacks3(str) {
|
|
68329
|
+
if (/:[^\\/]/.test(str))
|
|
68330
|
+
return true;
|
|
67752
68331
|
const parts2 = str.split(/[/\\]/);
|
|
67753
68332
|
for (const part of parts2) {
|
|
67754
|
-
if (
|
|
68333
|
+
if (WINDOWS_RESERVED_NAMES3.test(part))
|
|
67755
68334
|
return true;
|
|
67756
|
-
}
|
|
67757
68335
|
}
|
|
67758
68336
|
return false;
|
|
67759
68337
|
}
|
|
67760
|
-
function
|
|
68338
|
+
function isPathInWorkspace3(filePath, workspace) {
|
|
67761
68339
|
try {
|
|
67762
|
-
const resolvedPath =
|
|
67763
|
-
const realWorkspace =
|
|
67764
|
-
const realResolvedPath =
|
|
67765
|
-
const relativePath =
|
|
67766
|
-
if (relativePath.startsWith("..") ||
|
|
68340
|
+
const resolvedPath = path67.resolve(workspace, filePath);
|
|
68341
|
+
const realWorkspace = fs55.realpathSync(workspace);
|
|
68342
|
+
const realResolvedPath = fs55.realpathSync(resolvedPath);
|
|
68343
|
+
const relativePath = path67.relative(realWorkspace, realResolvedPath);
|
|
68344
|
+
if (relativePath.startsWith("..") || path67.isAbsolute(relativePath)) {
|
|
67767
68345
|
return false;
|
|
67768
68346
|
}
|
|
67769
68347
|
return true;
|
|
@@ -67771,301 +68349,675 @@ function isPathInWorkspace(filePath, workspace) {
|
|
|
67771
68349
|
return false;
|
|
67772
68350
|
}
|
|
67773
68351
|
}
|
|
67774
|
-
function
|
|
67775
|
-
return
|
|
68352
|
+
function validatePathForRead2(filePath, workspace) {
|
|
68353
|
+
return isPathInWorkspace3(filePath, workspace);
|
|
67776
68354
|
}
|
|
67777
|
-
function
|
|
67778
|
-
const
|
|
67779
|
-
|
|
67780
|
-
|
|
68355
|
+
function findRgInEnvPath() {
|
|
68356
|
+
const searchPath = process.env.PATH ?? "";
|
|
68357
|
+
for (const dir of searchPath.split(path67.delimiter)) {
|
|
68358
|
+
if (!dir)
|
|
68359
|
+
continue;
|
|
68360
|
+
const isWindows = process.platform === "win32";
|
|
68361
|
+
const candidate = path67.join(dir, isWindows ? "rg.exe" : "rg");
|
|
68362
|
+
if (fs55.existsSync(candidate))
|
|
68363
|
+
return candidate;
|
|
67781
68364
|
}
|
|
67782
|
-
|
|
68365
|
+
return null;
|
|
68366
|
+
}
|
|
68367
|
+
async function isRipgrepAvailable() {
|
|
68368
|
+
const rgPath = findRgInEnvPath();
|
|
68369
|
+
if (!rgPath)
|
|
68370
|
+
return false;
|
|
67783
68371
|
try {
|
|
67784
|
-
const
|
|
67785
|
-
|
|
67786
|
-
|
|
67787
|
-
}
|
|
67788
|
-
|
|
68372
|
+
const proc = Bun.spawn([rgPath, "--version"], {
|
|
68373
|
+
stdout: "pipe",
|
|
68374
|
+
stderr: "pipe"
|
|
68375
|
+
});
|
|
68376
|
+
const exitCode = await proc.exited;
|
|
68377
|
+
return exitCode === 0;
|
|
67789
68378
|
} catch {
|
|
67790
|
-
return
|
|
68379
|
+
return false;
|
|
67791
68380
|
}
|
|
67792
|
-
|
|
67793
|
-
|
|
67794
|
-
const
|
|
67795
|
-
|
|
67796
|
-
|
|
67797
|
-
|
|
67798
|
-
|
|
67799
|
-
|
|
67800
|
-
|
|
67801
|
-
|
|
67802
|
-
|
|
67803
|
-
|
|
67804
|
-
|
|
67805
|
-
|
|
67806
|
-
|
|
67807
|
-
|
|
67808
|
-
|
|
67809
|
-
jsdoc = `${jsdoc.substring(0, 300)}...`;
|
|
68381
|
+
}
|
|
68382
|
+
async function ripgrepSearch(opts) {
|
|
68383
|
+
const rgPath = findRgInEnvPath();
|
|
68384
|
+
if (!rgPath) {
|
|
68385
|
+
return {
|
|
68386
|
+
error: true,
|
|
68387
|
+
type: "rg-not-found",
|
|
68388
|
+
message: "ripgrep (rg) not found in PATH"
|
|
68389
|
+
};
|
|
68390
|
+
}
|
|
68391
|
+
const args2 = [
|
|
68392
|
+
"--json",
|
|
68393
|
+
"-n"
|
|
68394
|
+
];
|
|
68395
|
+
if (opts.include) {
|
|
68396
|
+
for (const pattern of opts.include.split(",")) {
|
|
68397
|
+
args2.push("--glob", pattern.trim());
|
|
67810
68398
|
}
|
|
67811
|
-
|
|
67812
|
-
|
|
67813
|
-
|
|
67814
|
-
|
|
67815
|
-
kind: "function",
|
|
67816
|
-
exported: true,
|
|
67817
|
-
signature: `function ${fnMatch[1]}${fnMatch[2] || ""}(${fnMatch[3].trim()})${fnMatch[4] ? `: ${fnMatch[4].trim()}` : ""}`,
|
|
67818
|
-
line: lineNum,
|
|
67819
|
-
jsdoc
|
|
67820
|
-
});
|
|
67821
|
-
continue;
|
|
68399
|
+
}
|
|
68400
|
+
if (opts.exclude) {
|
|
68401
|
+
for (const pattern of opts.exclude.split(",")) {
|
|
68402
|
+
args2.push("--glob", `!${pattern.trim()}`);
|
|
67822
68403
|
}
|
|
67823
|
-
|
|
67824
|
-
|
|
67825
|
-
|
|
67826
|
-
|
|
67827
|
-
|
|
67828
|
-
|
|
67829
|
-
|
|
67830
|
-
|
|
67831
|
-
|
|
67832
|
-
|
|
67833
|
-
|
|
67834
|
-
|
|
67835
|
-
|
|
68404
|
+
}
|
|
68405
|
+
if (opts.mode !== "regex") {
|
|
68406
|
+
args2.push("--fixed-strings");
|
|
68407
|
+
}
|
|
68408
|
+
args2.push(opts.query);
|
|
68409
|
+
args2.push(opts.workspace);
|
|
68410
|
+
try {
|
|
68411
|
+
const proc = Bun.spawn([rgPath, ...args2], {
|
|
68412
|
+
stdout: "pipe",
|
|
68413
|
+
stderr: "pipe",
|
|
68414
|
+
cwd: opts.workspace
|
|
68415
|
+
});
|
|
68416
|
+
const timeout = new Promise((resolve26) => setTimeout(() => resolve26("timeout"), REGEX_TIMEOUT_MS));
|
|
68417
|
+
const exitPromise = proc.exited;
|
|
68418
|
+
const result = await Promise.race([exitPromise, timeout]);
|
|
68419
|
+
if (result === "timeout") {
|
|
68420
|
+
proc.kill();
|
|
68421
|
+
return {
|
|
68422
|
+
error: true,
|
|
68423
|
+
type: "regex-timeout",
|
|
68424
|
+
message: `Regex search timed out after ${REGEX_TIMEOUT_MS}ms`
|
|
68425
|
+
};
|
|
67836
68426
|
}
|
|
67837
|
-
const
|
|
67838
|
-
|
|
67839
|
-
|
|
67840
|
-
|
|
67841
|
-
|
|
67842
|
-
|
|
67843
|
-
|
|
67844
|
-
|
|
67845
|
-
|
|
67846
|
-
|
|
67847
|
-
|
|
67848
|
-
|
|
67849
|
-
|
|
67850
|
-
|
|
67851
|
-
|
|
67852
|
-
|
|
67853
|
-
|
|
67854
|
-
|
|
67855
|
-
|
|
67856
|
-
|
|
67857
|
-
|
|
67858
|
-
|
|
67859
|
-
|
|
68427
|
+
const stdout = await new Response(proc.stdout).text();
|
|
68428
|
+
const stderr = await new Response(proc.stderr).text();
|
|
68429
|
+
if (proc.exitCode !== 0 && stderr) {
|
|
68430
|
+
if (stderr.includes("Invalid regex") || stderr.includes("SyntaxError")) {
|
|
68431
|
+
return {
|
|
68432
|
+
error: true,
|
|
68433
|
+
type: "invalid-query",
|
|
68434
|
+
message: `Invalid query: ${stderr.split(`
|
|
68435
|
+
`)[0]}`
|
|
68436
|
+
};
|
|
68437
|
+
}
|
|
68438
|
+
}
|
|
68439
|
+
const matches = [];
|
|
68440
|
+
let total = 0;
|
|
68441
|
+
for (const line of stdout.split(`
|
|
68442
|
+
`)) {
|
|
68443
|
+
if (!line.trim())
|
|
68444
|
+
continue;
|
|
68445
|
+
try {
|
|
68446
|
+
const entry = JSON.parse(line);
|
|
68447
|
+
if (entry.type === "match") {
|
|
68448
|
+
total++;
|
|
68449
|
+
if (matches.length < opts.maxResults) {
|
|
68450
|
+
let lineText = entry.data.lines.text.trimEnd();
|
|
68451
|
+
if (lineText.length > opts.maxLines) {
|
|
68452
|
+
lineText = `${lineText.substring(0, opts.maxLines)}...`;
|
|
68453
|
+
}
|
|
68454
|
+
const match = {
|
|
68455
|
+
file: entry.data.path.text || entry.data.path,
|
|
68456
|
+
lineNumber: entry.data.line_number,
|
|
68457
|
+
lineText
|
|
68458
|
+
};
|
|
68459
|
+
matches.push(match);
|
|
68460
|
+
}
|
|
67860
68461
|
}
|
|
67861
|
-
|
|
67862
|
-
|
|
67863
|
-
|
|
67864
|
-
|
|
67865
|
-
|
|
67866
|
-
|
|
67867
|
-
|
|
67868
|
-
|
|
67869
|
-
|
|
68462
|
+
} catch {}
|
|
68463
|
+
}
|
|
68464
|
+
return {
|
|
68465
|
+
matches,
|
|
68466
|
+
truncated: total > opts.maxResults,
|
|
68467
|
+
total,
|
|
68468
|
+
query: opts.query,
|
|
68469
|
+
mode: opts.mode,
|
|
68470
|
+
maxResults: opts.maxResults
|
|
68471
|
+
};
|
|
68472
|
+
} catch (err2) {
|
|
68473
|
+
return {
|
|
68474
|
+
error: true,
|
|
68475
|
+
type: "unknown",
|
|
68476
|
+
message: err2 instanceof Error ? err2.message : String(err2)
|
|
68477
|
+
};
|
|
68478
|
+
}
|
|
68479
|
+
}
|
|
68480
|
+
function escapeRegex4(str) {
|
|
68481
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
68482
|
+
}
|
|
68483
|
+
function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
|
|
68484
|
+
const files = [];
|
|
68485
|
+
if (!validatePathForRead2(dir, workspace)) {
|
|
68486
|
+
return files;
|
|
68487
|
+
}
|
|
68488
|
+
try {
|
|
68489
|
+
const entries = fs55.readdirSync(dir, { withFileTypes: true });
|
|
68490
|
+
for (const entry of entries) {
|
|
68491
|
+
const fullPath = path67.join(dir, entry.name);
|
|
68492
|
+
const relativePath = path67.relative(workspace, fullPath);
|
|
68493
|
+
if (!validatePathForRead2(fullPath, workspace)) {
|
|
68494
|
+
continue;
|
|
68495
|
+
}
|
|
68496
|
+
if (entry.isDirectory()) {
|
|
68497
|
+
const subFiles = collectFiles(fullPath, workspace, includeGlobs, excludeGlobs);
|
|
68498
|
+
files.push(...subFiles);
|
|
68499
|
+
} else if (entry.isFile()) {
|
|
68500
|
+
if (includeGlobs.length > 0 && !matchesGlobs(relativePath, includeGlobs)) {
|
|
68501
|
+
continue;
|
|
67870
68502
|
}
|
|
68503
|
+
if (excludeGlobs.length > 0 && matchesGlobs(relativePath, excludeGlobs)) {
|
|
68504
|
+
continue;
|
|
68505
|
+
}
|
|
68506
|
+
files.push(relativePath);
|
|
67871
68507
|
}
|
|
67872
|
-
continue;
|
|
67873
68508
|
}
|
|
67874
|
-
|
|
67875
|
-
|
|
67876
|
-
|
|
67877
|
-
|
|
67878
|
-
|
|
67879
|
-
|
|
67880
|
-
|
|
67881
|
-
|
|
67882
|
-
|
|
67883
|
-
|
|
68509
|
+
} catch {}
|
|
68510
|
+
return files;
|
|
68511
|
+
}
|
|
68512
|
+
async function fallbackSearch(opts) {
|
|
68513
|
+
const includeGlobs = opts.include ? opts.include.split(",").map((p) => p.trim()).filter(Boolean) : [];
|
|
68514
|
+
const excludeGlobs = opts.exclude ? opts.exclude.split(",").map((p) => p.trim()).filter(Boolean) : [];
|
|
68515
|
+
const files = collectFiles(opts.workspace, opts.workspace, includeGlobs, excludeGlobs);
|
|
68516
|
+
let regex;
|
|
68517
|
+
try {
|
|
68518
|
+
if (opts.mode === "regex") {
|
|
68519
|
+
regex = new RegExp(opts.query);
|
|
68520
|
+
} else {
|
|
68521
|
+
regex = new RegExp(escapeRegex4(opts.query));
|
|
68522
|
+
}
|
|
68523
|
+
} catch (err2) {
|
|
68524
|
+
return {
|
|
68525
|
+
error: true,
|
|
68526
|
+
type: "invalid-query",
|
|
68527
|
+
message: err2 instanceof Error ? err2.message : "Invalid regex pattern"
|
|
68528
|
+
};
|
|
68529
|
+
}
|
|
68530
|
+
const matches = [];
|
|
68531
|
+
let total = 0;
|
|
68532
|
+
for (const file3 of files) {
|
|
68533
|
+
const fullPath = path67.join(opts.workspace, file3);
|
|
68534
|
+
if (!validatePathForRead2(fullPath, opts.workspace)) {
|
|
67884
68535
|
continue;
|
|
67885
68536
|
}
|
|
67886
|
-
|
|
67887
|
-
|
|
67888
|
-
|
|
67889
|
-
|
|
67890
|
-
|
|
67891
|
-
|
|
67892
|
-
|
|
67893
|
-
signature: `type ${typeMatch[1]}${typeMatch[2] ? `<${typeMatch[2]}>` : ""} = ${typeValue}`,
|
|
67894
|
-
line: lineNum,
|
|
67895
|
-
jsdoc
|
|
67896
|
-
});
|
|
68537
|
+
let stats;
|
|
68538
|
+
try {
|
|
68539
|
+
stats = fs55.statSync(fullPath);
|
|
68540
|
+
if (stats.size > MAX_FILE_SIZE_BYTES8) {
|
|
68541
|
+
continue;
|
|
68542
|
+
}
|
|
68543
|
+
} catch {
|
|
67897
68544
|
continue;
|
|
67898
68545
|
}
|
|
67899
|
-
|
|
67900
|
-
|
|
67901
|
-
|
|
67902
|
-
|
|
67903
|
-
kind: "enum",
|
|
67904
|
-
exported: true,
|
|
67905
|
-
signature: `enum ${enumMatch[1]}`,
|
|
67906
|
-
line: lineNum,
|
|
67907
|
-
jsdoc
|
|
67908
|
-
});
|
|
68546
|
+
let content;
|
|
68547
|
+
try {
|
|
68548
|
+
content = fs55.readFileSync(fullPath, "utf-8");
|
|
68549
|
+
} catch {
|
|
67909
68550
|
continue;
|
|
67910
68551
|
}
|
|
67911
|
-
const
|
|
67912
|
-
|
|
67913
|
-
|
|
67914
|
-
|
|
67915
|
-
|
|
67916
|
-
|
|
67917
|
-
|
|
67918
|
-
|
|
67919
|
-
|
|
67920
|
-
|
|
68552
|
+
const lines = content.split(`
|
|
68553
|
+
`);
|
|
68554
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
68555
|
+
const line = lines[i2];
|
|
68556
|
+
if (regex.test(line)) {
|
|
68557
|
+
total++;
|
|
68558
|
+
if (matches.length < opts.maxResults) {
|
|
68559
|
+
let lineText = line.trimEnd();
|
|
68560
|
+
if (lineText.length > opts.maxLines) {
|
|
68561
|
+
lineText = `${lineText.substring(0, opts.maxLines)}...`;
|
|
68562
|
+
}
|
|
68563
|
+
matches.push({
|
|
68564
|
+
file: file3,
|
|
68565
|
+
lineNumber: i2 + 1,
|
|
68566
|
+
lineText
|
|
68567
|
+
});
|
|
68568
|
+
}
|
|
68569
|
+
regex.lastIndex = 0;
|
|
68570
|
+
}
|
|
67921
68571
|
}
|
|
67922
68572
|
}
|
|
67923
|
-
return
|
|
67924
|
-
|
|
67925
|
-
|
|
67926
|
-
|
|
67927
|
-
|
|
68573
|
+
return {
|
|
68574
|
+
matches,
|
|
68575
|
+
truncated: total > opts.maxResults,
|
|
68576
|
+
total,
|
|
68577
|
+
query: opts.query,
|
|
68578
|
+
mode: opts.mode,
|
|
68579
|
+
maxResults: opts.maxResults
|
|
68580
|
+
};
|
|
67928
68581
|
}
|
|
67929
|
-
|
|
67930
|
-
|
|
67931
|
-
|
|
67932
|
-
|
|
68582
|
+
var search = createSwarmTool({
|
|
68583
|
+
description: "Search for text within workspace files using ripgrep-style interface. " + "Supports literal and regex search modes with glob include/exclude filtering. " + "Returns structured JSON output with file paths, line numbers, and line content.",
|
|
68584
|
+
args: {
|
|
68585
|
+
query: tool.schema.string().describe("Search query string (literal or regex depending on mode)"),
|
|
68586
|
+
mode: tool.schema.enum(["literal", "regex"]).default("literal").describe("Search mode: literal for exact string match, regex for regular expression"),
|
|
68587
|
+
include: tool.schema.string().optional().describe('Glob pattern for files to include (e.g., "*.ts", "src/**/*.js")'),
|
|
68588
|
+
exclude: tool.schema.string().optional().describe('Glob pattern for files to exclude (e.g., "node_modules/**", "*.test.ts")'),
|
|
68589
|
+
max_results: tool.schema.number().default(DEFAULT_MAX_RESULTS).describe("Maximum number of matches to return"),
|
|
68590
|
+
max_lines: tool.schema.number().default(DEFAULT_MAX_LINES).describe("Maximum characters per line in results")
|
|
68591
|
+
},
|
|
68592
|
+
execute: async (args2, directory) => {
|
|
68593
|
+
let query;
|
|
68594
|
+
let mode = "literal";
|
|
68595
|
+
let include;
|
|
68596
|
+
let exclude;
|
|
68597
|
+
let maxResults = DEFAULT_MAX_RESULTS;
|
|
68598
|
+
let maxLines = DEFAULT_MAX_LINES;
|
|
68599
|
+
try {
|
|
68600
|
+
const obj = args2;
|
|
68601
|
+
query = String(obj.query ?? "");
|
|
68602
|
+
mode = obj.mode === "regex" ? "regex" : "literal";
|
|
68603
|
+
include = obj.include;
|
|
68604
|
+
exclude = obj.exclude;
|
|
68605
|
+
const rawMaxResults = typeof obj.max_results === "number" ? obj.max_results : DEFAULT_MAX_RESULTS;
|
|
68606
|
+
const sanitizedMaxResults = Number.isNaN(rawMaxResults) ? DEFAULT_MAX_RESULTS : rawMaxResults;
|
|
68607
|
+
maxResults = Math.min(Math.max(0, sanitizedMaxResults), HARD_CAP_RESULTS);
|
|
68608
|
+
const rawMaxLines = typeof obj.max_lines === "number" ? obj.max_lines : DEFAULT_MAX_LINES;
|
|
68609
|
+
const sanitizedMaxLines = Number.isNaN(rawMaxLines) ? DEFAULT_MAX_LINES : rawMaxLines;
|
|
68610
|
+
maxLines = Math.min(Math.max(0, sanitizedMaxLines), HARD_CAP_LINES);
|
|
68611
|
+
} catch {
|
|
68612
|
+
return JSON.stringify({
|
|
68613
|
+
error: true,
|
|
68614
|
+
type: "invalid-query",
|
|
68615
|
+
message: "Could not parse search arguments"
|
|
68616
|
+
}, null, 2);
|
|
68617
|
+
}
|
|
68618
|
+
if (!query || query.trim() === "") {
|
|
68619
|
+
return JSON.stringify({
|
|
68620
|
+
error: true,
|
|
68621
|
+
type: "invalid-query",
|
|
68622
|
+
message: "Query cannot be empty"
|
|
68623
|
+
}, null, 2);
|
|
68624
|
+
}
|
|
68625
|
+
if (containsControlChars(query)) {
|
|
68626
|
+
return JSON.stringify({
|
|
68627
|
+
error: true,
|
|
68628
|
+
type: "invalid-query",
|
|
68629
|
+
message: "Query contains invalid control characters"
|
|
68630
|
+
}, null, 2);
|
|
68631
|
+
}
|
|
68632
|
+
if (include && containsPathTraversal(include)) {
|
|
68633
|
+
return JSON.stringify({
|
|
68634
|
+
error: true,
|
|
68635
|
+
type: "path-escape",
|
|
68636
|
+
message: "Include pattern contains path traversal sequence"
|
|
68637
|
+
}, null, 2);
|
|
68638
|
+
}
|
|
68639
|
+
if (exclude && containsPathTraversal(exclude)) {
|
|
68640
|
+
return JSON.stringify({
|
|
68641
|
+
error: true,
|
|
68642
|
+
type: "path-escape",
|
|
68643
|
+
message: "Exclude pattern contains path traversal sequence"
|
|
68644
|
+
}, null, 2);
|
|
68645
|
+
}
|
|
68646
|
+
if (include && containsWindowsAttacks3(include)) {
|
|
68647
|
+
return JSON.stringify({
|
|
68648
|
+
error: true,
|
|
68649
|
+
type: "path-escape",
|
|
68650
|
+
message: "Include pattern contains invalid Windows-specific sequence"
|
|
68651
|
+
}, null, 2);
|
|
68652
|
+
}
|
|
68653
|
+
if (exclude && containsWindowsAttacks3(exclude)) {
|
|
68654
|
+
return JSON.stringify({
|
|
68655
|
+
error: true,
|
|
68656
|
+
type: "path-escape",
|
|
68657
|
+
message: "Exclude pattern contains invalid Windows-specific sequence"
|
|
68658
|
+
}, null, 2);
|
|
68659
|
+
}
|
|
68660
|
+
if (!fs55.existsSync(directory)) {
|
|
68661
|
+
return JSON.stringify({
|
|
68662
|
+
error: true,
|
|
68663
|
+
type: "unknown",
|
|
68664
|
+
message: "Workspace directory does not exist"
|
|
68665
|
+
}, null, 2);
|
|
68666
|
+
}
|
|
68667
|
+
const rgAvailable = await isRipgrepAvailable();
|
|
68668
|
+
let result;
|
|
68669
|
+
if (rgAvailable) {
|
|
68670
|
+
result = await ripgrepSearch({
|
|
68671
|
+
query,
|
|
68672
|
+
mode,
|
|
68673
|
+
include,
|
|
68674
|
+
exclude,
|
|
68675
|
+
maxResults,
|
|
68676
|
+
maxLines,
|
|
68677
|
+
workspace: directory
|
|
68678
|
+
});
|
|
68679
|
+
} else {
|
|
68680
|
+
result = await fallbackSearch({
|
|
68681
|
+
query,
|
|
68682
|
+
mode,
|
|
68683
|
+
include,
|
|
68684
|
+
exclude,
|
|
68685
|
+
maxResults,
|
|
68686
|
+
maxLines,
|
|
68687
|
+
workspace: directory
|
|
68688
|
+
});
|
|
68689
|
+
}
|
|
68690
|
+
if ("error" in result && result.error) {
|
|
68691
|
+
return JSON.stringify(result, null, 2);
|
|
68692
|
+
}
|
|
68693
|
+
return JSON.stringify(result, null, 2);
|
|
67933
68694
|
}
|
|
67934
|
-
|
|
68695
|
+
});
|
|
68696
|
+
|
|
68697
|
+
// src/tools/index.ts
|
|
68698
|
+
init_secretscan();
|
|
68699
|
+
|
|
68700
|
+
// src/tools/suggest-patch.ts
|
|
68701
|
+
init_tool();
|
|
68702
|
+
init_create_tool();
|
|
68703
|
+
import * as fs56 from "fs";
|
|
68704
|
+
import * as path68 from "path";
|
|
68705
|
+
var WINDOWS_RESERVED_NAMES4 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
68706
|
+
function containsWindowsAttacks4(str) {
|
|
68707
|
+
if (/:[^\\/]/.test(str))
|
|
68708
|
+
return true;
|
|
68709
|
+
const parts2 = str.split(/[/\\]/);
|
|
68710
|
+
for (const part of parts2) {
|
|
68711
|
+
if (WINDOWS_RESERVED_NAMES4.test(part))
|
|
68712
|
+
return true;
|
|
68713
|
+
}
|
|
68714
|
+
return false;
|
|
68715
|
+
}
|
|
68716
|
+
function isPathInWorkspace4(filePath, workspace) {
|
|
67935
68717
|
try {
|
|
67936
|
-
const
|
|
67937
|
-
if (
|
|
67938
|
-
|
|
68718
|
+
const resolvedPath = path68.resolve(workspace, filePath);
|
|
68719
|
+
if (!fs56.existsSync(resolvedPath)) {
|
|
68720
|
+
return true;
|
|
68721
|
+
}
|
|
68722
|
+
const realWorkspace = fs56.realpathSync(workspace);
|
|
68723
|
+
const realResolvedPath = fs56.realpathSync(resolvedPath);
|
|
68724
|
+
const relativePath = path68.relative(realWorkspace, realResolvedPath);
|
|
68725
|
+
if (relativePath.startsWith("..") || path68.isAbsolute(relativePath)) {
|
|
68726
|
+
return false;
|
|
67939
68727
|
}
|
|
67940
|
-
|
|
68728
|
+
return true;
|
|
67941
68729
|
} catch {
|
|
67942
|
-
return
|
|
68730
|
+
return false;
|
|
67943
68731
|
}
|
|
68732
|
+
}
|
|
68733
|
+
function validateFilePath(filePath, workspace) {
|
|
68734
|
+
if (!filePath || filePath.trim() === "")
|
|
68735
|
+
return false;
|
|
68736
|
+
if (containsPathTraversal(filePath))
|
|
68737
|
+
return false;
|
|
68738
|
+
if (containsControlChars(filePath))
|
|
68739
|
+
return false;
|
|
68740
|
+
if (containsWindowsAttacks4(filePath))
|
|
68741
|
+
return false;
|
|
68742
|
+
return isPathInWorkspace4(filePath, workspace);
|
|
68743
|
+
}
|
|
68744
|
+
function findContextMatch(content, contextBefore, contextAfter, oldContent) {
|
|
67944
68745
|
const lines = content.split(`
|
|
67945
68746
|
`);
|
|
67946
|
-
|
|
67947
|
-
|
|
67948
|
-
|
|
67949
|
-
|
|
67950
|
-
|
|
67951
|
-
|
|
67952
|
-
|
|
67953
|
-
|
|
67954
|
-
|
|
67955
|
-
|
|
67956
|
-
|
|
67957
|
-
|
|
67958
|
-
|
|
67959
|
-
|
|
67960
|
-
|
|
67961
|
-
|
|
67962
|
-
|
|
67963
|
-
|
|
67964
|
-
|
|
67965
|
-
|
|
67966
|
-
|
|
67967
|
-
|
|
67968
|
-
|
|
67969
|
-
|
|
67970
|
-
|
|
67971
|
-
|
|
67972
|
-
|
|
67973
|
-
|
|
68747
|
+
if ((!contextBefore || contextBefore.length === 0) && (!contextAfter || contextAfter.length === 0)) {
|
|
68748
|
+
return null;
|
|
68749
|
+
}
|
|
68750
|
+
if (contextBefore && contextBefore.length > 0) {
|
|
68751
|
+
for (let i2 = 0;i2 <= lines.length - contextBefore.length; i2++) {
|
|
68752
|
+
const slice = lines.slice(i2, i2 + contextBefore.length);
|
|
68753
|
+
if (arraysEqual(slice, contextBefore)) {
|
|
68754
|
+
const afterStart = i2 + contextBefore.length;
|
|
68755
|
+
if (contextAfter && contextAfter.length > 0) {
|
|
68756
|
+
for (let j = afterStart;j <= lines.length - contextAfter.length; j++) {
|
|
68757
|
+
const afterSlice = lines.slice(j, j + contextAfter.length);
|
|
68758
|
+
if (arraysEqual(afterSlice, contextAfter)) {
|
|
68759
|
+
if (j === afterStart) {
|
|
68760
|
+
return {
|
|
68761
|
+
startLineIndex: i2,
|
|
68762
|
+
endLineIndex: j + contextAfter.length - 1,
|
|
68763
|
+
matchedBefore: contextBefore,
|
|
68764
|
+
matchedAfter: contextAfter
|
|
68765
|
+
};
|
|
68766
|
+
} else {
|
|
68767
|
+
if (oldContent && oldContent.length > 0) {
|
|
68768
|
+
const oldContentLines = oldContent.split(`
|
|
68769
|
+
`);
|
|
68770
|
+
const betweenLines = lines.slice(afterStart, j);
|
|
68771
|
+
if (arraysEqual(betweenLines, oldContentLines)) {
|
|
68772
|
+
return {
|
|
68773
|
+
startLineIndex: i2,
|
|
68774
|
+
endLineIndex: j - 1,
|
|
68775
|
+
matchedBefore: contextBefore,
|
|
68776
|
+
matchedAfter: contextAfter
|
|
68777
|
+
};
|
|
68778
|
+
}
|
|
68779
|
+
} else {
|
|
68780
|
+
return {
|
|
68781
|
+
startLineIndex: i2,
|
|
68782
|
+
endLineIndex: j - 1,
|
|
68783
|
+
matchedBefore: contextBefore,
|
|
68784
|
+
matchedAfter: contextAfter
|
|
68785
|
+
};
|
|
68786
|
+
}
|
|
68787
|
+
}
|
|
68788
|
+
}
|
|
68789
|
+
}
|
|
68790
|
+
return null;
|
|
68791
|
+
} else {
|
|
68792
|
+
if (oldContent && oldContent.length > 0) {
|
|
68793
|
+
const oldContentLines = oldContent.split(`
|
|
68794
|
+
`);
|
|
68795
|
+
for (let k = afterStart;k <= lines.length - oldContentLines.length; k++) {
|
|
68796
|
+
const candidate = lines.slice(k, k + oldContentLines.length);
|
|
68797
|
+
if (arraysEqual(candidate, oldContentLines)) {
|
|
68798
|
+
return {
|
|
68799
|
+
startLineIndex: i2,
|
|
68800
|
+
endLineIndex: k + oldContentLines.length - 1,
|
|
68801
|
+
matchedBefore: contextBefore,
|
|
68802
|
+
matchedAfter: []
|
|
68803
|
+
};
|
|
68804
|
+
}
|
|
68805
|
+
}
|
|
68806
|
+
return null;
|
|
68807
|
+
} else {
|
|
68808
|
+
return {
|
|
68809
|
+
startLineIndex: i2,
|
|
68810
|
+
endLineIndex: afterStart - 1,
|
|
68811
|
+
matchedBefore: contextBefore,
|
|
68812
|
+
matchedAfter: []
|
|
68813
|
+
};
|
|
68814
|
+
}
|
|
68815
|
+
}
|
|
68816
|
+
}
|
|
67974
68817
|
}
|
|
67975
|
-
|
|
67976
|
-
|
|
67977
|
-
|
|
67978
|
-
|
|
67979
|
-
|
|
67980
|
-
|
|
67981
|
-
|
|
67982
|
-
|
|
67983
|
-
|
|
68818
|
+
} else if (contextAfter && contextAfter.length > 0) {
|
|
68819
|
+
for (let j = 0;j <= lines.length - contextAfter.length; j++) {
|
|
68820
|
+
const afterSlice = lines.slice(j, j + contextAfter.length);
|
|
68821
|
+
if (arraysEqual(afterSlice, contextAfter)) {
|
|
68822
|
+
return {
|
|
68823
|
+
startLineIndex: 0,
|
|
68824
|
+
endLineIndex: j - 1,
|
|
68825
|
+
matchedBefore: [],
|
|
68826
|
+
matchedAfter: contextAfter
|
|
68827
|
+
};
|
|
68828
|
+
}
|
|
67984
68829
|
}
|
|
67985
68830
|
}
|
|
67986
|
-
return
|
|
67987
|
-
if (a.line !== b.line)
|
|
67988
|
-
return a.line - b.line;
|
|
67989
|
-
return a.name.localeCompare(b.name);
|
|
67990
|
-
});
|
|
68831
|
+
return null;
|
|
67991
68832
|
}
|
|
67992
|
-
|
|
67993
|
-
|
|
68833
|
+
function arraysEqual(a, b) {
|
|
68834
|
+
if (a.length !== b.length)
|
|
68835
|
+
return false;
|
|
68836
|
+
for (let i2 = 0;i2 < a.length; i2++) {
|
|
68837
|
+
if (a[i2] !== b[i2])
|
|
68838
|
+
return false;
|
|
68839
|
+
}
|
|
68840
|
+
return true;
|
|
68841
|
+
}
|
|
68842
|
+
function validateOldContent(lines, startIndex, endIndex, oldContent) {
|
|
68843
|
+
if (!oldContent) {
|
|
68844
|
+
return { valid: true };
|
|
68845
|
+
}
|
|
68846
|
+
const currentContent = lines.slice(startIndex, endIndex + 1).join(`
|
|
68847
|
+
`);
|
|
68848
|
+
if (currentContent !== oldContent) {
|
|
68849
|
+
return {
|
|
68850
|
+
valid: false,
|
|
68851
|
+
expected: oldContent,
|
|
68852
|
+
actual: currentContent
|
|
68853
|
+
};
|
|
68854
|
+
}
|
|
68855
|
+
return { valid: true };
|
|
68856
|
+
}
|
|
68857
|
+
var suggestPatch = createSwarmTool({
|
|
68858
|
+
description: "Suggest a structured patch for specified files without modifying them. " + "Returns context-based patch proposals with anchors for reviewer use. " + "This is a read-only tool \u2014 it does not modify any files.",
|
|
67994
68859
|
args: {
|
|
67995
|
-
|
|
67996
|
-
|
|
68860
|
+
targetFiles: tool.schema.array(tool.schema.string()).describe("Array of file paths to patch").min(1),
|
|
68861
|
+
changes: tool.schema.array(tool.schema.object({
|
|
68862
|
+
file: tool.schema.string().describe("Path to the file this change applies to"),
|
|
68863
|
+
contextBefore: tool.schema.array(tool.schema.string()).optional().describe("Lines before the change region (anchor)"),
|
|
68864
|
+
contextAfter: tool.schema.array(tool.schema.string()).optional().describe("Lines after the change region (anchor)"),
|
|
68865
|
+
oldContent: tool.schema.string().optional().describe("Current content to be replaced"),
|
|
68866
|
+
newContent: tool.schema.string().describe("New content to replace with")
|
|
68867
|
+
})).describe("Array of change descriptions with context anchors").min(1)
|
|
67997
68868
|
},
|
|
67998
68869
|
execute: async (args2, directory) => {
|
|
67999
|
-
|
|
68000
|
-
let exportedOnly = true;
|
|
68001
|
-
try {
|
|
68002
|
-
const obj = args2;
|
|
68003
|
-
file3 = String(obj.file);
|
|
68004
|
-
exportedOnly = obj.exported_only === true;
|
|
68005
|
-
} catch {
|
|
68870
|
+
if (!args2 || typeof args2 !== "object") {
|
|
68006
68871
|
return JSON.stringify({
|
|
68007
|
-
|
|
68008
|
-
error:
|
|
68009
|
-
|
|
68872
|
+
success: false,
|
|
68873
|
+
error: true,
|
|
68874
|
+
type: "parse-error",
|
|
68875
|
+
message: "Could not parse suggest-patch arguments"
|
|
68010
68876
|
}, null, 2);
|
|
68011
68877
|
}
|
|
68012
|
-
const
|
|
68013
|
-
const
|
|
68014
|
-
|
|
68878
|
+
const obj = args2;
|
|
68879
|
+
const targetFiles = obj.targetFiles ?? [];
|
|
68880
|
+
const changes = obj.changes ?? [];
|
|
68881
|
+
if (!targetFiles || targetFiles.length === 0) {
|
|
68015
68882
|
return JSON.stringify({
|
|
68016
|
-
|
|
68017
|
-
error:
|
|
68018
|
-
|
|
68883
|
+
success: false,
|
|
68884
|
+
error: true,
|
|
68885
|
+
type: "parse-error",
|
|
68886
|
+
message: "targetFiles cannot be empty"
|
|
68019
68887
|
}, null, 2);
|
|
68020
68888
|
}
|
|
68021
|
-
if (
|
|
68889
|
+
if (!changes || changes.length === 0) {
|
|
68022
68890
|
return JSON.stringify({
|
|
68023
|
-
|
|
68024
|
-
error:
|
|
68025
|
-
|
|
68891
|
+
success: false,
|
|
68892
|
+
error: true,
|
|
68893
|
+
type: "parse-error",
|
|
68894
|
+
message: "changes cannot be empty"
|
|
68026
68895
|
}, null, 2);
|
|
68027
68896
|
}
|
|
68028
|
-
if (
|
|
68897
|
+
if (!fs56.existsSync(directory)) {
|
|
68029
68898
|
return JSON.stringify({
|
|
68030
|
-
|
|
68031
|
-
error:
|
|
68032
|
-
|
|
68899
|
+
success: false,
|
|
68900
|
+
error: true,
|
|
68901
|
+
type: "file-not-found",
|
|
68902
|
+
message: "Workspace directory does not exist"
|
|
68033
68903
|
}, null, 2);
|
|
68034
68904
|
}
|
|
68035
|
-
|
|
68905
|
+
const patches = [];
|
|
68906
|
+
const filesModifiedSet = new Set;
|
|
68907
|
+
const errors5 = [];
|
|
68908
|
+
const targetFileSet = new Set(targetFiles);
|
|
68909
|
+
for (let changeIndex = 0;changeIndex < changes.length; changeIndex++) {
|
|
68910
|
+
const change = changes[changeIndex];
|
|
68911
|
+
if (!targetFileSet.has(change.file)) {
|
|
68912
|
+
errors5.push({
|
|
68913
|
+
success: false,
|
|
68914
|
+
error: true,
|
|
68915
|
+
type: "parse-error",
|
|
68916
|
+
message: `File "${change.file}" is not in targetFiles`,
|
|
68917
|
+
details: { location: change.file }
|
|
68918
|
+
});
|
|
68919
|
+
continue;
|
|
68920
|
+
}
|
|
68921
|
+
if (!validateFilePath(change.file, directory)) {
|
|
68922
|
+
errors5.push({
|
|
68923
|
+
success: false,
|
|
68924
|
+
error: true,
|
|
68925
|
+
type: "parse-error",
|
|
68926
|
+
message: `Invalid file path: ${change.file}`,
|
|
68927
|
+
details: {
|
|
68928
|
+
location: change.file
|
|
68929
|
+
}
|
|
68930
|
+
});
|
|
68931
|
+
continue;
|
|
68932
|
+
}
|
|
68933
|
+
const fullPath = path68.resolve(directory, change.file);
|
|
68934
|
+
if (!fs56.existsSync(fullPath)) {
|
|
68935
|
+
errors5.push({
|
|
68936
|
+
success: false,
|
|
68937
|
+
error: true,
|
|
68938
|
+
type: "file-not-found",
|
|
68939
|
+
message: `File not found: ${change.file}`,
|
|
68940
|
+
details: {
|
|
68941
|
+
location: change.file
|
|
68942
|
+
}
|
|
68943
|
+
});
|
|
68944
|
+
continue;
|
|
68945
|
+
}
|
|
68946
|
+
let content;
|
|
68947
|
+
try {
|
|
68948
|
+
content = fs56.readFileSync(fullPath, "utf-8");
|
|
68949
|
+
} catch (err2) {
|
|
68950
|
+
errors5.push({
|
|
68951
|
+
success: false,
|
|
68952
|
+
error: true,
|
|
68953
|
+
type: "unknown",
|
|
68954
|
+
message: `Could not read file: ${err2 instanceof Error ? err2.message : String(err2)}`,
|
|
68955
|
+
details: {
|
|
68956
|
+
location: `${change.file}:0`
|
|
68957
|
+
}
|
|
68958
|
+
});
|
|
68959
|
+
continue;
|
|
68960
|
+
}
|
|
68961
|
+
const contextMatch = findContextMatch(content, change.contextBefore, change.contextAfter, change.oldContent);
|
|
68962
|
+
if (!contextMatch) {
|
|
68963
|
+
errors5.push({
|
|
68964
|
+
success: false,
|
|
68965
|
+
error: true,
|
|
68966
|
+
type: "context-mismatch",
|
|
68967
|
+
message: `Could not find context anchor in ${change.file}. Provide contextBefore/contextAfter lines to locate the change region.`,
|
|
68968
|
+
details: {
|
|
68969
|
+
location: change.file
|
|
68970
|
+
}
|
|
68971
|
+
});
|
|
68972
|
+
continue;
|
|
68973
|
+
}
|
|
68974
|
+
const lines = content.split(`
|
|
68975
|
+
`);
|
|
68976
|
+
const oldContentValidation = validateOldContent(lines, contextMatch.startLineIndex + contextMatch.matchedBefore.length, contextMatch.endLineIndex - contextMatch.matchedAfter.length + 1, change.oldContent);
|
|
68977
|
+
if (!oldContentValidation.valid) {
|
|
68978
|
+
errors5.push({
|
|
68979
|
+
success: false,
|
|
68980
|
+
error: true,
|
|
68981
|
+
type: "context-mismatch",
|
|
68982
|
+
message: `Content at the specified location does not match oldContent`,
|
|
68983
|
+
details: {
|
|
68984
|
+
expected: oldContentValidation.expected,
|
|
68985
|
+
actual: oldContentValidation.actual,
|
|
68986
|
+
location: `${change.file}:${contextMatch.startLineIndex + 1}-${contextMatch.endLineIndex + 1}`
|
|
68987
|
+
}
|
|
68988
|
+
});
|
|
68989
|
+
continue;
|
|
68990
|
+
}
|
|
68991
|
+
const originalContext = [
|
|
68992
|
+
...contextMatch.matchedBefore,
|
|
68993
|
+
...contextMatch.matchedAfter.length > 0 ? ["..."] : [],
|
|
68994
|
+
...contextMatch.matchedAfter
|
|
68995
|
+
];
|
|
68996
|
+
patches.push({
|
|
68997
|
+
file: change.file,
|
|
68998
|
+
originalContext,
|
|
68999
|
+
newContent: change.newContent,
|
|
69000
|
+
hunkIndex: changeIndex
|
|
69001
|
+
});
|
|
69002
|
+
filesModifiedSet.add(change.file);
|
|
69003
|
+
}
|
|
69004
|
+
if (patches.length > 0) {
|
|
68036
69005
|
return JSON.stringify({
|
|
68037
|
-
|
|
68038
|
-
|
|
68039
|
-
|
|
69006
|
+
success: true,
|
|
69007
|
+
patches,
|
|
69008
|
+
filesModified: Array.from(filesModifiedSet),
|
|
69009
|
+
...errors5.length > 0 && { errors: errors5 }
|
|
68040
69010
|
}, null, 2);
|
|
68041
69011
|
}
|
|
68042
|
-
|
|
68043
|
-
|
|
68044
|
-
case ".ts":
|
|
68045
|
-
case ".tsx":
|
|
68046
|
-
case ".js":
|
|
68047
|
-
case ".jsx":
|
|
68048
|
-
case ".mjs":
|
|
68049
|
-
case ".cjs":
|
|
68050
|
-
syms = extractTSSymbols(file3, cwd);
|
|
68051
|
-
break;
|
|
68052
|
-
case ".py":
|
|
68053
|
-
syms = extractPythonSymbols(file3, cwd);
|
|
68054
|
-
break;
|
|
68055
|
-
default:
|
|
68056
|
-
return JSON.stringify({
|
|
68057
|
-
file: file3,
|
|
68058
|
-
error: `Unsupported file extension: ${ext}. Supported: .ts, .tsx, .js, .jsx, .mjs, .cjs, .py`,
|
|
68059
|
-
symbols: []
|
|
68060
|
-
}, null, 2);
|
|
68061
|
-
}
|
|
68062
|
-
if (exportedOnly) {
|
|
68063
|
-
syms = syms.filter((s) => s.exported);
|
|
69012
|
+
if (errors5.length === 1) {
|
|
69013
|
+
return JSON.stringify(errors5[0], null, 2);
|
|
68064
69014
|
}
|
|
68065
69015
|
return JSON.stringify({
|
|
68066
|
-
|
|
68067
|
-
|
|
68068
|
-
|
|
69016
|
+
success: false,
|
|
69017
|
+
error: true,
|
|
69018
|
+
type: "context-mismatch",
|
|
69019
|
+
message: `All ${errors5.length} patch suggestions failed`,
|
|
69020
|
+
errors: errors5
|
|
68069
69021
|
}, null, 2);
|
|
68070
69022
|
}
|
|
68071
69023
|
});
|
|
@@ -68081,10 +69033,10 @@ init_test_runner();
|
|
|
68081
69033
|
init_dist();
|
|
68082
69034
|
init_utils();
|
|
68083
69035
|
init_create_tool();
|
|
68084
|
-
import * as
|
|
68085
|
-
import * as
|
|
69036
|
+
import * as fs57 from "fs";
|
|
69037
|
+
import * as path69 from "path";
|
|
68086
69038
|
var MAX_TEXT_LENGTH = 200;
|
|
68087
|
-
var
|
|
69039
|
+
var MAX_FILE_SIZE_BYTES9 = 1024 * 1024;
|
|
68088
69040
|
var SUPPORTED_EXTENSIONS2 = new Set([
|
|
68089
69041
|
".ts",
|
|
68090
69042
|
".tsx",
|
|
@@ -68147,9 +69099,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
68147
69099
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
68148
69100
|
}
|
|
68149
69101
|
try {
|
|
68150
|
-
const resolvedPath =
|
|
68151
|
-
const normalizedCwd =
|
|
68152
|
-
const normalizedResolved =
|
|
69102
|
+
const resolvedPath = path69.resolve(paths);
|
|
69103
|
+
const normalizedCwd = path69.resolve(cwd);
|
|
69104
|
+
const normalizedResolved = path69.resolve(resolvedPath);
|
|
68153
69105
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
68154
69106
|
return {
|
|
68155
69107
|
error: "paths must be within the current working directory",
|
|
@@ -68165,13 +69117,13 @@ function validatePathsInput(paths, cwd) {
|
|
|
68165
69117
|
}
|
|
68166
69118
|
}
|
|
68167
69119
|
function isSupportedExtension(filePath) {
|
|
68168
|
-
const ext =
|
|
69120
|
+
const ext = path69.extname(filePath).toLowerCase();
|
|
68169
69121
|
return SUPPORTED_EXTENSIONS2.has(ext);
|
|
68170
69122
|
}
|
|
68171
69123
|
function findSourceFiles2(dir, files = []) {
|
|
68172
69124
|
let entries;
|
|
68173
69125
|
try {
|
|
68174
|
-
entries =
|
|
69126
|
+
entries = fs57.readdirSync(dir);
|
|
68175
69127
|
} catch {
|
|
68176
69128
|
return files;
|
|
68177
69129
|
}
|
|
@@ -68180,10 +69132,10 @@ function findSourceFiles2(dir, files = []) {
|
|
|
68180
69132
|
if (SKIP_DIRECTORIES4.has(entry)) {
|
|
68181
69133
|
continue;
|
|
68182
69134
|
}
|
|
68183
|
-
const fullPath =
|
|
69135
|
+
const fullPath = path69.join(dir, entry);
|
|
68184
69136
|
let stat2;
|
|
68185
69137
|
try {
|
|
68186
|
-
stat2 =
|
|
69138
|
+
stat2 = fs57.statSync(fullPath);
|
|
68187
69139
|
} catch {
|
|
68188
69140
|
continue;
|
|
68189
69141
|
}
|
|
@@ -68276,7 +69228,7 @@ var todo_extract = createSwarmTool({
|
|
|
68276
69228
|
return JSON.stringify(errorResult, null, 2);
|
|
68277
69229
|
}
|
|
68278
69230
|
const scanPath = resolvedPath;
|
|
68279
|
-
if (!
|
|
69231
|
+
if (!fs57.existsSync(scanPath)) {
|
|
68280
69232
|
const errorResult = {
|
|
68281
69233
|
error: `path not found: ${pathsInput}`,
|
|
68282
69234
|
total: 0,
|
|
@@ -68286,13 +69238,13 @@ var todo_extract = createSwarmTool({
|
|
|
68286
69238
|
return JSON.stringify(errorResult, null, 2);
|
|
68287
69239
|
}
|
|
68288
69240
|
const filesToScan = [];
|
|
68289
|
-
const stat2 =
|
|
69241
|
+
const stat2 = fs57.statSync(scanPath);
|
|
68290
69242
|
if (stat2.isFile()) {
|
|
68291
69243
|
if (isSupportedExtension(scanPath)) {
|
|
68292
69244
|
filesToScan.push(scanPath);
|
|
68293
69245
|
} else {
|
|
68294
69246
|
const errorResult = {
|
|
68295
|
-
error: `unsupported file extension: ${
|
|
69247
|
+
error: `unsupported file extension: ${path69.extname(scanPath)}`,
|
|
68296
69248
|
total: 0,
|
|
68297
69249
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
68298
69250
|
entries: []
|
|
@@ -68305,11 +69257,11 @@ var todo_extract = createSwarmTool({
|
|
|
68305
69257
|
const allEntries = [];
|
|
68306
69258
|
for (const filePath of filesToScan) {
|
|
68307
69259
|
try {
|
|
68308
|
-
const fileStat =
|
|
68309
|
-
if (fileStat.size >
|
|
69260
|
+
const fileStat = fs57.statSync(filePath);
|
|
69261
|
+
if (fileStat.size > MAX_FILE_SIZE_BYTES9) {
|
|
68310
69262
|
continue;
|
|
68311
69263
|
}
|
|
68312
|
-
const content =
|
|
69264
|
+
const content = fs57.readFileSync(filePath, "utf-8");
|
|
68313
69265
|
const entries = parseTodoComments(content, filePath, tagsSet);
|
|
68314
69266
|
allEntries.push(...entries);
|
|
68315
69267
|
} catch {}
|
|
@@ -68338,18 +69290,18 @@ var todo_extract = createSwarmTool({
|
|
|
68338
69290
|
init_tool();
|
|
68339
69291
|
init_schema();
|
|
68340
69292
|
init_gate_evidence();
|
|
68341
|
-
import * as
|
|
68342
|
-
import * as
|
|
69293
|
+
import * as fs59 from "fs";
|
|
69294
|
+
import * as path71 from "path";
|
|
68343
69295
|
|
|
68344
69296
|
// src/hooks/diff-scope.ts
|
|
68345
|
-
import * as
|
|
68346
|
-
import * as
|
|
69297
|
+
import * as fs58 from "fs";
|
|
69298
|
+
import * as path70 from "path";
|
|
68347
69299
|
function getDeclaredScope(taskId, directory) {
|
|
68348
69300
|
try {
|
|
68349
|
-
const planPath =
|
|
68350
|
-
if (!
|
|
69301
|
+
const planPath = path70.join(directory, ".swarm", "plan.json");
|
|
69302
|
+
if (!fs58.existsSync(planPath))
|
|
68351
69303
|
return null;
|
|
68352
|
-
const raw =
|
|
69304
|
+
const raw = fs58.readFileSync(planPath, "utf-8");
|
|
68353
69305
|
const plan = JSON.parse(raw);
|
|
68354
69306
|
for (const phase of plan.phases ?? []) {
|
|
68355
69307
|
for (const task of phase.tasks ?? []) {
|
|
@@ -68462,7 +69414,7 @@ var TIER_3_PATTERNS = [
|
|
|
68462
69414
|
];
|
|
68463
69415
|
function matchesTier3Pattern(files) {
|
|
68464
69416
|
for (const file3 of files) {
|
|
68465
|
-
const fileName =
|
|
69417
|
+
const fileName = path71.basename(file3);
|
|
68466
69418
|
for (const pattern of TIER_3_PATTERNS) {
|
|
68467
69419
|
if (pattern.test(fileName)) {
|
|
68468
69420
|
return true;
|
|
@@ -68476,8 +69428,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
68476
69428
|
if (hasActiveTurboMode()) {
|
|
68477
69429
|
const resolvedDir2 = workingDirectory;
|
|
68478
69430
|
try {
|
|
68479
|
-
const planPath =
|
|
68480
|
-
const planRaw =
|
|
69431
|
+
const planPath = path71.join(resolvedDir2, ".swarm", "plan.json");
|
|
69432
|
+
const planRaw = fs59.readFileSync(planPath, "utf-8");
|
|
68481
69433
|
const plan = JSON.parse(planRaw);
|
|
68482
69434
|
for (const planPhase of plan.phases ?? []) {
|
|
68483
69435
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -68543,8 +69495,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
68543
69495
|
}
|
|
68544
69496
|
try {
|
|
68545
69497
|
const resolvedDir2 = workingDirectory;
|
|
68546
|
-
const planPath =
|
|
68547
|
-
const planRaw =
|
|
69498
|
+
const planPath = path71.join(resolvedDir2, ".swarm", "plan.json");
|
|
69499
|
+
const planRaw = fs59.readFileSync(planPath, "utf-8");
|
|
68548
69500
|
const plan = JSON.parse(planRaw);
|
|
68549
69501
|
for (const planPhase of plan.phases ?? []) {
|
|
68550
69502
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -68726,8 +69678,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
68726
69678
|
};
|
|
68727
69679
|
}
|
|
68728
69680
|
}
|
|
68729
|
-
normalizedDir =
|
|
68730
|
-
const pathParts = normalizedDir.split(
|
|
69681
|
+
normalizedDir = path71.normalize(args2.working_directory);
|
|
69682
|
+
const pathParts = normalizedDir.split(path71.sep);
|
|
68731
69683
|
if (pathParts.includes("..")) {
|
|
68732
69684
|
return {
|
|
68733
69685
|
success: false,
|
|
@@ -68737,11 +69689,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
68737
69689
|
]
|
|
68738
69690
|
};
|
|
68739
69691
|
}
|
|
68740
|
-
const resolvedDir =
|
|
69692
|
+
const resolvedDir = path71.resolve(normalizedDir);
|
|
68741
69693
|
try {
|
|
68742
|
-
const realPath =
|
|
68743
|
-
const planPath =
|
|
68744
|
-
if (!
|
|
69694
|
+
const realPath = fs59.realpathSync(resolvedDir);
|
|
69695
|
+
const planPath = path71.join(realPath, ".swarm", "plan.json");
|
|
69696
|
+
if (!fs59.existsSync(planPath)) {
|
|
68745
69697
|
return {
|
|
68746
69698
|
success: false,
|
|
68747
69699
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -68774,8 +69726,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
68774
69726
|
recoverTaskStateFromDelegations(args2.task_id);
|
|
68775
69727
|
let phaseRequiresReviewer = true;
|
|
68776
69728
|
try {
|
|
68777
|
-
const planPath =
|
|
68778
|
-
const planRaw =
|
|
69729
|
+
const planPath = path71.join(directory, ".swarm", "plan.json");
|
|
69730
|
+
const planRaw = fs59.readFileSync(planPath, "utf-8");
|
|
68779
69731
|
const plan = JSON.parse(planRaw);
|
|
68780
69732
|
const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
|
|
68781
69733
|
if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
|
|
@@ -68838,8 +69790,8 @@ var update_task_status = createSwarmTool({
|
|
|
68838
69790
|
init_tool();
|
|
68839
69791
|
init_utils2();
|
|
68840
69792
|
init_create_tool();
|
|
68841
|
-
import
|
|
68842
|
-
import
|
|
69793
|
+
import fs60 from "fs";
|
|
69794
|
+
import path72 from "path";
|
|
68843
69795
|
function normalizeVerdict(verdict) {
|
|
68844
69796
|
switch (verdict) {
|
|
68845
69797
|
case "APPROVED":
|
|
@@ -68886,7 +69838,7 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
68886
69838
|
entries: [evidenceEntry]
|
|
68887
69839
|
};
|
|
68888
69840
|
const filename = "drift-verifier.json";
|
|
68889
|
-
const relativePath =
|
|
69841
|
+
const relativePath = path72.join("evidence", String(phase), filename);
|
|
68890
69842
|
let validatedPath;
|
|
68891
69843
|
try {
|
|
68892
69844
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -68897,12 +69849,12 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
68897
69849
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
68898
69850
|
}, null, 2);
|
|
68899
69851
|
}
|
|
68900
|
-
const evidenceDir =
|
|
69852
|
+
const evidenceDir = path72.dirname(validatedPath);
|
|
68901
69853
|
try {
|
|
68902
|
-
await
|
|
68903
|
-
const tempPath =
|
|
68904
|
-
await
|
|
68905
|
-
await
|
|
69854
|
+
await fs60.promises.mkdir(evidenceDir, { recursive: true });
|
|
69855
|
+
const tempPath = path72.join(evidenceDir, `.${filename}.tmp`);
|
|
69856
|
+
await fs60.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
69857
|
+
await fs60.promises.rename(tempPath, validatedPath);
|
|
68906
69858
|
return JSON.stringify({
|
|
68907
69859
|
success: true,
|
|
68908
69860
|
phase,
|
|
@@ -69093,7 +70045,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
69093
70045
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
69094
70046
|
preflightTriggerManager = new PTM(automationConfig);
|
|
69095
70047
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
69096
|
-
const swarmDir =
|
|
70048
|
+
const swarmDir = path73.resolve(ctx.directory, ".swarm");
|
|
69097
70049
|
statusArtifact = new ASA(swarmDir);
|
|
69098
70050
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
69099
70051
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|
|
@@ -69223,6 +70175,9 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
69223
70175
|
symbols,
|
|
69224
70176
|
test_runner,
|
|
69225
70177
|
todo_extract,
|
|
70178
|
+
search,
|
|
70179
|
+
batch_symbols,
|
|
70180
|
+
suggest_patch: suggestPatch,
|
|
69226
70181
|
update_task_status,
|
|
69227
70182
|
write_retro,
|
|
69228
70183
|
write_drift_evidence,
|
|
@@ -69431,7 +70386,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
69431
70386
|
"command.execute.before": safeHook(commandHandler),
|
|
69432
70387
|
"tool.execute.before": async (input, output) => {
|
|
69433
70388
|
if (process.env.DEBUG_SWARM)
|
|
69434
|
-
console.error(`[DIAG] toolBefore tool=${input.tool
|
|
70389
|
+
console.error(`[DIAG] toolBefore tool=${normalizeToolName(input.tool) ?? input.tool} session=${input.sessionID}`);
|
|
69435
70390
|
if (!swarmState.activeAgent.has(input.sessionID)) {
|
|
69436
70391
|
swarmState.activeAgent.set(input.sessionID, ORCHESTRATOR_NAME);
|
|
69437
70392
|
}
|
|
@@ -69462,10 +70417,10 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
69462
70417
|
},
|
|
69463
70418
|
"tool.execute.after": async (input, output) => {
|
|
69464
70419
|
const _dbg = !!process.env.DEBUG_SWARM;
|
|
69465
|
-
const _toolName = input.tool
|
|
70420
|
+
const _toolName = normalizeToolName(input.tool) ?? input.tool;
|
|
69466
70421
|
if (_dbg)
|
|
69467
70422
|
console.error(`[DIAG] toolAfter START tool=${_toolName} session=${input.sessionID}`);
|
|
69468
|
-
const normalizedTool = input.tool
|
|
70423
|
+
const normalizedTool = normalizeToolName(input.tool);
|
|
69469
70424
|
const isTaskTool = normalizedTool === "Task" || normalizedTool === "task";
|
|
69470
70425
|
const hookChain = async () => {
|
|
69471
70426
|
await activityHooks.toolAfter(input, output);
|