opencode-swarm 6.44.3 → 6.45.1
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/agents/explorer.d.ts +1 -1
- package/dist/cli/index.js +17 -4
- package/dist/hooks/normalize-tool-name.d.ts +25 -0
- package/dist/index.js +1651 -651
- 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));
|
|
@@ -32503,7 +32519,7 @@ __export(exports_co_change_analyzer, {
|
|
|
32503
32519
|
buildCoChangeMatrix: () => buildCoChangeMatrix
|
|
32504
32520
|
});
|
|
32505
32521
|
import * as child_process2 from "child_process";
|
|
32506
|
-
import { randomUUID } from "crypto";
|
|
32522
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
32507
32523
|
import { readdir as readdir2, readFile as readFile4, stat } from "fs/promises";
|
|
32508
32524
|
import * as path19 from "path";
|
|
32509
32525
|
import { promisify } from "util";
|
|
@@ -32763,7 +32779,7 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
|
|
|
32763
32779
|
}
|
|
32764
32780
|
const confidence = Math.min(0.3 + 0.2 * Math.min(pair.coChangeCount / 10, 1), 0.5);
|
|
32765
32781
|
entries.push({
|
|
32766
|
-
id:
|
|
32782
|
+
id: randomUUID2(),
|
|
32767
32783
|
tier: "swarm",
|
|
32768
32784
|
lesson,
|
|
32769
32785
|
category: "architecture",
|
|
@@ -36198,17 +36214,17 @@ function getTestFilesFromConvention(sourceFiles) {
|
|
|
36198
36214
|
const testFiles = [];
|
|
36199
36215
|
for (const file3 of sourceFiles) {
|
|
36200
36216
|
const normalizedPath = file3.replace(/\\/g, "/");
|
|
36201
|
-
const
|
|
36217
|
+
const basename5 = path28.basename(file3);
|
|
36202
36218
|
const dirname12 = path28.dirname(file3);
|
|
36203
|
-
if (hasCompoundTestExtension(
|
|
36219
|
+
if (hasCompoundTestExtension(basename5) || basename5.includes(".spec.") || basename5.includes(".test.") || normalizedPath.includes("/__tests__/") || normalizedPath.includes("/tests/") || normalizedPath.includes("/test/")) {
|
|
36204
36220
|
if (!testFiles.includes(file3)) {
|
|
36205
36221
|
testFiles.push(file3);
|
|
36206
36222
|
}
|
|
36207
36223
|
continue;
|
|
36208
36224
|
}
|
|
36209
36225
|
for (const _pattern of TEST_PATTERNS) {
|
|
36210
|
-
const nameWithoutExt =
|
|
36211
|
-
const ext = path28.extname(
|
|
36226
|
+
const nameWithoutExt = basename5.replace(/\.[^.]+$/, "");
|
|
36227
|
+
const ext = path28.extname(basename5);
|
|
36212
36228
|
const possibleTestFiles = [
|
|
36213
36229
|
path28.join(dirname12, `${nameWithoutExt}.spec${ext}`),
|
|
36214
36230
|
path28.join(dirname12, `${nameWithoutExt}.test${ext}`),
|
|
@@ -38038,17 +38054,17 @@ function normalizeSeparators(filePath) {
|
|
|
38038
38054
|
}
|
|
38039
38055
|
function matchesDocPattern(filePath, patterns) {
|
|
38040
38056
|
const normalizedPath = normalizeSeparators(filePath);
|
|
38041
|
-
const
|
|
38057
|
+
const basename6 = path42.basename(filePath);
|
|
38042
38058
|
for (const pattern of patterns) {
|
|
38043
38059
|
if (!pattern.includes("/") && !pattern.includes("\\")) {
|
|
38044
|
-
if (
|
|
38060
|
+
if (basename6 === pattern) {
|
|
38045
38061
|
return true;
|
|
38046
38062
|
}
|
|
38047
38063
|
continue;
|
|
38048
38064
|
}
|
|
38049
38065
|
if (pattern.startsWith("**/")) {
|
|
38050
38066
|
const filenamePattern = pattern.slice(3);
|
|
38051
|
-
if (
|
|
38067
|
+
if (basename6 === filenamePattern) {
|
|
38052
38068
|
return true;
|
|
38053
38069
|
}
|
|
38054
38070
|
continue;
|
|
@@ -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
|
|
|
@@ -44081,7 +44118,8 @@ COMPLIANCE:
|
|
|
44081
44118
|
- [type]: [description] (or "No deviations observed")
|
|
44082
44119
|
|
|
44083
44120
|
KNOWLEDGE_UPDATES:
|
|
44084
|
-
- [action]
|
|
44121
|
+
- [action] new: [reason] (or "No recommendations")
|
|
44122
|
+
NOTE: Always use "new" as the token \u2014 existing entry IDs (UUID v4) are not available in this context. Any non-UUID token is treated as "new" by the parser. Only "promote new:" creates a new entry; "archive new:" and "flag_contradiction new:" are silently skipped because those actions require an existing entry to operate on.
|
|
44085
44123
|
|
|
44086
44124
|
EXTENDED_DIGEST:
|
|
44087
44125
|
[the full running digest with this phase appended]
|
|
@@ -44490,9 +44528,10 @@ Your unique value is catching LOGIC ERRORS, EDGE CASES, and SECURITY FLAWS that
|
|
|
44490
44528
|
|
|
44491
44529
|
DO (explicitly):
|
|
44492
44530
|
- 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,
|
|
44531
|
+
- VERIFY imports exist: if the coder added a new import, use search to verify the export exists in the source
|
|
44494
44532
|
- CHECK test files were updated: if the coder changed a function signature, the tests should reflect it
|
|
44495
44533
|
- VERIFY platform compatibility: path.join() used for all paths, no hardcoded separators
|
|
44534
|
+
- For confirmed issues requiring a concrete fix: use suggest_patch to produce a structured patch artifact for the coder
|
|
44496
44535
|
|
|
44497
44536
|
## REVIEW REASONING
|
|
44498
44537
|
For each changed function or method, answer these before formulating issues:
|
|
@@ -48164,6 +48203,7 @@ async function handleConfigCommand(directory, _args) {
|
|
|
48164
48203
|
init_schema();
|
|
48165
48204
|
|
|
48166
48205
|
// src/hooks/curator.ts
|
|
48206
|
+
import { randomUUID } from "crypto";
|
|
48167
48207
|
import * as fs12 from "fs";
|
|
48168
48208
|
import * as path18 from "path";
|
|
48169
48209
|
init_event_bus();
|
|
@@ -48185,7 +48225,8 @@ function parseKnowledgeRecommendations(llmOutput) {
|
|
|
48185
48225
|
const match = trimmed.match(/^-\s+(promote|archive|flag_contradiction)\s+(\S+):\s+(.+)$/i);
|
|
48186
48226
|
if (match) {
|
|
48187
48227
|
const action = match[1].toLowerCase();
|
|
48188
|
-
const
|
|
48228
|
+
const UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
48229
|
+
const entryId = match[2] === "new" || !UUID_V4.test(match[2]) ? undefined : match[2];
|
|
48189
48230
|
const reason = match[3].trim();
|
|
48190
48231
|
recommendations.push({
|
|
48191
48232
|
action,
|
|
@@ -48699,6 +48740,43 @@ async function applyCuratorKnowledgeUpdates(directory, recommendations, _knowled
|
|
|
48699
48740
|
if (modified) {
|
|
48700
48741
|
await rewriteKnowledge(knowledgePath, updatedEntries);
|
|
48701
48742
|
}
|
|
48743
|
+
for (const rec of recommendations) {
|
|
48744
|
+
if (rec.entry_id !== undefined)
|
|
48745
|
+
continue;
|
|
48746
|
+
if (rec.action !== "promote") {
|
|
48747
|
+
skipped++;
|
|
48748
|
+
continue;
|
|
48749
|
+
}
|
|
48750
|
+
const lesson = rec.lesson?.trim() ?? "";
|
|
48751
|
+
if (lesson.length < 15) {
|
|
48752
|
+
skipped++;
|
|
48753
|
+
continue;
|
|
48754
|
+
}
|
|
48755
|
+
const now = new Date().toISOString();
|
|
48756
|
+
const newEntry = {
|
|
48757
|
+
id: randomUUID(),
|
|
48758
|
+
tier: "swarm",
|
|
48759
|
+
lesson: lesson.slice(0, 280),
|
|
48760
|
+
category: "other",
|
|
48761
|
+
tags: [],
|
|
48762
|
+
scope: "global",
|
|
48763
|
+
confidence: 0.5,
|
|
48764
|
+
status: "candidate",
|
|
48765
|
+
confirmed_by: [],
|
|
48766
|
+
retrieval_outcomes: {
|
|
48767
|
+
applied_count: 0,
|
|
48768
|
+
succeeded_after_count: 0,
|
|
48769
|
+
failed_after_count: 0
|
|
48770
|
+
},
|
|
48771
|
+
schema_version: 1,
|
|
48772
|
+
created_at: now,
|
|
48773
|
+
updated_at: now,
|
|
48774
|
+
auto_generated: true,
|
|
48775
|
+
project_name: path18.basename(directory)
|
|
48776
|
+
};
|
|
48777
|
+
await appendKnowledge(knowledgePath, newEntry);
|
|
48778
|
+
applied++;
|
|
48779
|
+
}
|
|
48702
48780
|
return { applied, skipped };
|
|
48703
48781
|
}
|
|
48704
48782
|
|
|
@@ -50378,7 +50456,7 @@ init_schema();
|
|
|
50378
50456
|
|
|
50379
50457
|
// src/hooks/knowledge-migrator.ts
|
|
50380
50458
|
init_knowledge_store();
|
|
50381
|
-
import { randomUUID as
|
|
50459
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
50382
50460
|
import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
|
|
50383
50461
|
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
|
|
50384
50462
|
import * as path23 from "path";
|
|
@@ -50448,7 +50526,7 @@ async function migrateContextToKnowledge(directory, config3) {
|
|
|
50448
50526
|
}
|
|
50449
50527
|
const inferredTags = inferTags(raw.text);
|
|
50450
50528
|
const entry = {
|
|
50451
|
-
id:
|
|
50529
|
+
id: randomUUID3(),
|
|
50452
50530
|
tier: "swarm",
|
|
50453
50531
|
lesson: truncateLesson(raw.text),
|
|
50454
50532
|
category: raw.categoryHint ?? inferCategoryFromText(raw.text),
|
|
@@ -53344,6 +53422,17 @@ function detectLoop(sessionId, toolName, args2) {
|
|
|
53344
53422
|
};
|
|
53345
53423
|
}
|
|
53346
53424
|
|
|
53425
|
+
// src/hooks/normalize-tool-name.ts
|
|
53426
|
+
var NAMESPACE_PREFIX_PATTERN = /^[^:]+[:.]/;
|
|
53427
|
+
function normalizeToolName(toolName) {
|
|
53428
|
+
if (!toolName)
|
|
53429
|
+
return;
|
|
53430
|
+
return toolName.replace(NAMESPACE_PREFIX_PATTERN, "");
|
|
53431
|
+
}
|
|
53432
|
+
function normalizeToolNameLowerCase(toolName) {
|
|
53433
|
+
return toolName.replace(NAMESPACE_PREFIX_PATTERN, "").toLowerCase();
|
|
53434
|
+
}
|
|
53435
|
+
|
|
53347
53436
|
// src/hooks/guardrails.ts
|
|
53348
53437
|
var storedInputArgs = new Map;
|
|
53349
53438
|
var TRANSIENT_MODEL_ERROR_PATTERN = /rate.?limit|429|503|timeout|overloaded|model.?not.?found|temporarily unavailable|server error/i;
|
|
@@ -53366,7 +53455,7 @@ function extractPhaseNumber(phaseString) {
|
|
|
53366
53455
|
return match ? parseInt(match[1], 10) : 1;
|
|
53367
53456
|
}
|
|
53368
53457
|
function isWriteTool(toolName) {
|
|
53369
|
-
const normalized = toolName
|
|
53458
|
+
const normalized = normalizeToolName(toolName);
|
|
53370
53459
|
return WRITE_TOOL_NAMES.includes(normalized);
|
|
53371
53460
|
}
|
|
53372
53461
|
function isArchitect(sessionId) {
|
|
@@ -53421,7 +53510,7 @@ function hasTraversalSegments(filePath) {
|
|
|
53421
53510
|
return normalized.startsWith("..") || normalized.includes("/../") || normalized.endsWith("/..");
|
|
53422
53511
|
}
|
|
53423
53512
|
function isGateTool(toolName) {
|
|
53424
|
-
const normalized = toolName
|
|
53513
|
+
const normalized = normalizeToolName(toolName);
|
|
53425
53514
|
const gateTools = [
|
|
53426
53515
|
"diff",
|
|
53427
53516
|
"syntax_check",
|
|
@@ -53437,7 +53526,7 @@ function isGateTool(toolName) {
|
|
|
53437
53526
|
return gateTools.includes(normalized);
|
|
53438
53527
|
}
|
|
53439
53528
|
function isAgentDelegation(toolName, args2) {
|
|
53440
|
-
const normalized = toolName
|
|
53529
|
+
const normalized = normalizeToolName(toolName);
|
|
53441
53530
|
if (normalized !== "Task" && normalized !== "task") {
|
|
53442
53531
|
return { isDelegation: false, targetAgent: null };
|
|
53443
53532
|
}
|
|
@@ -53932,7 +54021,7 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
|
|
|
53932
54021
|
}
|
|
53933
54022
|
}
|
|
53934
54023
|
const sessionId = input.sessionID;
|
|
53935
|
-
const normalizedToolName = input.tool
|
|
54024
|
+
const normalizedToolName = normalizeToolName(input.tool);
|
|
53936
54025
|
if (isWriteTool(normalizedToolName)) {
|
|
53937
54026
|
toolCallsSinceLastWrite.set(sessionId, 0);
|
|
53938
54027
|
noOpWarningIssued.delete(sessionId);
|
|
@@ -54490,7 +54579,7 @@ function createDelegationGateHook(config3, directory) {
|
|
|
54490
54579
|
const toolBefore = async (input, output) => {
|
|
54491
54580
|
if (!input.sessionID)
|
|
54492
54581
|
return;
|
|
54493
|
-
const normalized = input.tool
|
|
54582
|
+
const normalized = normalizeToolName(input.tool);
|
|
54494
54583
|
if (normalized !== "Task" && normalized !== "task")
|
|
54495
54584
|
return;
|
|
54496
54585
|
const args2 = output.args;
|
|
@@ -54546,7 +54635,7 @@ function createDelegationGateHook(config3, directory) {
|
|
|
54546
54635
|
const session = swarmState.agentSessions.get(input.sessionID);
|
|
54547
54636
|
if (!session)
|
|
54548
54637
|
return;
|
|
54549
|
-
const normalized = input.tool
|
|
54638
|
+
const normalized = normalizeToolName(input.tool);
|
|
54550
54639
|
if (normalized === "Task" || normalized === "task") {
|
|
54551
54640
|
const directArgs = input.args;
|
|
54552
54641
|
const storedArgs = getStoredInputArgs(input.callID);
|
|
@@ -57354,12 +57443,12 @@ var WRITE_TOOL_PATTERNS = [
|
|
|
57354
57443
|
"prepend"
|
|
57355
57444
|
];
|
|
57356
57445
|
function isWriteTool2(toolName) {
|
|
57357
|
-
const normalized = toolName
|
|
57446
|
+
const normalized = normalizeToolNameLowerCase(toolName);
|
|
57358
57447
|
return WRITE_TOOL_PATTERNS.some((p) => normalized.includes(p));
|
|
57359
57448
|
}
|
|
57360
57449
|
var READ_TOOL_PATTERNS = ["read", "cat", "view", "fetch", "get"];
|
|
57361
57450
|
function isReadTool(toolName) {
|
|
57362
|
-
const normalized = toolName
|
|
57451
|
+
const normalized = normalizeToolNameLowerCase(toolName);
|
|
57363
57452
|
return READ_TOOL_PATTERNS.some((p) => normalized.includes(p));
|
|
57364
57453
|
}
|
|
57365
57454
|
|
|
@@ -57796,7 +57885,7 @@ function createScopeGuardHook(config3, directory, injectAdvisory) {
|
|
|
57796
57885
|
toolBefore: async (input, output) => {
|
|
57797
57886
|
if (!enabled)
|
|
57798
57887
|
return;
|
|
57799
|
-
const toolName = input.tool
|
|
57888
|
+
const toolName = normalizeToolName(input.tool);
|
|
57800
57889
|
if (!WRITE_TOOLS.has(toolName))
|
|
57801
57890
|
return;
|
|
57802
57891
|
const sessionId = input.sessionID;
|
|
@@ -57859,7 +57948,7 @@ function createSelfReviewHook(config3, injectAdvisory) {
|
|
|
57859
57948
|
toolAfter: async (input, output) => {
|
|
57860
57949
|
if (!enabled)
|
|
57861
57950
|
return;
|
|
57862
|
-
const toolName = input.tool
|
|
57951
|
+
const toolName = normalizeToolName(input.tool);
|
|
57863
57952
|
if (toolName !== "update_task_status")
|
|
57864
57953
|
return;
|
|
57865
57954
|
const args2 = output.args;
|
|
@@ -58359,6 +58448,520 @@ async function loadSnapshot(directory) {
|
|
|
58359
58448
|
// src/index.ts
|
|
58360
58449
|
init_telemetry();
|
|
58361
58450
|
|
|
58451
|
+
// src/tools/batch-symbols.ts
|
|
58452
|
+
init_tool();
|
|
58453
|
+
init_create_tool();
|
|
58454
|
+
import * as fs38 from "fs";
|
|
58455
|
+
import * as path49 from "path";
|
|
58456
|
+
|
|
58457
|
+
// src/tools/symbols.ts
|
|
58458
|
+
init_tool();
|
|
58459
|
+
init_create_tool();
|
|
58460
|
+
import * as fs37 from "fs";
|
|
58461
|
+
import * as path48 from "path";
|
|
58462
|
+
var MAX_FILE_SIZE_BYTES2 = 1024 * 1024;
|
|
58463
|
+
var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
58464
|
+
function containsWindowsAttacks(str) {
|
|
58465
|
+
if (/:[^\\/]/.test(str)) {
|
|
58466
|
+
return true;
|
|
58467
|
+
}
|
|
58468
|
+
const parts2 = str.split(/[/\\]/);
|
|
58469
|
+
for (const part of parts2) {
|
|
58470
|
+
if (WINDOWS_RESERVED_NAMES.test(part)) {
|
|
58471
|
+
return true;
|
|
58472
|
+
}
|
|
58473
|
+
}
|
|
58474
|
+
return false;
|
|
58475
|
+
}
|
|
58476
|
+
function isPathInWorkspace(filePath, workspace) {
|
|
58477
|
+
try {
|
|
58478
|
+
const resolvedPath = path48.resolve(workspace, filePath);
|
|
58479
|
+
const realWorkspace = fs37.realpathSync(workspace);
|
|
58480
|
+
const realResolvedPath = fs37.realpathSync(resolvedPath);
|
|
58481
|
+
const relativePath = path48.relative(realWorkspace, realResolvedPath);
|
|
58482
|
+
if (relativePath.startsWith("..") || path48.isAbsolute(relativePath)) {
|
|
58483
|
+
return false;
|
|
58484
|
+
}
|
|
58485
|
+
return true;
|
|
58486
|
+
} catch {
|
|
58487
|
+
return false;
|
|
58488
|
+
}
|
|
58489
|
+
}
|
|
58490
|
+
function validatePathForRead(filePath, workspace) {
|
|
58491
|
+
return isPathInWorkspace(filePath, workspace);
|
|
58492
|
+
}
|
|
58493
|
+
function extractTSSymbols(filePath, cwd) {
|
|
58494
|
+
const fullPath = path48.join(cwd, filePath);
|
|
58495
|
+
if (!validatePathForRead(fullPath, cwd)) {
|
|
58496
|
+
return [];
|
|
58497
|
+
}
|
|
58498
|
+
let content;
|
|
58499
|
+
try {
|
|
58500
|
+
const stats = fs37.statSync(fullPath);
|
|
58501
|
+
if (stats.size > MAX_FILE_SIZE_BYTES2) {
|
|
58502
|
+
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES2})`);
|
|
58503
|
+
}
|
|
58504
|
+
content = fs37.readFileSync(fullPath, "utf-8");
|
|
58505
|
+
} catch {
|
|
58506
|
+
return [];
|
|
58507
|
+
}
|
|
58508
|
+
const lines = content.split(`
|
|
58509
|
+
`);
|
|
58510
|
+
const symbols = [];
|
|
58511
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
58512
|
+
const line = lines[i2];
|
|
58513
|
+
const lineNum = i2 + 1;
|
|
58514
|
+
let jsdoc;
|
|
58515
|
+
if (i2 > 0 && lines[i2 - 1].trim().endsWith("*/")) {
|
|
58516
|
+
const jsdocLines = [];
|
|
58517
|
+
for (let j = i2 - 1;j >= 0; j--) {
|
|
58518
|
+
jsdocLines.unshift(lines[j]);
|
|
58519
|
+
if (lines[j].trim().startsWith("/**"))
|
|
58520
|
+
break;
|
|
58521
|
+
}
|
|
58522
|
+
jsdoc = jsdocLines.join(`
|
|
58523
|
+
`).trim();
|
|
58524
|
+
if (jsdoc.length > 300)
|
|
58525
|
+
jsdoc = `${jsdoc.substring(0, 300)}...`;
|
|
58526
|
+
}
|
|
58527
|
+
const fnMatch = line.match(/^export\s+(?:async\s+)?function\s+(\w+)\s*(<[^>]*>)?\s*\(([^)]*)\)(?:\s*:\s*(.+?))?(?:\s*\{|$)/);
|
|
58528
|
+
if (fnMatch) {
|
|
58529
|
+
symbols.push({
|
|
58530
|
+
name: fnMatch[1],
|
|
58531
|
+
kind: "function",
|
|
58532
|
+
exported: true,
|
|
58533
|
+
signature: `function ${fnMatch[1]}${fnMatch[2] || ""}(${fnMatch[3].trim()})${fnMatch[4] ? `: ${fnMatch[4].trim()}` : ""}`,
|
|
58534
|
+
line: lineNum,
|
|
58535
|
+
jsdoc
|
|
58536
|
+
});
|
|
58537
|
+
continue;
|
|
58538
|
+
}
|
|
58539
|
+
const constMatch = line.match(/^export\s+const\s+(\w+)(?:\s*:\s*(.+?))?\s*=/);
|
|
58540
|
+
if (constMatch) {
|
|
58541
|
+
const restOfLine = line.substring(line.indexOf("=") + 1).trim();
|
|
58542
|
+
const isArrow = restOfLine.startsWith("(") || restOfLine.startsWith("async (") || restOfLine.match(/^\w+\s*=>/);
|
|
58543
|
+
symbols.push({
|
|
58544
|
+
name: constMatch[1],
|
|
58545
|
+
kind: isArrow ? "function" : "const",
|
|
58546
|
+
exported: true,
|
|
58547
|
+
signature: `const ${constMatch[1]}${constMatch[2] ? `: ${constMatch[2].trim()}` : ""}`,
|
|
58548
|
+
line: lineNum,
|
|
58549
|
+
jsdoc
|
|
58550
|
+
});
|
|
58551
|
+
continue;
|
|
58552
|
+
}
|
|
58553
|
+
const classMatch = line.match(/^export\s+(?:abstract\s+)?class\s+(\w+)(?:\s+(?:extends|implements)\s+(.+?))?(?:\s*\{|$)/);
|
|
58554
|
+
if (classMatch) {
|
|
58555
|
+
symbols.push({
|
|
58556
|
+
name: classMatch[1],
|
|
58557
|
+
kind: "class",
|
|
58558
|
+
exported: true,
|
|
58559
|
+
signature: `class ${classMatch[1]}${classMatch[2] ? ` extends/implements ${classMatch[2].trim()}` : ""}`,
|
|
58560
|
+
line: lineNum,
|
|
58561
|
+
jsdoc
|
|
58562
|
+
});
|
|
58563
|
+
let braceDepth = (line.match(/\{/g) || []).length - (line.match(/\}/g) || []).length;
|
|
58564
|
+
for (let j = i2 + 1;j < lines.length && braceDepth > 0; j++) {
|
|
58565
|
+
const memberLine = lines[j];
|
|
58566
|
+
braceDepth += (memberLine.match(/\{/g) || []).length - (memberLine.match(/\}/g) || []).length;
|
|
58567
|
+
const methodMatch = memberLine.match(/^\s+(?:public\s+)?(?:async\s+)?(\w+)\s*\(([^)]*)\)(?:\s*:\s*(.+?))?(?:\s*\{|;|$)/);
|
|
58568
|
+
if (methodMatch && !memberLine.includes("private") && !memberLine.includes("protected") && !memberLine.trim().startsWith("//")) {
|
|
58569
|
+
symbols.push({
|
|
58570
|
+
name: `${classMatch[1]}.${methodMatch[1]}`,
|
|
58571
|
+
kind: "method",
|
|
58572
|
+
exported: true,
|
|
58573
|
+
signature: `${methodMatch[1]}(${methodMatch[2].trim()})${methodMatch[3] ? `: ${methodMatch[3].trim()}` : ""}`,
|
|
58574
|
+
line: j + 1
|
|
58575
|
+
});
|
|
58576
|
+
}
|
|
58577
|
+
const propMatch = memberLine.match(/^\s+(?:public\s+)?(?:readonly\s+)?(\w+)(?:\?)?:\s*(.+?)(?:\s*[;=]|$)/);
|
|
58578
|
+
if (propMatch && !memberLine.includes("private") && !memberLine.includes("protected") && !memberLine.trim().startsWith("//")) {
|
|
58579
|
+
symbols.push({
|
|
58580
|
+
name: `${classMatch[1]}.${propMatch[1]}`,
|
|
58581
|
+
kind: "property",
|
|
58582
|
+
exported: true,
|
|
58583
|
+
signature: `${propMatch[1]}: ${propMatch[2].trim()}`,
|
|
58584
|
+
line: j + 1
|
|
58585
|
+
});
|
|
58586
|
+
}
|
|
58587
|
+
}
|
|
58588
|
+
continue;
|
|
58589
|
+
}
|
|
58590
|
+
const ifaceMatch = line.match(/^export\s+interface\s+(\w+)(?:\s*<([^>]+)>)?(?:\s+extends\s+(.+?))?(?:\s*\{|$)/);
|
|
58591
|
+
if (ifaceMatch) {
|
|
58592
|
+
symbols.push({
|
|
58593
|
+
name: ifaceMatch[1],
|
|
58594
|
+
kind: "interface",
|
|
58595
|
+
exported: true,
|
|
58596
|
+
signature: `interface ${ifaceMatch[1]}${ifaceMatch[2] ? `<${ifaceMatch[2]}>` : ""}${ifaceMatch[3] ? ` extends ${ifaceMatch[3].trim()}` : ""}`,
|
|
58597
|
+
line: lineNum,
|
|
58598
|
+
jsdoc
|
|
58599
|
+
});
|
|
58600
|
+
continue;
|
|
58601
|
+
}
|
|
58602
|
+
const typeMatch = line.match(/^export\s+type\s+(\w+)(?:\s*<([^>]+)>)?\s*=/);
|
|
58603
|
+
if (typeMatch) {
|
|
58604
|
+
const typeValue = line.substring(line.indexOf("=") + 1).trim().substring(0, 100);
|
|
58605
|
+
symbols.push({
|
|
58606
|
+
name: typeMatch[1],
|
|
58607
|
+
kind: "type",
|
|
58608
|
+
exported: true,
|
|
58609
|
+
signature: `type ${typeMatch[1]}${typeMatch[2] ? `<${typeMatch[2]}>` : ""} = ${typeValue}`,
|
|
58610
|
+
line: lineNum,
|
|
58611
|
+
jsdoc
|
|
58612
|
+
});
|
|
58613
|
+
continue;
|
|
58614
|
+
}
|
|
58615
|
+
const enumMatch = line.match(/^export\s+(?:const\s+)?enum\s+(\w+)/);
|
|
58616
|
+
if (enumMatch) {
|
|
58617
|
+
symbols.push({
|
|
58618
|
+
name: enumMatch[1],
|
|
58619
|
+
kind: "enum",
|
|
58620
|
+
exported: true,
|
|
58621
|
+
signature: `enum ${enumMatch[1]}`,
|
|
58622
|
+
line: lineNum,
|
|
58623
|
+
jsdoc
|
|
58624
|
+
});
|
|
58625
|
+
continue;
|
|
58626
|
+
}
|
|
58627
|
+
const defaultMatch = line.match(/^export\s+default\s+(?:function\s+)?(\w+)/);
|
|
58628
|
+
if (defaultMatch) {
|
|
58629
|
+
symbols.push({
|
|
58630
|
+
name: defaultMatch[1],
|
|
58631
|
+
kind: "function",
|
|
58632
|
+
exported: true,
|
|
58633
|
+
signature: `default ${defaultMatch[1]}`,
|
|
58634
|
+
line: lineNum,
|
|
58635
|
+
jsdoc
|
|
58636
|
+
});
|
|
58637
|
+
}
|
|
58638
|
+
}
|
|
58639
|
+
return symbols.sort((a, b) => {
|
|
58640
|
+
if (a.line !== b.line)
|
|
58641
|
+
return a.line - b.line;
|
|
58642
|
+
return a.name.localeCompare(b.name);
|
|
58643
|
+
});
|
|
58644
|
+
}
|
|
58645
|
+
function extractPythonSymbols(filePath, cwd) {
|
|
58646
|
+
const fullPath = path48.join(cwd, filePath);
|
|
58647
|
+
if (!validatePathForRead(fullPath, cwd)) {
|
|
58648
|
+
return [];
|
|
58649
|
+
}
|
|
58650
|
+
let content;
|
|
58651
|
+
try {
|
|
58652
|
+
const stats = fs37.statSync(fullPath);
|
|
58653
|
+
if (stats.size > MAX_FILE_SIZE_BYTES2) {
|
|
58654
|
+
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES2})`);
|
|
58655
|
+
}
|
|
58656
|
+
content = fs37.readFileSync(fullPath, "utf-8");
|
|
58657
|
+
} catch {
|
|
58658
|
+
return [];
|
|
58659
|
+
}
|
|
58660
|
+
const lines = content.split(`
|
|
58661
|
+
`);
|
|
58662
|
+
const symbols = [];
|
|
58663
|
+
const allMatch = content.match(/__all__\s*=\s*\[([^\]]+)\]/);
|
|
58664
|
+
const explicitExports = allMatch ? allMatch[1].split(",").map((s) => s.trim().replace(/['"]/g, "")) : null;
|
|
58665
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
58666
|
+
const line = lines[i2];
|
|
58667
|
+
if (line.startsWith(" ") || line.startsWith("\t"))
|
|
58668
|
+
continue;
|
|
58669
|
+
const fnMatch = line.match(/^(?:async\s+)?def\s+(\w+)\s*\(([^)]*)\)(?:\s*->\s*(.+?))?:/);
|
|
58670
|
+
if (fnMatch && !fnMatch[1].startsWith("_")) {
|
|
58671
|
+
const exported = !explicitExports || explicitExports.includes(fnMatch[1]);
|
|
58672
|
+
symbols.push({
|
|
58673
|
+
name: fnMatch[1],
|
|
58674
|
+
kind: "function",
|
|
58675
|
+
exported,
|
|
58676
|
+
signature: `def ${fnMatch[1]}(${fnMatch[2].trim()})${fnMatch[3] ? ` -> ${fnMatch[3].trim()}` : ""}`,
|
|
58677
|
+
line: i2 + 1
|
|
58678
|
+
});
|
|
58679
|
+
}
|
|
58680
|
+
const classMatch = line.match(/^class\s+(\w+)(?:\(([^)]*)\))?:/);
|
|
58681
|
+
if (classMatch && !classMatch[1].startsWith("_")) {
|
|
58682
|
+
const exported = !explicitExports || explicitExports.includes(classMatch[1]);
|
|
58683
|
+
symbols.push({
|
|
58684
|
+
name: classMatch[1],
|
|
58685
|
+
kind: "class",
|
|
58686
|
+
exported,
|
|
58687
|
+
signature: `class ${classMatch[1]}${classMatch[2] ? `(${classMatch[2].trim()})` : ""}`,
|
|
58688
|
+
line: i2 + 1
|
|
58689
|
+
});
|
|
58690
|
+
}
|
|
58691
|
+
const constMatch = line.match(/^([A-Z][A-Z0-9_]+)\s*[:=]/);
|
|
58692
|
+
if (constMatch) {
|
|
58693
|
+
symbols.push({
|
|
58694
|
+
name: constMatch[1],
|
|
58695
|
+
kind: "const",
|
|
58696
|
+
exported: true,
|
|
58697
|
+
signature: line.trim().substring(0, 100),
|
|
58698
|
+
line: i2 + 1
|
|
58699
|
+
});
|
|
58700
|
+
}
|
|
58701
|
+
}
|
|
58702
|
+
return symbols.sort((a, b) => {
|
|
58703
|
+
if (a.line !== b.line)
|
|
58704
|
+
return a.line - b.line;
|
|
58705
|
+
return a.name.localeCompare(b.name);
|
|
58706
|
+
});
|
|
58707
|
+
}
|
|
58708
|
+
var symbols = createSwarmTool({
|
|
58709
|
+
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.",
|
|
58710
|
+
args: {
|
|
58711
|
+
file: tool.schema.string().describe('File path to extract symbols from (e.g., "src/auth/login.ts")'),
|
|
58712
|
+
exported_only: tool.schema.boolean().default(true).describe("If true, only return exported/public symbols. If false, include all top-level symbols.")
|
|
58713
|
+
},
|
|
58714
|
+
execute: async (args2, directory) => {
|
|
58715
|
+
let file3;
|
|
58716
|
+
let exportedOnly = true;
|
|
58717
|
+
try {
|
|
58718
|
+
const obj = args2;
|
|
58719
|
+
file3 = String(obj.file);
|
|
58720
|
+
exportedOnly = obj.exported_only === true;
|
|
58721
|
+
} catch {
|
|
58722
|
+
return JSON.stringify({
|
|
58723
|
+
file: "<unknown>",
|
|
58724
|
+
error: "Invalid arguments: could not extract file path",
|
|
58725
|
+
symbols: []
|
|
58726
|
+
}, null, 2);
|
|
58727
|
+
}
|
|
58728
|
+
const cwd = directory;
|
|
58729
|
+
const ext = path48.extname(file3);
|
|
58730
|
+
if (containsControlChars(file3)) {
|
|
58731
|
+
return JSON.stringify({
|
|
58732
|
+
file: file3,
|
|
58733
|
+
error: "Path contains invalid control characters",
|
|
58734
|
+
symbols: []
|
|
58735
|
+
}, null, 2);
|
|
58736
|
+
}
|
|
58737
|
+
if (containsPathTraversal(file3)) {
|
|
58738
|
+
return JSON.stringify({
|
|
58739
|
+
file: file3,
|
|
58740
|
+
error: "Path contains path traversal sequence",
|
|
58741
|
+
symbols: []
|
|
58742
|
+
}, null, 2);
|
|
58743
|
+
}
|
|
58744
|
+
if (containsWindowsAttacks(file3)) {
|
|
58745
|
+
return JSON.stringify({
|
|
58746
|
+
file: file3,
|
|
58747
|
+
error: "Path contains invalid Windows-specific sequence",
|
|
58748
|
+
symbols: []
|
|
58749
|
+
}, null, 2);
|
|
58750
|
+
}
|
|
58751
|
+
if (!isPathInWorkspace(file3, cwd)) {
|
|
58752
|
+
return JSON.stringify({
|
|
58753
|
+
file: file3,
|
|
58754
|
+
error: "Path is outside workspace",
|
|
58755
|
+
symbols: []
|
|
58756
|
+
}, null, 2);
|
|
58757
|
+
}
|
|
58758
|
+
let syms;
|
|
58759
|
+
switch (ext) {
|
|
58760
|
+
case ".ts":
|
|
58761
|
+
case ".tsx":
|
|
58762
|
+
case ".js":
|
|
58763
|
+
case ".jsx":
|
|
58764
|
+
case ".mjs":
|
|
58765
|
+
case ".cjs":
|
|
58766
|
+
syms = extractTSSymbols(file3, cwd);
|
|
58767
|
+
break;
|
|
58768
|
+
case ".py":
|
|
58769
|
+
syms = extractPythonSymbols(file3, cwd);
|
|
58770
|
+
break;
|
|
58771
|
+
default:
|
|
58772
|
+
return JSON.stringify({
|
|
58773
|
+
file: file3,
|
|
58774
|
+
error: `Unsupported file extension: ${ext}. Supported: .ts, .tsx, .js, .jsx, .mjs, .cjs, .py`,
|
|
58775
|
+
symbols: []
|
|
58776
|
+
}, null, 2);
|
|
58777
|
+
}
|
|
58778
|
+
if (exportedOnly) {
|
|
58779
|
+
syms = syms.filter((s) => s.exported);
|
|
58780
|
+
}
|
|
58781
|
+
return JSON.stringify({
|
|
58782
|
+
file: file3,
|
|
58783
|
+
symbolCount: syms.length,
|
|
58784
|
+
symbols: syms
|
|
58785
|
+
}, null, 2);
|
|
58786
|
+
}
|
|
58787
|
+
});
|
|
58788
|
+
|
|
58789
|
+
// src/tools/batch-symbols.ts
|
|
58790
|
+
var WINDOWS_RESERVED_NAMES2 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
58791
|
+
function containsWindowsAttacks2(str) {
|
|
58792
|
+
if (/:[^\\/]/.test(str)) {
|
|
58793
|
+
return true;
|
|
58794
|
+
}
|
|
58795
|
+
const parts2 = str.split(/[/\\]/);
|
|
58796
|
+
for (const part of parts2) {
|
|
58797
|
+
if (WINDOWS_RESERVED_NAMES2.test(part)) {
|
|
58798
|
+
return true;
|
|
58799
|
+
}
|
|
58800
|
+
}
|
|
58801
|
+
return false;
|
|
58802
|
+
}
|
|
58803
|
+
function isPathInWorkspace2(filePath, workspace) {
|
|
58804
|
+
try {
|
|
58805
|
+
const resolvedPath = path49.resolve(workspace, filePath);
|
|
58806
|
+
if (!fs38.existsSync(resolvedPath)) {
|
|
58807
|
+
return true;
|
|
58808
|
+
}
|
|
58809
|
+
const realWorkspace = fs38.realpathSync(workspace);
|
|
58810
|
+
const realResolvedPath = fs38.realpathSync(resolvedPath);
|
|
58811
|
+
const relativePath = path49.relative(realWorkspace, realResolvedPath);
|
|
58812
|
+
if (relativePath.startsWith("..") || path49.isAbsolute(relativePath)) {
|
|
58813
|
+
return false;
|
|
58814
|
+
}
|
|
58815
|
+
return true;
|
|
58816
|
+
} catch {
|
|
58817
|
+
return false;
|
|
58818
|
+
}
|
|
58819
|
+
}
|
|
58820
|
+
function processFile(file3, cwd, exportedOnly) {
|
|
58821
|
+
const ext = path49.extname(file3);
|
|
58822
|
+
if (containsControlChars(file3)) {
|
|
58823
|
+
return {
|
|
58824
|
+
file: file3,
|
|
58825
|
+
success: false,
|
|
58826
|
+
error: "Path contains invalid control characters",
|
|
58827
|
+
errorType: "invalid-path"
|
|
58828
|
+
};
|
|
58829
|
+
}
|
|
58830
|
+
if (containsPathTraversal(file3)) {
|
|
58831
|
+
return {
|
|
58832
|
+
file: file3,
|
|
58833
|
+
success: false,
|
|
58834
|
+
error: "Path contains path traversal sequence",
|
|
58835
|
+
errorType: "path-traversal"
|
|
58836
|
+
};
|
|
58837
|
+
}
|
|
58838
|
+
if (containsWindowsAttacks2(file3)) {
|
|
58839
|
+
return {
|
|
58840
|
+
file: file3,
|
|
58841
|
+
success: false,
|
|
58842
|
+
error: "Path contains invalid Windows-specific sequence",
|
|
58843
|
+
errorType: "invalid-path"
|
|
58844
|
+
};
|
|
58845
|
+
}
|
|
58846
|
+
if (!isPathInWorkspace2(file3, cwd)) {
|
|
58847
|
+
return {
|
|
58848
|
+
file: file3,
|
|
58849
|
+
success: false,
|
|
58850
|
+
error: "Path is outside workspace",
|
|
58851
|
+
errorType: "path-outside-workspace"
|
|
58852
|
+
};
|
|
58853
|
+
}
|
|
58854
|
+
const fullPath = path49.join(cwd, file3);
|
|
58855
|
+
if (!fs38.existsSync(fullPath)) {
|
|
58856
|
+
return {
|
|
58857
|
+
file: file3,
|
|
58858
|
+
success: false,
|
|
58859
|
+
error: `File not found: ${file3}`,
|
|
58860
|
+
errorType: "file-not-found"
|
|
58861
|
+
};
|
|
58862
|
+
}
|
|
58863
|
+
let syms;
|
|
58864
|
+
switch (ext) {
|
|
58865
|
+
case ".ts":
|
|
58866
|
+
case ".tsx":
|
|
58867
|
+
case ".js":
|
|
58868
|
+
case ".jsx":
|
|
58869
|
+
case ".mjs":
|
|
58870
|
+
case ".cjs":
|
|
58871
|
+
syms = extractTSSymbols(file3, cwd);
|
|
58872
|
+
break;
|
|
58873
|
+
case ".py":
|
|
58874
|
+
syms = extractPythonSymbols(file3, cwd);
|
|
58875
|
+
break;
|
|
58876
|
+
default:
|
|
58877
|
+
return {
|
|
58878
|
+
file: file3,
|
|
58879
|
+
success: false,
|
|
58880
|
+
error: `Unsupported file extension: ${ext}. Supported: .ts, .tsx, .js, .jsx, .mjs, .cjs, .py`,
|
|
58881
|
+
errorType: "unsupported-language"
|
|
58882
|
+
};
|
|
58883
|
+
}
|
|
58884
|
+
let isEmptyFile = false;
|
|
58885
|
+
try {
|
|
58886
|
+
const stats = fs38.statSync(fullPath);
|
|
58887
|
+
if (stats.size === 0) {
|
|
58888
|
+
isEmptyFile = true;
|
|
58889
|
+
}
|
|
58890
|
+
} catch {}
|
|
58891
|
+
if (syms.length === 0) {
|
|
58892
|
+
try {
|
|
58893
|
+
const content = fs38.readFileSync(fullPath, "utf-8");
|
|
58894
|
+
if (content.trim().length === 0) {
|
|
58895
|
+
isEmptyFile = true;
|
|
58896
|
+
}
|
|
58897
|
+
} catch {}
|
|
58898
|
+
}
|
|
58899
|
+
if (isEmptyFile) {
|
|
58900
|
+
return {
|
|
58901
|
+
file: file3,
|
|
58902
|
+
success: true,
|
|
58903
|
+
symbols: [],
|
|
58904
|
+
error: "empty-file",
|
|
58905
|
+
errorType: "empty-file"
|
|
58906
|
+
};
|
|
58907
|
+
}
|
|
58908
|
+
if (exportedOnly) {
|
|
58909
|
+
syms = syms.filter((s) => s.exported);
|
|
58910
|
+
}
|
|
58911
|
+
return {
|
|
58912
|
+
file: file3,
|
|
58913
|
+
success: true,
|
|
58914
|
+
symbols: syms
|
|
58915
|
+
};
|
|
58916
|
+
}
|
|
58917
|
+
var batch_symbols = createSwarmTool({
|
|
58918
|
+
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.",
|
|
58919
|
+
args: {
|
|
58920
|
+
files: tool.schema.array(tool.schema.string()).describe("Array of file paths to extract symbols from"),
|
|
58921
|
+
exported_only: tool.schema.boolean().default(true).describe("If true, only return exported/public symbols. If false, include all top-level symbols.")
|
|
58922
|
+
},
|
|
58923
|
+
execute: async (args2, directory) => {
|
|
58924
|
+
let files;
|
|
58925
|
+
let exportedOnly = true;
|
|
58926
|
+
try {
|
|
58927
|
+
const obj = args2;
|
|
58928
|
+
if (!Array.isArray(obj.files)) {
|
|
58929
|
+
return JSON.stringify({
|
|
58930
|
+
results: [],
|
|
58931
|
+
totalFiles: 0,
|
|
58932
|
+
successCount: 0,
|
|
58933
|
+
failureCount: 0,
|
|
58934
|
+
error: "Invalid arguments: files must be an array"
|
|
58935
|
+
}, null, 2);
|
|
58936
|
+
}
|
|
58937
|
+
files = obj.files.map((f) => String(f));
|
|
58938
|
+
exportedOnly = obj.exported_only === true;
|
|
58939
|
+
} catch {
|
|
58940
|
+
return JSON.stringify({
|
|
58941
|
+
results: [],
|
|
58942
|
+
totalFiles: 0,
|
|
58943
|
+
successCount: 0,
|
|
58944
|
+
failureCount: 0,
|
|
58945
|
+
error: "Invalid arguments: could not extract files array"
|
|
58946
|
+
}, null, 2);
|
|
58947
|
+
}
|
|
58948
|
+
const cwd = directory;
|
|
58949
|
+
const results = [];
|
|
58950
|
+
for (const file3 of files) {
|
|
58951
|
+
const result = processFile(file3, cwd, exportedOnly);
|
|
58952
|
+
results.push(result);
|
|
58953
|
+
}
|
|
58954
|
+
const successCount = results.filter((r) => r.success).length;
|
|
58955
|
+
const failureCount = results.filter((r) => !r.success).length;
|
|
58956
|
+
const batchResult = {
|
|
58957
|
+
results,
|
|
58958
|
+
totalFiles: files.length,
|
|
58959
|
+
successCount,
|
|
58960
|
+
failureCount
|
|
58961
|
+
};
|
|
58962
|
+
return JSON.stringify(batchResult, null, 2);
|
|
58963
|
+
}
|
|
58964
|
+
});
|
|
58362
58965
|
// src/tools/build-check.ts
|
|
58363
58966
|
init_dist();
|
|
58364
58967
|
init_discovery();
|
|
@@ -58538,8 +59141,8 @@ init_dist();
|
|
|
58538
59141
|
init_manager();
|
|
58539
59142
|
init_create_tool();
|
|
58540
59143
|
init_resolve_working_directory();
|
|
58541
|
-
import * as
|
|
58542
|
-
import * as
|
|
59144
|
+
import * as fs39 from "fs";
|
|
59145
|
+
import * as path50 from "path";
|
|
58543
59146
|
var EVIDENCE_DIR = ".swarm/evidence";
|
|
58544
59147
|
var TASK_ID_PATTERN2 = /^\d+\.\d+(\.\d+)*$/;
|
|
58545
59148
|
function isValidTaskId3(taskId) {
|
|
@@ -58556,18 +59159,18 @@ function isValidTaskId3(taskId) {
|
|
|
58556
59159
|
return TASK_ID_PATTERN2.test(taskId);
|
|
58557
59160
|
}
|
|
58558
59161
|
function isPathWithinSwarm(filePath, workspaceRoot) {
|
|
58559
|
-
const normalizedWorkspace =
|
|
58560
|
-
const swarmPath =
|
|
58561
|
-
const normalizedPath =
|
|
59162
|
+
const normalizedWorkspace = path50.resolve(workspaceRoot);
|
|
59163
|
+
const swarmPath = path50.join(normalizedWorkspace, ".swarm", "evidence");
|
|
59164
|
+
const normalizedPath = path50.resolve(filePath);
|
|
58562
59165
|
return normalizedPath.startsWith(swarmPath);
|
|
58563
59166
|
}
|
|
58564
59167
|
function readEvidenceFile(evidencePath) {
|
|
58565
|
-
if (!
|
|
59168
|
+
if (!fs39.existsSync(evidencePath)) {
|
|
58566
59169
|
return null;
|
|
58567
59170
|
}
|
|
58568
59171
|
let content;
|
|
58569
59172
|
try {
|
|
58570
|
-
content =
|
|
59173
|
+
content = fs39.readFileSync(evidencePath, "utf-8");
|
|
58571
59174
|
} catch {
|
|
58572
59175
|
return null;
|
|
58573
59176
|
}
|
|
@@ -58639,7 +59242,7 @@ var check_gate_status = createSwarmTool({
|
|
|
58639
59242
|
};
|
|
58640
59243
|
return JSON.stringify(errorResult, null, 2);
|
|
58641
59244
|
}
|
|
58642
|
-
const evidencePath =
|
|
59245
|
+
const evidencePath = path50.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
|
|
58643
59246
|
if (!isPathWithinSwarm(evidencePath, directory)) {
|
|
58644
59247
|
const errorResult = {
|
|
58645
59248
|
taskId: taskIdInput,
|
|
@@ -58732,8 +59335,8 @@ init_co_change_analyzer();
|
|
|
58732
59335
|
// src/tools/completion-verify.ts
|
|
58733
59336
|
init_dist();
|
|
58734
59337
|
init_utils2();
|
|
58735
|
-
import * as
|
|
58736
|
-
import * as
|
|
59338
|
+
import * as fs40 from "fs";
|
|
59339
|
+
import * as path51 from "path";
|
|
58737
59340
|
init_create_tool();
|
|
58738
59341
|
init_resolve_working_directory();
|
|
58739
59342
|
function extractMatches(regex, text) {
|
|
@@ -58829,7 +59432,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
58829
59432
|
let plan;
|
|
58830
59433
|
try {
|
|
58831
59434
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
58832
|
-
const planRaw =
|
|
59435
|
+
const planRaw = fs40.readFileSync(planPath, "utf-8");
|
|
58833
59436
|
plan = JSON.parse(planRaw);
|
|
58834
59437
|
} catch {
|
|
58835
59438
|
const result2 = {
|
|
@@ -58887,10 +59490,10 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
58887
59490
|
let hasFileReadFailure = false;
|
|
58888
59491
|
for (const filePath of fileTargets) {
|
|
58889
59492
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
58890
|
-
const resolvedPath =
|
|
58891
|
-
const projectRoot =
|
|
58892
|
-
const
|
|
58893
|
-
const withinProject =
|
|
59493
|
+
const resolvedPath = path51.resolve(directory, normalizedPath);
|
|
59494
|
+
const projectRoot = path51.resolve(directory);
|
|
59495
|
+
const relative9 = path51.relative(projectRoot, resolvedPath);
|
|
59496
|
+
const withinProject = relative9 === "" || !relative9.startsWith("..") && !path51.isAbsolute(relative9);
|
|
58894
59497
|
if (!withinProject) {
|
|
58895
59498
|
blockedTasks.push({
|
|
58896
59499
|
task_id: task.id,
|
|
@@ -58903,7 +59506,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
58903
59506
|
}
|
|
58904
59507
|
let fileContent;
|
|
58905
59508
|
try {
|
|
58906
|
-
fileContent =
|
|
59509
|
+
fileContent = fs40.readFileSync(resolvedPath, "utf-8");
|
|
58907
59510
|
} catch {
|
|
58908
59511
|
blockedTasks.push({
|
|
58909
59512
|
task_id: task.id,
|
|
@@ -58945,9 +59548,9 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
58945
59548
|
blockedTasks
|
|
58946
59549
|
};
|
|
58947
59550
|
try {
|
|
58948
|
-
const evidenceDir =
|
|
58949
|
-
const evidencePath =
|
|
58950
|
-
|
|
59551
|
+
const evidenceDir = path51.join(directory, ".swarm", "evidence", `${phase}`);
|
|
59552
|
+
const evidencePath = path51.join(evidenceDir, "completion-verify.json");
|
|
59553
|
+
fs40.mkdirSync(evidenceDir, { recursive: true });
|
|
58951
59554
|
const evidenceBundle = {
|
|
58952
59555
|
schema_version: "1.0.0",
|
|
58953
59556
|
task_id: "completion-verify",
|
|
@@ -58968,7 +59571,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
58968
59571
|
}
|
|
58969
59572
|
]
|
|
58970
59573
|
};
|
|
58971
|
-
|
|
59574
|
+
fs40.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
|
|
58972
59575
|
} catch {}
|
|
58973
59576
|
return JSON.stringify(result, null, 2);
|
|
58974
59577
|
}
|
|
@@ -59022,13 +59625,13 @@ var completion_verify = createSwarmTool({
|
|
|
59022
59625
|
});
|
|
59023
59626
|
// src/tools/complexity-hotspots.ts
|
|
59024
59627
|
init_dist();
|
|
59025
|
-
import * as
|
|
59026
|
-
import * as
|
|
59628
|
+
import * as fs42 from "fs";
|
|
59629
|
+
import * as path53 from "path";
|
|
59027
59630
|
|
|
59028
59631
|
// src/quality/metrics.ts
|
|
59029
|
-
import * as
|
|
59030
|
-
import * as
|
|
59031
|
-
var
|
|
59632
|
+
import * as fs41 from "fs";
|
|
59633
|
+
import * as path52 from "path";
|
|
59634
|
+
var MAX_FILE_SIZE_BYTES3 = 256 * 1024;
|
|
59032
59635
|
var MIN_DUPLICATION_LINES = 10;
|
|
59033
59636
|
function estimateCyclomaticComplexity(content) {
|
|
59034
59637
|
let processed = content.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
@@ -59065,11 +59668,11 @@ function estimateCyclomaticComplexity(content) {
|
|
|
59065
59668
|
}
|
|
59066
59669
|
function getComplexityForFile(filePath) {
|
|
59067
59670
|
try {
|
|
59068
|
-
const stat2 =
|
|
59069
|
-
if (stat2.size >
|
|
59671
|
+
const stat2 = fs41.statSync(filePath);
|
|
59672
|
+
if (stat2.size > MAX_FILE_SIZE_BYTES3) {
|
|
59070
59673
|
return null;
|
|
59071
59674
|
}
|
|
59072
|
-
const content =
|
|
59675
|
+
const content = fs41.readFileSync(filePath, "utf-8");
|
|
59073
59676
|
return estimateCyclomaticComplexity(content);
|
|
59074
59677
|
} catch {
|
|
59075
59678
|
return null;
|
|
@@ -59079,8 +59682,8 @@ async function computeComplexityDelta(files, workingDir) {
|
|
|
59079
59682
|
let totalComplexity = 0;
|
|
59080
59683
|
const analyzedFiles = [];
|
|
59081
59684
|
for (const file3 of files) {
|
|
59082
|
-
const fullPath =
|
|
59083
|
-
if (!
|
|
59685
|
+
const fullPath = path52.isAbsolute(file3) ? file3 : path52.join(workingDir, file3);
|
|
59686
|
+
if (!fs41.existsSync(fullPath)) {
|
|
59084
59687
|
continue;
|
|
59085
59688
|
}
|
|
59086
59689
|
const complexity = getComplexityForFile(fullPath);
|
|
@@ -59201,8 +59804,8 @@ function countGoExports(content) {
|
|
|
59201
59804
|
}
|
|
59202
59805
|
function getExportCountForFile(filePath) {
|
|
59203
59806
|
try {
|
|
59204
|
-
const content =
|
|
59205
|
-
const ext =
|
|
59807
|
+
const content = fs41.readFileSync(filePath, "utf-8");
|
|
59808
|
+
const ext = path52.extname(filePath).toLowerCase();
|
|
59206
59809
|
switch (ext) {
|
|
59207
59810
|
case ".ts":
|
|
59208
59811
|
case ".tsx":
|
|
@@ -59228,8 +59831,8 @@ async function computePublicApiDelta(files, workingDir) {
|
|
|
59228
59831
|
let totalExports = 0;
|
|
59229
59832
|
const analyzedFiles = [];
|
|
59230
59833
|
for (const file3 of files) {
|
|
59231
|
-
const fullPath =
|
|
59232
|
-
if (!
|
|
59834
|
+
const fullPath = path52.isAbsolute(file3) ? file3 : path52.join(workingDir, file3);
|
|
59835
|
+
if (!fs41.existsSync(fullPath)) {
|
|
59233
59836
|
continue;
|
|
59234
59837
|
}
|
|
59235
59838
|
const exports = getExportCountForFile(fullPath);
|
|
@@ -59262,16 +59865,16 @@ async function computeDuplicationRatio(files, workingDir) {
|
|
|
59262
59865
|
let duplicateLines = 0;
|
|
59263
59866
|
const analyzedFiles = [];
|
|
59264
59867
|
for (const file3 of files) {
|
|
59265
|
-
const fullPath =
|
|
59266
|
-
if (!
|
|
59868
|
+
const fullPath = path52.isAbsolute(file3) ? file3 : path52.join(workingDir, file3);
|
|
59869
|
+
if (!fs41.existsSync(fullPath)) {
|
|
59267
59870
|
continue;
|
|
59268
59871
|
}
|
|
59269
59872
|
try {
|
|
59270
|
-
const stat2 =
|
|
59271
|
-
if (stat2.size >
|
|
59873
|
+
const stat2 = fs41.statSync(fullPath);
|
|
59874
|
+
if (stat2.size > MAX_FILE_SIZE_BYTES3) {
|
|
59272
59875
|
continue;
|
|
59273
59876
|
}
|
|
59274
|
-
const content =
|
|
59877
|
+
const content = fs41.readFileSync(fullPath, "utf-8");
|
|
59275
59878
|
const lines = content.split(`
|
|
59276
59879
|
`).filter((line) => line.trim().length > 0);
|
|
59277
59880
|
if (lines.length < MIN_DUPLICATION_LINES) {
|
|
@@ -59295,8 +59898,8 @@ function countCodeLines(content) {
|
|
|
59295
59898
|
return lines.length;
|
|
59296
59899
|
}
|
|
59297
59900
|
function isTestFile(filePath) {
|
|
59298
|
-
const
|
|
59299
|
-
const _ext =
|
|
59901
|
+
const basename8 = path52.basename(filePath);
|
|
59902
|
+
const _ext = path52.extname(filePath).toLowerCase();
|
|
59300
59903
|
const testPatterns = [
|
|
59301
59904
|
".test.",
|
|
59302
59905
|
".spec.",
|
|
@@ -59311,7 +59914,7 @@ function isTestFile(filePath) {
|
|
|
59311
59914
|
".spec.jsx"
|
|
59312
59915
|
];
|
|
59313
59916
|
for (const pattern of testPatterns) {
|
|
59314
|
-
if (
|
|
59917
|
+
if (basename8.includes(pattern)) {
|
|
59315
59918
|
return true;
|
|
59316
59919
|
}
|
|
59317
59920
|
}
|
|
@@ -59377,8 +59980,8 @@ function matchGlobSegment(globSegments, pathSegments) {
|
|
|
59377
59980
|
}
|
|
59378
59981
|
return gIndex === globSegments.length && pIndex === pathSegments.length;
|
|
59379
59982
|
}
|
|
59380
|
-
function matchesGlobSegment(
|
|
59381
|
-
const normalizedPath =
|
|
59983
|
+
function matchesGlobSegment(path53, glob) {
|
|
59984
|
+
const normalizedPath = path53.replace(/\\/g, "/");
|
|
59382
59985
|
const normalizedGlob = glob.replace(/\\/g, "/");
|
|
59383
59986
|
if (normalizedPath.includes("//")) {
|
|
59384
59987
|
return false;
|
|
@@ -59409,8 +60012,8 @@ function simpleGlobToRegex2(glob) {
|
|
|
59409
60012
|
function hasGlobstar(glob) {
|
|
59410
60013
|
return glob.includes("**");
|
|
59411
60014
|
}
|
|
59412
|
-
function globMatches(
|
|
59413
|
-
const normalizedPath =
|
|
60015
|
+
function globMatches(path53, glob) {
|
|
60016
|
+
const normalizedPath = path53.replace(/\\/g, "/");
|
|
59414
60017
|
if (!glob || glob === "") {
|
|
59415
60018
|
if (normalizedPath.includes("//")) {
|
|
59416
60019
|
return false;
|
|
@@ -59446,31 +60049,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
|
|
|
59446
60049
|
async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
59447
60050
|
let testLines = 0;
|
|
59448
60051
|
let codeLines = 0;
|
|
59449
|
-
const srcDir =
|
|
59450
|
-
if (
|
|
60052
|
+
const srcDir = path52.join(workingDir, "src");
|
|
60053
|
+
if (fs41.existsSync(srcDir)) {
|
|
59451
60054
|
await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
59452
60055
|
codeLines += lines;
|
|
59453
60056
|
});
|
|
59454
60057
|
}
|
|
59455
60058
|
const possibleSrcDirs = ["lib", "app", "source", "core"];
|
|
59456
60059
|
for (const dir of possibleSrcDirs) {
|
|
59457
|
-
const dirPath =
|
|
59458
|
-
if (
|
|
60060
|
+
const dirPath = path52.join(workingDir, dir);
|
|
60061
|
+
if (fs41.existsSync(dirPath)) {
|
|
59459
60062
|
await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
59460
60063
|
codeLines += lines;
|
|
59461
60064
|
});
|
|
59462
60065
|
}
|
|
59463
60066
|
}
|
|
59464
|
-
const testsDir =
|
|
59465
|
-
if (
|
|
60067
|
+
const testsDir = path52.join(workingDir, "tests");
|
|
60068
|
+
if (fs41.existsSync(testsDir)) {
|
|
59466
60069
|
await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
59467
60070
|
testLines += lines;
|
|
59468
60071
|
});
|
|
59469
60072
|
}
|
|
59470
60073
|
const possibleTestDirs = ["test", "__tests__", "specs"];
|
|
59471
60074
|
for (const dir of possibleTestDirs) {
|
|
59472
|
-
const dirPath =
|
|
59473
|
-
if (
|
|
60075
|
+
const dirPath = path52.join(workingDir, dir);
|
|
60076
|
+
if (fs41.existsSync(dirPath) && dirPath !== testsDir) {
|
|
59474
60077
|
await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
59475
60078
|
testLines += lines;
|
|
59476
60079
|
});
|
|
@@ -59482,9 +60085,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
59482
60085
|
}
|
|
59483
60086
|
async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
|
|
59484
60087
|
try {
|
|
59485
|
-
const entries =
|
|
60088
|
+
const entries = fs41.readdirSync(dirPath, { withFileTypes: true });
|
|
59486
60089
|
for (const entry of entries) {
|
|
59487
|
-
const fullPath =
|
|
60090
|
+
const fullPath = path52.join(dirPath, entry.name);
|
|
59488
60091
|
if (entry.isDirectory()) {
|
|
59489
60092
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
|
|
59490
60093
|
continue;
|
|
@@ -59492,7 +60095,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
59492
60095
|
await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
|
|
59493
60096
|
} else if (entry.isFile()) {
|
|
59494
60097
|
const relativePath = fullPath.replace(`${dirPath}/`, "");
|
|
59495
|
-
const ext =
|
|
60098
|
+
const ext = path52.extname(entry.name).toLowerCase();
|
|
59496
60099
|
const validExts = [
|
|
59497
60100
|
".ts",
|
|
59498
60101
|
".tsx",
|
|
@@ -59528,7 +60131,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
59528
60131
|
continue;
|
|
59529
60132
|
}
|
|
59530
60133
|
try {
|
|
59531
|
-
const content =
|
|
60134
|
+
const content = fs41.readFileSync(fullPath, "utf-8");
|
|
59532
60135
|
const lines = countCodeLines(content);
|
|
59533
60136
|
callback(lines);
|
|
59534
60137
|
} catch {}
|
|
@@ -59635,7 +60238,7 @@ async function computeQualityMetrics(changedFiles, thresholds, workingDir) {
|
|
|
59635
60238
|
|
|
59636
60239
|
// src/tools/complexity-hotspots.ts
|
|
59637
60240
|
init_create_tool();
|
|
59638
|
-
var
|
|
60241
|
+
var MAX_FILE_SIZE_BYTES4 = 256 * 1024;
|
|
59639
60242
|
var DEFAULT_DAYS = 90;
|
|
59640
60243
|
var DEFAULT_TOP_N = 20;
|
|
59641
60244
|
var DEFAULT_EXTENSIONS = "ts,tsx,js,jsx,py,rs,ps1";
|
|
@@ -59729,11 +60332,11 @@ async function getGitChurn(days, directory) {
|
|
|
59729
60332
|
}
|
|
59730
60333
|
function getComplexityForFile2(filePath) {
|
|
59731
60334
|
try {
|
|
59732
|
-
const stat2 =
|
|
59733
|
-
if (stat2.size >
|
|
60335
|
+
const stat2 = fs42.statSync(filePath);
|
|
60336
|
+
if (stat2.size > MAX_FILE_SIZE_BYTES4) {
|
|
59734
60337
|
return null;
|
|
59735
60338
|
}
|
|
59736
|
-
const content =
|
|
60339
|
+
const content = fs42.readFileSync(filePath, "utf-8");
|
|
59737
60340
|
return estimateCyclomaticComplexity(content);
|
|
59738
60341
|
} catch {
|
|
59739
60342
|
return null;
|
|
@@ -59744,7 +60347,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
59744
60347
|
const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
|
|
59745
60348
|
const filteredChurn = new Map;
|
|
59746
60349
|
for (const [file3, count] of churnMap) {
|
|
59747
|
-
const ext =
|
|
60350
|
+
const ext = path53.extname(file3).toLowerCase();
|
|
59748
60351
|
if (extSet.has(ext)) {
|
|
59749
60352
|
filteredChurn.set(file3, count);
|
|
59750
60353
|
}
|
|
@@ -59754,8 +60357,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
59754
60357
|
let analyzedFiles = 0;
|
|
59755
60358
|
for (const [file3, churnCount] of filteredChurn) {
|
|
59756
60359
|
let fullPath = file3;
|
|
59757
|
-
if (!
|
|
59758
|
-
fullPath =
|
|
60360
|
+
if (!fs42.existsSync(fullPath)) {
|
|
60361
|
+
fullPath = path53.join(cwd, file3);
|
|
59759
60362
|
}
|
|
59760
60363
|
const complexity = getComplexityForFile2(fullPath);
|
|
59761
60364
|
if (complexity !== null) {
|
|
@@ -59977,7 +60580,12 @@ var curator_analyze = createSwarmTool({
|
|
|
59977
60580
|
let applied = 0;
|
|
59978
60581
|
let skipped = 0;
|
|
59979
60582
|
if (typedArgs.recommendations && typedArgs.recommendations.length > 0) {
|
|
59980
|
-
const
|
|
60583
|
+
const UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
60584
|
+
const sanitizedRecs = typedArgs.recommendations.map((rec) => ({
|
|
60585
|
+
...rec,
|
|
60586
|
+
entry_id: rec.entry_id === undefined || UUID_V4.test(rec.entry_id) ? rec.entry_id : undefined
|
|
60587
|
+
}));
|
|
60588
|
+
const result = await applyCuratorKnowledgeUpdates(directory, sanitizedRecs, knowledgeConfig);
|
|
59981
60589
|
applied = result.applied;
|
|
59982
60590
|
skipped = result.skipped;
|
|
59983
60591
|
}
|
|
@@ -59997,8 +60605,8 @@ var curator_analyze = createSwarmTool({
|
|
|
59997
60605
|
});
|
|
59998
60606
|
// src/tools/declare-scope.ts
|
|
59999
60607
|
init_tool();
|
|
60000
|
-
import * as
|
|
60001
|
-
import * as
|
|
60608
|
+
import * as fs43 from "fs";
|
|
60609
|
+
import * as path54 from "path";
|
|
60002
60610
|
init_create_tool();
|
|
60003
60611
|
function validateTaskIdFormat(taskId) {
|
|
60004
60612
|
const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
|
|
@@ -60077,8 +60685,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
60077
60685
|
};
|
|
60078
60686
|
}
|
|
60079
60687
|
}
|
|
60080
|
-
normalizedDir =
|
|
60081
|
-
const pathParts = normalizedDir.split(
|
|
60688
|
+
normalizedDir = path54.normalize(args2.working_directory);
|
|
60689
|
+
const pathParts = normalizedDir.split(path54.sep);
|
|
60082
60690
|
if (pathParts.includes("..")) {
|
|
60083
60691
|
return {
|
|
60084
60692
|
success: false,
|
|
@@ -60088,11 +60696,11 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
60088
60696
|
]
|
|
60089
60697
|
};
|
|
60090
60698
|
}
|
|
60091
|
-
const resolvedDir =
|
|
60699
|
+
const resolvedDir = path54.resolve(normalizedDir);
|
|
60092
60700
|
try {
|
|
60093
|
-
const realPath =
|
|
60094
|
-
const planPath2 =
|
|
60095
|
-
if (!
|
|
60701
|
+
const realPath = fs43.realpathSync(resolvedDir);
|
|
60702
|
+
const planPath2 = path54.join(realPath, ".swarm", "plan.json");
|
|
60703
|
+
if (!fs43.existsSync(planPath2)) {
|
|
60096
60704
|
return {
|
|
60097
60705
|
success: false,
|
|
60098
60706
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -60115,8 +60723,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
60115
60723
|
console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
|
|
60116
60724
|
}
|
|
60117
60725
|
const directory = normalizedDir || fallbackDir;
|
|
60118
|
-
const planPath =
|
|
60119
|
-
if (!
|
|
60726
|
+
const planPath = path54.resolve(directory, ".swarm", "plan.json");
|
|
60727
|
+
if (!fs43.existsSync(planPath)) {
|
|
60120
60728
|
return {
|
|
60121
60729
|
success: false,
|
|
60122
60730
|
message: "No plan found",
|
|
@@ -60125,7 +60733,7 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
60125
60733
|
}
|
|
60126
60734
|
let planContent;
|
|
60127
60735
|
try {
|
|
60128
|
-
planContent = JSON.parse(
|
|
60736
|
+
planContent = JSON.parse(fs43.readFileSync(planPath, "utf-8"));
|
|
60129
60737
|
} catch {
|
|
60130
60738
|
return {
|
|
60131
60739
|
success: false,
|
|
@@ -60157,8 +60765,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
60157
60765
|
const normalizeErrors = [];
|
|
60158
60766
|
const dir = normalizedDir || fallbackDir || process.cwd();
|
|
60159
60767
|
const mergedFiles = rawMergedFiles.map((file3) => {
|
|
60160
|
-
if (
|
|
60161
|
-
const relativePath =
|
|
60768
|
+
if (path54.isAbsolute(file3)) {
|
|
60769
|
+
const relativePath = path54.relative(dir, file3).replace(/\\/g, "/");
|
|
60162
60770
|
if (relativePath.startsWith("..")) {
|
|
60163
60771
|
normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
|
|
60164
60772
|
return file3;
|
|
@@ -60205,7 +60813,7 @@ import * as child_process5 from "child_process";
|
|
|
60205
60813
|
|
|
60206
60814
|
// src/diff/ast-diff.ts
|
|
60207
60815
|
init_tree_sitter();
|
|
60208
|
-
import { extname as
|
|
60816
|
+
import { extname as extname9 } from "path";
|
|
60209
60817
|
|
|
60210
60818
|
// src/lang/registry.ts
|
|
60211
60819
|
init_runtime();
|
|
@@ -60290,7 +60898,7 @@ var QUERIES = {
|
|
|
60290
60898
|
var AST_TIMEOUT_MS = 500;
|
|
60291
60899
|
async function computeASTDiff(filePath, oldContent, newContent) {
|
|
60292
60900
|
const startTime = Date.now();
|
|
60293
|
-
const extension =
|
|
60901
|
+
const extension = extname9(filePath).toLowerCase();
|
|
60294
60902
|
const language = getLanguageForExtension(extension);
|
|
60295
60903
|
if (!language) {
|
|
60296
60904
|
return {
|
|
@@ -60352,26 +60960,26 @@ async function computeASTDiff(filePath, oldContent, newContent) {
|
|
|
60352
60960
|
}
|
|
60353
60961
|
}
|
|
60354
60962
|
function extractSymbols(tree, language) {
|
|
60355
|
-
const
|
|
60963
|
+
const symbols2 = [];
|
|
60356
60964
|
const queryStr = QUERIES[language.id];
|
|
60357
60965
|
if (!queryStr) {
|
|
60358
|
-
return
|
|
60966
|
+
return symbols2;
|
|
60359
60967
|
}
|
|
60360
60968
|
try {
|
|
60361
60969
|
const lang = tree.language;
|
|
60362
60970
|
if (!lang) {
|
|
60363
|
-
return
|
|
60971
|
+
return symbols2;
|
|
60364
60972
|
}
|
|
60365
60973
|
const query = new Query(lang, queryStr);
|
|
60366
60974
|
const matches = query.matches(tree.rootNode);
|
|
60367
60975
|
for (const match of matches) {
|
|
60368
60976
|
const symbol3 = parseMatch(match, language.id);
|
|
60369
60977
|
if (symbol3) {
|
|
60370
|
-
|
|
60978
|
+
symbols2.push(symbol3);
|
|
60371
60979
|
}
|
|
60372
60980
|
}
|
|
60373
60981
|
} catch {}
|
|
60374
|
-
return
|
|
60982
|
+
return symbols2;
|
|
60375
60983
|
}
|
|
60376
60984
|
function parseMatch(match, languageId) {
|
|
60377
60985
|
const captures = match.captures;
|
|
@@ -60484,20 +61092,20 @@ function validateBase(base) {
|
|
|
60484
61092
|
function validatePaths(paths) {
|
|
60485
61093
|
if (!paths)
|
|
60486
61094
|
return null;
|
|
60487
|
-
for (const
|
|
60488
|
-
if (!
|
|
61095
|
+
for (const path56 of paths) {
|
|
61096
|
+
if (!path56 || path56.length === 0) {
|
|
60489
61097
|
return "empty path not allowed";
|
|
60490
61098
|
}
|
|
60491
|
-
if (
|
|
61099
|
+
if (path56.length > MAX_PATH_LENGTH) {
|
|
60492
61100
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
60493
61101
|
}
|
|
60494
|
-
if (SHELL_METACHARACTERS2.test(
|
|
61102
|
+
if (SHELL_METACHARACTERS2.test(path56)) {
|
|
60495
61103
|
return "path contains shell metacharacters";
|
|
60496
61104
|
}
|
|
60497
|
-
if (
|
|
61105
|
+
if (path56.startsWith("-")) {
|
|
60498
61106
|
return 'path cannot start with "-" (option-like arguments not allowed)';
|
|
60499
61107
|
}
|
|
60500
|
-
if (CONTROL_CHAR_PATTERN2.test(
|
|
61108
|
+
if (CONTROL_CHAR_PATTERN2.test(path56)) {
|
|
60501
61109
|
return "path contains control characters";
|
|
60502
61110
|
}
|
|
60503
61111
|
}
|
|
@@ -60578,8 +61186,8 @@ var diff = createSwarmTool({
|
|
|
60578
61186
|
if (parts2.length >= 3) {
|
|
60579
61187
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
60580
61188
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
60581
|
-
const
|
|
60582
|
-
files.push({ path:
|
|
61189
|
+
const path56 = parts2[2];
|
|
61190
|
+
files.push({ path: path56, additions, deletions });
|
|
60583
61191
|
}
|
|
60584
61192
|
}
|
|
60585
61193
|
const contractChanges = [];
|
|
@@ -60861,9 +61469,9 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
60861
61469
|
// src/tools/evidence-check.ts
|
|
60862
61470
|
init_dist();
|
|
60863
61471
|
init_create_tool();
|
|
60864
|
-
import * as
|
|
60865
|
-
import * as
|
|
60866
|
-
var
|
|
61472
|
+
import * as fs44 from "fs";
|
|
61473
|
+
import * as path56 from "path";
|
|
61474
|
+
var MAX_FILE_SIZE_BYTES5 = 1024 * 1024;
|
|
60867
61475
|
var MAX_EVIDENCE_FILES = 1000;
|
|
60868
61476
|
var EVIDENCE_DIR2 = ".swarm/evidence";
|
|
60869
61477
|
var PLAN_FILE = ".swarm/plan.md";
|
|
@@ -60889,9 +61497,9 @@ function validateRequiredTypes(input) {
|
|
|
60889
61497
|
return null;
|
|
60890
61498
|
}
|
|
60891
61499
|
function isPathWithinSwarm2(filePath, cwd) {
|
|
60892
|
-
const normalizedCwd =
|
|
60893
|
-
const swarmPath =
|
|
60894
|
-
const normalizedPath =
|
|
61500
|
+
const normalizedCwd = path56.resolve(cwd);
|
|
61501
|
+
const swarmPath = path56.join(normalizedCwd, ".swarm");
|
|
61502
|
+
const normalizedPath = path56.resolve(filePath);
|
|
60895
61503
|
return normalizedPath.startsWith(swarmPath);
|
|
60896
61504
|
}
|
|
60897
61505
|
function parseCompletedTasks(planContent) {
|
|
@@ -60907,12 +61515,12 @@ function parseCompletedTasks(planContent) {
|
|
|
60907
61515
|
}
|
|
60908
61516
|
function readEvidenceFiles(evidenceDir, _cwd) {
|
|
60909
61517
|
const evidence = [];
|
|
60910
|
-
if (!
|
|
61518
|
+
if (!fs44.existsSync(evidenceDir) || !fs44.statSync(evidenceDir).isDirectory()) {
|
|
60911
61519
|
return evidence;
|
|
60912
61520
|
}
|
|
60913
61521
|
let files;
|
|
60914
61522
|
try {
|
|
60915
|
-
files =
|
|
61523
|
+
files = fs44.readdirSync(evidenceDir);
|
|
60916
61524
|
} catch {
|
|
60917
61525
|
return evidence;
|
|
60918
61526
|
}
|
|
@@ -60921,14 +61529,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
60921
61529
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
60922
61530
|
continue;
|
|
60923
61531
|
}
|
|
60924
|
-
const filePath =
|
|
61532
|
+
const filePath = path56.join(evidenceDir, filename);
|
|
60925
61533
|
try {
|
|
60926
|
-
const resolvedPath =
|
|
60927
|
-
const evidenceDirResolved =
|
|
61534
|
+
const resolvedPath = path56.resolve(filePath);
|
|
61535
|
+
const evidenceDirResolved = path56.resolve(evidenceDir);
|
|
60928
61536
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
60929
61537
|
continue;
|
|
60930
61538
|
}
|
|
60931
|
-
const stat2 =
|
|
61539
|
+
const stat2 = fs44.lstatSync(filePath);
|
|
60932
61540
|
if (!stat2.isFile()) {
|
|
60933
61541
|
continue;
|
|
60934
61542
|
}
|
|
@@ -60937,8 +61545,8 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
60937
61545
|
}
|
|
60938
61546
|
let fileStat;
|
|
60939
61547
|
try {
|
|
60940
|
-
fileStat =
|
|
60941
|
-
if (fileStat.size >
|
|
61548
|
+
fileStat = fs44.statSync(filePath);
|
|
61549
|
+
if (fileStat.size > MAX_FILE_SIZE_BYTES5) {
|
|
60942
61550
|
continue;
|
|
60943
61551
|
}
|
|
60944
61552
|
} catch {
|
|
@@ -60946,7 +61554,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
60946
61554
|
}
|
|
60947
61555
|
let content;
|
|
60948
61556
|
try {
|
|
60949
|
-
content =
|
|
61557
|
+
content = fs44.readFileSync(filePath, "utf-8");
|
|
60950
61558
|
} catch {
|
|
60951
61559
|
continue;
|
|
60952
61560
|
}
|
|
@@ -61042,7 +61650,7 @@ var evidence_check = createSwarmTool({
|
|
|
61042
61650
|
return JSON.stringify(errorResult, null, 2);
|
|
61043
61651
|
}
|
|
61044
61652
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
|
|
61045
|
-
const planPath =
|
|
61653
|
+
const planPath = path56.join(cwd, PLAN_FILE);
|
|
61046
61654
|
if (!isPathWithinSwarm2(planPath, cwd)) {
|
|
61047
61655
|
const errorResult = {
|
|
61048
61656
|
error: "plan file path validation failed",
|
|
@@ -61056,7 +61664,7 @@ var evidence_check = createSwarmTool({
|
|
|
61056
61664
|
}
|
|
61057
61665
|
let planContent;
|
|
61058
61666
|
try {
|
|
61059
|
-
planContent =
|
|
61667
|
+
planContent = fs44.readFileSync(planPath, "utf-8");
|
|
61060
61668
|
} catch {
|
|
61061
61669
|
const result2 = {
|
|
61062
61670
|
message: "No completed tasks found in plan.",
|
|
@@ -61074,7 +61682,7 @@ var evidence_check = createSwarmTool({
|
|
|
61074
61682
|
};
|
|
61075
61683
|
return JSON.stringify(result2, null, 2);
|
|
61076
61684
|
}
|
|
61077
|
-
const evidenceDir =
|
|
61685
|
+
const evidenceDir = path56.join(cwd, EVIDENCE_DIR2);
|
|
61078
61686
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
61079
61687
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
61080
61688
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -61091,8 +61699,8 @@ var evidence_check = createSwarmTool({
|
|
|
61091
61699
|
// src/tools/file-extractor.ts
|
|
61092
61700
|
init_tool();
|
|
61093
61701
|
init_create_tool();
|
|
61094
|
-
import * as
|
|
61095
|
-
import * as
|
|
61702
|
+
import * as fs45 from "fs";
|
|
61703
|
+
import * as path57 from "path";
|
|
61096
61704
|
var EXT_MAP = {
|
|
61097
61705
|
python: ".py",
|
|
61098
61706
|
py: ".py",
|
|
@@ -61154,8 +61762,8 @@ var extract_code_blocks = createSwarmTool({
|
|
|
61154
61762
|
execute: async (args2, directory) => {
|
|
61155
61763
|
const { content, output_dir, prefix } = args2;
|
|
61156
61764
|
const targetDir = output_dir || directory;
|
|
61157
|
-
if (!
|
|
61158
|
-
|
|
61765
|
+
if (!fs45.existsSync(targetDir)) {
|
|
61766
|
+
fs45.mkdirSync(targetDir, { recursive: true });
|
|
61159
61767
|
}
|
|
61160
61768
|
if (!content) {
|
|
61161
61769
|
return "Error: content is required";
|
|
@@ -61173,16 +61781,16 @@ var extract_code_blocks = createSwarmTool({
|
|
|
61173
61781
|
if (prefix) {
|
|
61174
61782
|
filename = `${prefix}_${filename}`;
|
|
61175
61783
|
}
|
|
61176
|
-
let filepath =
|
|
61177
|
-
const base =
|
|
61178
|
-
const ext =
|
|
61784
|
+
let filepath = path57.join(targetDir, filename);
|
|
61785
|
+
const base = path57.basename(filepath, path57.extname(filepath));
|
|
61786
|
+
const ext = path57.extname(filepath);
|
|
61179
61787
|
let counter = 1;
|
|
61180
|
-
while (
|
|
61181
|
-
filepath =
|
|
61788
|
+
while (fs45.existsSync(filepath)) {
|
|
61789
|
+
filepath = path57.join(targetDir, `${base}_${counter}${ext}`);
|
|
61182
61790
|
counter++;
|
|
61183
61791
|
}
|
|
61184
61792
|
try {
|
|
61185
|
-
|
|
61793
|
+
fs45.writeFileSync(filepath, code.trim(), "utf-8");
|
|
61186
61794
|
savedFiles.push(filepath);
|
|
61187
61795
|
} catch (error93) {
|
|
61188
61796
|
errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
@@ -61212,7 +61820,7 @@ init_create_tool();
|
|
|
61212
61820
|
var GITINGEST_TIMEOUT_MS = 1e4;
|
|
61213
61821
|
var GITINGEST_MAX_RESPONSE_BYTES = 5242880;
|
|
61214
61822
|
var GITINGEST_MAX_RETRIES = 2;
|
|
61215
|
-
var delay = (ms) => new Promise((
|
|
61823
|
+
var delay = (ms) => new Promise((resolve20) => setTimeout(resolve20, ms));
|
|
61216
61824
|
async function fetchGitingest(args2) {
|
|
61217
61825
|
for (let attempt = 0;attempt <= GITINGEST_MAX_RETRIES; attempt++) {
|
|
61218
61826
|
try {
|
|
@@ -61298,11 +61906,11 @@ var gitingest = createSwarmTool({
|
|
|
61298
61906
|
// src/tools/imports.ts
|
|
61299
61907
|
init_dist();
|
|
61300
61908
|
init_create_tool();
|
|
61301
|
-
import * as
|
|
61302
|
-
import * as
|
|
61909
|
+
import * as fs46 from "fs";
|
|
61910
|
+
import * as path58 from "path";
|
|
61303
61911
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
61304
61912
|
var MAX_SYMBOL_LENGTH = 256;
|
|
61305
|
-
var
|
|
61913
|
+
var MAX_FILE_SIZE_BYTES6 = 1024 * 1024;
|
|
61306
61914
|
var MAX_CONSUMERS = 100;
|
|
61307
61915
|
var SUPPORTED_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
61308
61916
|
var BINARY_SIGNATURES2 = [
|
|
@@ -61347,7 +61955,7 @@ function validateSymbolInput(symbol3) {
|
|
|
61347
61955
|
return null;
|
|
61348
61956
|
}
|
|
61349
61957
|
function isBinaryFile2(filePath, buffer) {
|
|
61350
|
-
const ext =
|
|
61958
|
+
const ext = path58.extname(filePath).toLowerCase();
|
|
61351
61959
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
61352
61960
|
return false;
|
|
61353
61961
|
}
|
|
@@ -61371,15 +61979,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
61371
61979
|
const imports = [];
|
|
61372
61980
|
let _resolvedTarget;
|
|
61373
61981
|
try {
|
|
61374
|
-
_resolvedTarget =
|
|
61982
|
+
_resolvedTarget = path58.resolve(targetFile);
|
|
61375
61983
|
} catch {
|
|
61376
61984
|
_resolvedTarget = targetFile;
|
|
61377
61985
|
}
|
|
61378
|
-
const targetBasename =
|
|
61986
|
+
const targetBasename = path58.basename(targetFile, path58.extname(targetFile));
|
|
61379
61987
|
const targetWithExt = targetFile;
|
|
61380
61988
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
61381
|
-
const normalizedTargetWithExt =
|
|
61382
|
-
const normalizedTargetWithoutExt =
|
|
61989
|
+
const normalizedTargetWithExt = path58.normalize(targetWithExt).replace(/\\/g, "/");
|
|
61990
|
+
const normalizedTargetWithoutExt = path58.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
61383
61991
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
61384
61992
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
61385
61993
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -61402,9 +62010,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
61402
62010
|
}
|
|
61403
62011
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
61404
62012
|
let isMatch = false;
|
|
61405
|
-
const _targetDir =
|
|
61406
|
-
const targetExt =
|
|
61407
|
-
const targetBasenameNoExt =
|
|
62013
|
+
const _targetDir = path58.dirname(targetFile);
|
|
62014
|
+
const targetExt = path58.extname(targetFile);
|
|
62015
|
+
const targetBasenameNoExt = path58.basename(targetFile, targetExt);
|
|
61408
62016
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
61409
62017
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
61410
62018
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -61461,7 +62069,7 @@ var SKIP_DIRECTORIES3 = new Set([
|
|
|
61461
62069
|
function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
|
|
61462
62070
|
let entries;
|
|
61463
62071
|
try {
|
|
61464
|
-
entries =
|
|
62072
|
+
entries = fs46.readdirSync(dir);
|
|
61465
62073
|
} catch (e) {
|
|
61466
62074
|
stats.fileErrors.push({
|
|
61467
62075
|
path: dir,
|
|
@@ -61472,13 +62080,13 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
|
|
|
61472
62080
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
61473
62081
|
for (const entry of entries) {
|
|
61474
62082
|
if (SKIP_DIRECTORIES3.has(entry)) {
|
|
61475
|
-
stats.skippedDirs.push(
|
|
62083
|
+
stats.skippedDirs.push(path58.join(dir, entry));
|
|
61476
62084
|
continue;
|
|
61477
62085
|
}
|
|
61478
|
-
const fullPath =
|
|
62086
|
+
const fullPath = path58.join(dir, entry);
|
|
61479
62087
|
let stat2;
|
|
61480
62088
|
try {
|
|
61481
|
-
stat2 =
|
|
62089
|
+
stat2 = fs46.statSync(fullPath);
|
|
61482
62090
|
} catch (e) {
|
|
61483
62091
|
stats.fileErrors.push({
|
|
61484
62092
|
path: fullPath,
|
|
@@ -61489,7 +62097,7 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
|
|
|
61489
62097
|
if (stat2.isDirectory()) {
|
|
61490
62098
|
findSourceFiles(fullPath, files, stats);
|
|
61491
62099
|
} else if (stat2.isFile()) {
|
|
61492
|
-
const ext =
|
|
62100
|
+
const ext = path58.extname(fullPath).toLowerCase();
|
|
61493
62101
|
if (SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
61494
62102
|
files.push(fullPath);
|
|
61495
62103
|
}
|
|
@@ -61546,8 +62154,8 @@ var imports = createSwarmTool({
|
|
|
61546
62154
|
return JSON.stringify(errorResult, null, 2);
|
|
61547
62155
|
}
|
|
61548
62156
|
try {
|
|
61549
|
-
const targetFile =
|
|
61550
|
-
if (!
|
|
62157
|
+
const targetFile = path58.resolve(file3);
|
|
62158
|
+
if (!fs46.existsSync(targetFile)) {
|
|
61551
62159
|
const errorResult = {
|
|
61552
62160
|
error: `target file not found: ${file3}`,
|
|
61553
62161
|
target: file3,
|
|
@@ -61557,7 +62165,7 @@ var imports = createSwarmTool({
|
|
|
61557
62165
|
};
|
|
61558
62166
|
return JSON.stringify(errorResult, null, 2);
|
|
61559
62167
|
}
|
|
61560
|
-
const targetStat =
|
|
62168
|
+
const targetStat = fs46.statSync(targetFile);
|
|
61561
62169
|
if (!targetStat.isFile()) {
|
|
61562
62170
|
const errorResult = {
|
|
61563
62171
|
error: "target must be a file, not a directory",
|
|
@@ -61568,7 +62176,7 @@ var imports = createSwarmTool({
|
|
|
61568
62176
|
};
|
|
61569
62177
|
return JSON.stringify(errorResult, null, 2);
|
|
61570
62178
|
}
|
|
61571
|
-
const baseDir =
|
|
62179
|
+
const baseDir = path58.dirname(targetFile);
|
|
61572
62180
|
const scanStats = {
|
|
61573
62181
|
skippedDirs: [],
|
|
61574
62182
|
skippedFiles: 0,
|
|
@@ -61583,12 +62191,12 @@ var imports = createSwarmTool({
|
|
|
61583
62191
|
if (consumers.length >= MAX_CONSUMERS)
|
|
61584
62192
|
break;
|
|
61585
62193
|
try {
|
|
61586
|
-
const stat2 =
|
|
61587
|
-
if (stat2.size >
|
|
62194
|
+
const stat2 = fs46.statSync(filePath);
|
|
62195
|
+
if (stat2.size > MAX_FILE_SIZE_BYTES6) {
|
|
61588
62196
|
skippedFileCount++;
|
|
61589
62197
|
continue;
|
|
61590
62198
|
}
|
|
61591
|
-
const buffer =
|
|
62199
|
+
const buffer = fs46.readFileSync(filePath);
|
|
61592
62200
|
if (isBinaryFile2(filePath, buffer)) {
|
|
61593
62201
|
skippedFileCount++;
|
|
61594
62202
|
continue;
|
|
@@ -61655,7 +62263,7 @@ var imports = createSwarmTool({
|
|
|
61655
62263
|
init_dist();
|
|
61656
62264
|
init_config();
|
|
61657
62265
|
init_knowledge_store();
|
|
61658
|
-
import { randomUUID as
|
|
62266
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
61659
62267
|
init_manager2();
|
|
61660
62268
|
init_create_tool();
|
|
61661
62269
|
var VALID_CATEGORIES2 = [
|
|
@@ -61730,7 +62338,7 @@ var knowledgeAdd = createSwarmTool({
|
|
|
61730
62338
|
project_name = plan?.title ?? "";
|
|
61731
62339
|
} catch {}
|
|
61732
62340
|
const entry = {
|
|
61733
|
-
id:
|
|
62341
|
+
id: randomUUID6(),
|
|
61734
62342
|
tier: "swarm",
|
|
61735
62343
|
lesson,
|
|
61736
62344
|
category,
|
|
@@ -61788,7 +62396,7 @@ init_dist();
|
|
|
61788
62396
|
init_config();
|
|
61789
62397
|
init_knowledge_store();
|
|
61790
62398
|
init_create_tool();
|
|
61791
|
-
import { existsSync as
|
|
62399
|
+
import { existsSync as existsSync36 } from "fs";
|
|
61792
62400
|
var DEFAULT_LIMIT = 10;
|
|
61793
62401
|
var MAX_LESSON_LENGTH = 200;
|
|
61794
62402
|
var VALID_CATEGORIES3 = [
|
|
@@ -61857,14 +62465,14 @@ function validateLimit(limit) {
|
|
|
61857
62465
|
}
|
|
61858
62466
|
async function readSwarmKnowledge(directory) {
|
|
61859
62467
|
const swarmPath = resolveSwarmKnowledgePath(directory);
|
|
61860
|
-
if (!
|
|
62468
|
+
if (!existsSync36(swarmPath)) {
|
|
61861
62469
|
return [];
|
|
61862
62470
|
}
|
|
61863
62471
|
return readKnowledge(swarmPath);
|
|
61864
62472
|
}
|
|
61865
62473
|
async function readHiveKnowledge() {
|
|
61866
62474
|
const hivePath = resolveHiveKnowledgePath();
|
|
61867
|
-
if (!
|
|
62475
|
+
if (!existsSync36(hivePath)) {
|
|
61868
62476
|
return [];
|
|
61869
62477
|
}
|
|
61870
62478
|
return readKnowledge(hivePath);
|
|
@@ -62177,8 +62785,8 @@ init_dist();
|
|
|
62177
62785
|
init_config();
|
|
62178
62786
|
init_schema();
|
|
62179
62787
|
init_manager();
|
|
62180
|
-
import * as
|
|
62181
|
-
import * as
|
|
62788
|
+
import * as fs47 from "fs";
|
|
62789
|
+
import * as path59 from "path";
|
|
62182
62790
|
init_review_receipt();
|
|
62183
62791
|
init_utils2();
|
|
62184
62792
|
init_ledger();
|
|
@@ -62402,11 +63010,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
62402
63010
|
safeWarn(`[phase_complete] Completion verify error (non-blocking):`, completionError);
|
|
62403
63011
|
}
|
|
62404
63012
|
try {
|
|
62405
|
-
const driftEvidencePath =
|
|
63013
|
+
const driftEvidencePath = path59.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
|
|
62406
63014
|
let driftVerdictFound = false;
|
|
62407
63015
|
let driftVerdictApproved = false;
|
|
62408
63016
|
try {
|
|
62409
|
-
const driftEvidenceContent =
|
|
63017
|
+
const driftEvidenceContent = fs47.readFileSync(driftEvidencePath, "utf-8");
|
|
62410
63018
|
const driftEvidence = JSON.parse(driftEvidenceContent);
|
|
62411
63019
|
const entries = driftEvidence.entries ?? [];
|
|
62412
63020
|
for (const entry of entries) {
|
|
@@ -62436,14 +63044,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
62436
63044
|
driftVerdictFound = false;
|
|
62437
63045
|
}
|
|
62438
63046
|
if (!driftVerdictFound) {
|
|
62439
|
-
const specPath =
|
|
62440
|
-
const specExists =
|
|
63047
|
+
const specPath = path59.join(dir, ".swarm", "spec.md");
|
|
63048
|
+
const specExists = fs47.existsSync(specPath);
|
|
62441
63049
|
if (!specExists) {
|
|
62442
63050
|
let incompleteTaskCount = 0;
|
|
62443
63051
|
let planPhaseFound = false;
|
|
62444
63052
|
try {
|
|
62445
63053
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
62446
|
-
const planRaw =
|
|
63054
|
+
const planRaw = fs47.readFileSync(planPath, "utf-8");
|
|
62447
63055
|
const plan = JSON.parse(planRaw);
|
|
62448
63056
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
62449
63057
|
if (targetPhase) {
|
|
@@ -62488,7 +63096,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
62488
63096
|
const knowledgeConfig = KnowledgeConfigSchema.parse(config3.knowledge ?? {});
|
|
62489
63097
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
62490
63098
|
try {
|
|
62491
|
-
const projectName =
|
|
63099
|
+
const projectName = path59.basename(dir);
|
|
62492
63100
|
const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
|
|
62493
63101
|
if (curationResult) {
|
|
62494
63102
|
const sessionState = swarmState.agentSessions.get(sessionID);
|
|
@@ -62568,7 +63176,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
62568
63176
|
let phaseRequiredAgents;
|
|
62569
63177
|
try {
|
|
62570
63178
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
62571
|
-
const planRaw =
|
|
63179
|
+
const planRaw = fs47.readFileSync(planPath, "utf-8");
|
|
62572
63180
|
const plan = JSON.parse(planRaw);
|
|
62573
63181
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
62574
63182
|
phaseRequiredAgents = phaseObj?.required_agents;
|
|
@@ -62583,7 +63191,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
62583
63191
|
if (agentsMissing.length > 0) {
|
|
62584
63192
|
try {
|
|
62585
63193
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
62586
|
-
const planRaw =
|
|
63194
|
+
const planRaw = fs47.readFileSync(planPath, "utf-8");
|
|
62587
63195
|
const plan = JSON.parse(planRaw);
|
|
62588
63196
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
62589
63197
|
if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
|
|
@@ -62623,7 +63231,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
62623
63231
|
if (phaseCompleteConfig.regression_sweep?.enforce) {
|
|
62624
63232
|
try {
|
|
62625
63233
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
62626
|
-
const planRaw =
|
|
63234
|
+
const planRaw = fs47.readFileSync(planPath, "utf-8");
|
|
62627
63235
|
const plan = JSON.parse(planRaw);
|
|
62628
63236
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
62629
63237
|
if (targetPhase) {
|
|
@@ -62661,7 +63269,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
62661
63269
|
};
|
|
62662
63270
|
try {
|
|
62663
63271
|
const eventsPath = validateSwarmPath(dir, "events.jsonl");
|
|
62664
|
-
|
|
63272
|
+
fs47.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
62665
63273
|
`, "utf-8");
|
|
62666
63274
|
} catch (writeError) {
|
|
62667
63275
|
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -62703,12 +63311,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
62703
63311
|
warnings.push(`Warning: failed to update plan.json phase status`);
|
|
62704
63312
|
try {
|
|
62705
63313
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
62706
|
-
const planRaw =
|
|
63314
|
+
const planRaw = fs47.readFileSync(planPath, "utf-8");
|
|
62707
63315
|
const plan2 = JSON.parse(planRaw);
|
|
62708
63316
|
const phaseObj = plan2.phases.find((p) => p.id === phase);
|
|
62709
63317
|
if (phaseObj) {
|
|
62710
63318
|
phaseObj.status = "complete";
|
|
62711
|
-
|
|
63319
|
+
fs47.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
|
|
62712
63320
|
}
|
|
62713
63321
|
} catch {}
|
|
62714
63322
|
} else if (plan) {
|
|
@@ -62745,12 +63353,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
62745
63353
|
warnings.push(`Warning: failed to update plan.json phase status`);
|
|
62746
63354
|
try {
|
|
62747
63355
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
62748
|
-
const planRaw =
|
|
63356
|
+
const planRaw = fs47.readFileSync(planPath, "utf-8");
|
|
62749
63357
|
const plan = JSON.parse(planRaw);
|
|
62750
63358
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
62751
63359
|
if (phaseObj) {
|
|
62752
63360
|
phaseObj.status = "complete";
|
|
62753
|
-
|
|
63361
|
+
fs47.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
|
|
62754
63362
|
}
|
|
62755
63363
|
} catch {}
|
|
62756
63364
|
}
|
|
@@ -62807,8 +63415,8 @@ init_dist();
|
|
|
62807
63415
|
init_discovery();
|
|
62808
63416
|
init_utils();
|
|
62809
63417
|
init_create_tool();
|
|
62810
|
-
import * as
|
|
62811
|
-
import * as
|
|
63418
|
+
import * as fs48 from "fs";
|
|
63419
|
+
import * as path60 from "path";
|
|
62812
63420
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
62813
63421
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
62814
63422
|
function isValidEcosystem(value) {
|
|
@@ -62826,28 +63434,28 @@ function validateArgs3(args2) {
|
|
|
62826
63434
|
function detectEcosystems(directory) {
|
|
62827
63435
|
const ecosystems = [];
|
|
62828
63436
|
const cwd = directory;
|
|
62829
|
-
if (
|
|
63437
|
+
if (fs48.existsSync(path60.join(cwd, "package.json"))) {
|
|
62830
63438
|
ecosystems.push("npm");
|
|
62831
63439
|
}
|
|
62832
|
-
if (
|
|
63440
|
+
if (fs48.existsSync(path60.join(cwd, "pyproject.toml")) || fs48.existsSync(path60.join(cwd, "requirements.txt"))) {
|
|
62833
63441
|
ecosystems.push("pip");
|
|
62834
63442
|
}
|
|
62835
|
-
if (
|
|
63443
|
+
if (fs48.existsSync(path60.join(cwd, "Cargo.toml"))) {
|
|
62836
63444
|
ecosystems.push("cargo");
|
|
62837
63445
|
}
|
|
62838
|
-
if (
|
|
63446
|
+
if (fs48.existsSync(path60.join(cwd, "go.mod"))) {
|
|
62839
63447
|
ecosystems.push("go");
|
|
62840
63448
|
}
|
|
62841
63449
|
try {
|
|
62842
|
-
const files =
|
|
63450
|
+
const files = fs48.readdirSync(cwd);
|
|
62843
63451
|
if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
62844
63452
|
ecosystems.push("dotnet");
|
|
62845
63453
|
}
|
|
62846
63454
|
} catch {}
|
|
62847
|
-
if (
|
|
63455
|
+
if (fs48.existsSync(path60.join(cwd, "Gemfile")) || fs48.existsSync(path60.join(cwd, "Gemfile.lock"))) {
|
|
62848
63456
|
ecosystems.push("ruby");
|
|
62849
63457
|
}
|
|
62850
|
-
if (
|
|
63458
|
+
if (fs48.existsSync(path60.join(cwd, "pubspec.yaml"))) {
|
|
62851
63459
|
ecosystems.push("dart");
|
|
62852
63460
|
}
|
|
62853
63461
|
return ecosystems;
|
|
@@ -62860,7 +63468,7 @@ async function runNpmAudit(directory) {
|
|
|
62860
63468
|
stderr: "pipe",
|
|
62861
63469
|
cwd: directory
|
|
62862
63470
|
});
|
|
62863
|
-
const timeoutPromise = new Promise((
|
|
63471
|
+
const timeoutPromise = new Promise((resolve21) => setTimeout(() => resolve21("timeout"), AUDIT_TIMEOUT_MS));
|
|
62864
63472
|
const result = await Promise.race([
|
|
62865
63473
|
Promise.all([
|
|
62866
63474
|
new Response(proc.stdout).text(),
|
|
@@ -62983,7 +63591,7 @@ async function runPipAudit(directory) {
|
|
|
62983
63591
|
stderr: "pipe",
|
|
62984
63592
|
cwd: directory
|
|
62985
63593
|
});
|
|
62986
|
-
const timeoutPromise = new Promise((
|
|
63594
|
+
const timeoutPromise = new Promise((resolve21) => setTimeout(() => resolve21("timeout"), AUDIT_TIMEOUT_MS));
|
|
62987
63595
|
const result = await Promise.race([
|
|
62988
63596
|
Promise.all([
|
|
62989
63597
|
new Response(proc.stdout).text(),
|
|
@@ -63114,7 +63722,7 @@ async function runCargoAudit(directory) {
|
|
|
63114
63722
|
stderr: "pipe",
|
|
63115
63723
|
cwd: directory
|
|
63116
63724
|
});
|
|
63117
|
-
const timeoutPromise = new Promise((
|
|
63725
|
+
const timeoutPromise = new Promise((resolve21) => setTimeout(() => resolve21("timeout"), AUDIT_TIMEOUT_MS));
|
|
63118
63726
|
const result = await Promise.race([
|
|
63119
63727
|
Promise.all([
|
|
63120
63728
|
new Response(proc.stdout).text(),
|
|
@@ -63241,7 +63849,7 @@ async function runGoAudit(directory) {
|
|
|
63241
63849
|
stderr: "pipe",
|
|
63242
63850
|
cwd: directory
|
|
63243
63851
|
});
|
|
63244
|
-
const timeoutPromise = new Promise((
|
|
63852
|
+
const timeoutPromise = new Promise((resolve21) => setTimeout(() => resolve21("timeout"), AUDIT_TIMEOUT_MS));
|
|
63245
63853
|
const result = await Promise.race([
|
|
63246
63854
|
Promise.all([
|
|
63247
63855
|
new Response(proc.stdout).text(),
|
|
@@ -63377,7 +63985,7 @@ async function runDotnetAudit(directory) {
|
|
|
63377
63985
|
stderr: "pipe",
|
|
63378
63986
|
cwd: directory
|
|
63379
63987
|
});
|
|
63380
|
-
const timeoutPromise = new Promise((
|
|
63988
|
+
const timeoutPromise = new Promise((resolve21) => setTimeout(() => resolve21("timeout"), AUDIT_TIMEOUT_MS));
|
|
63381
63989
|
const result = await Promise.race([
|
|
63382
63990
|
Promise.all([
|
|
63383
63991
|
new Response(proc.stdout).text(),
|
|
@@ -63496,7 +64104,7 @@ async function runBundleAudit(directory) {
|
|
|
63496
64104
|
stderr: "pipe",
|
|
63497
64105
|
cwd: directory
|
|
63498
64106
|
});
|
|
63499
|
-
const timeoutPromise = new Promise((
|
|
64107
|
+
const timeoutPromise = new Promise((resolve21) => setTimeout(() => resolve21("timeout"), AUDIT_TIMEOUT_MS));
|
|
63500
64108
|
const result = await Promise.race([
|
|
63501
64109
|
Promise.all([
|
|
63502
64110
|
new Response(proc.stdout).text(),
|
|
@@ -63644,7 +64252,7 @@ async function runDartAudit(directory) {
|
|
|
63644
64252
|
stderr: "pipe",
|
|
63645
64253
|
cwd: directory
|
|
63646
64254
|
});
|
|
63647
|
-
const timeoutPromise = new Promise((
|
|
64255
|
+
const timeoutPromise = new Promise((resolve21) => setTimeout(() => resolve21("timeout"), AUDIT_TIMEOUT_MS));
|
|
63648
64256
|
const result = await Promise.race([
|
|
63649
64257
|
Promise.all([
|
|
63650
64258
|
new Response(proc.stdout).text(),
|
|
@@ -63869,8 +64477,8 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
|
|
|
63869
64477
|
]);
|
|
63870
64478
|
// src/tools/pre-check-batch.ts
|
|
63871
64479
|
init_dist();
|
|
63872
|
-
import * as
|
|
63873
|
-
import * as
|
|
64480
|
+
import * as fs50 from "fs";
|
|
64481
|
+
import * as path62 from "path";
|
|
63874
64482
|
|
|
63875
64483
|
// node_modules/yocto-queue/index.js
|
|
63876
64484
|
class Node2 {
|
|
@@ -63961,26 +64569,26 @@ function pLimit(concurrency) {
|
|
|
63961
64569
|
activeCount--;
|
|
63962
64570
|
resumeNext();
|
|
63963
64571
|
};
|
|
63964
|
-
const run2 = async (function_,
|
|
64572
|
+
const run2 = async (function_, resolve21, arguments_2) => {
|
|
63965
64573
|
const result = (async () => function_(...arguments_2))();
|
|
63966
|
-
|
|
64574
|
+
resolve21(result);
|
|
63967
64575
|
try {
|
|
63968
64576
|
await result;
|
|
63969
64577
|
} catch {}
|
|
63970
64578
|
next();
|
|
63971
64579
|
};
|
|
63972
|
-
const enqueue = (function_,
|
|
64580
|
+
const enqueue = (function_, resolve21, reject, arguments_2) => {
|
|
63973
64581
|
const queueItem = { reject };
|
|
63974
64582
|
new Promise((internalResolve) => {
|
|
63975
64583
|
queueItem.run = internalResolve;
|
|
63976
64584
|
queue.enqueue(queueItem);
|
|
63977
|
-
}).then(run2.bind(undefined, function_,
|
|
64585
|
+
}).then(run2.bind(undefined, function_, resolve21, arguments_2));
|
|
63978
64586
|
if (activeCount < concurrency) {
|
|
63979
64587
|
resumeNext();
|
|
63980
64588
|
}
|
|
63981
64589
|
};
|
|
63982
|
-
const generator = (function_, ...arguments_2) => new Promise((
|
|
63983
|
-
enqueue(function_,
|
|
64590
|
+
const generator = (function_, ...arguments_2) => new Promise((resolve21, reject) => {
|
|
64591
|
+
enqueue(function_, resolve21, reject, arguments_2);
|
|
63984
64592
|
});
|
|
63985
64593
|
Object.defineProperties(generator, {
|
|
63986
64594
|
activeCount: {
|
|
@@ -64144,9 +64752,9 @@ async function qualityBudget(input, directory) {
|
|
|
64144
64752
|
init_dist();
|
|
64145
64753
|
init_manager();
|
|
64146
64754
|
init_detector();
|
|
64147
|
-
import * as
|
|
64148
|
-
import * as
|
|
64149
|
-
import { extname as
|
|
64755
|
+
import * as fs49 from "fs";
|
|
64756
|
+
import * as path61 from "path";
|
|
64757
|
+
import { extname as extname12 } from "path";
|
|
64150
64758
|
|
|
64151
64759
|
// src/sast/rules/c.ts
|
|
64152
64760
|
var cRules = [
|
|
@@ -64896,7 +65504,7 @@ function mapSemgrepSeverity(severity) {
|
|
|
64896
65504
|
}
|
|
64897
65505
|
}
|
|
64898
65506
|
async function executeWithTimeout(command, args2, options) {
|
|
64899
|
-
return new Promise((
|
|
65507
|
+
return new Promise((resolve21) => {
|
|
64900
65508
|
const child = child_process6.spawn(command, args2, {
|
|
64901
65509
|
shell: false,
|
|
64902
65510
|
cwd: options.cwd
|
|
@@ -64905,7 +65513,7 @@ async function executeWithTimeout(command, args2, options) {
|
|
|
64905
65513
|
let stderr = "";
|
|
64906
65514
|
const timeout = setTimeout(() => {
|
|
64907
65515
|
child.kill("SIGTERM");
|
|
64908
|
-
|
|
65516
|
+
resolve21({
|
|
64909
65517
|
stdout,
|
|
64910
65518
|
stderr: "Process timed out",
|
|
64911
65519
|
exitCode: 124
|
|
@@ -64919,7 +65527,7 @@ async function executeWithTimeout(command, args2, options) {
|
|
|
64919
65527
|
});
|
|
64920
65528
|
child.on("close", (code) => {
|
|
64921
65529
|
clearTimeout(timeout);
|
|
64922
|
-
|
|
65530
|
+
resolve21({
|
|
64923
65531
|
stdout,
|
|
64924
65532
|
stderr,
|
|
64925
65533
|
exitCode: code ?? 0
|
|
@@ -64927,7 +65535,7 @@ async function executeWithTimeout(command, args2, options) {
|
|
|
64927
65535
|
});
|
|
64928
65536
|
child.on("error", (err2) => {
|
|
64929
65537
|
clearTimeout(timeout);
|
|
64930
|
-
|
|
65538
|
+
resolve21({
|
|
64931
65539
|
stdout,
|
|
64932
65540
|
stderr: err2.message,
|
|
64933
65541
|
exitCode: 1
|
|
@@ -65004,7 +65612,7 @@ async function runSemgrep(options) {
|
|
|
65004
65612
|
// src/tools/sast-scan.ts
|
|
65005
65613
|
init_utils();
|
|
65006
65614
|
init_create_tool();
|
|
65007
|
-
var
|
|
65615
|
+
var MAX_FILE_SIZE_BYTES7 = 512 * 1024;
|
|
65008
65616
|
var MAX_FILES_SCANNED2 = 1000;
|
|
65009
65617
|
var MAX_FINDINGS2 = 100;
|
|
65010
65618
|
var SEVERITY_ORDER = {
|
|
@@ -65015,17 +65623,17 @@ var SEVERITY_ORDER = {
|
|
|
65015
65623
|
};
|
|
65016
65624
|
function shouldSkipFile(filePath) {
|
|
65017
65625
|
try {
|
|
65018
|
-
const stats =
|
|
65019
|
-
if (stats.size >
|
|
65626
|
+
const stats = fs49.statSync(filePath);
|
|
65627
|
+
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
65020
65628
|
return { skip: true, reason: "file too large" };
|
|
65021
65629
|
}
|
|
65022
65630
|
if (stats.size === 0) {
|
|
65023
65631
|
return { skip: true, reason: "empty file" };
|
|
65024
65632
|
}
|
|
65025
|
-
const fd =
|
|
65633
|
+
const fd = fs49.openSync(filePath, "r");
|
|
65026
65634
|
const buffer = Buffer.alloc(8192);
|
|
65027
|
-
const bytesRead =
|
|
65028
|
-
|
|
65635
|
+
const bytesRead = fs49.readSync(fd, buffer, 0, 8192, 0);
|
|
65636
|
+
fs49.closeSync(fd);
|
|
65029
65637
|
if (bytesRead > 0) {
|
|
65030
65638
|
let nullCount = 0;
|
|
65031
65639
|
for (let i2 = 0;i2 < bytesRead; i2++) {
|
|
@@ -65064,7 +65672,7 @@ function countBySeverity(findings) {
|
|
|
65064
65672
|
}
|
|
65065
65673
|
function scanFileWithTierA(filePath, language) {
|
|
65066
65674
|
try {
|
|
65067
|
-
const content =
|
|
65675
|
+
const content = fs49.readFileSync(filePath, "utf-8");
|
|
65068
65676
|
const findings = executeRulesSync(filePath, content, language);
|
|
65069
65677
|
return findings.map((f) => ({
|
|
65070
65678
|
rule_id: f.rule_id,
|
|
@@ -65111,13 +65719,13 @@ async function sastScan(input, directory, config3) {
|
|
|
65111
65719
|
_filesSkipped++;
|
|
65112
65720
|
continue;
|
|
65113
65721
|
}
|
|
65114
|
-
const resolvedPath =
|
|
65115
|
-
const resolvedDirectory =
|
|
65116
|
-
if (!resolvedPath.startsWith(resolvedDirectory +
|
|
65722
|
+
const resolvedPath = path61.isAbsolute(filePath) ? filePath : path61.resolve(directory, filePath);
|
|
65723
|
+
const resolvedDirectory = path61.resolve(directory);
|
|
65724
|
+
if (!resolvedPath.startsWith(resolvedDirectory + path61.sep) && resolvedPath !== resolvedDirectory) {
|
|
65117
65725
|
_filesSkipped++;
|
|
65118
65726
|
continue;
|
|
65119
65727
|
}
|
|
65120
|
-
if (!
|
|
65728
|
+
if (!fs49.existsSync(resolvedPath)) {
|
|
65121
65729
|
_filesSkipped++;
|
|
65122
65730
|
continue;
|
|
65123
65731
|
}
|
|
@@ -65126,7 +65734,7 @@ async function sastScan(input, directory, config3) {
|
|
|
65126
65734
|
_filesSkipped++;
|
|
65127
65735
|
continue;
|
|
65128
65736
|
}
|
|
65129
|
-
const ext =
|
|
65737
|
+
const ext = extname12(resolvedPath).toLowerCase();
|
|
65130
65738
|
const profile = getProfileForFile(resolvedPath);
|
|
65131
65739
|
const langDef = getLanguageForExtension(ext);
|
|
65132
65740
|
if (!profile && !langDef) {
|
|
@@ -65315,20 +65923,20 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
65315
65923
|
let resolved;
|
|
65316
65924
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
65317
65925
|
if (isWinAbs) {
|
|
65318
|
-
resolved =
|
|
65319
|
-
} else if (
|
|
65320
|
-
resolved =
|
|
65926
|
+
resolved = path62.win32.resolve(inputPath);
|
|
65927
|
+
} else if (path62.isAbsolute(inputPath)) {
|
|
65928
|
+
resolved = path62.resolve(inputPath);
|
|
65321
65929
|
} else {
|
|
65322
|
-
resolved =
|
|
65930
|
+
resolved = path62.resolve(baseDir, inputPath);
|
|
65323
65931
|
}
|
|
65324
|
-
const workspaceResolved =
|
|
65325
|
-
let
|
|
65932
|
+
const workspaceResolved = path62.resolve(workspaceDir);
|
|
65933
|
+
let relative11;
|
|
65326
65934
|
if (isWinAbs) {
|
|
65327
|
-
|
|
65935
|
+
relative11 = path62.win32.relative(workspaceResolved, resolved);
|
|
65328
65936
|
} else {
|
|
65329
|
-
|
|
65937
|
+
relative11 = path62.relative(workspaceResolved, resolved);
|
|
65330
65938
|
}
|
|
65331
|
-
if (
|
|
65939
|
+
if (relative11.startsWith("..")) {
|
|
65332
65940
|
return "path traversal detected";
|
|
65333
65941
|
}
|
|
65334
65942
|
return null;
|
|
@@ -65391,7 +65999,7 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
65391
65999
|
if (typeof file3 !== "string") {
|
|
65392
66000
|
continue;
|
|
65393
66001
|
}
|
|
65394
|
-
const resolvedPath =
|
|
66002
|
+
const resolvedPath = path62.resolve(file3);
|
|
65395
66003
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
65396
66004
|
if (validationError) {
|
|
65397
66005
|
continue;
|
|
@@ -65484,7 +66092,7 @@ async function runSecretscanWrapped(files, directory, _config) {
|
|
|
65484
66092
|
}
|
|
65485
66093
|
}
|
|
65486
66094
|
async function runSecretscanWithFiles(files, directory) {
|
|
65487
|
-
const
|
|
66095
|
+
const MAX_FILE_SIZE_BYTES8 = 512 * 1024;
|
|
65488
66096
|
const MAX_FINDINGS3 = 100;
|
|
65489
66097
|
const DEFAULT_EXCLUDE_EXTENSIONS2 = new Set([
|
|
65490
66098
|
".png",
|
|
@@ -65548,7 +66156,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
65548
66156
|
skippedFiles++;
|
|
65549
66157
|
continue;
|
|
65550
66158
|
}
|
|
65551
|
-
const resolvedPath =
|
|
66159
|
+
const resolvedPath = path62.resolve(file3);
|
|
65552
66160
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
65553
66161
|
if (validationError) {
|
|
65554
66162
|
skippedFiles++;
|
|
@@ -65566,25 +66174,25 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
65566
66174
|
};
|
|
65567
66175
|
}
|
|
65568
66176
|
for (const file3 of validatedFiles) {
|
|
65569
|
-
const ext =
|
|
66177
|
+
const ext = path62.extname(file3).toLowerCase();
|
|
65570
66178
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
65571
66179
|
skippedFiles++;
|
|
65572
66180
|
continue;
|
|
65573
66181
|
}
|
|
65574
66182
|
let stat2;
|
|
65575
66183
|
try {
|
|
65576
|
-
stat2 =
|
|
66184
|
+
stat2 = fs50.statSync(file3);
|
|
65577
66185
|
} catch {
|
|
65578
66186
|
skippedFiles++;
|
|
65579
66187
|
continue;
|
|
65580
66188
|
}
|
|
65581
|
-
if (stat2.size >
|
|
66189
|
+
if (stat2.size > MAX_FILE_SIZE_BYTES8) {
|
|
65582
66190
|
skippedFiles++;
|
|
65583
66191
|
continue;
|
|
65584
66192
|
}
|
|
65585
66193
|
let content;
|
|
65586
66194
|
try {
|
|
65587
|
-
const buffer =
|
|
66195
|
+
const buffer = fs50.readFileSync(file3);
|
|
65588
66196
|
if (buffer.includes(0)) {
|
|
65589
66197
|
skippedFiles++;
|
|
65590
66198
|
continue;
|
|
@@ -65772,7 +66380,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
|
|
|
65772
66380
|
const preexistingFindings = [];
|
|
65773
66381
|
for (const finding of findings) {
|
|
65774
66382
|
const filePath = finding.location.file;
|
|
65775
|
-
const normalised =
|
|
66383
|
+
const normalised = path62.relative(directory, filePath).replace(/\\/g, "/");
|
|
65776
66384
|
const changedLines = changedLineRanges.get(normalised);
|
|
65777
66385
|
if (changedLines && changedLines.has(finding.location.line)) {
|
|
65778
66386
|
newFindings.push(finding);
|
|
@@ -65823,7 +66431,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
|
|
|
65823
66431
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
65824
66432
|
continue;
|
|
65825
66433
|
}
|
|
65826
|
-
changedFiles.push(
|
|
66434
|
+
changedFiles.push(path62.resolve(directory, file3));
|
|
65827
66435
|
}
|
|
65828
66436
|
if (changedFiles.length === 0) {
|
|
65829
66437
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -66011,7 +66619,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
66011
66619
|
};
|
|
66012
66620
|
return JSON.stringify(errorResult, null, 2);
|
|
66013
66621
|
}
|
|
66014
|
-
const resolvedDirectory =
|
|
66622
|
+
const resolvedDirectory = path62.resolve(typedArgs.directory);
|
|
66015
66623
|
const workspaceAnchor = resolvedDirectory;
|
|
66016
66624
|
const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
|
|
66017
66625
|
if (dirError) {
|
|
@@ -66117,31 +66725,31 @@ ${paginatedContent}`;
|
|
|
66117
66725
|
});
|
|
66118
66726
|
// src/tools/save-plan.ts
|
|
66119
66727
|
init_tool();
|
|
66120
|
-
import * as
|
|
66121
|
-
import * as
|
|
66728
|
+
import * as fs52 from "fs";
|
|
66729
|
+
import * as path64 from "path";
|
|
66122
66730
|
|
|
66123
66731
|
// src/parallel/file-locks.ts
|
|
66124
66732
|
var import_proper_lockfile3 = __toESM(require_proper_lockfile(), 1);
|
|
66125
|
-
import * as
|
|
66126
|
-
import * as
|
|
66733
|
+
import * as fs51 from "fs";
|
|
66734
|
+
import * as path63 from "path";
|
|
66127
66735
|
var LOCKS_DIR = ".swarm/locks";
|
|
66128
66736
|
var LOCK_TIMEOUT_MS = 5 * 60 * 1000;
|
|
66129
66737
|
function getLockFilePath(directory, filePath) {
|
|
66130
|
-
const normalized =
|
|
66131
|
-
if (!normalized.startsWith(
|
|
66738
|
+
const normalized = path63.resolve(directory, filePath);
|
|
66739
|
+
if (!normalized.startsWith(path63.resolve(directory))) {
|
|
66132
66740
|
throw new Error("Invalid file path: path traversal not allowed");
|
|
66133
66741
|
}
|
|
66134
66742
|
const hash3 = Buffer.from(normalized).toString("base64").replace(/[/+=]/g, "_");
|
|
66135
|
-
return
|
|
66743
|
+
return path63.join(directory, LOCKS_DIR, `${hash3}.lock`);
|
|
66136
66744
|
}
|
|
66137
66745
|
async function tryAcquireLock(directory, filePath, agent, taskId) {
|
|
66138
66746
|
const lockPath = getLockFilePath(directory, filePath);
|
|
66139
|
-
const locksDir =
|
|
66140
|
-
if (!
|
|
66141
|
-
|
|
66747
|
+
const locksDir = path63.dirname(lockPath);
|
|
66748
|
+
if (!fs51.existsSync(locksDir)) {
|
|
66749
|
+
fs51.mkdirSync(locksDir, { recursive: true });
|
|
66142
66750
|
}
|
|
66143
|
-
if (!
|
|
66144
|
-
|
|
66751
|
+
if (!fs51.existsSync(lockPath)) {
|
|
66752
|
+
fs51.writeFileSync(lockPath, "", "utf-8");
|
|
66145
66753
|
}
|
|
66146
66754
|
let release;
|
|
66147
66755
|
try {
|
|
@@ -66289,14 +66897,14 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
66289
66897
|
await savePlan(dir, plan);
|
|
66290
66898
|
await writeCheckpoint(dir).catch(() => {});
|
|
66291
66899
|
try {
|
|
66292
|
-
const markerPath =
|
|
66900
|
+
const markerPath = path64.join(dir, ".swarm", ".plan-write-marker");
|
|
66293
66901
|
const marker = JSON.stringify({
|
|
66294
66902
|
source: "save_plan",
|
|
66295
66903
|
timestamp: new Date().toISOString(),
|
|
66296
66904
|
phases_count: plan.phases.length,
|
|
66297
66905
|
tasks_count: tasksCount
|
|
66298
66906
|
});
|
|
66299
|
-
await
|
|
66907
|
+
await fs52.promises.writeFile(markerPath, marker, "utf8");
|
|
66300
66908
|
} catch {}
|
|
66301
66909
|
const warnings = [];
|
|
66302
66910
|
let criticReviewFound = false;
|
|
@@ -66312,7 +66920,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
66312
66920
|
return {
|
|
66313
66921
|
success: true,
|
|
66314
66922
|
message: "Plan saved successfully",
|
|
66315
|
-
plan_path:
|
|
66923
|
+
plan_path: path64.join(dir, ".swarm", "plan.json"),
|
|
66316
66924
|
phases_count: plan.phases.length,
|
|
66317
66925
|
tasks_count: tasksCount,
|
|
66318
66926
|
...warnings.length > 0 ? { warnings } : {}
|
|
@@ -66356,8 +66964,8 @@ var save_plan = createSwarmTool({
|
|
|
66356
66964
|
// src/tools/sbom-generate.ts
|
|
66357
66965
|
init_dist();
|
|
66358
66966
|
init_manager();
|
|
66359
|
-
import * as
|
|
66360
|
-
import * as
|
|
66967
|
+
import * as fs53 from "fs";
|
|
66968
|
+
import * as path65 from "path";
|
|
66361
66969
|
|
|
66362
66970
|
// src/sbom/detectors/index.ts
|
|
66363
66971
|
init_utils();
|
|
@@ -67205,9 +67813,9 @@ function findManifestFiles(rootDir) {
|
|
|
67205
67813
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
67206
67814
|
function searchDir(dir) {
|
|
67207
67815
|
try {
|
|
67208
|
-
const entries =
|
|
67816
|
+
const entries = fs53.readdirSync(dir, { withFileTypes: true });
|
|
67209
67817
|
for (const entry of entries) {
|
|
67210
|
-
const fullPath =
|
|
67818
|
+
const fullPath = path65.join(dir, entry.name);
|
|
67211
67819
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
67212
67820
|
continue;
|
|
67213
67821
|
}
|
|
@@ -67216,7 +67824,7 @@ function findManifestFiles(rootDir) {
|
|
|
67216
67824
|
} else if (entry.isFile()) {
|
|
67217
67825
|
for (const pattern of patterns) {
|
|
67218
67826
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
67219
|
-
manifestFiles.push(
|
|
67827
|
+
manifestFiles.push(path65.relative(rootDir, fullPath));
|
|
67220
67828
|
break;
|
|
67221
67829
|
}
|
|
67222
67830
|
}
|
|
@@ -67232,13 +67840,13 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
67232
67840
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
67233
67841
|
for (const dir of directories) {
|
|
67234
67842
|
try {
|
|
67235
|
-
const entries =
|
|
67843
|
+
const entries = fs53.readdirSync(dir, { withFileTypes: true });
|
|
67236
67844
|
for (const entry of entries) {
|
|
67237
|
-
const fullPath =
|
|
67845
|
+
const fullPath = path65.join(dir, entry.name);
|
|
67238
67846
|
if (entry.isFile()) {
|
|
67239
67847
|
for (const pattern of patterns) {
|
|
67240
67848
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
67241
|
-
found.push(
|
|
67849
|
+
found.push(path65.relative(workingDir, fullPath));
|
|
67242
67850
|
break;
|
|
67243
67851
|
}
|
|
67244
67852
|
}
|
|
@@ -67251,11 +67859,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
67251
67859
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
67252
67860
|
const dirs = new Set;
|
|
67253
67861
|
for (const file3 of changedFiles) {
|
|
67254
|
-
let currentDir =
|
|
67862
|
+
let currentDir = path65.dirname(file3);
|
|
67255
67863
|
while (true) {
|
|
67256
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
67257
|
-
dirs.add(
|
|
67258
|
-
const parent =
|
|
67864
|
+
if (currentDir && currentDir !== "." && currentDir !== path65.sep) {
|
|
67865
|
+
dirs.add(path65.join(workingDir, currentDir));
|
|
67866
|
+
const parent = path65.dirname(currentDir);
|
|
67259
67867
|
if (parent === currentDir)
|
|
67260
67868
|
break;
|
|
67261
67869
|
currentDir = parent;
|
|
@@ -67269,7 +67877,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
67269
67877
|
}
|
|
67270
67878
|
function ensureOutputDir(outputDir) {
|
|
67271
67879
|
try {
|
|
67272
|
-
|
|
67880
|
+
fs53.mkdirSync(outputDir, { recursive: true });
|
|
67273
67881
|
} catch (error93) {
|
|
67274
67882
|
if (!error93 || error93.code !== "EEXIST") {
|
|
67275
67883
|
throw error93;
|
|
@@ -67339,7 +67947,7 @@ var sbom_generate = createSwarmTool({
|
|
|
67339
67947
|
const changedFiles = obj.changed_files;
|
|
67340
67948
|
const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
|
|
67341
67949
|
const workingDir = directory;
|
|
67342
|
-
const outputDir =
|
|
67950
|
+
const outputDir = path65.isAbsolute(relativeOutputDir) ? relativeOutputDir : path65.join(workingDir, relativeOutputDir);
|
|
67343
67951
|
let manifestFiles = [];
|
|
67344
67952
|
if (scope === "all") {
|
|
67345
67953
|
manifestFiles = findManifestFiles(workingDir);
|
|
@@ -67362,11 +67970,11 @@ var sbom_generate = createSwarmTool({
|
|
|
67362
67970
|
const processedFiles = [];
|
|
67363
67971
|
for (const manifestFile of manifestFiles) {
|
|
67364
67972
|
try {
|
|
67365
|
-
const fullPath =
|
|
67366
|
-
if (!
|
|
67973
|
+
const fullPath = path65.isAbsolute(manifestFile) ? manifestFile : path65.join(workingDir, manifestFile);
|
|
67974
|
+
if (!fs53.existsSync(fullPath)) {
|
|
67367
67975
|
continue;
|
|
67368
67976
|
}
|
|
67369
|
-
const content =
|
|
67977
|
+
const content = fs53.readFileSync(fullPath, "utf-8");
|
|
67370
67978
|
const components = detectComponents(manifestFile, content);
|
|
67371
67979
|
processedFiles.push(manifestFile);
|
|
67372
67980
|
if (components.length > 0) {
|
|
@@ -67379,8 +67987,8 @@ var sbom_generate = createSwarmTool({
|
|
|
67379
67987
|
const bom = generateCycloneDX(allComponents);
|
|
67380
67988
|
const bomJson = serializeCycloneDX(bom);
|
|
67381
67989
|
const filename = generateSbomFilename();
|
|
67382
|
-
const outputPath =
|
|
67383
|
-
|
|
67990
|
+
const outputPath = path65.join(outputDir, filename);
|
|
67991
|
+
fs53.writeFileSync(outputPath, bomJson, "utf-8");
|
|
67384
67992
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
67385
67993
|
try {
|
|
67386
67994
|
const timestamp = new Date().toISOString();
|
|
@@ -67422,8 +68030,8 @@ var sbom_generate = createSwarmTool({
|
|
|
67422
68030
|
// src/tools/schema-drift.ts
|
|
67423
68031
|
init_dist();
|
|
67424
68032
|
init_create_tool();
|
|
67425
|
-
import * as
|
|
67426
|
-
import * as
|
|
68033
|
+
import * as fs54 from "fs";
|
|
68034
|
+
import * as path66 from "path";
|
|
67427
68035
|
var SPEC_CANDIDATES = [
|
|
67428
68036
|
"openapi.json",
|
|
67429
68037
|
"openapi.yaml",
|
|
@@ -67455,28 +68063,28 @@ function normalizePath2(p) {
|
|
|
67455
68063
|
}
|
|
67456
68064
|
function discoverSpecFile(cwd, specFileArg) {
|
|
67457
68065
|
if (specFileArg) {
|
|
67458
|
-
const resolvedPath =
|
|
67459
|
-
const normalizedCwd = cwd.endsWith(
|
|
68066
|
+
const resolvedPath = path66.resolve(cwd, specFileArg);
|
|
68067
|
+
const normalizedCwd = cwd.endsWith(path66.sep) ? cwd : cwd + path66.sep;
|
|
67460
68068
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
67461
68069
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
67462
68070
|
}
|
|
67463
|
-
const ext =
|
|
68071
|
+
const ext = path66.extname(resolvedPath).toLowerCase();
|
|
67464
68072
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
67465
68073
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
67466
68074
|
}
|
|
67467
|
-
const stats =
|
|
68075
|
+
const stats = fs54.statSync(resolvedPath);
|
|
67468
68076
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
67469
68077
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
67470
68078
|
}
|
|
67471
|
-
if (!
|
|
68079
|
+
if (!fs54.existsSync(resolvedPath)) {
|
|
67472
68080
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
67473
68081
|
}
|
|
67474
68082
|
return resolvedPath;
|
|
67475
68083
|
}
|
|
67476
68084
|
for (const candidate of SPEC_CANDIDATES) {
|
|
67477
|
-
const candidatePath =
|
|
67478
|
-
if (
|
|
67479
|
-
const stats =
|
|
68085
|
+
const candidatePath = path66.resolve(cwd, candidate);
|
|
68086
|
+
if (fs54.existsSync(candidatePath)) {
|
|
68087
|
+
const stats = fs54.statSync(candidatePath);
|
|
67480
68088
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
67481
68089
|
return candidatePath;
|
|
67482
68090
|
}
|
|
@@ -67485,8 +68093,8 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
67485
68093
|
return null;
|
|
67486
68094
|
}
|
|
67487
68095
|
function parseSpec(specFile) {
|
|
67488
|
-
const content =
|
|
67489
|
-
const ext =
|
|
68096
|
+
const content = fs54.readFileSync(specFile, "utf-8");
|
|
68097
|
+
const ext = path66.extname(specFile).toLowerCase();
|
|
67490
68098
|
if (ext === ".json") {
|
|
67491
68099
|
return parseJsonSpec(content);
|
|
67492
68100
|
}
|
|
@@ -67557,12 +68165,12 @@ function extractRoutes(cwd) {
|
|
|
67557
68165
|
function walkDir(dir) {
|
|
67558
68166
|
let entries;
|
|
67559
68167
|
try {
|
|
67560
|
-
entries =
|
|
68168
|
+
entries = fs54.readdirSync(dir, { withFileTypes: true });
|
|
67561
68169
|
} catch {
|
|
67562
68170
|
return;
|
|
67563
68171
|
}
|
|
67564
68172
|
for (const entry of entries) {
|
|
67565
|
-
const fullPath =
|
|
68173
|
+
const fullPath = path66.join(dir, entry.name);
|
|
67566
68174
|
if (entry.isSymbolicLink()) {
|
|
67567
68175
|
continue;
|
|
67568
68176
|
}
|
|
@@ -67572,7 +68180,7 @@ function extractRoutes(cwd) {
|
|
|
67572
68180
|
}
|
|
67573
68181
|
walkDir(fullPath);
|
|
67574
68182
|
} else if (entry.isFile()) {
|
|
67575
|
-
const ext =
|
|
68183
|
+
const ext = path66.extname(entry.name).toLowerCase();
|
|
67576
68184
|
const baseName = entry.name.toLowerCase();
|
|
67577
68185
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
67578
68186
|
continue;
|
|
@@ -67590,7 +68198,7 @@ function extractRoutes(cwd) {
|
|
|
67590
68198
|
}
|
|
67591
68199
|
function extractRoutesFromFile(filePath) {
|
|
67592
68200
|
const routes = [];
|
|
67593
|
-
const content =
|
|
68201
|
+
const content = fs54.readFileSync(filePath, "utf-8");
|
|
67594
68202
|
const lines = content.split(/\r?\n/);
|
|
67595
68203
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
67596
68204
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -67734,36 +68342,51 @@ var schema_drift = createSwarmTool({
|
|
|
67734
68342
|
}
|
|
67735
68343
|
}
|
|
67736
68344
|
});
|
|
67737
|
-
|
|
67738
|
-
// src/tools/index.ts
|
|
67739
|
-
init_secretscan();
|
|
67740
|
-
|
|
67741
|
-
// src/tools/symbols.ts
|
|
68345
|
+
// src/tools/search.ts
|
|
67742
68346
|
init_tool();
|
|
67743
68347
|
init_create_tool();
|
|
67744
|
-
import * as
|
|
67745
|
-
import * as
|
|
67746
|
-
var
|
|
67747
|
-
var
|
|
67748
|
-
|
|
67749
|
-
|
|
67750
|
-
|
|
68348
|
+
import * as fs55 from "fs";
|
|
68349
|
+
import * as path67 from "path";
|
|
68350
|
+
var DEFAULT_MAX_RESULTS = 100;
|
|
68351
|
+
var DEFAULT_MAX_LINES = 200;
|
|
68352
|
+
var REGEX_TIMEOUT_MS = 5000;
|
|
68353
|
+
var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
|
|
68354
|
+
var HARD_CAP_RESULTS = 1e4;
|
|
68355
|
+
var HARD_CAP_LINES = 1e4;
|
|
68356
|
+
function globMatch(pattern, filePath) {
|
|
68357
|
+
const normalizedPattern = pattern.replace(/\\/g, "/");
|
|
68358
|
+
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
68359
|
+
const regexPattern = normalizedPattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{DOUBLESTAR}}").replace(/\*/g, "[^/]*").replace(/\?/g, ".").replace(/\{\{DOUBLESTAR\}\}/g, ".*");
|
|
68360
|
+
try {
|
|
68361
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
68362
|
+
return regex.test(normalizedPath);
|
|
68363
|
+
} catch {
|
|
68364
|
+
return false;
|
|
67751
68365
|
}
|
|
68366
|
+
}
|
|
68367
|
+
function matchesGlobs(filePath, globs) {
|
|
68368
|
+
if (globs.length === 0)
|
|
68369
|
+
return true;
|
|
68370
|
+
return globs.some((glob) => globMatch(glob, filePath));
|
|
68371
|
+
}
|
|
68372
|
+
var WINDOWS_RESERVED_NAMES3 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
68373
|
+
function containsWindowsAttacks3(str) {
|
|
68374
|
+
if (/:[^\\/]/.test(str))
|
|
68375
|
+
return true;
|
|
67752
68376
|
const parts2 = str.split(/[/\\]/);
|
|
67753
68377
|
for (const part of parts2) {
|
|
67754
|
-
if (
|
|
68378
|
+
if (WINDOWS_RESERVED_NAMES3.test(part))
|
|
67755
68379
|
return true;
|
|
67756
|
-
}
|
|
67757
68380
|
}
|
|
67758
68381
|
return false;
|
|
67759
68382
|
}
|
|
67760
|
-
function
|
|
68383
|
+
function isPathInWorkspace3(filePath, workspace) {
|
|
67761
68384
|
try {
|
|
67762
|
-
const resolvedPath =
|
|
67763
|
-
const realWorkspace =
|
|
67764
|
-
const realResolvedPath =
|
|
67765
|
-
const relativePath =
|
|
67766
|
-
if (relativePath.startsWith("..") ||
|
|
68385
|
+
const resolvedPath = path67.resolve(workspace, filePath);
|
|
68386
|
+
const realWorkspace = fs55.realpathSync(workspace);
|
|
68387
|
+
const realResolvedPath = fs55.realpathSync(resolvedPath);
|
|
68388
|
+
const relativePath = path67.relative(realWorkspace, realResolvedPath);
|
|
68389
|
+
if (relativePath.startsWith("..") || path67.isAbsolute(relativePath)) {
|
|
67767
68390
|
return false;
|
|
67768
68391
|
}
|
|
67769
68392
|
return true;
|
|
@@ -67771,301 +68394,675 @@ function isPathInWorkspace(filePath, workspace) {
|
|
|
67771
68394
|
return false;
|
|
67772
68395
|
}
|
|
67773
68396
|
}
|
|
67774
|
-
function
|
|
67775
|
-
return
|
|
68397
|
+
function validatePathForRead2(filePath, workspace) {
|
|
68398
|
+
return isPathInWorkspace3(filePath, workspace);
|
|
67776
68399
|
}
|
|
67777
|
-
function
|
|
67778
|
-
const
|
|
67779
|
-
|
|
67780
|
-
|
|
68400
|
+
function findRgInEnvPath() {
|
|
68401
|
+
const searchPath = process.env.PATH ?? "";
|
|
68402
|
+
for (const dir of searchPath.split(path67.delimiter)) {
|
|
68403
|
+
if (!dir)
|
|
68404
|
+
continue;
|
|
68405
|
+
const isWindows = process.platform === "win32";
|
|
68406
|
+
const candidate = path67.join(dir, isWindows ? "rg.exe" : "rg");
|
|
68407
|
+
if (fs55.existsSync(candidate))
|
|
68408
|
+
return candidate;
|
|
67781
68409
|
}
|
|
67782
|
-
|
|
68410
|
+
return null;
|
|
68411
|
+
}
|
|
68412
|
+
async function isRipgrepAvailable() {
|
|
68413
|
+
const rgPath = findRgInEnvPath();
|
|
68414
|
+
if (!rgPath)
|
|
68415
|
+
return false;
|
|
67783
68416
|
try {
|
|
67784
|
-
const
|
|
67785
|
-
|
|
67786
|
-
|
|
67787
|
-
}
|
|
67788
|
-
|
|
68417
|
+
const proc = Bun.spawn([rgPath, "--version"], {
|
|
68418
|
+
stdout: "pipe",
|
|
68419
|
+
stderr: "pipe"
|
|
68420
|
+
});
|
|
68421
|
+
const exitCode = await proc.exited;
|
|
68422
|
+
return exitCode === 0;
|
|
67789
68423
|
} catch {
|
|
67790
|
-
return
|
|
68424
|
+
return false;
|
|
67791
68425
|
}
|
|
67792
|
-
|
|
67793
|
-
|
|
67794
|
-
const
|
|
67795
|
-
|
|
67796
|
-
|
|
67797
|
-
|
|
67798
|
-
|
|
67799
|
-
|
|
67800
|
-
|
|
67801
|
-
|
|
67802
|
-
|
|
67803
|
-
|
|
67804
|
-
|
|
67805
|
-
|
|
67806
|
-
|
|
67807
|
-
|
|
67808
|
-
|
|
67809
|
-
jsdoc = `${jsdoc.substring(0, 300)}...`;
|
|
68426
|
+
}
|
|
68427
|
+
async function ripgrepSearch(opts) {
|
|
68428
|
+
const rgPath = findRgInEnvPath();
|
|
68429
|
+
if (!rgPath) {
|
|
68430
|
+
return {
|
|
68431
|
+
error: true,
|
|
68432
|
+
type: "rg-not-found",
|
|
68433
|
+
message: "ripgrep (rg) not found in PATH"
|
|
68434
|
+
};
|
|
68435
|
+
}
|
|
68436
|
+
const args2 = [
|
|
68437
|
+
"--json",
|
|
68438
|
+
"-n"
|
|
68439
|
+
];
|
|
68440
|
+
if (opts.include) {
|
|
68441
|
+
for (const pattern of opts.include.split(",")) {
|
|
68442
|
+
args2.push("--glob", pattern.trim());
|
|
67810
68443
|
}
|
|
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;
|
|
68444
|
+
}
|
|
68445
|
+
if (opts.exclude) {
|
|
68446
|
+
for (const pattern of opts.exclude.split(",")) {
|
|
68447
|
+
args2.push("--glob", `!${pattern.trim()}`);
|
|
67822
68448
|
}
|
|
67823
|
-
|
|
67824
|
-
|
|
67825
|
-
|
|
67826
|
-
|
|
67827
|
-
|
|
67828
|
-
|
|
67829
|
-
|
|
67830
|
-
|
|
67831
|
-
|
|
67832
|
-
|
|
67833
|
-
|
|
67834
|
-
|
|
67835
|
-
|
|
68449
|
+
}
|
|
68450
|
+
if (opts.mode !== "regex") {
|
|
68451
|
+
args2.push("--fixed-strings");
|
|
68452
|
+
}
|
|
68453
|
+
args2.push(opts.query);
|
|
68454
|
+
args2.push(opts.workspace);
|
|
68455
|
+
try {
|
|
68456
|
+
const proc = Bun.spawn([rgPath, ...args2], {
|
|
68457
|
+
stdout: "pipe",
|
|
68458
|
+
stderr: "pipe",
|
|
68459
|
+
cwd: opts.workspace
|
|
68460
|
+
});
|
|
68461
|
+
const timeout = new Promise((resolve26) => setTimeout(() => resolve26("timeout"), REGEX_TIMEOUT_MS));
|
|
68462
|
+
const exitPromise = proc.exited;
|
|
68463
|
+
const result = await Promise.race([exitPromise, timeout]);
|
|
68464
|
+
if (result === "timeout") {
|
|
68465
|
+
proc.kill();
|
|
68466
|
+
return {
|
|
68467
|
+
error: true,
|
|
68468
|
+
type: "regex-timeout",
|
|
68469
|
+
message: `Regex search timed out after ${REGEX_TIMEOUT_MS}ms`
|
|
68470
|
+
};
|
|
67836
68471
|
}
|
|
67837
|
-
const
|
|
67838
|
-
|
|
67839
|
-
|
|
67840
|
-
|
|
67841
|
-
|
|
67842
|
-
|
|
67843
|
-
|
|
67844
|
-
|
|
67845
|
-
|
|
67846
|
-
|
|
67847
|
-
|
|
67848
|
-
|
|
67849
|
-
|
|
67850
|
-
|
|
67851
|
-
|
|
67852
|
-
|
|
67853
|
-
|
|
67854
|
-
|
|
67855
|
-
|
|
67856
|
-
|
|
67857
|
-
|
|
67858
|
-
|
|
67859
|
-
|
|
68472
|
+
const stdout = await new Response(proc.stdout).text();
|
|
68473
|
+
const stderr = await new Response(proc.stderr).text();
|
|
68474
|
+
if (proc.exitCode !== 0 && stderr) {
|
|
68475
|
+
if (stderr.includes("Invalid regex") || stderr.includes("SyntaxError")) {
|
|
68476
|
+
return {
|
|
68477
|
+
error: true,
|
|
68478
|
+
type: "invalid-query",
|
|
68479
|
+
message: `Invalid query: ${stderr.split(`
|
|
68480
|
+
`)[0]}`
|
|
68481
|
+
};
|
|
68482
|
+
}
|
|
68483
|
+
}
|
|
68484
|
+
const matches = [];
|
|
68485
|
+
let total = 0;
|
|
68486
|
+
for (const line of stdout.split(`
|
|
68487
|
+
`)) {
|
|
68488
|
+
if (!line.trim())
|
|
68489
|
+
continue;
|
|
68490
|
+
try {
|
|
68491
|
+
const entry = JSON.parse(line);
|
|
68492
|
+
if (entry.type === "match") {
|
|
68493
|
+
total++;
|
|
68494
|
+
if (matches.length < opts.maxResults) {
|
|
68495
|
+
let lineText = entry.data.lines.text.trimEnd();
|
|
68496
|
+
if (lineText.length > opts.maxLines) {
|
|
68497
|
+
lineText = `${lineText.substring(0, opts.maxLines)}...`;
|
|
68498
|
+
}
|
|
68499
|
+
const match = {
|
|
68500
|
+
file: entry.data.path.text || entry.data.path,
|
|
68501
|
+
lineNumber: entry.data.line_number,
|
|
68502
|
+
lineText
|
|
68503
|
+
};
|
|
68504
|
+
matches.push(match);
|
|
68505
|
+
}
|
|
67860
68506
|
}
|
|
67861
|
-
|
|
67862
|
-
|
|
67863
|
-
|
|
67864
|
-
|
|
67865
|
-
|
|
67866
|
-
|
|
67867
|
-
|
|
67868
|
-
|
|
67869
|
-
|
|
68507
|
+
} catch {}
|
|
68508
|
+
}
|
|
68509
|
+
return {
|
|
68510
|
+
matches,
|
|
68511
|
+
truncated: total > opts.maxResults,
|
|
68512
|
+
total,
|
|
68513
|
+
query: opts.query,
|
|
68514
|
+
mode: opts.mode,
|
|
68515
|
+
maxResults: opts.maxResults
|
|
68516
|
+
};
|
|
68517
|
+
} catch (err2) {
|
|
68518
|
+
return {
|
|
68519
|
+
error: true,
|
|
68520
|
+
type: "unknown",
|
|
68521
|
+
message: err2 instanceof Error ? err2.message : String(err2)
|
|
68522
|
+
};
|
|
68523
|
+
}
|
|
68524
|
+
}
|
|
68525
|
+
function escapeRegex4(str) {
|
|
68526
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
68527
|
+
}
|
|
68528
|
+
function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
|
|
68529
|
+
const files = [];
|
|
68530
|
+
if (!validatePathForRead2(dir, workspace)) {
|
|
68531
|
+
return files;
|
|
68532
|
+
}
|
|
68533
|
+
try {
|
|
68534
|
+
const entries = fs55.readdirSync(dir, { withFileTypes: true });
|
|
68535
|
+
for (const entry of entries) {
|
|
68536
|
+
const fullPath = path67.join(dir, entry.name);
|
|
68537
|
+
const relativePath = path67.relative(workspace, fullPath);
|
|
68538
|
+
if (!validatePathForRead2(fullPath, workspace)) {
|
|
68539
|
+
continue;
|
|
68540
|
+
}
|
|
68541
|
+
if (entry.isDirectory()) {
|
|
68542
|
+
const subFiles = collectFiles(fullPath, workspace, includeGlobs, excludeGlobs);
|
|
68543
|
+
files.push(...subFiles);
|
|
68544
|
+
} else if (entry.isFile()) {
|
|
68545
|
+
if (includeGlobs.length > 0 && !matchesGlobs(relativePath, includeGlobs)) {
|
|
68546
|
+
continue;
|
|
67870
68547
|
}
|
|
68548
|
+
if (excludeGlobs.length > 0 && matchesGlobs(relativePath, excludeGlobs)) {
|
|
68549
|
+
continue;
|
|
68550
|
+
}
|
|
68551
|
+
files.push(relativePath);
|
|
67871
68552
|
}
|
|
67872
|
-
continue;
|
|
67873
68553
|
}
|
|
67874
|
-
|
|
67875
|
-
|
|
67876
|
-
|
|
67877
|
-
|
|
67878
|
-
|
|
67879
|
-
|
|
67880
|
-
|
|
67881
|
-
|
|
67882
|
-
|
|
67883
|
-
|
|
68554
|
+
} catch {}
|
|
68555
|
+
return files;
|
|
68556
|
+
}
|
|
68557
|
+
async function fallbackSearch(opts) {
|
|
68558
|
+
const includeGlobs = opts.include ? opts.include.split(",").map((p) => p.trim()).filter(Boolean) : [];
|
|
68559
|
+
const excludeGlobs = opts.exclude ? opts.exclude.split(",").map((p) => p.trim()).filter(Boolean) : [];
|
|
68560
|
+
const files = collectFiles(opts.workspace, opts.workspace, includeGlobs, excludeGlobs);
|
|
68561
|
+
let regex;
|
|
68562
|
+
try {
|
|
68563
|
+
if (opts.mode === "regex") {
|
|
68564
|
+
regex = new RegExp(opts.query);
|
|
68565
|
+
} else {
|
|
68566
|
+
regex = new RegExp(escapeRegex4(opts.query));
|
|
68567
|
+
}
|
|
68568
|
+
} catch (err2) {
|
|
68569
|
+
return {
|
|
68570
|
+
error: true,
|
|
68571
|
+
type: "invalid-query",
|
|
68572
|
+
message: err2 instanceof Error ? err2.message : "Invalid regex pattern"
|
|
68573
|
+
};
|
|
68574
|
+
}
|
|
68575
|
+
const matches = [];
|
|
68576
|
+
let total = 0;
|
|
68577
|
+
for (const file3 of files) {
|
|
68578
|
+
const fullPath = path67.join(opts.workspace, file3);
|
|
68579
|
+
if (!validatePathForRead2(fullPath, opts.workspace)) {
|
|
67884
68580
|
continue;
|
|
67885
68581
|
}
|
|
67886
|
-
|
|
67887
|
-
|
|
67888
|
-
|
|
67889
|
-
|
|
67890
|
-
|
|
67891
|
-
|
|
67892
|
-
|
|
67893
|
-
signature: `type ${typeMatch[1]}${typeMatch[2] ? `<${typeMatch[2]}>` : ""} = ${typeValue}`,
|
|
67894
|
-
line: lineNum,
|
|
67895
|
-
jsdoc
|
|
67896
|
-
});
|
|
68582
|
+
let stats;
|
|
68583
|
+
try {
|
|
68584
|
+
stats = fs55.statSync(fullPath);
|
|
68585
|
+
if (stats.size > MAX_FILE_SIZE_BYTES8) {
|
|
68586
|
+
continue;
|
|
68587
|
+
}
|
|
68588
|
+
} catch {
|
|
67897
68589
|
continue;
|
|
67898
68590
|
}
|
|
67899
|
-
|
|
67900
|
-
|
|
67901
|
-
|
|
67902
|
-
|
|
67903
|
-
kind: "enum",
|
|
67904
|
-
exported: true,
|
|
67905
|
-
signature: `enum ${enumMatch[1]}`,
|
|
67906
|
-
line: lineNum,
|
|
67907
|
-
jsdoc
|
|
67908
|
-
});
|
|
68591
|
+
let content;
|
|
68592
|
+
try {
|
|
68593
|
+
content = fs55.readFileSync(fullPath, "utf-8");
|
|
68594
|
+
} catch {
|
|
67909
68595
|
continue;
|
|
67910
68596
|
}
|
|
67911
|
-
const
|
|
67912
|
-
|
|
67913
|
-
|
|
67914
|
-
|
|
67915
|
-
|
|
67916
|
-
|
|
67917
|
-
|
|
67918
|
-
|
|
67919
|
-
|
|
67920
|
-
|
|
68597
|
+
const lines = content.split(`
|
|
68598
|
+
`);
|
|
68599
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
68600
|
+
const line = lines[i2];
|
|
68601
|
+
if (regex.test(line)) {
|
|
68602
|
+
total++;
|
|
68603
|
+
if (matches.length < opts.maxResults) {
|
|
68604
|
+
let lineText = line.trimEnd();
|
|
68605
|
+
if (lineText.length > opts.maxLines) {
|
|
68606
|
+
lineText = `${lineText.substring(0, opts.maxLines)}...`;
|
|
68607
|
+
}
|
|
68608
|
+
matches.push({
|
|
68609
|
+
file: file3,
|
|
68610
|
+
lineNumber: i2 + 1,
|
|
68611
|
+
lineText
|
|
68612
|
+
});
|
|
68613
|
+
}
|
|
68614
|
+
regex.lastIndex = 0;
|
|
68615
|
+
}
|
|
67921
68616
|
}
|
|
67922
68617
|
}
|
|
67923
|
-
return
|
|
67924
|
-
|
|
67925
|
-
|
|
67926
|
-
|
|
67927
|
-
|
|
68618
|
+
return {
|
|
68619
|
+
matches,
|
|
68620
|
+
truncated: total > opts.maxResults,
|
|
68621
|
+
total,
|
|
68622
|
+
query: opts.query,
|
|
68623
|
+
mode: opts.mode,
|
|
68624
|
+
maxResults: opts.maxResults
|
|
68625
|
+
};
|
|
67928
68626
|
}
|
|
67929
|
-
|
|
67930
|
-
|
|
67931
|
-
|
|
67932
|
-
|
|
68627
|
+
var search = createSwarmTool({
|
|
68628
|
+
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.",
|
|
68629
|
+
args: {
|
|
68630
|
+
query: tool.schema.string().describe("Search query string (literal or regex depending on mode)"),
|
|
68631
|
+
mode: tool.schema.enum(["literal", "regex"]).default("literal").describe("Search mode: literal for exact string match, regex for regular expression"),
|
|
68632
|
+
include: tool.schema.string().optional().describe('Glob pattern for files to include (e.g., "*.ts", "src/**/*.js")'),
|
|
68633
|
+
exclude: tool.schema.string().optional().describe('Glob pattern for files to exclude (e.g., "node_modules/**", "*.test.ts")'),
|
|
68634
|
+
max_results: tool.schema.number().default(DEFAULT_MAX_RESULTS).describe("Maximum number of matches to return"),
|
|
68635
|
+
max_lines: tool.schema.number().default(DEFAULT_MAX_LINES).describe("Maximum characters per line in results")
|
|
68636
|
+
},
|
|
68637
|
+
execute: async (args2, directory) => {
|
|
68638
|
+
let query;
|
|
68639
|
+
let mode = "literal";
|
|
68640
|
+
let include;
|
|
68641
|
+
let exclude;
|
|
68642
|
+
let maxResults = DEFAULT_MAX_RESULTS;
|
|
68643
|
+
let maxLines = DEFAULT_MAX_LINES;
|
|
68644
|
+
try {
|
|
68645
|
+
const obj = args2;
|
|
68646
|
+
query = String(obj.query ?? "");
|
|
68647
|
+
mode = obj.mode === "regex" ? "regex" : "literal";
|
|
68648
|
+
include = obj.include;
|
|
68649
|
+
exclude = obj.exclude;
|
|
68650
|
+
const rawMaxResults = typeof obj.max_results === "number" ? obj.max_results : DEFAULT_MAX_RESULTS;
|
|
68651
|
+
const sanitizedMaxResults = Number.isNaN(rawMaxResults) ? DEFAULT_MAX_RESULTS : rawMaxResults;
|
|
68652
|
+
maxResults = Math.min(Math.max(0, sanitizedMaxResults), HARD_CAP_RESULTS);
|
|
68653
|
+
const rawMaxLines = typeof obj.max_lines === "number" ? obj.max_lines : DEFAULT_MAX_LINES;
|
|
68654
|
+
const sanitizedMaxLines = Number.isNaN(rawMaxLines) ? DEFAULT_MAX_LINES : rawMaxLines;
|
|
68655
|
+
maxLines = Math.min(Math.max(0, sanitizedMaxLines), HARD_CAP_LINES);
|
|
68656
|
+
} catch {
|
|
68657
|
+
return JSON.stringify({
|
|
68658
|
+
error: true,
|
|
68659
|
+
type: "invalid-query",
|
|
68660
|
+
message: "Could not parse search arguments"
|
|
68661
|
+
}, null, 2);
|
|
68662
|
+
}
|
|
68663
|
+
if (!query || query.trim() === "") {
|
|
68664
|
+
return JSON.stringify({
|
|
68665
|
+
error: true,
|
|
68666
|
+
type: "invalid-query",
|
|
68667
|
+
message: "Query cannot be empty"
|
|
68668
|
+
}, null, 2);
|
|
68669
|
+
}
|
|
68670
|
+
if (containsControlChars(query)) {
|
|
68671
|
+
return JSON.stringify({
|
|
68672
|
+
error: true,
|
|
68673
|
+
type: "invalid-query",
|
|
68674
|
+
message: "Query contains invalid control characters"
|
|
68675
|
+
}, null, 2);
|
|
68676
|
+
}
|
|
68677
|
+
if (include && containsPathTraversal(include)) {
|
|
68678
|
+
return JSON.stringify({
|
|
68679
|
+
error: true,
|
|
68680
|
+
type: "path-escape",
|
|
68681
|
+
message: "Include pattern contains path traversal sequence"
|
|
68682
|
+
}, null, 2);
|
|
68683
|
+
}
|
|
68684
|
+
if (exclude && containsPathTraversal(exclude)) {
|
|
68685
|
+
return JSON.stringify({
|
|
68686
|
+
error: true,
|
|
68687
|
+
type: "path-escape",
|
|
68688
|
+
message: "Exclude pattern contains path traversal sequence"
|
|
68689
|
+
}, null, 2);
|
|
68690
|
+
}
|
|
68691
|
+
if (include && containsWindowsAttacks3(include)) {
|
|
68692
|
+
return JSON.stringify({
|
|
68693
|
+
error: true,
|
|
68694
|
+
type: "path-escape",
|
|
68695
|
+
message: "Include pattern contains invalid Windows-specific sequence"
|
|
68696
|
+
}, null, 2);
|
|
68697
|
+
}
|
|
68698
|
+
if (exclude && containsWindowsAttacks3(exclude)) {
|
|
68699
|
+
return JSON.stringify({
|
|
68700
|
+
error: true,
|
|
68701
|
+
type: "path-escape",
|
|
68702
|
+
message: "Exclude pattern contains invalid Windows-specific sequence"
|
|
68703
|
+
}, null, 2);
|
|
68704
|
+
}
|
|
68705
|
+
if (!fs55.existsSync(directory)) {
|
|
68706
|
+
return JSON.stringify({
|
|
68707
|
+
error: true,
|
|
68708
|
+
type: "unknown",
|
|
68709
|
+
message: "Workspace directory does not exist"
|
|
68710
|
+
}, null, 2);
|
|
68711
|
+
}
|
|
68712
|
+
const rgAvailable = await isRipgrepAvailable();
|
|
68713
|
+
let result;
|
|
68714
|
+
if (rgAvailable) {
|
|
68715
|
+
result = await ripgrepSearch({
|
|
68716
|
+
query,
|
|
68717
|
+
mode,
|
|
68718
|
+
include,
|
|
68719
|
+
exclude,
|
|
68720
|
+
maxResults,
|
|
68721
|
+
maxLines,
|
|
68722
|
+
workspace: directory
|
|
68723
|
+
});
|
|
68724
|
+
} else {
|
|
68725
|
+
result = await fallbackSearch({
|
|
68726
|
+
query,
|
|
68727
|
+
mode,
|
|
68728
|
+
include,
|
|
68729
|
+
exclude,
|
|
68730
|
+
maxResults,
|
|
68731
|
+
maxLines,
|
|
68732
|
+
workspace: directory
|
|
68733
|
+
});
|
|
68734
|
+
}
|
|
68735
|
+
if ("error" in result && result.error) {
|
|
68736
|
+
return JSON.stringify(result, null, 2);
|
|
68737
|
+
}
|
|
68738
|
+
return JSON.stringify(result, null, 2);
|
|
67933
68739
|
}
|
|
67934
|
-
|
|
68740
|
+
});
|
|
68741
|
+
|
|
68742
|
+
// src/tools/index.ts
|
|
68743
|
+
init_secretscan();
|
|
68744
|
+
|
|
68745
|
+
// src/tools/suggest-patch.ts
|
|
68746
|
+
init_tool();
|
|
68747
|
+
init_create_tool();
|
|
68748
|
+
import * as fs56 from "fs";
|
|
68749
|
+
import * as path68 from "path";
|
|
68750
|
+
var WINDOWS_RESERVED_NAMES4 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
68751
|
+
function containsWindowsAttacks4(str) {
|
|
68752
|
+
if (/:[^\\/]/.test(str))
|
|
68753
|
+
return true;
|
|
68754
|
+
const parts2 = str.split(/[/\\]/);
|
|
68755
|
+
for (const part of parts2) {
|
|
68756
|
+
if (WINDOWS_RESERVED_NAMES4.test(part))
|
|
68757
|
+
return true;
|
|
68758
|
+
}
|
|
68759
|
+
return false;
|
|
68760
|
+
}
|
|
68761
|
+
function isPathInWorkspace4(filePath, workspace) {
|
|
67935
68762
|
try {
|
|
67936
|
-
const
|
|
67937
|
-
if (
|
|
67938
|
-
|
|
68763
|
+
const resolvedPath = path68.resolve(workspace, filePath);
|
|
68764
|
+
if (!fs56.existsSync(resolvedPath)) {
|
|
68765
|
+
return true;
|
|
68766
|
+
}
|
|
68767
|
+
const realWorkspace = fs56.realpathSync(workspace);
|
|
68768
|
+
const realResolvedPath = fs56.realpathSync(resolvedPath);
|
|
68769
|
+
const relativePath = path68.relative(realWorkspace, realResolvedPath);
|
|
68770
|
+
if (relativePath.startsWith("..") || path68.isAbsolute(relativePath)) {
|
|
68771
|
+
return false;
|
|
67939
68772
|
}
|
|
67940
|
-
|
|
68773
|
+
return true;
|
|
67941
68774
|
} catch {
|
|
67942
|
-
return
|
|
68775
|
+
return false;
|
|
67943
68776
|
}
|
|
68777
|
+
}
|
|
68778
|
+
function validateFilePath(filePath, workspace) {
|
|
68779
|
+
if (!filePath || filePath.trim() === "")
|
|
68780
|
+
return false;
|
|
68781
|
+
if (containsPathTraversal(filePath))
|
|
68782
|
+
return false;
|
|
68783
|
+
if (containsControlChars(filePath))
|
|
68784
|
+
return false;
|
|
68785
|
+
if (containsWindowsAttacks4(filePath))
|
|
68786
|
+
return false;
|
|
68787
|
+
return isPathInWorkspace4(filePath, workspace);
|
|
68788
|
+
}
|
|
68789
|
+
function findContextMatch(content, contextBefore, contextAfter, oldContent) {
|
|
67944
68790
|
const lines = content.split(`
|
|
67945
68791
|
`);
|
|
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
|
-
|
|
68792
|
+
if ((!contextBefore || contextBefore.length === 0) && (!contextAfter || contextAfter.length === 0)) {
|
|
68793
|
+
return null;
|
|
68794
|
+
}
|
|
68795
|
+
if (contextBefore && contextBefore.length > 0) {
|
|
68796
|
+
for (let i2 = 0;i2 <= lines.length - contextBefore.length; i2++) {
|
|
68797
|
+
const slice = lines.slice(i2, i2 + contextBefore.length);
|
|
68798
|
+
if (arraysEqual(slice, contextBefore)) {
|
|
68799
|
+
const afterStart = i2 + contextBefore.length;
|
|
68800
|
+
if (contextAfter && contextAfter.length > 0) {
|
|
68801
|
+
for (let j = afterStart;j <= lines.length - contextAfter.length; j++) {
|
|
68802
|
+
const afterSlice = lines.slice(j, j + contextAfter.length);
|
|
68803
|
+
if (arraysEqual(afterSlice, contextAfter)) {
|
|
68804
|
+
if (j === afterStart) {
|
|
68805
|
+
return {
|
|
68806
|
+
startLineIndex: i2,
|
|
68807
|
+
endLineIndex: j + contextAfter.length - 1,
|
|
68808
|
+
matchedBefore: contextBefore,
|
|
68809
|
+
matchedAfter: contextAfter
|
|
68810
|
+
};
|
|
68811
|
+
} else {
|
|
68812
|
+
if (oldContent && oldContent.length > 0) {
|
|
68813
|
+
const oldContentLines = oldContent.split(`
|
|
68814
|
+
`);
|
|
68815
|
+
const betweenLines = lines.slice(afterStart, j);
|
|
68816
|
+
if (arraysEqual(betweenLines, oldContentLines)) {
|
|
68817
|
+
return {
|
|
68818
|
+
startLineIndex: i2,
|
|
68819
|
+
endLineIndex: j - 1,
|
|
68820
|
+
matchedBefore: contextBefore,
|
|
68821
|
+
matchedAfter: contextAfter
|
|
68822
|
+
};
|
|
68823
|
+
}
|
|
68824
|
+
} else {
|
|
68825
|
+
return {
|
|
68826
|
+
startLineIndex: i2,
|
|
68827
|
+
endLineIndex: j - 1,
|
|
68828
|
+
matchedBefore: contextBefore,
|
|
68829
|
+
matchedAfter: contextAfter
|
|
68830
|
+
};
|
|
68831
|
+
}
|
|
68832
|
+
}
|
|
68833
|
+
}
|
|
68834
|
+
}
|
|
68835
|
+
return null;
|
|
68836
|
+
} else {
|
|
68837
|
+
if (oldContent && oldContent.length > 0) {
|
|
68838
|
+
const oldContentLines = oldContent.split(`
|
|
68839
|
+
`);
|
|
68840
|
+
for (let k = afterStart;k <= lines.length - oldContentLines.length; k++) {
|
|
68841
|
+
const candidate = lines.slice(k, k + oldContentLines.length);
|
|
68842
|
+
if (arraysEqual(candidate, oldContentLines)) {
|
|
68843
|
+
return {
|
|
68844
|
+
startLineIndex: i2,
|
|
68845
|
+
endLineIndex: k + oldContentLines.length - 1,
|
|
68846
|
+
matchedBefore: contextBefore,
|
|
68847
|
+
matchedAfter: []
|
|
68848
|
+
};
|
|
68849
|
+
}
|
|
68850
|
+
}
|
|
68851
|
+
return null;
|
|
68852
|
+
} else {
|
|
68853
|
+
return {
|
|
68854
|
+
startLineIndex: i2,
|
|
68855
|
+
endLineIndex: afterStart - 1,
|
|
68856
|
+
matchedBefore: contextBefore,
|
|
68857
|
+
matchedAfter: []
|
|
68858
|
+
};
|
|
68859
|
+
}
|
|
68860
|
+
}
|
|
68861
|
+
}
|
|
67974
68862
|
}
|
|
67975
|
-
|
|
67976
|
-
|
|
67977
|
-
|
|
67978
|
-
|
|
67979
|
-
|
|
67980
|
-
|
|
67981
|
-
|
|
67982
|
-
|
|
67983
|
-
|
|
68863
|
+
} else if (contextAfter && contextAfter.length > 0) {
|
|
68864
|
+
for (let j = 0;j <= lines.length - contextAfter.length; j++) {
|
|
68865
|
+
const afterSlice = lines.slice(j, j + contextAfter.length);
|
|
68866
|
+
if (arraysEqual(afterSlice, contextAfter)) {
|
|
68867
|
+
return {
|
|
68868
|
+
startLineIndex: 0,
|
|
68869
|
+
endLineIndex: j - 1,
|
|
68870
|
+
matchedBefore: [],
|
|
68871
|
+
matchedAfter: contextAfter
|
|
68872
|
+
};
|
|
68873
|
+
}
|
|
67984
68874
|
}
|
|
67985
68875
|
}
|
|
67986
|
-
return
|
|
67987
|
-
if (a.line !== b.line)
|
|
67988
|
-
return a.line - b.line;
|
|
67989
|
-
return a.name.localeCompare(b.name);
|
|
67990
|
-
});
|
|
68876
|
+
return null;
|
|
67991
68877
|
}
|
|
67992
|
-
|
|
67993
|
-
|
|
68878
|
+
function arraysEqual(a, b) {
|
|
68879
|
+
if (a.length !== b.length)
|
|
68880
|
+
return false;
|
|
68881
|
+
for (let i2 = 0;i2 < a.length; i2++) {
|
|
68882
|
+
if (a[i2] !== b[i2])
|
|
68883
|
+
return false;
|
|
68884
|
+
}
|
|
68885
|
+
return true;
|
|
68886
|
+
}
|
|
68887
|
+
function validateOldContent(lines, startIndex, endIndex, oldContent) {
|
|
68888
|
+
if (!oldContent) {
|
|
68889
|
+
return { valid: true };
|
|
68890
|
+
}
|
|
68891
|
+
const currentContent = lines.slice(startIndex, endIndex + 1).join(`
|
|
68892
|
+
`);
|
|
68893
|
+
if (currentContent !== oldContent) {
|
|
68894
|
+
return {
|
|
68895
|
+
valid: false,
|
|
68896
|
+
expected: oldContent,
|
|
68897
|
+
actual: currentContent
|
|
68898
|
+
};
|
|
68899
|
+
}
|
|
68900
|
+
return { valid: true };
|
|
68901
|
+
}
|
|
68902
|
+
var suggestPatch = createSwarmTool({
|
|
68903
|
+
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
68904
|
args: {
|
|
67995
|
-
|
|
67996
|
-
|
|
68905
|
+
targetFiles: tool.schema.array(tool.schema.string()).describe("Array of file paths to patch").min(1),
|
|
68906
|
+
changes: tool.schema.array(tool.schema.object({
|
|
68907
|
+
file: tool.schema.string().describe("Path to the file this change applies to"),
|
|
68908
|
+
contextBefore: tool.schema.array(tool.schema.string()).optional().describe("Lines before the change region (anchor)"),
|
|
68909
|
+
contextAfter: tool.schema.array(tool.schema.string()).optional().describe("Lines after the change region (anchor)"),
|
|
68910
|
+
oldContent: tool.schema.string().optional().describe("Current content to be replaced"),
|
|
68911
|
+
newContent: tool.schema.string().describe("New content to replace with")
|
|
68912
|
+
})).describe("Array of change descriptions with context anchors").min(1)
|
|
67997
68913
|
},
|
|
67998
68914
|
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 {
|
|
68915
|
+
if (!args2 || typeof args2 !== "object") {
|
|
68006
68916
|
return JSON.stringify({
|
|
68007
|
-
|
|
68008
|
-
error:
|
|
68009
|
-
|
|
68917
|
+
success: false,
|
|
68918
|
+
error: true,
|
|
68919
|
+
type: "parse-error",
|
|
68920
|
+
message: "Could not parse suggest-patch arguments"
|
|
68010
68921
|
}, null, 2);
|
|
68011
68922
|
}
|
|
68012
|
-
const
|
|
68013
|
-
const
|
|
68014
|
-
|
|
68923
|
+
const obj = args2;
|
|
68924
|
+
const targetFiles = obj.targetFiles ?? [];
|
|
68925
|
+
const changes = obj.changes ?? [];
|
|
68926
|
+
if (!targetFiles || targetFiles.length === 0) {
|
|
68015
68927
|
return JSON.stringify({
|
|
68016
|
-
|
|
68017
|
-
error:
|
|
68018
|
-
|
|
68928
|
+
success: false,
|
|
68929
|
+
error: true,
|
|
68930
|
+
type: "parse-error",
|
|
68931
|
+
message: "targetFiles cannot be empty"
|
|
68019
68932
|
}, null, 2);
|
|
68020
68933
|
}
|
|
68021
|
-
if (
|
|
68934
|
+
if (!changes || changes.length === 0) {
|
|
68022
68935
|
return JSON.stringify({
|
|
68023
|
-
|
|
68024
|
-
error:
|
|
68025
|
-
|
|
68936
|
+
success: false,
|
|
68937
|
+
error: true,
|
|
68938
|
+
type: "parse-error",
|
|
68939
|
+
message: "changes cannot be empty"
|
|
68026
68940
|
}, null, 2);
|
|
68027
68941
|
}
|
|
68028
|
-
if (
|
|
68942
|
+
if (!fs56.existsSync(directory)) {
|
|
68029
68943
|
return JSON.stringify({
|
|
68030
|
-
|
|
68031
|
-
error:
|
|
68032
|
-
|
|
68944
|
+
success: false,
|
|
68945
|
+
error: true,
|
|
68946
|
+
type: "file-not-found",
|
|
68947
|
+
message: "Workspace directory does not exist"
|
|
68033
68948
|
}, null, 2);
|
|
68034
68949
|
}
|
|
68035
|
-
|
|
68950
|
+
const patches = [];
|
|
68951
|
+
const filesModifiedSet = new Set;
|
|
68952
|
+
const errors5 = [];
|
|
68953
|
+
const targetFileSet = new Set(targetFiles);
|
|
68954
|
+
for (let changeIndex = 0;changeIndex < changes.length; changeIndex++) {
|
|
68955
|
+
const change = changes[changeIndex];
|
|
68956
|
+
if (!targetFileSet.has(change.file)) {
|
|
68957
|
+
errors5.push({
|
|
68958
|
+
success: false,
|
|
68959
|
+
error: true,
|
|
68960
|
+
type: "parse-error",
|
|
68961
|
+
message: `File "${change.file}" is not in targetFiles`,
|
|
68962
|
+
details: { location: change.file }
|
|
68963
|
+
});
|
|
68964
|
+
continue;
|
|
68965
|
+
}
|
|
68966
|
+
if (!validateFilePath(change.file, directory)) {
|
|
68967
|
+
errors5.push({
|
|
68968
|
+
success: false,
|
|
68969
|
+
error: true,
|
|
68970
|
+
type: "parse-error",
|
|
68971
|
+
message: `Invalid file path: ${change.file}`,
|
|
68972
|
+
details: {
|
|
68973
|
+
location: change.file
|
|
68974
|
+
}
|
|
68975
|
+
});
|
|
68976
|
+
continue;
|
|
68977
|
+
}
|
|
68978
|
+
const fullPath = path68.resolve(directory, change.file);
|
|
68979
|
+
if (!fs56.existsSync(fullPath)) {
|
|
68980
|
+
errors5.push({
|
|
68981
|
+
success: false,
|
|
68982
|
+
error: true,
|
|
68983
|
+
type: "file-not-found",
|
|
68984
|
+
message: `File not found: ${change.file}`,
|
|
68985
|
+
details: {
|
|
68986
|
+
location: change.file
|
|
68987
|
+
}
|
|
68988
|
+
});
|
|
68989
|
+
continue;
|
|
68990
|
+
}
|
|
68991
|
+
let content;
|
|
68992
|
+
try {
|
|
68993
|
+
content = fs56.readFileSync(fullPath, "utf-8");
|
|
68994
|
+
} catch (err2) {
|
|
68995
|
+
errors5.push({
|
|
68996
|
+
success: false,
|
|
68997
|
+
error: true,
|
|
68998
|
+
type: "unknown",
|
|
68999
|
+
message: `Could not read file: ${err2 instanceof Error ? err2.message : String(err2)}`,
|
|
69000
|
+
details: {
|
|
69001
|
+
location: `${change.file}:0`
|
|
69002
|
+
}
|
|
69003
|
+
});
|
|
69004
|
+
continue;
|
|
69005
|
+
}
|
|
69006
|
+
const contextMatch = findContextMatch(content, change.contextBefore, change.contextAfter, change.oldContent);
|
|
69007
|
+
if (!contextMatch) {
|
|
69008
|
+
errors5.push({
|
|
69009
|
+
success: false,
|
|
69010
|
+
error: true,
|
|
69011
|
+
type: "context-mismatch",
|
|
69012
|
+
message: `Could not find context anchor in ${change.file}. Provide contextBefore/contextAfter lines to locate the change region.`,
|
|
69013
|
+
details: {
|
|
69014
|
+
location: change.file
|
|
69015
|
+
}
|
|
69016
|
+
});
|
|
69017
|
+
continue;
|
|
69018
|
+
}
|
|
69019
|
+
const lines = content.split(`
|
|
69020
|
+
`);
|
|
69021
|
+
const oldContentValidation = validateOldContent(lines, contextMatch.startLineIndex + contextMatch.matchedBefore.length, contextMatch.endLineIndex - contextMatch.matchedAfter.length + 1, change.oldContent);
|
|
69022
|
+
if (!oldContentValidation.valid) {
|
|
69023
|
+
errors5.push({
|
|
69024
|
+
success: false,
|
|
69025
|
+
error: true,
|
|
69026
|
+
type: "context-mismatch",
|
|
69027
|
+
message: `Content at the specified location does not match oldContent`,
|
|
69028
|
+
details: {
|
|
69029
|
+
expected: oldContentValidation.expected,
|
|
69030
|
+
actual: oldContentValidation.actual,
|
|
69031
|
+
location: `${change.file}:${contextMatch.startLineIndex + 1}-${contextMatch.endLineIndex + 1}`
|
|
69032
|
+
}
|
|
69033
|
+
});
|
|
69034
|
+
continue;
|
|
69035
|
+
}
|
|
69036
|
+
const originalContext = [
|
|
69037
|
+
...contextMatch.matchedBefore,
|
|
69038
|
+
...contextMatch.matchedAfter.length > 0 ? ["..."] : [],
|
|
69039
|
+
...contextMatch.matchedAfter
|
|
69040
|
+
];
|
|
69041
|
+
patches.push({
|
|
69042
|
+
file: change.file,
|
|
69043
|
+
originalContext,
|
|
69044
|
+
newContent: change.newContent,
|
|
69045
|
+
hunkIndex: changeIndex
|
|
69046
|
+
});
|
|
69047
|
+
filesModifiedSet.add(change.file);
|
|
69048
|
+
}
|
|
69049
|
+
if (patches.length > 0) {
|
|
68036
69050
|
return JSON.stringify({
|
|
68037
|
-
|
|
68038
|
-
|
|
68039
|
-
|
|
69051
|
+
success: true,
|
|
69052
|
+
patches,
|
|
69053
|
+
filesModified: Array.from(filesModifiedSet),
|
|
69054
|
+
...errors5.length > 0 && { errors: errors5 }
|
|
68040
69055
|
}, null, 2);
|
|
68041
69056
|
}
|
|
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);
|
|
69057
|
+
if (errors5.length === 1) {
|
|
69058
|
+
return JSON.stringify(errors5[0], null, 2);
|
|
68064
69059
|
}
|
|
68065
69060
|
return JSON.stringify({
|
|
68066
|
-
|
|
68067
|
-
|
|
68068
|
-
|
|
69061
|
+
success: false,
|
|
69062
|
+
error: true,
|
|
69063
|
+
type: "context-mismatch",
|
|
69064
|
+
message: `All ${errors5.length} patch suggestions failed`,
|
|
69065
|
+
errors: errors5
|
|
68069
69066
|
}, null, 2);
|
|
68070
69067
|
}
|
|
68071
69068
|
});
|
|
@@ -68081,10 +69078,10 @@ init_test_runner();
|
|
|
68081
69078
|
init_dist();
|
|
68082
69079
|
init_utils();
|
|
68083
69080
|
init_create_tool();
|
|
68084
|
-
import * as
|
|
68085
|
-
import * as
|
|
69081
|
+
import * as fs57 from "fs";
|
|
69082
|
+
import * as path69 from "path";
|
|
68086
69083
|
var MAX_TEXT_LENGTH = 200;
|
|
68087
|
-
var
|
|
69084
|
+
var MAX_FILE_SIZE_BYTES9 = 1024 * 1024;
|
|
68088
69085
|
var SUPPORTED_EXTENSIONS2 = new Set([
|
|
68089
69086
|
".ts",
|
|
68090
69087
|
".tsx",
|
|
@@ -68147,9 +69144,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
68147
69144
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
68148
69145
|
}
|
|
68149
69146
|
try {
|
|
68150
|
-
const resolvedPath =
|
|
68151
|
-
const normalizedCwd =
|
|
68152
|
-
const normalizedResolved =
|
|
69147
|
+
const resolvedPath = path69.resolve(paths);
|
|
69148
|
+
const normalizedCwd = path69.resolve(cwd);
|
|
69149
|
+
const normalizedResolved = path69.resolve(resolvedPath);
|
|
68153
69150
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
68154
69151
|
return {
|
|
68155
69152
|
error: "paths must be within the current working directory",
|
|
@@ -68165,13 +69162,13 @@ function validatePathsInput(paths, cwd) {
|
|
|
68165
69162
|
}
|
|
68166
69163
|
}
|
|
68167
69164
|
function isSupportedExtension(filePath) {
|
|
68168
|
-
const ext =
|
|
69165
|
+
const ext = path69.extname(filePath).toLowerCase();
|
|
68169
69166
|
return SUPPORTED_EXTENSIONS2.has(ext);
|
|
68170
69167
|
}
|
|
68171
69168
|
function findSourceFiles2(dir, files = []) {
|
|
68172
69169
|
let entries;
|
|
68173
69170
|
try {
|
|
68174
|
-
entries =
|
|
69171
|
+
entries = fs57.readdirSync(dir);
|
|
68175
69172
|
} catch {
|
|
68176
69173
|
return files;
|
|
68177
69174
|
}
|
|
@@ -68180,10 +69177,10 @@ function findSourceFiles2(dir, files = []) {
|
|
|
68180
69177
|
if (SKIP_DIRECTORIES4.has(entry)) {
|
|
68181
69178
|
continue;
|
|
68182
69179
|
}
|
|
68183
|
-
const fullPath =
|
|
69180
|
+
const fullPath = path69.join(dir, entry);
|
|
68184
69181
|
let stat2;
|
|
68185
69182
|
try {
|
|
68186
|
-
stat2 =
|
|
69183
|
+
stat2 = fs57.statSync(fullPath);
|
|
68187
69184
|
} catch {
|
|
68188
69185
|
continue;
|
|
68189
69186
|
}
|
|
@@ -68276,7 +69273,7 @@ var todo_extract = createSwarmTool({
|
|
|
68276
69273
|
return JSON.stringify(errorResult, null, 2);
|
|
68277
69274
|
}
|
|
68278
69275
|
const scanPath = resolvedPath;
|
|
68279
|
-
if (!
|
|
69276
|
+
if (!fs57.existsSync(scanPath)) {
|
|
68280
69277
|
const errorResult = {
|
|
68281
69278
|
error: `path not found: ${pathsInput}`,
|
|
68282
69279
|
total: 0,
|
|
@@ -68286,13 +69283,13 @@ var todo_extract = createSwarmTool({
|
|
|
68286
69283
|
return JSON.stringify(errorResult, null, 2);
|
|
68287
69284
|
}
|
|
68288
69285
|
const filesToScan = [];
|
|
68289
|
-
const stat2 =
|
|
69286
|
+
const stat2 = fs57.statSync(scanPath);
|
|
68290
69287
|
if (stat2.isFile()) {
|
|
68291
69288
|
if (isSupportedExtension(scanPath)) {
|
|
68292
69289
|
filesToScan.push(scanPath);
|
|
68293
69290
|
} else {
|
|
68294
69291
|
const errorResult = {
|
|
68295
|
-
error: `unsupported file extension: ${
|
|
69292
|
+
error: `unsupported file extension: ${path69.extname(scanPath)}`,
|
|
68296
69293
|
total: 0,
|
|
68297
69294
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
68298
69295
|
entries: []
|
|
@@ -68305,11 +69302,11 @@ var todo_extract = createSwarmTool({
|
|
|
68305
69302
|
const allEntries = [];
|
|
68306
69303
|
for (const filePath of filesToScan) {
|
|
68307
69304
|
try {
|
|
68308
|
-
const fileStat =
|
|
68309
|
-
if (fileStat.size >
|
|
69305
|
+
const fileStat = fs57.statSync(filePath);
|
|
69306
|
+
if (fileStat.size > MAX_FILE_SIZE_BYTES9) {
|
|
68310
69307
|
continue;
|
|
68311
69308
|
}
|
|
68312
|
-
const content =
|
|
69309
|
+
const content = fs57.readFileSync(filePath, "utf-8");
|
|
68313
69310
|
const entries = parseTodoComments(content, filePath, tagsSet);
|
|
68314
69311
|
allEntries.push(...entries);
|
|
68315
69312
|
} catch {}
|
|
@@ -68338,18 +69335,18 @@ var todo_extract = createSwarmTool({
|
|
|
68338
69335
|
init_tool();
|
|
68339
69336
|
init_schema();
|
|
68340
69337
|
init_gate_evidence();
|
|
68341
|
-
import * as
|
|
68342
|
-
import * as
|
|
69338
|
+
import * as fs59 from "fs";
|
|
69339
|
+
import * as path71 from "path";
|
|
68343
69340
|
|
|
68344
69341
|
// src/hooks/diff-scope.ts
|
|
68345
|
-
import * as
|
|
68346
|
-
import * as
|
|
69342
|
+
import * as fs58 from "fs";
|
|
69343
|
+
import * as path70 from "path";
|
|
68347
69344
|
function getDeclaredScope(taskId, directory) {
|
|
68348
69345
|
try {
|
|
68349
|
-
const planPath =
|
|
68350
|
-
if (!
|
|
69346
|
+
const planPath = path70.join(directory, ".swarm", "plan.json");
|
|
69347
|
+
if (!fs58.existsSync(planPath))
|
|
68351
69348
|
return null;
|
|
68352
|
-
const raw =
|
|
69349
|
+
const raw = fs58.readFileSync(planPath, "utf-8");
|
|
68353
69350
|
const plan = JSON.parse(raw);
|
|
68354
69351
|
for (const phase of plan.phases ?? []) {
|
|
68355
69352
|
for (const task of phase.tasks ?? []) {
|
|
@@ -68462,7 +69459,7 @@ var TIER_3_PATTERNS = [
|
|
|
68462
69459
|
];
|
|
68463
69460
|
function matchesTier3Pattern(files) {
|
|
68464
69461
|
for (const file3 of files) {
|
|
68465
|
-
const fileName =
|
|
69462
|
+
const fileName = path71.basename(file3);
|
|
68466
69463
|
for (const pattern of TIER_3_PATTERNS) {
|
|
68467
69464
|
if (pattern.test(fileName)) {
|
|
68468
69465
|
return true;
|
|
@@ -68476,8 +69473,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
68476
69473
|
if (hasActiveTurboMode()) {
|
|
68477
69474
|
const resolvedDir2 = workingDirectory;
|
|
68478
69475
|
try {
|
|
68479
|
-
const planPath =
|
|
68480
|
-
const planRaw =
|
|
69476
|
+
const planPath = path71.join(resolvedDir2, ".swarm", "plan.json");
|
|
69477
|
+
const planRaw = fs59.readFileSync(planPath, "utf-8");
|
|
68481
69478
|
const plan = JSON.parse(planRaw);
|
|
68482
69479
|
for (const planPhase of plan.phases ?? []) {
|
|
68483
69480
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -68543,8 +69540,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
68543
69540
|
}
|
|
68544
69541
|
try {
|
|
68545
69542
|
const resolvedDir2 = workingDirectory;
|
|
68546
|
-
const planPath =
|
|
68547
|
-
const planRaw =
|
|
69543
|
+
const planPath = path71.join(resolvedDir2, ".swarm", "plan.json");
|
|
69544
|
+
const planRaw = fs59.readFileSync(planPath, "utf-8");
|
|
68548
69545
|
const plan = JSON.parse(planRaw);
|
|
68549
69546
|
for (const planPhase of plan.phases ?? []) {
|
|
68550
69547
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -68726,8 +69723,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
68726
69723
|
};
|
|
68727
69724
|
}
|
|
68728
69725
|
}
|
|
68729
|
-
normalizedDir =
|
|
68730
|
-
const pathParts = normalizedDir.split(
|
|
69726
|
+
normalizedDir = path71.normalize(args2.working_directory);
|
|
69727
|
+
const pathParts = normalizedDir.split(path71.sep);
|
|
68731
69728
|
if (pathParts.includes("..")) {
|
|
68732
69729
|
return {
|
|
68733
69730
|
success: false,
|
|
@@ -68737,11 +69734,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
68737
69734
|
]
|
|
68738
69735
|
};
|
|
68739
69736
|
}
|
|
68740
|
-
const resolvedDir =
|
|
69737
|
+
const resolvedDir = path71.resolve(normalizedDir);
|
|
68741
69738
|
try {
|
|
68742
|
-
const realPath =
|
|
68743
|
-
const planPath =
|
|
68744
|
-
if (!
|
|
69739
|
+
const realPath = fs59.realpathSync(resolvedDir);
|
|
69740
|
+
const planPath = path71.join(realPath, ".swarm", "plan.json");
|
|
69741
|
+
if (!fs59.existsSync(planPath)) {
|
|
68745
69742
|
return {
|
|
68746
69743
|
success: false,
|
|
68747
69744
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -68774,8 +69771,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
68774
69771
|
recoverTaskStateFromDelegations(args2.task_id);
|
|
68775
69772
|
let phaseRequiresReviewer = true;
|
|
68776
69773
|
try {
|
|
68777
|
-
const planPath =
|
|
68778
|
-
const planRaw =
|
|
69774
|
+
const planPath = path71.join(directory, ".swarm", "plan.json");
|
|
69775
|
+
const planRaw = fs59.readFileSync(planPath, "utf-8");
|
|
68779
69776
|
const plan = JSON.parse(planRaw);
|
|
68780
69777
|
const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
|
|
68781
69778
|
if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
|
|
@@ -68838,8 +69835,8 @@ var update_task_status = createSwarmTool({
|
|
|
68838
69835
|
init_tool();
|
|
68839
69836
|
init_utils2();
|
|
68840
69837
|
init_create_tool();
|
|
68841
|
-
import
|
|
68842
|
-
import
|
|
69838
|
+
import fs60 from "fs";
|
|
69839
|
+
import path72 from "path";
|
|
68843
69840
|
function normalizeVerdict(verdict) {
|
|
68844
69841
|
switch (verdict) {
|
|
68845
69842
|
case "APPROVED":
|
|
@@ -68886,7 +69883,7 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
68886
69883
|
entries: [evidenceEntry]
|
|
68887
69884
|
};
|
|
68888
69885
|
const filename = "drift-verifier.json";
|
|
68889
|
-
const relativePath =
|
|
69886
|
+
const relativePath = path72.join("evidence", String(phase), filename);
|
|
68890
69887
|
let validatedPath;
|
|
68891
69888
|
try {
|
|
68892
69889
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -68897,12 +69894,12 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
68897
69894
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
68898
69895
|
}, null, 2);
|
|
68899
69896
|
}
|
|
68900
|
-
const evidenceDir =
|
|
69897
|
+
const evidenceDir = path72.dirname(validatedPath);
|
|
68901
69898
|
try {
|
|
68902
|
-
await
|
|
68903
|
-
const tempPath =
|
|
68904
|
-
await
|
|
68905
|
-
await
|
|
69899
|
+
await fs60.promises.mkdir(evidenceDir, { recursive: true });
|
|
69900
|
+
const tempPath = path72.join(evidenceDir, `.${filename}.tmp`);
|
|
69901
|
+
await fs60.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
69902
|
+
await fs60.promises.rename(tempPath, validatedPath);
|
|
68906
69903
|
return JSON.stringify({
|
|
68907
69904
|
success: true,
|
|
68908
69905
|
phase,
|
|
@@ -69093,7 +70090,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
69093
70090
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
69094
70091
|
preflightTriggerManager = new PTM(automationConfig);
|
|
69095
70092
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
69096
|
-
const swarmDir =
|
|
70093
|
+
const swarmDir = path73.resolve(ctx.directory, ".swarm");
|
|
69097
70094
|
statusArtifact = new ASA(swarmDir);
|
|
69098
70095
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
69099
70096
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|
|
@@ -69223,6 +70220,9 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
69223
70220
|
symbols,
|
|
69224
70221
|
test_runner,
|
|
69225
70222
|
todo_extract,
|
|
70223
|
+
search,
|
|
70224
|
+
batch_symbols,
|
|
70225
|
+
suggest_patch: suggestPatch,
|
|
69226
70226
|
update_task_status,
|
|
69227
70227
|
write_retro,
|
|
69228
70228
|
write_drift_evidence,
|
|
@@ -69431,7 +70431,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
69431
70431
|
"command.execute.before": safeHook(commandHandler),
|
|
69432
70432
|
"tool.execute.before": async (input, output) => {
|
|
69433
70433
|
if (process.env.DEBUG_SWARM)
|
|
69434
|
-
console.error(`[DIAG] toolBefore tool=${input.tool
|
|
70434
|
+
console.error(`[DIAG] toolBefore tool=${normalizeToolName(input.tool) ?? input.tool} session=${input.sessionID}`);
|
|
69435
70435
|
if (!swarmState.activeAgent.has(input.sessionID)) {
|
|
69436
70436
|
swarmState.activeAgent.set(input.sessionID, ORCHESTRATOR_NAME);
|
|
69437
70437
|
}
|
|
@@ -69462,10 +70462,10 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
69462
70462
|
},
|
|
69463
70463
|
"tool.execute.after": async (input, output) => {
|
|
69464
70464
|
const _dbg = !!process.env.DEBUG_SWARM;
|
|
69465
|
-
const _toolName = input.tool
|
|
70465
|
+
const _toolName = normalizeToolName(input.tool) ?? input.tool;
|
|
69466
70466
|
if (_dbg)
|
|
69467
70467
|
console.error(`[DIAG] toolAfter START tool=${_toolName} session=${input.sessionID}`);
|
|
69468
|
-
const normalizedTool = input.tool
|
|
70468
|
+
const normalizedTool = normalizeToolName(input.tool);
|
|
69469
70469
|
const isTaskTool = normalizedTool === "Task" || normalizedTool === "task";
|
|
69470
70470
|
const hookChain = async () => {
|
|
69471
70471
|
await activityHooks.toolAfter(input, output);
|