opencode-swarm 6.38.0 → 6.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/dist/cli/index.js +91 -80
- package/dist/index.js +800 -795
- package/dist/lang/grammars/tree-sitter-bash.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-c-sharp.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-cpp.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-css.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-go.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-ini.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-java.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-javascript.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-php.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-powershell.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-python.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-regex.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-ruby.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-rust.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-tsx.wasm +0 -0
- package/dist/lang/grammars/tree-sitter-typescript.wasm +0 -0
- package/dist/lang/grammars/tree-sitter.wasm +0 -0
- package/dist/tools/lint.d.ts +1 -2
- package/dist/tools/tool-names.d.ts +1 -1
- package/dist/utils/path-security.d.ts +26 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,43 +4,25 @@ var __getProtoOf = Object.getPrototypeOf;
|
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
function __accessProp(key) {
|
|
8
|
-
return this[key];
|
|
9
|
-
}
|
|
10
|
-
var __toESMCache_node;
|
|
11
|
-
var __toESMCache_esm;
|
|
12
7
|
var __toESM = (mod, isNodeMode, target) => {
|
|
13
|
-
var canCache = mod != null && typeof mod === "object";
|
|
14
|
-
if (canCache) {
|
|
15
|
-
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
16
|
-
var cached = cache.get(mod);
|
|
17
|
-
if (cached)
|
|
18
|
-
return cached;
|
|
19
|
-
}
|
|
20
8
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
21
9
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
22
10
|
for (let key of __getOwnPropNames(mod))
|
|
23
11
|
if (!__hasOwnProp.call(to, key))
|
|
24
12
|
__defProp(to, key, {
|
|
25
|
-
get:
|
|
13
|
+
get: () => mod[key],
|
|
26
14
|
enumerable: true
|
|
27
15
|
});
|
|
28
|
-
if (canCache)
|
|
29
|
-
cache.set(mod, to);
|
|
30
16
|
return to;
|
|
31
17
|
};
|
|
32
18
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
33
|
-
var __returnValue = (v) => v;
|
|
34
|
-
function __exportSetter(name2, newValue) {
|
|
35
|
-
this[name2] = __returnValue.bind(null, newValue);
|
|
36
|
-
}
|
|
37
19
|
var __export = (target, all) => {
|
|
38
20
|
for (var name2 in all)
|
|
39
21
|
__defProp(target, name2, {
|
|
40
22
|
get: all[name2],
|
|
41
23
|
enumerable: true,
|
|
42
24
|
configurable: true,
|
|
43
|
-
set:
|
|
25
|
+
set: (newValue) => all[name2] = () => newValue
|
|
44
26
|
});
|
|
45
27
|
};
|
|
46
28
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -80,7 +62,13 @@ var init_tool_names = __esm(() => {
|
|
|
80
62
|
"update_task_status",
|
|
81
63
|
"write_retro",
|
|
82
64
|
"declare_scope",
|
|
83
|
-
"knowledge_query"
|
|
65
|
+
"knowledge_query",
|
|
66
|
+
"doc_scan",
|
|
67
|
+
"doc_extract",
|
|
68
|
+
"curator_analyze",
|
|
69
|
+
"knowledgeAdd",
|
|
70
|
+
"knowledgeRecall",
|
|
71
|
+
"knowledgeRemove"
|
|
84
72
|
];
|
|
85
73
|
TOOL_NAME_SET = new Set(TOOL_NAMES);
|
|
86
74
|
});
|
|
@@ -146,6 +134,7 @@ var init_constants = __esm(() => {
|
|
|
146
134
|
architect: [
|
|
147
135
|
"checkpoint",
|
|
148
136
|
"check_gate_status",
|
|
137
|
+
"completion_verify",
|
|
149
138
|
"complexity_hotspots",
|
|
150
139
|
"detect_domains",
|
|
151
140
|
"evidence_check",
|
|
@@ -157,6 +146,7 @@ var init_constants = __esm(() => {
|
|
|
157
146
|
"diff",
|
|
158
147
|
"pkg_audit",
|
|
159
148
|
"pre_check_batch",
|
|
149
|
+
"quality_budget",
|
|
160
150
|
"retrieve_summary",
|
|
161
151
|
"save_plan",
|
|
162
152
|
"schema_drift",
|
|
@@ -166,7 +156,19 @@ var init_constants = __esm(() => {
|
|
|
166
156
|
"todo_extract",
|
|
167
157
|
"update_task_status",
|
|
168
158
|
"write_retro",
|
|
169
|
-
"declare_scope"
|
|
159
|
+
"declare_scope",
|
|
160
|
+
"sast_scan",
|
|
161
|
+
"sbom_generate",
|
|
162
|
+
"build_check",
|
|
163
|
+
"syntax_check",
|
|
164
|
+
"placeholder_scan",
|
|
165
|
+
"phase_complete",
|
|
166
|
+
"doc_scan",
|
|
167
|
+
"doc_extract",
|
|
168
|
+
"curator_analyze",
|
|
169
|
+
"knowledgeAdd",
|
|
170
|
+
"knowledgeRecall",
|
|
171
|
+
"knowledgeRemove"
|
|
170
172
|
],
|
|
171
173
|
explorer: [
|
|
172
174
|
"complexity_hotspots",
|
|
@@ -177,7 +179,9 @@ var init_constants = __esm(() => {
|
|
|
177
179
|
"retrieve_summary",
|
|
178
180
|
"schema_drift",
|
|
179
181
|
"symbols",
|
|
180
|
-
"todo_extract"
|
|
182
|
+
"todo_extract",
|
|
183
|
+
"doc_scan",
|
|
184
|
+
"knowledgeRecall"
|
|
181
185
|
],
|
|
182
186
|
coder: [
|
|
183
187
|
"diff",
|
|
@@ -185,7 +189,11 @@ var init_constants = __esm(() => {
|
|
|
185
189
|
"lint",
|
|
186
190
|
"symbols",
|
|
187
191
|
"extract_code_blocks",
|
|
188
|
-
"retrieve_summary"
|
|
192
|
+
"retrieve_summary",
|
|
193
|
+
"build_check",
|
|
194
|
+
"syntax_check",
|
|
195
|
+
"knowledgeAdd",
|
|
196
|
+
"knowledgeRecall"
|
|
189
197
|
],
|
|
190
198
|
test_engineer: [
|
|
191
199
|
"test_runner",
|
|
@@ -195,7 +203,9 @@ var init_constants = __esm(() => {
|
|
|
195
203
|
"retrieve_summary",
|
|
196
204
|
"imports",
|
|
197
205
|
"complexity_hotspots",
|
|
198
|
-
"pkg_audit"
|
|
206
|
+
"pkg_audit",
|
|
207
|
+
"build_check",
|
|
208
|
+
"syntax_check"
|
|
199
209
|
],
|
|
200
210
|
sme: [
|
|
201
211
|
"complexity_hotspots",
|
|
@@ -204,7 +214,8 @@ var init_constants = __esm(() => {
|
|
|
204
214
|
"imports",
|
|
205
215
|
"retrieve_summary",
|
|
206
216
|
"schema_drift",
|
|
207
|
-
"symbols"
|
|
217
|
+
"symbols",
|
|
218
|
+
"knowledgeRecall"
|
|
208
219
|
],
|
|
209
220
|
reviewer: [
|
|
210
221
|
"diff",
|
|
@@ -217,28 +228,34 @@ var init_constants = __esm(() => {
|
|
|
217
228
|
"complexity_hotspots",
|
|
218
229
|
"retrieve_summary",
|
|
219
230
|
"extract_code_blocks",
|
|
220
|
-
"test_runner"
|
|
231
|
+
"test_runner",
|
|
232
|
+
"sast_scan",
|
|
233
|
+
"placeholder_scan",
|
|
234
|
+
"knowledgeRecall"
|
|
221
235
|
],
|
|
222
236
|
critic: [
|
|
223
237
|
"complexity_hotspots",
|
|
224
238
|
"detect_domains",
|
|
225
239
|
"imports",
|
|
226
240
|
"retrieve_summary",
|
|
227
|
-
"symbols"
|
|
241
|
+
"symbols",
|
|
242
|
+
"knowledgeRecall"
|
|
228
243
|
],
|
|
229
244
|
critic_sounding_board: [
|
|
230
245
|
"complexity_hotspots",
|
|
231
246
|
"detect_domains",
|
|
232
247
|
"imports",
|
|
233
248
|
"retrieve_summary",
|
|
234
|
-
"symbols"
|
|
249
|
+
"symbols",
|
|
250
|
+
"knowledgeRecall"
|
|
235
251
|
],
|
|
236
252
|
critic_drift_verifier: [
|
|
237
253
|
"complexity_hotspots",
|
|
238
254
|
"detect_domains",
|
|
239
255
|
"imports",
|
|
240
256
|
"retrieve_summary",
|
|
241
|
-
"symbols"
|
|
257
|
+
"symbols",
|
|
258
|
+
"knowledgeRecall"
|
|
242
259
|
],
|
|
243
260
|
docs: [
|
|
244
261
|
"detect_domains",
|
|
@@ -248,9 +265,15 @@ var init_constants = __esm(() => {
|
|
|
248
265
|
"retrieve_summary",
|
|
249
266
|
"schema_drift",
|
|
250
267
|
"symbols",
|
|
251
|
-
"todo_extract"
|
|
268
|
+
"todo_extract",
|
|
269
|
+
"knowledgeRecall"
|
|
252
270
|
],
|
|
253
|
-
designer: [
|
|
271
|
+
designer: [
|
|
272
|
+
"extract_code_blocks",
|
|
273
|
+
"retrieve_summary",
|
|
274
|
+
"symbols",
|
|
275
|
+
"knowledgeRecall"
|
|
276
|
+
]
|
|
254
277
|
};
|
|
255
278
|
for (const [agentName, tools] of Object.entries(AGENT_TOOL_MAP)) {
|
|
256
279
|
const invalidTools = tools.filter((tool) => !TOOL_NAME_SET.has(tool));
|
|
@@ -31853,6 +31876,163 @@ var require_proper_lockfile = __commonJS((exports, module2) => {
|
|
|
31853
31876
|
module2.exports.checkSync = checkSync;
|
|
31854
31877
|
});
|
|
31855
31878
|
|
|
31879
|
+
// src/hooks/knowledge-store.ts
|
|
31880
|
+
import { existsSync as existsSync7 } from "fs";
|
|
31881
|
+
import { appendFile, mkdir, readFile as readFile2, writeFile } from "fs/promises";
|
|
31882
|
+
import * as os4 from "os";
|
|
31883
|
+
import * as path12 from "path";
|
|
31884
|
+
function resolveSwarmKnowledgePath(directory) {
|
|
31885
|
+
return path12.join(directory, ".swarm", "knowledge.jsonl");
|
|
31886
|
+
}
|
|
31887
|
+
function resolveSwarmRejectedPath(directory) {
|
|
31888
|
+
return path12.join(directory, ".swarm", "knowledge-rejected.jsonl");
|
|
31889
|
+
}
|
|
31890
|
+
function resolveHiveKnowledgePath() {
|
|
31891
|
+
const platform = process.platform;
|
|
31892
|
+
const home = os4.homedir();
|
|
31893
|
+
let dataDir;
|
|
31894
|
+
if (platform === "win32") {
|
|
31895
|
+
dataDir = path12.join(process.env.LOCALAPPDATA || path12.join(home, "AppData", "Local"), "opencode-swarm", "Data");
|
|
31896
|
+
} else if (platform === "darwin") {
|
|
31897
|
+
dataDir = path12.join(home, "Library", "Application Support", "opencode-swarm");
|
|
31898
|
+
} else {
|
|
31899
|
+
dataDir = path12.join(process.env.XDG_DATA_HOME || path12.join(home, ".local", "share"), "opencode-swarm");
|
|
31900
|
+
}
|
|
31901
|
+
return path12.join(dataDir, "shared-learnings.jsonl");
|
|
31902
|
+
}
|
|
31903
|
+
function resolveHiveRejectedPath() {
|
|
31904
|
+
const hivePath = resolveHiveKnowledgePath();
|
|
31905
|
+
return path12.join(path12.dirname(hivePath), "shared-learnings-rejected.jsonl");
|
|
31906
|
+
}
|
|
31907
|
+
async function readKnowledge(filePath) {
|
|
31908
|
+
if (!existsSync7(filePath))
|
|
31909
|
+
return [];
|
|
31910
|
+
const content = await readFile2(filePath, "utf-8");
|
|
31911
|
+
const results = [];
|
|
31912
|
+
for (const line of content.split(`
|
|
31913
|
+
`)) {
|
|
31914
|
+
const trimmed = line.trim();
|
|
31915
|
+
if (!trimmed)
|
|
31916
|
+
continue;
|
|
31917
|
+
try {
|
|
31918
|
+
results.push(JSON.parse(trimmed));
|
|
31919
|
+
} catch {
|
|
31920
|
+
console.warn(`[knowledge-store] Skipping corrupted JSONL line in ${filePath}: ${trimmed.slice(0, 80)}`);
|
|
31921
|
+
}
|
|
31922
|
+
}
|
|
31923
|
+
return results;
|
|
31924
|
+
}
|
|
31925
|
+
async function readRejectedLessons(directory) {
|
|
31926
|
+
return readKnowledge(resolveSwarmRejectedPath(directory));
|
|
31927
|
+
}
|
|
31928
|
+
async function appendKnowledge(filePath, entry) {
|
|
31929
|
+
await mkdir(path12.dirname(filePath), { recursive: true });
|
|
31930
|
+
await appendFile(filePath, `${JSON.stringify(entry)}
|
|
31931
|
+
`, "utf-8");
|
|
31932
|
+
}
|
|
31933
|
+
async function rewriteKnowledge(filePath, entries) {
|
|
31934
|
+
const dir = path12.dirname(filePath);
|
|
31935
|
+
await mkdir(dir, { recursive: true });
|
|
31936
|
+
let release = null;
|
|
31937
|
+
try {
|
|
31938
|
+
release = await import_proper_lockfile.default.lock(dir, {
|
|
31939
|
+
retries: { retries: 3, minTimeout: 100 }
|
|
31940
|
+
});
|
|
31941
|
+
const content = entries.map((e) => JSON.stringify(e)).join(`
|
|
31942
|
+
`) + (entries.length > 0 ? `
|
|
31943
|
+
` : "");
|
|
31944
|
+
await writeFile(filePath, content, "utf-8");
|
|
31945
|
+
} finally {
|
|
31946
|
+
if (release) {
|
|
31947
|
+
try {
|
|
31948
|
+
await release();
|
|
31949
|
+
} catch {}
|
|
31950
|
+
}
|
|
31951
|
+
}
|
|
31952
|
+
}
|
|
31953
|
+
async function appendRejectedLesson(directory, lesson) {
|
|
31954
|
+
const filePath = resolveSwarmRejectedPath(directory);
|
|
31955
|
+
const existing = await readRejectedLessons(directory);
|
|
31956
|
+
const MAX = 20;
|
|
31957
|
+
const updated = [...existing, lesson];
|
|
31958
|
+
if (updated.length > MAX) {
|
|
31959
|
+
const trimmed = updated.slice(updated.length - MAX);
|
|
31960
|
+
await rewriteKnowledge(filePath, trimmed);
|
|
31961
|
+
} else {
|
|
31962
|
+
await appendKnowledge(filePath, lesson);
|
|
31963
|
+
}
|
|
31964
|
+
}
|
|
31965
|
+
function normalize2(text) {
|
|
31966
|
+
return text.toLowerCase().replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
|
|
31967
|
+
}
|
|
31968
|
+
function wordBigrams(text) {
|
|
31969
|
+
const words = normalize2(text).split(" ").filter(Boolean);
|
|
31970
|
+
const bigrams = new Set;
|
|
31971
|
+
for (let i2 = 0;i2 < words.length - 1; i2++) {
|
|
31972
|
+
bigrams.add(`${words[i2]} ${words[i2 + 1]}`);
|
|
31973
|
+
}
|
|
31974
|
+
return bigrams;
|
|
31975
|
+
}
|
|
31976
|
+
function jaccardBigram(a, b) {
|
|
31977
|
+
if (a.size === 0 && b.size === 0)
|
|
31978
|
+
return 1;
|
|
31979
|
+
const aArr = Array.from(a);
|
|
31980
|
+
const intersection3 = new Set(aArr.filter((x) => b.has(x)));
|
|
31981
|
+
const union3 = new Set([...aArr, ...Array.from(b)]);
|
|
31982
|
+
return intersection3.size / union3.size;
|
|
31983
|
+
}
|
|
31984
|
+
function findNearDuplicate(candidate, entries, threshold = 0.6) {
|
|
31985
|
+
const candidateBigrams = wordBigrams(candidate);
|
|
31986
|
+
return entries.find((entry) => {
|
|
31987
|
+
const entryBigrams = wordBigrams(entry.lesson);
|
|
31988
|
+
return jaccardBigram(candidateBigrams, entryBigrams) >= threshold;
|
|
31989
|
+
});
|
|
31990
|
+
}
|
|
31991
|
+
function computeConfidence(confirmedByCount, autoGenerated) {
|
|
31992
|
+
let score = 0.5;
|
|
31993
|
+
score += Math.min(confirmedByCount, 3) * 0.1;
|
|
31994
|
+
if (!autoGenerated)
|
|
31995
|
+
score += 0.1;
|
|
31996
|
+
return Math.min(score, 1);
|
|
31997
|
+
}
|
|
31998
|
+
function inferTags(lesson) {
|
|
31999
|
+
const lower = lesson.toLowerCase();
|
|
32000
|
+
const tags = [];
|
|
32001
|
+
if (/\b(?:typescript|ts)\b/.test(lower))
|
|
32002
|
+
tags.push("typescript");
|
|
32003
|
+
if (/\b(?:javascript|js)\b/.test(lower))
|
|
32004
|
+
tags.push("javascript");
|
|
32005
|
+
if (/\b(?:python)\b/.test(lower))
|
|
32006
|
+
tags.push("python");
|
|
32007
|
+
if (/\b(?:bun|node|deno)\b/.test(lower))
|
|
32008
|
+
tags.push("runtime");
|
|
32009
|
+
if (/\b(?:react|vue|svelte|angular)\b/.test(lower))
|
|
32010
|
+
tags.push("frontend");
|
|
32011
|
+
if (/\b(?:git|github|gitlab)\b/.test(lower))
|
|
32012
|
+
tags.push("git");
|
|
32013
|
+
if (/\b(?:docker|kubernetes|k8s)\b/.test(lower))
|
|
32014
|
+
tags.push("container");
|
|
32015
|
+
if (/\b(?:sql|postgres|mysql|sqlite)\b/.test(lower))
|
|
32016
|
+
tags.push("database");
|
|
32017
|
+
if (/\b(?:test|spec|vitest|jest|mocha)\b/.test(lower))
|
|
32018
|
+
tags.push("testing");
|
|
32019
|
+
if (/\b(?:ci|cd|pipeline|workflow|action)\b/.test(lower))
|
|
32020
|
+
tags.push("ci-cd");
|
|
32021
|
+
if (/\b(?:security|auth|token|password|encrypt)\b/.test(lower))
|
|
32022
|
+
tags.push("security");
|
|
32023
|
+
if (/\b(?:performance|latency|throughput|cache)\b/.test(lower))
|
|
32024
|
+
tags.push("performance");
|
|
32025
|
+
if (/\b(?:api|rest|graphql|grpc|endpoint)\b/.test(lower))
|
|
32026
|
+
tags.push("api");
|
|
32027
|
+
if (/\b(?:swarm|architect|agent|hook|plan)\b/.test(lower))
|
|
32028
|
+
tags.push("opencode-swarm");
|
|
32029
|
+
return Array.from(new Set(tags));
|
|
32030
|
+
}
|
|
32031
|
+
var import_proper_lockfile;
|
|
32032
|
+
var init_knowledge_store = __esm(() => {
|
|
32033
|
+
import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
32034
|
+
});
|
|
32035
|
+
|
|
31856
32036
|
// src/services/config-doctor.ts
|
|
31857
32037
|
var exports_config_doctor = {};
|
|
31858
32038
|
__export(exports_config_doctor, {
|
|
@@ -33735,6 +33915,53 @@ var init_discovery = __esm(() => {
|
|
|
33735
33915
|
});
|
|
33736
33916
|
});
|
|
33737
33917
|
|
|
33918
|
+
// src/utils/path-security.ts
|
|
33919
|
+
function containsPathTraversal(str) {
|
|
33920
|
+
if (/\.\.[/\\]/.test(str))
|
|
33921
|
+
return true;
|
|
33922
|
+
if (/(?:^|[/\\])\.\.(?:[/\\]|$)/.test(str))
|
|
33923
|
+
return true;
|
|
33924
|
+
if (/%2e%2e/i.test(str))
|
|
33925
|
+
return true;
|
|
33926
|
+
if (/%2e\./i.test(str))
|
|
33927
|
+
return true;
|
|
33928
|
+
if (/%2e/i.test(str) && /\.\./.test(str))
|
|
33929
|
+
return true;
|
|
33930
|
+
if (/%252e%252e/i.test(str))
|
|
33931
|
+
return true;
|
|
33932
|
+
if (/\uff0e/.test(str))
|
|
33933
|
+
return true;
|
|
33934
|
+
if (/\u3002/.test(str))
|
|
33935
|
+
return true;
|
|
33936
|
+
if (/\uff65/.test(str))
|
|
33937
|
+
return true;
|
|
33938
|
+
if (/%2f/i.test(str))
|
|
33939
|
+
return true;
|
|
33940
|
+
if (/%5c/i.test(str))
|
|
33941
|
+
return true;
|
|
33942
|
+
return false;
|
|
33943
|
+
}
|
|
33944
|
+
function containsControlChars(str) {
|
|
33945
|
+
return /[\0\t\r\n]/.test(str);
|
|
33946
|
+
}
|
|
33947
|
+
function validateDirectory(directory) {
|
|
33948
|
+
if (!directory || directory.trim() === "") {
|
|
33949
|
+
throw new Error("Invalid directory: empty");
|
|
33950
|
+
}
|
|
33951
|
+
if (containsPathTraversal(directory)) {
|
|
33952
|
+
throw new Error("Invalid directory: path traversal detected");
|
|
33953
|
+
}
|
|
33954
|
+
if (containsControlChars(directory)) {
|
|
33955
|
+
throw new Error("Invalid directory: control characters detected");
|
|
33956
|
+
}
|
|
33957
|
+
if (directory.startsWith("/") || directory.startsWith("\\")) {
|
|
33958
|
+
throw new Error("Invalid directory: absolute path");
|
|
33959
|
+
}
|
|
33960
|
+
if (/^[A-Za-z]:[/\\]/.test(directory)) {
|
|
33961
|
+
throw new Error("Invalid directory: Windows absolute path");
|
|
33962
|
+
}
|
|
33963
|
+
}
|
|
33964
|
+
|
|
33738
33965
|
// src/tools/lint.ts
|
|
33739
33966
|
import * as fs12 from "fs";
|
|
33740
33967
|
import * as path23 from "path";
|
|
@@ -34133,19 +34360,6 @@ function isHighEntropyString(str) {
|
|
|
34133
34360
|
const entropy = calculateShannonEntropy(str);
|
|
34134
34361
|
return entropy > 4;
|
|
34135
34362
|
}
|
|
34136
|
-
function containsPathTraversal(str) {
|
|
34137
|
-
if (/\.\.[/\\]/.test(str))
|
|
34138
|
-
return true;
|
|
34139
|
-
if (/[/\\]\.\.$/.test(str) || str === "..")
|
|
34140
|
-
return true;
|
|
34141
|
-
if (/\.\.[/\\]/.test(path24.normalize(str.replace(/\*/g, "x"))))
|
|
34142
|
-
return true;
|
|
34143
|
-
if (str.includes("%2e%2e") || str.includes("%2E%2E"))
|
|
34144
|
-
return true;
|
|
34145
|
-
if (str.includes("..") && /%2e/i.test(str))
|
|
34146
|
-
return true;
|
|
34147
|
-
return false;
|
|
34148
|
-
}
|
|
34149
34363
|
function validateExcludePattern(exc) {
|
|
34150
34364
|
if (exc.length === 0)
|
|
34151
34365
|
return null;
|
|
@@ -34198,9 +34412,6 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
34198
34412
|
}
|
|
34199
34413
|
return false;
|
|
34200
34414
|
}
|
|
34201
|
-
function containsControlChars(str) {
|
|
34202
|
-
return /[\0\t\r\n]/.test(str);
|
|
34203
|
-
}
|
|
34204
34415
|
function validateDirectoryInput(dir) {
|
|
34205
34416
|
if (!dir || dir.length === 0) {
|
|
34206
34417
|
return "directory is required";
|
|
@@ -34812,31 +35023,6 @@ var init_secretscan = __esm(() => {
|
|
|
34812
35023
|
// src/tools/test-runner.ts
|
|
34813
35024
|
import * as fs14 from "fs";
|
|
34814
35025
|
import * as path25 from "path";
|
|
34815
|
-
function containsPathTraversal2(str) {
|
|
34816
|
-
if (/\.\.[/\\]/.test(str))
|
|
34817
|
-
return true;
|
|
34818
|
-
if (/(?:^|[/\\])\.\.(?:[/\\]|$)/.test(str))
|
|
34819
|
-
return true;
|
|
34820
|
-
if (/%2e%2e/i.test(str))
|
|
34821
|
-
return true;
|
|
34822
|
-
if (/%2e\./i.test(str))
|
|
34823
|
-
return true;
|
|
34824
|
-
if (/%2e/i.test(str) && /\.\./.test(str))
|
|
34825
|
-
return true;
|
|
34826
|
-
if (/%252e%252e/i.test(str))
|
|
34827
|
-
return true;
|
|
34828
|
-
if (/\uff0e/.test(str))
|
|
34829
|
-
return true;
|
|
34830
|
-
if (/\u3002/.test(str))
|
|
34831
|
-
return true;
|
|
34832
|
-
if (/\uff65/.test(str))
|
|
34833
|
-
return true;
|
|
34834
|
-
if (/%2f/i.test(str))
|
|
34835
|
-
return true;
|
|
34836
|
-
if (/%5c/i.test(str))
|
|
34837
|
-
return true;
|
|
34838
|
-
return false;
|
|
34839
|
-
}
|
|
34840
35026
|
function isAbsolutePath(str) {
|
|
34841
35027
|
if (str.startsWith("/"))
|
|
34842
35028
|
return true;
|
|
@@ -34848,9 +35034,6 @@ function isAbsolutePath(str) {
|
|
|
34848
35034
|
return true;
|
|
34849
35035
|
return false;
|
|
34850
35036
|
}
|
|
34851
|
-
function containsControlChars2(str) {
|
|
34852
|
-
return /[\x00-\x08\x0a\x0b\x0c\x0d\x0e-\x1f\x7f\x80-\x9f]/.test(str);
|
|
34853
|
-
}
|
|
34854
35037
|
function containsPowerShellMetacharacters(str) {
|
|
34855
35038
|
return POWERSHELL_METACHARACTERS.test(str);
|
|
34856
35039
|
}
|
|
@@ -34871,9 +35054,9 @@ function validateArgs2(args2) {
|
|
|
34871
35054
|
return false;
|
|
34872
35055
|
if (isAbsolutePath(f))
|
|
34873
35056
|
return false;
|
|
34874
|
-
if (
|
|
35057
|
+
if (containsPathTraversal(f))
|
|
34875
35058
|
return false;
|
|
34876
|
-
if (
|
|
35059
|
+
if (containsControlChars(f))
|
|
34877
35060
|
return false;
|
|
34878
35061
|
if (containsPowerShellMetacharacters(f))
|
|
34879
35062
|
return false;
|
|
@@ -35702,7 +35885,7 @@ var init_test_runner = __esm(() => {
|
|
|
35702
35885
|
};
|
|
35703
35886
|
return JSON.stringify(errorResult, null, 2);
|
|
35704
35887
|
}
|
|
35705
|
-
if (
|
|
35888
|
+
if (containsControlChars(workingDir)) {
|
|
35706
35889
|
const errorResult = {
|
|
35707
35890
|
success: false,
|
|
35708
35891
|
framework: "none",
|
|
@@ -35711,7 +35894,7 @@ var init_test_runner = __esm(() => {
|
|
|
35711
35894
|
};
|
|
35712
35895
|
return JSON.stringify(errorResult, null, 2);
|
|
35713
35896
|
}
|
|
35714
|
-
if (
|
|
35897
|
+
if (containsPathTraversal(workingDir)) {
|
|
35715
35898
|
const errorResult = {
|
|
35716
35899
|
success: false,
|
|
35717
35900
|
framework: "none",
|
|
@@ -36643,6 +36826,395 @@ var init_preflight_integration = __esm(() => {
|
|
|
36643
36826
|
init_preflight_service();
|
|
36644
36827
|
});
|
|
36645
36828
|
|
|
36829
|
+
// src/tools/doc-scan.ts
|
|
36830
|
+
var exports_doc_scan = {};
|
|
36831
|
+
__export(exports_doc_scan, {
|
|
36832
|
+
scanDocIndex: () => scanDocIndex,
|
|
36833
|
+
extractDocConstraints: () => extractDocConstraints,
|
|
36834
|
+
doc_scan: () => doc_scan,
|
|
36835
|
+
doc_extract: () => doc_extract
|
|
36836
|
+
});
|
|
36837
|
+
import * as crypto4 from "crypto";
|
|
36838
|
+
import * as fs25 from "fs";
|
|
36839
|
+
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
|
|
36840
|
+
import * as path36 from "path";
|
|
36841
|
+
function normalizeSeparators(filePath) {
|
|
36842
|
+
return filePath.replace(/\\/g, "/");
|
|
36843
|
+
}
|
|
36844
|
+
function matchesDocPattern(filePath, patterns) {
|
|
36845
|
+
const normalizedPath = normalizeSeparators(filePath);
|
|
36846
|
+
const basename5 = path36.basename(filePath);
|
|
36847
|
+
for (const pattern of patterns) {
|
|
36848
|
+
if (!pattern.includes("/") && !pattern.includes("\\")) {
|
|
36849
|
+
if (basename5 === pattern) {
|
|
36850
|
+
return true;
|
|
36851
|
+
}
|
|
36852
|
+
continue;
|
|
36853
|
+
}
|
|
36854
|
+
if (pattern.startsWith("**/")) {
|
|
36855
|
+
const filenamePattern = pattern.slice(3);
|
|
36856
|
+
if (basename5 === filenamePattern) {
|
|
36857
|
+
return true;
|
|
36858
|
+
}
|
|
36859
|
+
continue;
|
|
36860
|
+
}
|
|
36861
|
+
const patternNormalized = normalizeSeparators(pattern);
|
|
36862
|
+
const dirPrefix = patternNormalized.replace(/\/\*\*.*$/, "").replace(/\/\*.*$/, "");
|
|
36863
|
+
if (normalizedPath.startsWith(`${dirPrefix}/`) || normalizedPath === dirPrefix) {
|
|
36864
|
+
return true;
|
|
36865
|
+
}
|
|
36866
|
+
}
|
|
36867
|
+
return false;
|
|
36868
|
+
}
|
|
36869
|
+
function extractTitleAndSummary(content, filename) {
|
|
36870
|
+
const lines = content.split(`
|
|
36871
|
+
`);
|
|
36872
|
+
let title = filename;
|
|
36873
|
+
let summary = "";
|
|
36874
|
+
let foundTitle = false;
|
|
36875
|
+
const potentialSummaryLines = [];
|
|
36876
|
+
for (let i2 = 0;i2 < lines.length && i2 < READ_LINES_LIMIT; i2++) {
|
|
36877
|
+
const line = lines[i2].trim();
|
|
36878
|
+
if (!foundTitle && line.startsWith("# ")) {
|
|
36879
|
+
title = line.slice(2).trim();
|
|
36880
|
+
foundTitle = true;
|
|
36881
|
+
continue;
|
|
36882
|
+
}
|
|
36883
|
+
if (line && !line.startsWith("#")) {
|
|
36884
|
+
potentialSummaryLines.push(line);
|
|
36885
|
+
}
|
|
36886
|
+
}
|
|
36887
|
+
for (const line of potentialSummaryLines) {
|
|
36888
|
+
summary += (summary ? " " : "") + line;
|
|
36889
|
+
if (summary.length >= MAX_SUMMARY_LENGTH) {
|
|
36890
|
+
break;
|
|
36891
|
+
}
|
|
36892
|
+
}
|
|
36893
|
+
if (summary.length > MAX_SUMMARY_LENGTH) {
|
|
36894
|
+
summary = `${summary.slice(0, MAX_SUMMARY_LENGTH - 3)}...`;
|
|
36895
|
+
}
|
|
36896
|
+
return { title, summary };
|
|
36897
|
+
}
|
|
36898
|
+
function stripMarkdown(text) {
|
|
36899
|
+
return text.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/^\s*[-*\u2022]\s+/gm, "").replace(/^\s*\d+\.\s+/gm, "").trim();
|
|
36900
|
+
}
|
|
36901
|
+
async function scanDocIndex(directory) {
|
|
36902
|
+
const manifestPath = path36.join(directory, ".swarm", "doc-manifest.json");
|
|
36903
|
+
const defaultPatterns = DocsConfigSchema.parse({}).doc_patterns;
|
|
36904
|
+
const extraPatterns = [
|
|
36905
|
+
"ARCHITECTURE.md",
|
|
36906
|
+
"CLAUDE.md",
|
|
36907
|
+
"AGENTS.md",
|
|
36908
|
+
".github/*.md",
|
|
36909
|
+
"doc/**/*.md"
|
|
36910
|
+
];
|
|
36911
|
+
const allPatterns = [...defaultPatterns, ...extraPatterns];
|
|
36912
|
+
try {
|
|
36913
|
+
const manifestContent = await readFile5(manifestPath, "utf-8");
|
|
36914
|
+
const existingManifest = JSON.parse(manifestContent);
|
|
36915
|
+
if (existingManifest.schema_version === 1 && existingManifest.files) {
|
|
36916
|
+
let cacheValid = true;
|
|
36917
|
+
for (const file3 of existingManifest.files) {
|
|
36918
|
+
try {
|
|
36919
|
+
const fullPath = path36.join(directory, file3.path);
|
|
36920
|
+
const stat2 = fs25.statSync(fullPath);
|
|
36921
|
+
if (stat2.mtimeMs > new Date(existingManifest.scanned_at).getTime()) {
|
|
36922
|
+
cacheValid = false;
|
|
36923
|
+
break;
|
|
36924
|
+
}
|
|
36925
|
+
} catch {
|
|
36926
|
+
cacheValid = false;
|
|
36927
|
+
break;
|
|
36928
|
+
}
|
|
36929
|
+
}
|
|
36930
|
+
if (cacheValid) {
|
|
36931
|
+
return { manifest: existingManifest, cached: true };
|
|
36932
|
+
}
|
|
36933
|
+
}
|
|
36934
|
+
} catch {}
|
|
36935
|
+
const discoveredFiles = [];
|
|
36936
|
+
let rawEntries;
|
|
36937
|
+
try {
|
|
36938
|
+
rawEntries = fs25.readdirSync(directory, { recursive: true });
|
|
36939
|
+
} catch {
|
|
36940
|
+
const manifest2 = {
|
|
36941
|
+
schema_version: 1,
|
|
36942
|
+
scanned_at: new Date().toISOString(),
|
|
36943
|
+
files: []
|
|
36944
|
+
};
|
|
36945
|
+
return { manifest: manifest2, cached: false };
|
|
36946
|
+
}
|
|
36947
|
+
const entries = rawEntries.filter((e) => typeof e === "string");
|
|
36948
|
+
for (const entry of entries) {
|
|
36949
|
+
const fullPath = path36.join(directory, entry);
|
|
36950
|
+
let stat2;
|
|
36951
|
+
try {
|
|
36952
|
+
stat2 = fs25.statSync(fullPath);
|
|
36953
|
+
} catch {
|
|
36954
|
+
continue;
|
|
36955
|
+
}
|
|
36956
|
+
if (!stat2.isFile())
|
|
36957
|
+
continue;
|
|
36958
|
+
const pathParts = normalizeSeparators(entry).split("/");
|
|
36959
|
+
let skipThisFile = false;
|
|
36960
|
+
for (const part of pathParts) {
|
|
36961
|
+
if (SKIP_DIRECTORIES2.has(part)) {
|
|
36962
|
+
skipThisFile = true;
|
|
36963
|
+
break;
|
|
36964
|
+
}
|
|
36965
|
+
}
|
|
36966
|
+
if (skipThisFile)
|
|
36967
|
+
continue;
|
|
36968
|
+
for (const pattern of SKIP_PATTERNS) {
|
|
36969
|
+
if (pattern.test(entry)) {
|
|
36970
|
+
skipThisFile = true;
|
|
36971
|
+
break;
|
|
36972
|
+
}
|
|
36973
|
+
}
|
|
36974
|
+
if (skipThisFile)
|
|
36975
|
+
continue;
|
|
36976
|
+
if (!matchesDocPattern(entry, allPatterns)) {
|
|
36977
|
+
continue;
|
|
36978
|
+
}
|
|
36979
|
+
let content;
|
|
36980
|
+
try {
|
|
36981
|
+
content = fs25.readFileSync(fullPath, "utf-8");
|
|
36982
|
+
} catch {
|
|
36983
|
+
continue;
|
|
36984
|
+
}
|
|
36985
|
+
const { title, summary } = extractTitleAndSummary(content, path36.basename(entry));
|
|
36986
|
+
const lineCount = content.split(`
|
|
36987
|
+
`).length;
|
|
36988
|
+
discoveredFiles.push({
|
|
36989
|
+
path: entry,
|
|
36990
|
+
title,
|
|
36991
|
+
summary,
|
|
36992
|
+
lines: lineCount,
|
|
36993
|
+
mtime: stat2.mtimeMs
|
|
36994
|
+
});
|
|
36995
|
+
}
|
|
36996
|
+
discoveredFiles.sort((a, b) => a.path.toLowerCase().localeCompare(b.path.toLowerCase()));
|
|
36997
|
+
let truncated = false;
|
|
36998
|
+
if (discoveredFiles.length > MAX_INDEXED_FILES) {
|
|
36999
|
+
discoveredFiles.splice(MAX_INDEXED_FILES);
|
|
37000
|
+
truncated = true;
|
|
37001
|
+
}
|
|
37002
|
+
if (truncated && discoveredFiles.length > 0) {
|
|
37003
|
+
discoveredFiles[0].summary = `[Warning: ${MAX_INDEXED_FILES}+ docs found, listing first ${MAX_INDEXED_FILES}] ` + discoveredFiles[0].summary;
|
|
37004
|
+
}
|
|
37005
|
+
const manifest = {
|
|
37006
|
+
schema_version: 1,
|
|
37007
|
+
scanned_at: new Date().toISOString(),
|
|
37008
|
+
files: discoveredFiles
|
|
37009
|
+
};
|
|
37010
|
+
try {
|
|
37011
|
+
await mkdir5(path36.dirname(manifestPath), { recursive: true });
|
|
37012
|
+
await writeFile4(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
37013
|
+
} catch {}
|
|
37014
|
+
return { manifest, cached: false };
|
|
37015
|
+
}
|
|
37016
|
+
function isConstraintLine(line) {
|
|
37017
|
+
const upperLine = line.toUpperCase();
|
|
37018
|
+
for (const pattern of CONSTRAINT_PATTERNS) {
|
|
37019
|
+
if (pattern.test(upperLine)) {
|
|
37020
|
+
return true;
|
|
37021
|
+
}
|
|
37022
|
+
}
|
|
37023
|
+
if (/^\s*[-*\u2022]/.test(line) && ACTION_WORDS.test(line)) {
|
|
37024
|
+
return true;
|
|
37025
|
+
}
|
|
37026
|
+
return false;
|
|
37027
|
+
}
|
|
37028
|
+
function extractConstraintsFromContent(content) {
|
|
37029
|
+
const lines = content.split(`
|
|
37030
|
+
`);
|
|
37031
|
+
const constraints = [];
|
|
37032
|
+
for (const line of lines) {
|
|
37033
|
+
if (constraints.length >= MAX_CONSTRAINTS_PER_DOC) {
|
|
37034
|
+
break;
|
|
37035
|
+
}
|
|
37036
|
+
const trimmed = line.trim();
|
|
37037
|
+
if (!trimmed)
|
|
37038
|
+
continue;
|
|
37039
|
+
if (isConstraintLine(trimmed)) {
|
|
37040
|
+
const cleaned = stripMarkdown(trimmed);
|
|
37041
|
+
const len = cleaned.length;
|
|
37042
|
+
if (len >= MIN_LESSON_LENGTH && len <= MAX_CONSTRAINT_LENGTH) {
|
|
37043
|
+
constraints.push(cleaned);
|
|
37044
|
+
}
|
|
37045
|
+
}
|
|
37046
|
+
}
|
|
37047
|
+
return constraints;
|
|
37048
|
+
}
|
|
37049
|
+
async function extractDocConstraints(directory, taskFiles, taskDescription) {
|
|
37050
|
+
const manifestPath = path36.join(directory, ".swarm", "doc-manifest.json");
|
|
37051
|
+
let manifest;
|
|
37052
|
+
try {
|
|
37053
|
+
const content = await readFile5(manifestPath, "utf-8");
|
|
37054
|
+
manifest = JSON.parse(content);
|
|
37055
|
+
} catch {
|
|
37056
|
+
const result = await scanDocIndex(directory);
|
|
37057
|
+
manifest = result.manifest;
|
|
37058
|
+
}
|
|
37059
|
+
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
37060
|
+
const existingEntries = await readKnowledge(knowledgePath);
|
|
37061
|
+
const taskContext = [...taskFiles, taskDescription].join(" ");
|
|
37062
|
+
const taskBigrams = wordBigrams(normalize2(taskContext));
|
|
37063
|
+
let extractedCount = 0;
|
|
37064
|
+
let skippedCount = 0;
|
|
37065
|
+
const details = [];
|
|
37066
|
+
for (const docFile of manifest.files) {
|
|
37067
|
+
const docContext = `${docFile.path} ${docFile.title} ${docFile.summary}`;
|
|
37068
|
+
const docBigrams = wordBigrams(normalize2(docContext));
|
|
37069
|
+
const score = jaccardBigram(taskBigrams, docBigrams);
|
|
37070
|
+
if (score <= RELEVANCE_THRESHOLD) {
|
|
37071
|
+
skippedCount++;
|
|
37072
|
+
continue;
|
|
37073
|
+
}
|
|
37074
|
+
let fullContent;
|
|
37075
|
+
try {
|
|
37076
|
+
fullContent = await readFile5(path36.join(directory, docFile.path), "utf-8");
|
|
37077
|
+
} catch {
|
|
37078
|
+
skippedCount++;
|
|
37079
|
+
continue;
|
|
37080
|
+
}
|
|
37081
|
+
const constraints = extractConstraintsFromContent(fullContent);
|
|
37082
|
+
if (constraints.length === 0) {
|
|
37083
|
+
skippedCount++;
|
|
37084
|
+
continue;
|
|
37085
|
+
}
|
|
37086
|
+
const docDetails = {
|
|
37087
|
+
path: docFile.path,
|
|
37088
|
+
score,
|
|
37089
|
+
constraints: []
|
|
37090
|
+
};
|
|
37091
|
+
for (const constraint of constraints) {
|
|
37092
|
+
const duplicate = findNearDuplicate(constraint, existingEntries, DEDUP_THRESHOLD);
|
|
37093
|
+
if (!duplicate) {
|
|
37094
|
+
const entry = {
|
|
37095
|
+
id: crypto4.randomUUID(),
|
|
37096
|
+
tier: "swarm",
|
|
37097
|
+
lesson: constraint,
|
|
37098
|
+
category: "architecture",
|
|
37099
|
+
tags: ["doc-scan", path36.basename(docFile.path)],
|
|
37100
|
+
scope: "global",
|
|
37101
|
+
confidence: 0.5,
|
|
37102
|
+
status: "candidate",
|
|
37103
|
+
confirmed_by: [],
|
|
37104
|
+
project_name: "",
|
|
37105
|
+
retrieval_outcomes: {
|
|
37106
|
+
applied_count: 0,
|
|
37107
|
+
succeeded_after_count: 0,
|
|
37108
|
+
failed_after_count: 0
|
|
37109
|
+
},
|
|
37110
|
+
schema_version: 1,
|
|
37111
|
+
created_at: new Date().toISOString(),
|
|
37112
|
+
updated_at: new Date().toISOString(),
|
|
37113
|
+
auto_generated: true,
|
|
37114
|
+
hive_eligible: false
|
|
37115
|
+
};
|
|
37116
|
+
await appendKnowledge(knowledgePath, entry);
|
|
37117
|
+
existingEntries.push(entry);
|
|
37118
|
+
extractedCount++;
|
|
37119
|
+
docDetails.constraints.push(constraint);
|
|
37120
|
+
}
|
|
37121
|
+
}
|
|
37122
|
+
if (docDetails.constraints.length > 0) {
|
|
37123
|
+
details.push(docDetails);
|
|
37124
|
+
} else {
|
|
37125
|
+
skippedCount++;
|
|
37126
|
+
}
|
|
37127
|
+
}
|
|
37128
|
+
return { extracted: extractedCount, skipped: skippedCount, details };
|
|
37129
|
+
}
|
|
37130
|
+
var SKIP_DIRECTORIES2, SKIP_PATTERNS, MAX_SUMMARY_LENGTH = 200, MAX_INDEXED_FILES = 100, READ_LINES_LIMIT = 30, MIN_LESSON_LENGTH = 15, MAX_CONSTRAINTS_PER_DOC = 5, MAX_CONSTRAINT_LENGTH = 200, RELEVANCE_THRESHOLD = 0.1, DEDUP_THRESHOLD = 0.6, CONSTRAINT_PATTERNS, ACTION_WORDS, doc_scan, doc_extract;
|
|
37131
|
+
var init_doc_scan = __esm(() => {
|
|
37132
|
+
init_dist();
|
|
37133
|
+
init_schema();
|
|
37134
|
+
init_knowledge_store();
|
|
37135
|
+
init_create_tool();
|
|
37136
|
+
SKIP_DIRECTORIES2 = new Set([
|
|
37137
|
+
"node_modules",
|
|
37138
|
+
".git",
|
|
37139
|
+
".swarm",
|
|
37140
|
+
"dist",
|
|
37141
|
+
"build",
|
|
37142
|
+
".next",
|
|
37143
|
+
"vendor"
|
|
37144
|
+
]);
|
|
37145
|
+
SKIP_PATTERNS = [/\.test\./, /\.spec\./, /\.d\.ts$/];
|
|
37146
|
+
CONSTRAINT_PATTERNS = [
|
|
37147
|
+
/\bMUST\b/,
|
|
37148
|
+
/\bMUST NOT\b/,
|
|
37149
|
+
/\bSHOULD\b/,
|
|
37150
|
+
/\bSHOULD NOT\b/,
|
|
37151
|
+
/\bDO NOT\b/,
|
|
37152
|
+
/\bALWAYS\b/,
|
|
37153
|
+
/\bNEVER\b/,
|
|
37154
|
+
/\bREQUIRED\b/
|
|
37155
|
+
];
|
|
37156
|
+
ACTION_WORDS = /\b(must|should|don't|avoid|ensure|use|follow)\b/i;
|
|
37157
|
+
doc_scan = createSwarmTool({
|
|
37158
|
+
description: "Scan project documentation files and build an index manifest. Caches results in .swarm/doc-manifest.json for fast subsequent scans.",
|
|
37159
|
+
args: {
|
|
37160
|
+
force: tool.schema.boolean().optional().describe("Force re-scan even if cache is valid")
|
|
37161
|
+
},
|
|
37162
|
+
execute: async (args2, directory) => {
|
|
37163
|
+
let force = false;
|
|
37164
|
+
try {
|
|
37165
|
+
if (args2 && typeof args2 === "object") {
|
|
37166
|
+
const obj = args2;
|
|
37167
|
+
if (obj.force === true)
|
|
37168
|
+
force = true;
|
|
37169
|
+
}
|
|
37170
|
+
} catch {}
|
|
37171
|
+
if (force) {
|
|
37172
|
+
const manifestPath = path36.join(directory, ".swarm", "doc-manifest.json");
|
|
37173
|
+
try {
|
|
37174
|
+
fs25.unlinkSync(manifestPath);
|
|
37175
|
+
} catch {}
|
|
37176
|
+
}
|
|
37177
|
+
const { manifest, cached: cached3 } = await scanDocIndex(directory);
|
|
37178
|
+
return JSON.stringify({
|
|
37179
|
+
success: true,
|
|
37180
|
+
files_count: manifest.files.length,
|
|
37181
|
+
cached: cached3,
|
|
37182
|
+
manifest
|
|
37183
|
+
}, null, 2);
|
|
37184
|
+
}
|
|
37185
|
+
});
|
|
37186
|
+
doc_extract = createSwarmTool({
|
|
37187
|
+
description: "Extract actionable constraints from project documentation relevant to the current task. Scans docs via doc-manifest, scores relevance via Jaccard bigram similarity, and stores non-duplicate constraints in .swarm/knowledge.jsonl.",
|
|
37188
|
+
args: {
|
|
37189
|
+
task_files: tool.schema.array(tool.schema.string()).describe("List of file paths involved in the current task"),
|
|
37190
|
+
task_description: tool.schema.string().describe("Description of the current task")
|
|
37191
|
+
},
|
|
37192
|
+
execute: async (args2, directory) => {
|
|
37193
|
+
let taskFiles = [];
|
|
37194
|
+
let taskDescription = "";
|
|
37195
|
+
try {
|
|
37196
|
+
if (args2 && typeof args2 === "object") {
|
|
37197
|
+
const obj = args2;
|
|
37198
|
+
if (Array.isArray(obj.task_files)) {
|
|
37199
|
+
taskFiles = obj.task_files.filter((f) => typeof f === "string");
|
|
37200
|
+
}
|
|
37201
|
+
if (typeof obj.task_description === "string") {
|
|
37202
|
+
taskDescription = obj.task_description;
|
|
37203
|
+
}
|
|
37204
|
+
}
|
|
37205
|
+
} catch {}
|
|
37206
|
+
if (taskFiles.length === 0 && !taskDescription) {
|
|
37207
|
+
return JSON.stringify({
|
|
37208
|
+
success: false,
|
|
37209
|
+
error: "task_files or task_description is required"
|
|
37210
|
+
});
|
|
37211
|
+
}
|
|
37212
|
+
const result = await extractDocConstraints(directory, taskFiles, taskDescription);
|
|
37213
|
+
return JSON.stringify({ success: true, ...result }, null, 2);
|
|
37214
|
+
}
|
|
37215
|
+
});
|
|
37216
|
+
});
|
|
37217
|
+
|
|
36646
37218
|
// src/hooks/curator-drift.ts
|
|
36647
37219
|
var exports_curator_drift = {};
|
|
36648
37220
|
__export(exports_curator_drift, {
|
|
@@ -36651,11 +37223,11 @@ __export(exports_curator_drift, {
|
|
|
36651
37223
|
readPriorDriftReports: () => readPriorDriftReports,
|
|
36652
37224
|
buildDriftInjectionText: () => buildDriftInjectionText
|
|
36653
37225
|
});
|
|
36654
|
-
import * as
|
|
36655
|
-
import * as
|
|
37226
|
+
import * as fs28 from "fs";
|
|
37227
|
+
import * as path39 from "path";
|
|
36656
37228
|
async function readPriorDriftReports(directory) {
|
|
36657
|
-
const swarmDir =
|
|
36658
|
-
const entries = await
|
|
37229
|
+
const swarmDir = path39.join(directory, ".swarm");
|
|
37230
|
+
const entries = await fs28.promises.readdir(swarmDir).catch(() => null);
|
|
36659
37231
|
if (entries === null)
|
|
36660
37232
|
return [];
|
|
36661
37233
|
const reportFiles = entries.filter((name2) => name2.startsWith(DRIFT_REPORT_PREFIX) && name2.endsWith(".json")).sort();
|
|
@@ -36681,10 +37253,10 @@ async function readPriorDriftReports(directory) {
|
|
|
36681
37253
|
async function writeDriftReport(directory, report) {
|
|
36682
37254
|
const filename = `${DRIFT_REPORT_PREFIX}${report.phase}.json`;
|
|
36683
37255
|
const filePath = validateSwarmPath(directory, filename);
|
|
36684
|
-
const swarmDir =
|
|
36685
|
-
await
|
|
37256
|
+
const swarmDir = path39.dirname(filePath);
|
|
37257
|
+
await fs28.promises.mkdir(swarmDir, { recursive: true });
|
|
36686
37258
|
try {
|
|
36687
|
-
await
|
|
37259
|
+
await fs28.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
|
|
36688
37260
|
} catch (err2) {
|
|
36689
37261
|
throw new Error(`[curator-drift] Failed to write drift report to ${filePath}: ${String(err2)}`);
|
|
36690
37262
|
}
|
|
@@ -38274,11 +38846,11 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
38274
38846
|
throw toThrow;
|
|
38275
38847
|
}, "quit_");
|
|
38276
38848
|
var scriptDirectory = "";
|
|
38277
|
-
function locateFile(
|
|
38849
|
+
function locateFile(path46) {
|
|
38278
38850
|
if (Module["locateFile"]) {
|
|
38279
|
-
return Module["locateFile"](
|
|
38851
|
+
return Module["locateFile"](path46, scriptDirectory);
|
|
38280
38852
|
}
|
|
38281
|
-
return scriptDirectory +
|
|
38853
|
+
return scriptDirectory + path46;
|
|
38282
38854
|
}
|
|
38283
38855
|
__name(locateFile, "locateFile");
|
|
38284
38856
|
var readAsync, readBinary;
|
|
@@ -40701,10 +41273,11 @@ Two small delegations with two QA gates > one large delegation with one QA gate.
|
|
|
40701
41273
|
Never silently consume LOW-confidence result as verified.
|
|
40702
41274
|
6f-1. **DOCUMENTATION AWARENESS**
|
|
40703
41275
|
Before implementation begins:
|
|
40704
|
-
1. Check if .swarm/doc-manifest.json exists. If not, delegate to explorer to run DOCUMENTATION DISCOVERY MODE.
|
|
41276
|
+
1. Check if .swarm/doc-manifest.json exists. If not, delegate to explorer to run DOCUMENTATION DISCOVERY MODE (or call doc_scan directly).
|
|
40705
41277
|
2. The explorer indexes project documentation (CONTRIBUTING.md, architecture.md, README.md, etc.) and writes constraints to the knowledge system.
|
|
40706
|
-
3.
|
|
40707
|
-
4.
|
|
41278
|
+
3. When beginning a new task, if .swarm/doc-manifest.json exists, call doc_extract with the task's file list and description to load relevant documentation constraints.
|
|
41279
|
+
4. Before starting each phase, call knowledge_recall with query "doc-constraints" to check if any project documentation constrains the current task.
|
|
41280
|
+
5. Key constraints from project docs (commit conventions, release process, test framework, platform requirements) take priority over your own assumptions.
|
|
40708
41281
|
7. **TIERED QA GATE** \u2014 Execute AFTER every coder task. Pipeline determined by change tier:
|
|
40709
41282
|
NOTE: These gates are enforced by runtime hooks. If you skip the {{AGENT_PREFIX}}reviewer delegation,
|
|
40710
41283
|
the next coder delegation will be BLOCKED by the plugin. This is not a suggestion \u2014
|
|
@@ -42423,9 +42996,10 @@ MIGRATION_NEEDED: [yes \u2014 description of required caller updates | no]
|
|
|
42423
42996
|
|
|
42424
42997
|
## DOCUMENTATION DISCOVERY MODE
|
|
42425
42998
|
Activates automatically during codebase reality check at plan ingestion.
|
|
42999
|
+
Use the doc_scan tool to scan and index documentation files. If doc_scan is unavailable, fall back to manual globbing.
|
|
42426
43000
|
|
|
42427
43001
|
STEPS:
|
|
42428
|
-
1.
|
|
43002
|
+
1. Call doc_scan to build the manifest, OR glob for documentation files:
|
|
42429
43003
|
- Root: README.md, CONTRIBUTING.md, CHANGELOG.md, ARCHITECTURE.md, CLAUDE.md, AGENTS.md, .github/*.md
|
|
42430
43004
|
- docs/**/*.md, doc/**/*.md (one level deep only)
|
|
42431
43005
|
|
|
@@ -44729,162 +45303,7 @@ import path15 from "path";
|
|
|
44729
45303
|
import * as fs9 from "fs";
|
|
44730
45304
|
import * as path13 from "path";
|
|
44731
45305
|
init_event_bus();
|
|
44732
|
-
|
|
44733
|
-
// src/hooks/knowledge-store.ts
|
|
44734
|
-
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
44735
|
-
import { existsSync as existsSync7 } from "fs";
|
|
44736
|
-
import { appendFile, mkdir, readFile as readFile2, writeFile } from "fs/promises";
|
|
44737
|
-
import * as os4 from "os";
|
|
44738
|
-
import * as path12 from "path";
|
|
44739
|
-
function resolveSwarmKnowledgePath(directory) {
|
|
44740
|
-
return path12.join(directory, ".swarm", "knowledge.jsonl");
|
|
44741
|
-
}
|
|
44742
|
-
function resolveSwarmRejectedPath(directory) {
|
|
44743
|
-
return path12.join(directory, ".swarm", "knowledge-rejected.jsonl");
|
|
44744
|
-
}
|
|
44745
|
-
function resolveHiveKnowledgePath() {
|
|
44746
|
-
const platform = process.platform;
|
|
44747
|
-
const home = os4.homedir();
|
|
44748
|
-
let dataDir;
|
|
44749
|
-
if (platform === "win32") {
|
|
44750
|
-
dataDir = path12.join(process.env.LOCALAPPDATA || path12.join(home, "AppData", "Local"), "opencode-swarm", "Data");
|
|
44751
|
-
} else if (platform === "darwin") {
|
|
44752
|
-
dataDir = path12.join(home, "Library", "Application Support", "opencode-swarm");
|
|
44753
|
-
} else {
|
|
44754
|
-
dataDir = path12.join(process.env.XDG_DATA_HOME || path12.join(home, ".local", "share"), "opencode-swarm");
|
|
44755
|
-
}
|
|
44756
|
-
return path12.join(dataDir, "shared-learnings.jsonl");
|
|
44757
|
-
}
|
|
44758
|
-
function resolveHiveRejectedPath() {
|
|
44759
|
-
const hivePath = resolveHiveKnowledgePath();
|
|
44760
|
-
return path12.join(path12.dirname(hivePath), "shared-learnings-rejected.jsonl");
|
|
44761
|
-
}
|
|
44762
|
-
async function readKnowledge(filePath) {
|
|
44763
|
-
if (!existsSync7(filePath))
|
|
44764
|
-
return [];
|
|
44765
|
-
const content = await readFile2(filePath, "utf-8");
|
|
44766
|
-
const results = [];
|
|
44767
|
-
for (const line of content.split(`
|
|
44768
|
-
`)) {
|
|
44769
|
-
const trimmed = line.trim();
|
|
44770
|
-
if (!trimmed)
|
|
44771
|
-
continue;
|
|
44772
|
-
try {
|
|
44773
|
-
results.push(JSON.parse(trimmed));
|
|
44774
|
-
} catch {
|
|
44775
|
-
console.warn(`[knowledge-store] Skipping corrupted JSONL line in ${filePath}: ${trimmed.slice(0, 80)}`);
|
|
44776
|
-
}
|
|
44777
|
-
}
|
|
44778
|
-
return results;
|
|
44779
|
-
}
|
|
44780
|
-
async function readRejectedLessons(directory) {
|
|
44781
|
-
return readKnowledge(resolveSwarmRejectedPath(directory));
|
|
44782
|
-
}
|
|
44783
|
-
async function appendKnowledge(filePath, entry) {
|
|
44784
|
-
await mkdir(path12.dirname(filePath), { recursive: true });
|
|
44785
|
-
await appendFile(filePath, `${JSON.stringify(entry)}
|
|
44786
|
-
`, "utf-8");
|
|
44787
|
-
}
|
|
44788
|
-
async function rewriteKnowledge(filePath, entries) {
|
|
44789
|
-
const dir = path12.dirname(filePath);
|
|
44790
|
-
await mkdir(dir, { recursive: true });
|
|
44791
|
-
let release = null;
|
|
44792
|
-
try {
|
|
44793
|
-
release = await import_proper_lockfile.default.lock(dir, {
|
|
44794
|
-
retries: { retries: 3, minTimeout: 100 }
|
|
44795
|
-
});
|
|
44796
|
-
const content = entries.map((e) => JSON.stringify(e)).join(`
|
|
44797
|
-
`) + (entries.length > 0 ? `
|
|
44798
|
-
` : "");
|
|
44799
|
-
await writeFile(filePath, content, "utf-8");
|
|
44800
|
-
} finally {
|
|
44801
|
-
if (release) {
|
|
44802
|
-
try {
|
|
44803
|
-
await release();
|
|
44804
|
-
} catch {}
|
|
44805
|
-
}
|
|
44806
|
-
}
|
|
44807
|
-
}
|
|
44808
|
-
async function appendRejectedLesson(directory, lesson) {
|
|
44809
|
-
const filePath = resolveSwarmRejectedPath(directory);
|
|
44810
|
-
const existing = await readRejectedLessons(directory);
|
|
44811
|
-
const MAX = 20;
|
|
44812
|
-
const updated = [...existing, lesson];
|
|
44813
|
-
if (updated.length > MAX) {
|
|
44814
|
-
const trimmed = updated.slice(updated.length - MAX);
|
|
44815
|
-
await rewriteKnowledge(filePath, trimmed);
|
|
44816
|
-
} else {
|
|
44817
|
-
await appendKnowledge(filePath, lesson);
|
|
44818
|
-
}
|
|
44819
|
-
}
|
|
44820
|
-
function normalize2(text) {
|
|
44821
|
-
return text.toLowerCase().replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
|
|
44822
|
-
}
|
|
44823
|
-
function wordBigrams(text) {
|
|
44824
|
-
const words = normalize2(text).split(" ").filter(Boolean);
|
|
44825
|
-
const bigrams = new Set;
|
|
44826
|
-
for (let i2 = 0;i2 < words.length - 1; i2++) {
|
|
44827
|
-
bigrams.add(`${words[i2]} ${words[i2 + 1]}`);
|
|
44828
|
-
}
|
|
44829
|
-
return bigrams;
|
|
44830
|
-
}
|
|
44831
|
-
function jaccardBigram(a, b) {
|
|
44832
|
-
if (a.size === 0 && b.size === 0)
|
|
44833
|
-
return 1;
|
|
44834
|
-
const aArr = Array.from(a);
|
|
44835
|
-
const intersection3 = new Set(aArr.filter((x) => b.has(x)));
|
|
44836
|
-
const union3 = new Set([...aArr, ...Array.from(b)]);
|
|
44837
|
-
return intersection3.size / union3.size;
|
|
44838
|
-
}
|
|
44839
|
-
function findNearDuplicate(candidate, entries, threshold = 0.6) {
|
|
44840
|
-
const candidateBigrams = wordBigrams(candidate);
|
|
44841
|
-
return entries.find((entry) => {
|
|
44842
|
-
const entryBigrams = wordBigrams(entry.lesson);
|
|
44843
|
-
return jaccardBigram(candidateBigrams, entryBigrams) >= threshold;
|
|
44844
|
-
});
|
|
44845
|
-
}
|
|
44846
|
-
function computeConfidence(confirmedByCount, autoGenerated) {
|
|
44847
|
-
let score = 0.5;
|
|
44848
|
-
score += Math.min(confirmedByCount, 3) * 0.1;
|
|
44849
|
-
if (!autoGenerated)
|
|
44850
|
-
score += 0.1;
|
|
44851
|
-
return Math.min(score, 1);
|
|
44852
|
-
}
|
|
44853
|
-
function inferTags(lesson) {
|
|
44854
|
-
const lower = lesson.toLowerCase();
|
|
44855
|
-
const tags = [];
|
|
44856
|
-
if (/\b(?:typescript|ts)\b/.test(lower))
|
|
44857
|
-
tags.push("typescript");
|
|
44858
|
-
if (/\b(?:javascript|js)\b/.test(lower))
|
|
44859
|
-
tags.push("javascript");
|
|
44860
|
-
if (/\b(?:python)\b/.test(lower))
|
|
44861
|
-
tags.push("python");
|
|
44862
|
-
if (/\b(?:bun|node|deno)\b/.test(lower))
|
|
44863
|
-
tags.push("runtime");
|
|
44864
|
-
if (/\b(?:react|vue|svelte|angular)\b/.test(lower))
|
|
44865
|
-
tags.push("frontend");
|
|
44866
|
-
if (/\b(?:git|github|gitlab)\b/.test(lower))
|
|
44867
|
-
tags.push("git");
|
|
44868
|
-
if (/\b(?:docker|kubernetes|k8s)\b/.test(lower))
|
|
44869
|
-
tags.push("container");
|
|
44870
|
-
if (/\b(?:sql|postgres|mysql|sqlite)\b/.test(lower))
|
|
44871
|
-
tags.push("database");
|
|
44872
|
-
if (/\b(?:test|spec|vitest|jest|mocha)\b/.test(lower))
|
|
44873
|
-
tags.push("testing");
|
|
44874
|
-
if (/\b(?:ci|cd|pipeline|workflow|action)\b/.test(lower))
|
|
44875
|
-
tags.push("ci-cd");
|
|
44876
|
-
if (/\b(?:security|auth|token|password|encrypt)\b/.test(lower))
|
|
44877
|
-
tags.push("security");
|
|
44878
|
-
if (/\b(?:performance|latency|throughput|cache)\b/.test(lower))
|
|
44879
|
-
tags.push("performance");
|
|
44880
|
-
if (/\b(?:api|rest|graphql|grpc|endpoint)\b/.test(lower))
|
|
44881
|
-
tags.push("api");
|
|
44882
|
-
if (/\b(?:swarm|architect|agent|hook|plan)\b/.test(lower))
|
|
44883
|
-
tags.push("opencode-swarm");
|
|
44884
|
-
return Array.from(new Set(tags));
|
|
44885
|
-
}
|
|
44886
|
-
|
|
44887
|
-
// src/hooks/curator.ts
|
|
45306
|
+
init_knowledge_store();
|
|
44888
45307
|
init_utils2();
|
|
44889
45308
|
var CURATOR_LLM_TIMEOUT_MS = 30000;
|
|
44890
45309
|
function parseKnowledgeRecommendations(llmOutput) {
|
|
@@ -45387,7 +45806,11 @@ async function applyCuratorKnowledgeUpdates(directory, recommendations, _knowled
|
|
|
45387
45806
|
return { applied, skipped };
|
|
45388
45807
|
}
|
|
45389
45808
|
|
|
45809
|
+
// src/hooks/hive-promoter.ts
|
|
45810
|
+
init_knowledge_store();
|
|
45811
|
+
|
|
45390
45812
|
// src/hooks/knowledge-validator.ts
|
|
45813
|
+
init_knowledge_store();
|
|
45391
45814
|
var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
|
|
45392
45815
|
import { appendFile as appendFile2, mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
45393
45816
|
import * as path14 from "path";
|
|
@@ -45993,6 +46416,7 @@ async function promoteFromSwarm(directory, lessonId) {
|
|
|
45993
46416
|
}
|
|
45994
46417
|
|
|
45995
46418
|
// src/commands/curate.ts
|
|
46419
|
+
init_knowledge_store();
|
|
45996
46420
|
async function handleCurateCommand(directory, _args) {
|
|
45997
46421
|
try {
|
|
45998
46422
|
const config3 = KnowledgeConfigSchema.parse({});
|
|
@@ -46021,6 +46445,7 @@ function formatCurationSummary(summary) {
|
|
|
46021
46445
|
}
|
|
46022
46446
|
|
|
46023
46447
|
// src/commands/dark-matter.ts
|
|
46448
|
+
init_knowledge_store();
|
|
46024
46449
|
import path17 from "path";
|
|
46025
46450
|
|
|
46026
46451
|
// src/tools/co-change-analyzer.ts
|
|
@@ -47927,6 +48352,7 @@ async function handleHistoryCommand(directory, _args) {
|
|
|
47927
48352
|
init_schema();
|
|
47928
48353
|
|
|
47929
48354
|
// src/hooks/knowledge-migrator.ts
|
|
48355
|
+
init_knowledge_store();
|
|
47930
48356
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
47931
48357
|
import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
|
|
47932
48358
|
import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
|
|
@@ -48155,6 +48581,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
|
48155
48581
|
}
|
|
48156
48582
|
|
|
48157
48583
|
// src/commands/knowledge.ts
|
|
48584
|
+
init_knowledge_store();
|
|
48158
48585
|
async function handleKnowledgeQuarantineCommand(directory, args2) {
|
|
48159
48586
|
const entryId = args2[0];
|
|
48160
48587
|
if (!entryId) {
|
|
@@ -49212,20 +49639,6 @@ function getCompactionMetrics() {
|
|
|
49212
49639
|
|
|
49213
49640
|
// src/services/context-budget-service.ts
|
|
49214
49641
|
init_utils2();
|
|
49215
|
-
function validateDirectory(directory) {
|
|
49216
|
-
if (!directory || directory.trim() === "") {
|
|
49217
|
-
throw new Error("Invalid directory: empty");
|
|
49218
|
-
}
|
|
49219
|
-
if (/\.\.[/\\]/.test(directory)) {
|
|
49220
|
-
throw new Error("Invalid directory: path traversal detected");
|
|
49221
|
-
}
|
|
49222
|
-
if (directory.startsWith("/") || directory.startsWith("\\")) {
|
|
49223
|
-
throw new Error("Invalid directory: absolute path");
|
|
49224
|
-
}
|
|
49225
|
-
if (/^[A-Za-z]:[\\/]/.test(directory)) {
|
|
49226
|
-
throw new Error("Invalid directory: Windows absolute path");
|
|
49227
|
-
}
|
|
49228
|
-
}
|
|
49229
49642
|
var DEFAULT_CONTEXT_BUDGET_CONFIG = {
|
|
49230
49643
|
enabled: true,
|
|
49231
49644
|
budgetTokens: 40000,
|
|
@@ -52720,7 +53133,7 @@ init_schema();
|
|
|
52720
53133
|
init_manager();
|
|
52721
53134
|
init_detector();
|
|
52722
53135
|
init_manager2();
|
|
52723
|
-
import * as
|
|
53136
|
+
import * as fs26 from "fs";
|
|
52724
53137
|
|
|
52725
53138
|
// src/services/decision-drift-analyzer.ts
|
|
52726
53139
|
init_utils2();
|
|
@@ -53592,6 +54005,13 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
53592
54005
|
const maxInjectionTokens = config3.context_budget?.max_injection_tokens ?? Number.POSITIVE_INFINITY;
|
|
53593
54006
|
let injectedTokens = 0;
|
|
53594
54007
|
const contextContent = await readSwarmFileAsync(directory, "context.md");
|
|
54008
|
+
try {
|
|
54009
|
+
const { scanDocIndex: scanDocIndex2 } = await Promise.resolve().then(() => (init_doc_scan(), exports_doc_scan));
|
|
54010
|
+
const { manifest, cached: cached3 } = await scanDocIndex2(directory);
|
|
54011
|
+
if (!cached3) {
|
|
54012
|
+
warn(`[system-enhancer] Doc manifest generated: ${manifest.files.length} files indexed`);
|
|
54013
|
+
}
|
|
54014
|
+
} catch {}
|
|
53595
54015
|
const scoringEnabled = config3.context_budget?.scoring?.enabled === true;
|
|
53596
54016
|
if (!scoringEnabled) {
|
|
53597
54017
|
let plan2 = null;
|
|
@@ -53623,11 +54043,11 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
53623
54043
|
if (handoffContent) {
|
|
53624
54044
|
const handoffPath = validateSwarmPath(directory, "handoff.md");
|
|
53625
54045
|
const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
|
|
53626
|
-
if (
|
|
54046
|
+
if (fs26.existsSync(consumedPath)) {
|
|
53627
54047
|
warn("Duplicate handoff detected: handoff-consumed.md already exists");
|
|
53628
|
-
|
|
54048
|
+
fs26.unlinkSync(consumedPath);
|
|
53629
54049
|
}
|
|
53630
|
-
|
|
54050
|
+
fs26.renameSync(handoffPath, consumedPath);
|
|
53631
54051
|
const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
|
|
53632
54052
|
The previous model's session ended. Here is your starting context:
|
|
53633
54053
|
|
|
@@ -53773,7 +54193,7 @@ ${handoffBlock}`);
|
|
|
53773
54193
|
const lastHint = session.lastCompactionHint || 0;
|
|
53774
54194
|
for (const threshold of thresholds) {
|
|
53775
54195
|
if (totalToolCalls >= threshold && lastHint < threshold) {
|
|
53776
|
-
const totalToolCallsPlaceholder = "$
|
|
54196
|
+
const totalToolCallsPlaceholder = "${totalToolCalls}";
|
|
53777
54197
|
const messageTemplate = compactionConfig?.message ?? `[SWARM HINT] Session has ${totalToolCallsPlaceholder} tool calls. Consider compacting at next phase boundary to maintain context quality.`;
|
|
53778
54198
|
const message = messageTemplate.replace(totalToolCallsPlaceholder, String(totalToolCalls));
|
|
53779
54199
|
tryInject(message);
|
|
@@ -53908,11 +54328,11 @@ ${budgetWarning}`);
|
|
|
53908
54328
|
if (handoffContent) {
|
|
53909
54329
|
const handoffPath = validateSwarmPath(directory, "handoff.md");
|
|
53910
54330
|
const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
|
|
53911
|
-
if (
|
|
54331
|
+
if (fs26.existsSync(consumedPath)) {
|
|
53912
54332
|
warn("Duplicate handoff detected: handoff-consumed.md already exists");
|
|
53913
|
-
|
|
54333
|
+
fs26.unlinkSync(consumedPath);
|
|
53914
54334
|
}
|
|
53915
|
-
|
|
54335
|
+
fs26.renameSync(handoffPath, consumedPath);
|
|
53916
54336
|
const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
|
|
53917
54337
|
The previous model's session ended. Here is your starting context:
|
|
53918
54338
|
|
|
@@ -54109,7 +54529,7 @@ ${handoffBlock}`;
|
|
|
54109
54529
|
const lastHint_b = session_b.lastCompactionHint || 0;
|
|
54110
54530
|
for (const threshold of thresholds_b) {
|
|
54111
54531
|
if (totalToolCalls_b >= threshold && lastHint_b < threshold) {
|
|
54112
|
-
const totalToolCallsPlaceholder_b = "$
|
|
54532
|
+
const totalToolCallsPlaceholder_b = "${totalToolCalls}";
|
|
54113
54533
|
const messageTemplate_b = compactionConfig_b?.message ?? `[SWARM HINT] Session has ${totalToolCallsPlaceholder_b} tool calls. Consider compacting at next phase boundary to maintain context quality.`;
|
|
54114
54534
|
const compactionText = messageTemplate_b.replace(totalToolCallsPlaceholder_b, String(totalToolCalls_b));
|
|
54115
54535
|
candidates.push({
|
|
@@ -54682,8 +55102,8 @@ function isReadTool(toolName) {
|
|
|
54682
55102
|
}
|
|
54683
55103
|
|
|
54684
55104
|
// src/hooks/incremental-verify.ts
|
|
54685
|
-
import * as
|
|
54686
|
-
import * as
|
|
55105
|
+
import * as fs27 from "fs";
|
|
55106
|
+
import * as path37 from "path";
|
|
54687
55107
|
|
|
54688
55108
|
// src/hooks/spawn-helper.ts
|
|
54689
55109
|
import { spawn } from "child_process";
|
|
@@ -54758,21 +55178,21 @@ function spawnAsync(command, cwd, timeoutMs) {
|
|
|
54758
55178
|
// src/hooks/incremental-verify.ts
|
|
54759
55179
|
var emittedSkipAdvisories = new Set;
|
|
54760
55180
|
function detectPackageManager(projectDir) {
|
|
54761
|
-
if (
|
|
55181
|
+
if (fs27.existsSync(path37.join(projectDir, "bun.lockb")))
|
|
54762
55182
|
return "bun";
|
|
54763
|
-
if (
|
|
55183
|
+
if (fs27.existsSync(path37.join(projectDir, "pnpm-lock.yaml")))
|
|
54764
55184
|
return "pnpm";
|
|
54765
|
-
if (
|
|
55185
|
+
if (fs27.existsSync(path37.join(projectDir, "yarn.lock")))
|
|
54766
55186
|
return "yarn";
|
|
54767
|
-
if (
|
|
55187
|
+
if (fs27.existsSync(path37.join(projectDir, "package-lock.json")))
|
|
54768
55188
|
return "npm";
|
|
54769
55189
|
return "bun";
|
|
54770
55190
|
}
|
|
54771
55191
|
function detectTypecheckCommand(projectDir) {
|
|
54772
|
-
const pkgPath =
|
|
54773
|
-
if (
|
|
55192
|
+
const pkgPath = path37.join(projectDir, "package.json");
|
|
55193
|
+
if (fs27.existsSync(pkgPath)) {
|
|
54774
55194
|
try {
|
|
54775
|
-
const pkg = JSON.parse(
|
|
55195
|
+
const pkg = JSON.parse(fs27.readFileSync(pkgPath, "utf8"));
|
|
54776
55196
|
const scripts = pkg.scripts;
|
|
54777
55197
|
if (scripts?.typecheck) {
|
|
54778
55198
|
const pm = detectPackageManager(projectDir);
|
|
@@ -54786,8 +55206,8 @@ function detectTypecheckCommand(projectDir) {
|
|
|
54786
55206
|
...pkg.dependencies,
|
|
54787
55207
|
...pkg.devDependencies
|
|
54788
55208
|
};
|
|
54789
|
-
if (!deps?.typescript && !
|
|
54790
|
-
const hasTSMarkers = deps?.typescript ||
|
|
55209
|
+
if (!deps?.typescript && !fs27.existsSync(path37.join(projectDir, "tsconfig.json"))) {}
|
|
55210
|
+
const hasTSMarkers = deps?.typescript || fs27.existsSync(path37.join(projectDir, "tsconfig.json"));
|
|
54791
55211
|
if (hasTSMarkers) {
|
|
54792
55212
|
return { command: ["npx", "tsc", "--noEmit"], language: "typescript" };
|
|
54793
55213
|
}
|
|
@@ -54795,17 +55215,17 @@ function detectTypecheckCommand(projectDir) {
|
|
|
54795
55215
|
return null;
|
|
54796
55216
|
}
|
|
54797
55217
|
}
|
|
54798
|
-
if (
|
|
55218
|
+
if (fs27.existsSync(path37.join(projectDir, "go.mod"))) {
|
|
54799
55219
|
return { command: ["go", "vet", "./..."], language: "go" };
|
|
54800
55220
|
}
|
|
54801
|
-
if (
|
|
55221
|
+
if (fs27.existsSync(path37.join(projectDir, "Cargo.toml"))) {
|
|
54802
55222
|
return { command: ["cargo", "check"], language: "rust" };
|
|
54803
55223
|
}
|
|
54804
|
-
if (
|
|
55224
|
+
if (fs27.existsSync(path37.join(projectDir, "pyproject.toml")) || fs27.existsSync(path37.join(projectDir, "requirements.txt")) || fs27.existsSync(path37.join(projectDir, "setup.py"))) {
|
|
54805
55225
|
return { command: null, language: "python" };
|
|
54806
55226
|
}
|
|
54807
55227
|
try {
|
|
54808
|
-
const entries =
|
|
55228
|
+
const entries = fs27.readdirSync(projectDir);
|
|
54809
55229
|
if (entries.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
54810
55230
|
return {
|
|
54811
55231
|
command: ["dotnet", "build", "--no-restore"],
|
|
@@ -54874,9 +55294,10 @@ ${errorSummary}`);
|
|
|
54874
55294
|
}
|
|
54875
55295
|
|
|
54876
55296
|
// src/hooks/knowledge-reader.ts
|
|
55297
|
+
init_knowledge_store();
|
|
54877
55298
|
import { existsSync as existsSync22 } from "fs";
|
|
54878
|
-
import { mkdir as
|
|
54879
|
-
import * as
|
|
55299
|
+
import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
|
|
55300
|
+
import * as path38 from "path";
|
|
54880
55301
|
var JACCARD_THRESHOLD = 0.6;
|
|
54881
55302
|
var HIVE_TIER_BOOST = 0.05;
|
|
54882
55303
|
var SAME_PROJECT_PENALTY = -0.05;
|
|
@@ -54924,16 +55345,16 @@ function inferCategoriesFromPhase(phaseDescription) {
|
|
|
54924
55345
|
return ["process", "tooling"];
|
|
54925
55346
|
}
|
|
54926
55347
|
async function recordLessonsShown(directory, lessonIds, currentPhase) {
|
|
54927
|
-
const shownFile =
|
|
55348
|
+
const shownFile = path38.join(directory, ".swarm", ".knowledge-shown.json");
|
|
54928
55349
|
try {
|
|
54929
55350
|
let shownData = {};
|
|
54930
55351
|
if (existsSync22(shownFile)) {
|
|
54931
|
-
const content = await
|
|
55352
|
+
const content = await readFile6(shownFile, "utf-8");
|
|
54932
55353
|
shownData = JSON.parse(content);
|
|
54933
55354
|
}
|
|
54934
55355
|
shownData[currentPhase] = lessonIds;
|
|
54935
|
-
await
|
|
54936
|
-
await
|
|
55356
|
+
await mkdir6(path38.dirname(shownFile), { recursive: true });
|
|
55357
|
+
await writeFile5(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
|
|
54937
55358
|
} catch {
|
|
54938
55359
|
console.warn("[swarm] Knowledge: failed to record shown lessons");
|
|
54939
55360
|
}
|
|
@@ -55029,12 +55450,12 @@ async function readMergedKnowledge(directory, config3, context) {
|
|
|
55029
55450
|
return topN;
|
|
55030
55451
|
}
|
|
55031
55452
|
async function updateRetrievalOutcome(directory, phaseInfo, phaseSucceeded) {
|
|
55032
|
-
const shownFile =
|
|
55453
|
+
const shownFile = path38.join(directory, ".swarm", ".knowledge-shown.json");
|
|
55033
55454
|
try {
|
|
55034
55455
|
if (!existsSync22(shownFile)) {
|
|
55035
55456
|
return;
|
|
55036
55457
|
}
|
|
55037
|
-
const content = await
|
|
55458
|
+
const content = await readFile6(shownFile, "utf-8");
|
|
55038
55459
|
const shownData = JSON.parse(content);
|
|
55039
55460
|
const shownIds = shownData[phaseInfo];
|
|
55040
55461
|
if (!shownIds || shownIds.length === 0) {
|
|
@@ -55062,7 +55483,7 @@ async function updateRetrievalOutcome(directory, phaseInfo, phaseSucceeded) {
|
|
|
55062
55483
|
const remainingIds = shownIds.filter((id) => !foundInSwarm.has(id));
|
|
55063
55484
|
if (remainingIds.length === 0) {
|
|
55064
55485
|
delete shownData[phaseInfo];
|
|
55065
|
-
await
|
|
55486
|
+
await writeFile5(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
|
|
55066
55487
|
return;
|
|
55067
55488
|
}
|
|
55068
55489
|
const hivePath = resolveHiveKnowledgePath();
|
|
@@ -55083,13 +55504,14 @@ async function updateRetrievalOutcome(directory, phaseInfo, phaseSucceeded) {
|
|
|
55083
55504
|
await rewriteKnowledge(hivePath, hiveEntries);
|
|
55084
55505
|
}
|
|
55085
55506
|
delete shownData[phaseInfo];
|
|
55086
|
-
await
|
|
55507
|
+
await writeFile5(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
|
|
55087
55508
|
} catch {
|
|
55088
55509
|
console.warn("[swarm] Knowledge: failed to update retrieval outcomes");
|
|
55089
55510
|
}
|
|
55090
55511
|
}
|
|
55091
55512
|
|
|
55092
55513
|
// src/hooks/knowledge-curator.ts
|
|
55514
|
+
init_knowledge_store();
|
|
55093
55515
|
init_utils2();
|
|
55094
55516
|
var seenRetroSections = new Map;
|
|
55095
55517
|
function pruneSeenRetroSections() {
|
|
@@ -55416,20 +55838,6 @@ init_manager2();
|
|
|
55416
55838
|
|
|
55417
55839
|
// src/services/run-memory.ts
|
|
55418
55840
|
init_utils2();
|
|
55419
|
-
function validateDirectory2(directory) {
|
|
55420
|
-
if (!directory || directory.trim() === "") {
|
|
55421
|
-
throw new Error("Invalid directory: empty");
|
|
55422
|
-
}
|
|
55423
|
-
if (/\.\.[/\\]/.test(directory)) {
|
|
55424
|
-
throw new Error("Invalid directory: path traversal detected");
|
|
55425
|
-
}
|
|
55426
|
-
if (directory.startsWith("/") || directory.startsWith("\\")) {
|
|
55427
|
-
throw new Error("Invalid directory: absolute path");
|
|
55428
|
-
}
|
|
55429
|
-
if (/^[A-Za-z]:[\\/]/.test(directory)) {
|
|
55430
|
-
throw new Error("Invalid directory: Windows absolute path");
|
|
55431
|
-
}
|
|
55432
|
-
}
|
|
55433
55841
|
var RUN_MEMORY_FILENAME = "run-memory.jsonl";
|
|
55434
55842
|
var MAX_SUMMARY_TOKENS = 500;
|
|
55435
55843
|
function groupByTaskId(entries) {
|
|
@@ -55461,7 +55869,7 @@ function summarizeTask(taskId, entries) {
|
|
|
55461
55869
|
}
|
|
55462
55870
|
}
|
|
55463
55871
|
async function getRunMemorySummary(directory) {
|
|
55464
|
-
|
|
55872
|
+
validateDirectory(directory);
|
|
55465
55873
|
const content = await readSwarmFileAsync(directory, RUN_MEMORY_FILENAME);
|
|
55466
55874
|
if (!content) {
|
|
55467
55875
|
return null;
|
|
@@ -55519,6 +55927,7 @@ Use this data to avoid repeating known failure patterns.`;
|
|
|
55519
55927
|
|
|
55520
55928
|
// src/hooks/knowledge-injector.ts
|
|
55521
55929
|
init_curator_drift();
|
|
55930
|
+
init_knowledge_store();
|
|
55522
55931
|
init_utils2();
|
|
55523
55932
|
function formatStars(confidence) {
|
|
55524
55933
|
if (confidence >= 0.9)
|
|
@@ -55664,7 +56073,7 @@ ${injectionText}`;
|
|
|
55664
56073
|
// src/hooks/scope-guard.ts
|
|
55665
56074
|
init_constants();
|
|
55666
56075
|
init_schema();
|
|
55667
|
-
import * as
|
|
56076
|
+
import * as path40 from "path";
|
|
55668
56077
|
var WRITE_TOOLS = new Set([
|
|
55669
56078
|
"write",
|
|
55670
56079
|
"edit",
|
|
@@ -55726,13 +56135,13 @@ function createScopeGuardHook(config3, directory, injectAdvisory) {
|
|
|
55726
56135
|
}
|
|
55727
56136
|
function isFileInScope(filePath, scopeEntries, directory) {
|
|
55728
56137
|
const dir = directory ?? process.cwd();
|
|
55729
|
-
const resolvedFile =
|
|
56138
|
+
const resolvedFile = path40.resolve(dir, filePath);
|
|
55730
56139
|
return scopeEntries.some((scope) => {
|
|
55731
|
-
const resolvedScope =
|
|
56140
|
+
const resolvedScope = path40.resolve(dir, scope);
|
|
55732
56141
|
if (resolvedFile === resolvedScope)
|
|
55733
56142
|
return true;
|
|
55734
|
-
const rel =
|
|
55735
|
-
return rel.length > 0 && !rel.startsWith("..") && !
|
|
56143
|
+
const rel = path40.relative(resolvedScope, resolvedFile);
|
|
56144
|
+
return rel.length > 0 && !rel.startsWith("..") && !path40.isAbsolute(rel);
|
|
55736
56145
|
});
|
|
55737
56146
|
}
|
|
55738
56147
|
|
|
@@ -55781,8 +56190,8 @@ function createSelfReviewHook(config3, injectAdvisory) {
|
|
|
55781
56190
|
}
|
|
55782
56191
|
|
|
55783
56192
|
// src/hooks/slop-detector.ts
|
|
55784
|
-
import * as
|
|
55785
|
-
import * as
|
|
56193
|
+
import * as fs29 from "fs";
|
|
56194
|
+
import * as path41 from "path";
|
|
55786
56195
|
var WRITE_EDIT_TOOLS = new Set([
|
|
55787
56196
|
"write",
|
|
55788
56197
|
"edit",
|
|
@@ -55827,12 +56236,12 @@ function checkBoilerplateExplosion(content, taskDescription, threshold) {
|
|
|
55827
56236
|
function walkFiles(dir, exts, deadline) {
|
|
55828
56237
|
const results = [];
|
|
55829
56238
|
try {
|
|
55830
|
-
for (const entry of
|
|
56239
|
+
for (const entry of fs29.readdirSync(dir, { withFileTypes: true })) {
|
|
55831
56240
|
if (deadline !== undefined && Date.now() > deadline)
|
|
55832
56241
|
break;
|
|
55833
56242
|
if (entry.isSymbolicLink())
|
|
55834
56243
|
continue;
|
|
55835
|
-
const full =
|
|
56244
|
+
const full = path41.join(dir, entry.name);
|
|
55836
56245
|
if (entry.isDirectory()) {
|
|
55837
56246
|
if (entry.name === "node_modules" || entry.name === ".git")
|
|
55838
56247
|
continue;
|
|
@@ -55847,7 +56256,7 @@ function walkFiles(dir, exts, deadline) {
|
|
|
55847
56256
|
return results;
|
|
55848
56257
|
}
|
|
55849
56258
|
function checkDeadExports(content, projectDir, startTime) {
|
|
55850
|
-
const hasPackageJson =
|
|
56259
|
+
const hasPackageJson = fs29.existsSync(path41.join(projectDir, "package.json"));
|
|
55851
56260
|
if (!hasPackageJson)
|
|
55852
56261
|
return null;
|
|
55853
56262
|
const exportMatches = content.matchAll(/^\+(?:export)\s+(?:function|class|const|type|interface)\s+(\w{3,})/gm);
|
|
@@ -55870,7 +56279,7 @@ function checkDeadExports(content, projectDir, startTime) {
|
|
|
55870
56279
|
if (found || Date.now() - startTime > 480)
|
|
55871
56280
|
break;
|
|
55872
56281
|
try {
|
|
55873
|
-
const text =
|
|
56282
|
+
const text = fs29.readFileSync(file3, "utf-8");
|
|
55874
56283
|
if (importPattern.test(text))
|
|
55875
56284
|
found = true;
|
|
55876
56285
|
importPattern.lastIndex = 0;
|
|
@@ -56003,7 +56412,7 @@ Review before proceeding.`;
|
|
|
56003
56412
|
|
|
56004
56413
|
// src/hooks/steering-consumed.ts
|
|
56005
56414
|
init_utils2();
|
|
56006
|
-
import * as
|
|
56415
|
+
import * as fs30 from "fs";
|
|
56007
56416
|
function recordSteeringConsumed(directory, directiveId) {
|
|
56008
56417
|
try {
|
|
56009
56418
|
const eventsPath = validateSwarmPath(directory, "events.jsonl");
|
|
@@ -56012,7 +56421,7 @@ function recordSteeringConsumed(directory, directiveId) {
|
|
|
56012
56421
|
directiveId,
|
|
56013
56422
|
timestamp: new Date().toISOString()
|
|
56014
56423
|
};
|
|
56015
|
-
|
|
56424
|
+
fs30.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
56016
56425
|
`, "utf-8");
|
|
56017
56426
|
} catch {}
|
|
56018
56427
|
}
|
|
@@ -56409,8 +56818,8 @@ var build_check = createSwarmTool({
|
|
|
56409
56818
|
init_dist();
|
|
56410
56819
|
init_manager();
|
|
56411
56820
|
init_create_tool();
|
|
56412
|
-
import * as
|
|
56413
|
-
import * as
|
|
56821
|
+
import * as fs31 from "fs";
|
|
56822
|
+
import * as path42 from "path";
|
|
56414
56823
|
var EVIDENCE_DIR = ".swarm/evidence";
|
|
56415
56824
|
var TASK_ID_PATTERN2 = /^\d+\.\d+(\.\d+)*$/;
|
|
56416
56825
|
function isValidTaskId3(taskId) {
|
|
@@ -56427,18 +56836,18 @@ function isValidTaskId3(taskId) {
|
|
|
56427
56836
|
return TASK_ID_PATTERN2.test(taskId);
|
|
56428
56837
|
}
|
|
56429
56838
|
function isPathWithinSwarm(filePath, workspaceRoot) {
|
|
56430
|
-
const normalizedWorkspace =
|
|
56431
|
-
const swarmPath =
|
|
56432
|
-
const normalizedPath =
|
|
56839
|
+
const normalizedWorkspace = path42.resolve(workspaceRoot);
|
|
56840
|
+
const swarmPath = path42.join(normalizedWorkspace, ".swarm", "evidence");
|
|
56841
|
+
const normalizedPath = path42.resolve(filePath);
|
|
56433
56842
|
return normalizedPath.startsWith(swarmPath);
|
|
56434
56843
|
}
|
|
56435
56844
|
function readEvidenceFile(evidencePath) {
|
|
56436
|
-
if (!
|
|
56845
|
+
if (!fs31.existsSync(evidencePath)) {
|
|
56437
56846
|
return null;
|
|
56438
56847
|
}
|
|
56439
56848
|
let content;
|
|
56440
56849
|
try {
|
|
56441
|
-
content =
|
|
56850
|
+
content = fs31.readFileSync(evidencePath, "utf-8");
|
|
56442
56851
|
} catch {
|
|
56443
56852
|
return null;
|
|
56444
56853
|
}
|
|
@@ -56492,7 +56901,7 @@ var check_gate_status = createSwarmTool({
|
|
|
56492
56901
|
};
|
|
56493
56902
|
return JSON.stringify(errorResult, null, 2);
|
|
56494
56903
|
}
|
|
56495
|
-
const evidencePath =
|
|
56904
|
+
const evidencePath = path42.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
|
|
56496
56905
|
if (!isPathWithinSwarm(evidencePath, directory)) {
|
|
56497
56906
|
const errorResult = {
|
|
56498
56907
|
taskId: taskIdInput,
|
|
@@ -56584,8 +56993,8 @@ init_checkpoint();
|
|
|
56584
56993
|
// src/tools/completion-verify.ts
|
|
56585
56994
|
init_dist();
|
|
56586
56995
|
init_utils2();
|
|
56587
|
-
import * as
|
|
56588
|
-
import * as
|
|
56996
|
+
import * as fs32 from "fs";
|
|
56997
|
+
import * as path43 from "path";
|
|
56589
56998
|
init_create_tool();
|
|
56590
56999
|
function extractMatches(regex, text) {
|
|
56591
57000
|
return Array.from(text.matchAll(regex));
|
|
@@ -56667,7 +57076,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
56667
57076
|
let plan;
|
|
56668
57077
|
try {
|
|
56669
57078
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
56670
|
-
const planRaw =
|
|
57079
|
+
const planRaw = fs32.readFileSync(planPath, "utf-8");
|
|
56671
57080
|
plan = JSON.parse(planRaw);
|
|
56672
57081
|
} catch {
|
|
56673
57082
|
const result2 = {
|
|
@@ -56718,10 +57127,10 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
56718
57127
|
let foundCount = 0;
|
|
56719
57128
|
let hasFileReadFailure = false;
|
|
56720
57129
|
for (const filePath of fileTargets) {
|
|
56721
|
-
const resolvedPath =
|
|
57130
|
+
const resolvedPath = path43.resolve(directory, filePath);
|
|
56722
57131
|
let fileContent;
|
|
56723
57132
|
try {
|
|
56724
|
-
fileContent =
|
|
57133
|
+
fileContent = fs32.readFileSync(resolvedPath, "utf-8");
|
|
56725
57134
|
} catch {
|
|
56726
57135
|
blockedTasks.push({
|
|
56727
57136
|
task_id: task.id,
|
|
@@ -56763,9 +57172,9 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
56763
57172
|
blockedTasks
|
|
56764
57173
|
};
|
|
56765
57174
|
try {
|
|
56766
|
-
const evidenceDir =
|
|
56767
|
-
const evidencePath =
|
|
56768
|
-
|
|
57175
|
+
const evidenceDir = path43.join(directory, ".swarm", "evidence", `${phase}`);
|
|
57176
|
+
const evidencePath = path43.join(evidenceDir, "completion-verify.json");
|
|
57177
|
+
fs32.mkdirSync(evidenceDir, { recursive: true });
|
|
56769
57178
|
const evidenceBundle = {
|
|
56770
57179
|
schema_version: "1.0.0",
|
|
56771
57180
|
task_id: "completion-verify",
|
|
@@ -56786,7 +57195,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
56786
57195
|
}
|
|
56787
57196
|
]
|
|
56788
57197
|
};
|
|
56789
|
-
|
|
57198
|
+
fs32.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
|
|
56790
57199
|
} catch {}
|
|
56791
57200
|
return JSON.stringify(result, null, 2);
|
|
56792
57201
|
}
|
|
@@ -56826,16 +57235,13 @@ var completion_verify = createSwarmTool({
|
|
|
56826
57235
|
// src/tools/complexity-hotspots.ts
|
|
56827
57236
|
init_dist();
|
|
56828
57237
|
init_create_tool();
|
|
56829
|
-
import * as
|
|
56830
|
-
import * as
|
|
57238
|
+
import * as fs33 from "fs";
|
|
57239
|
+
import * as path44 from "path";
|
|
56831
57240
|
var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
|
|
56832
57241
|
var DEFAULT_DAYS = 90;
|
|
56833
57242
|
var DEFAULT_TOP_N = 20;
|
|
56834
57243
|
var DEFAULT_EXTENSIONS = "ts,tsx,js,jsx,py,rs,ps1";
|
|
56835
57244
|
var SHELL_METACHAR_REGEX = /[;&|%$`\\]/;
|
|
56836
|
-
function containsControlChars3(str) {
|
|
56837
|
-
return /[\0\t\r\n]/.test(str);
|
|
56838
|
-
}
|
|
56839
57245
|
function validateDays(days) {
|
|
56840
57246
|
if (typeof days === "undefined") {
|
|
56841
57247
|
return { valid: true, value: DEFAULT_DAYS, error: null };
|
|
@@ -56867,7 +57273,7 @@ function validateExtensions(extensions) {
|
|
|
56867
57273
|
if (typeof extensions !== "string") {
|
|
56868
57274
|
return { valid: false, value: "", error: "extensions must be a string" };
|
|
56869
57275
|
}
|
|
56870
|
-
if (
|
|
57276
|
+
if (containsControlChars(extensions)) {
|
|
56871
57277
|
return {
|
|
56872
57278
|
valid: false,
|
|
56873
57279
|
value: "",
|
|
@@ -56956,11 +57362,11 @@ function estimateComplexity(content) {
|
|
|
56956
57362
|
}
|
|
56957
57363
|
function getComplexityForFile(filePath) {
|
|
56958
57364
|
try {
|
|
56959
|
-
const stat2 =
|
|
57365
|
+
const stat2 = fs33.statSync(filePath);
|
|
56960
57366
|
if (stat2.size > MAX_FILE_SIZE_BYTES2) {
|
|
56961
57367
|
return null;
|
|
56962
57368
|
}
|
|
56963
|
-
const content =
|
|
57369
|
+
const content = fs33.readFileSync(filePath, "utf-8");
|
|
56964
57370
|
return estimateComplexity(content);
|
|
56965
57371
|
} catch {
|
|
56966
57372
|
return null;
|
|
@@ -56971,7 +57377,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
56971
57377
|
const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
|
|
56972
57378
|
const filteredChurn = new Map;
|
|
56973
57379
|
for (const [file3, count] of churnMap) {
|
|
56974
|
-
const ext =
|
|
57380
|
+
const ext = path44.extname(file3).toLowerCase();
|
|
56975
57381
|
if (extSet.has(ext)) {
|
|
56976
57382
|
filteredChurn.set(file3, count);
|
|
56977
57383
|
}
|
|
@@ -56981,8 +57387,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
56981
57387
|
let analyzedFiles = 0;
|
|
56982
57388
|
for (const [file3, churnCount] of filteredChurn) {
|
|
56983
57389
|
let fullPath = file3;
|
|
56984
|
-
if (!
|
|
56985
|
-
fullPath =
|
|
57390
|
+
if (!fs33.existsSync(fullPath)) {
|
|
57391
|
+
fullPath = path44.join(cwd, file3);
|
|
56986
57392
|
}
|
|
56987
57393
|
const complexity = getComplexityForFile(fullPath);
|
|
56988
57394
|
if (complexity !== null) {
|
|
@@ -57190,8 +57596,8 @@ var curator_analyze = createSwarmTool({
|
|
|
57190
57596
|
});
|
|
57191
57597
|
// src/tools/declare-scope.ts
|
|
57192
57598
|
init_tool();
|
|
57193
|
-
import * as
|
|
57194
|
-
import * as
|
|
57599
|
+
import * as fs34 from "fs";
|
|
57600
|
+
import * as path45 from "path";
|
|
57195
57601
|
init_create_tool();
|
|
57196
57602
|
function validateTaskIdFormat(taskId) {
|
|
57197
57603
|
const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
|
|
@@ -57270,8 +57676,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
57270
57676
|
};
|
|
57271
57677
|
}
|
|
57272
57678
|
}
|
|
57273
|
-
normalizedDir =
|
|
57274
|
-
const pathParts = normalizedDir.split(
|
|
57679
|
+
normalizedDir = path45.normalize(args2.working_directory);
|
|
57680
|
+
const pathParts = normalizedDir.split(path45.sep);
|
|
57275
57681
|
if (pathParts.includes("..")) {
|
|
57276
57682
|
return {
|
|
57277
57683
|
success: false,
|
|
@@ -57281,11 +57687,11 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
57281
57687
|
]
|
|
57282
57688
|
};
|
|
57283
57689
|
}
|
|
57284
|
-
const resolvedDir =
|
|
57690
|
+
const resolvedDir = path45.resolve(normalizedDir);
|
|
57285
57691
|
try {
|
|
57286
|
-
const realPath =
|
|
57287
|
-
const planPath2 =
|
|
57288
|
-
if (!
|
|
57692
|
+
const realPath = fs34.realpathSync(resolvedDir);
|
|
57693
|
+
const planPath2 = path45.join(realPath, ".swarm", "plan.json");
|
|
57694
|
+
if (!fs34.existsSync(planPath2)) {
|
|
57289
57695
|
return {
|
|
57290
57696
|
success: false,
|
|
57291
57697
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -57308,8 +57714,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
57308
57714
|
console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
|
|
57309
57715
|
}
|
|
57310
57716
|
const directory = normalizedDir || fallbackDir;
|
|
57311
|
-
const planPath =
|
|
57312
|
-
if (!
|
|
57717
|
+
const planPath = path45.resolve(directory, ".swarm", "plan.json");
|
|
57718
|
+
if (!fs34.existsSync(planPath)) {
|
|
57313
57719
|
return {
|
|
57314
57720
|
success: false,
|
|
57315
57721
|
message: "No plan found",
|
|
@@ -57318,7 +57724,7 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
57318
57724
|
}
|
|
57319
57725
|
let planContent;
|
|
57320
57726
|
try {
|
|
57321
|
-
planContent = JSON.parse(
|
|
57727
|
+
planContent = JSON.parse(fs34.readFileSync(planPath, "utf-8"));
|
|
57322
57728
|
} catch {
|
|
57323
57729
|
return {
|
|
57324
57730
|
success: false,
|
|
@@ -57643,20 +58049,20 @@ function validateBase(base) {
|
|
|
57643
58049
|
function validatePaths(paths) {
|
|
57644
58050
|
if (!paths)
|
|
57645
58051
|
return null;
|
|
57646
|
-
for (const
|
|
57647
|
-
if (!
|
|
58052
|
+
for (const path46 of paths) {
|
|
58053
|
+
if (!path46 || path46.length === 0) {
|
|
57648
58054
|
return "empty path not allowed";
|
|
57649
58055
|
}
|
|
57650
|
-
if (
|
|
58056
|
+
if (path46.length > MAX_PATH_LENGTH) {
|
|
57651
58057
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
57652
58058
|
}
|
|
57653
|
-
if (SHELL_METACHARACTERS2.test(
|
|
58059
|
+
if (SHELL_METACHARACTERS2.test(path46)) {
|
|
57654
58060
|
return "path contains shell metacharacters";
|
|
57655
58061
|
}
|
|
57656
|
-
if (
|
|
58062
|
+
if (path46.startsWith("-")) {
|
|
57657
58063
|
return 'path cannot start with "-" (option-like arguments not allowed)';
|
|
57658
58064
|
}
|
|
57659
|
-
if (CONTROL_CHAR_PATTERN2.test(
|
|
58065
|
+
if (CONTROL_CHAR_PATTERN2.test(path46)) {
|
|
57660
58066
|
return "path contains control characters";
|
|
57661
58067
|
}
|
|
57662
58068
|
}
|
|
@@ -57737,8 +58143,8 @@ var diff = createSwarmTool({
|
|
|
57737
58143
|
if (parts2.length >= 3) {
|
|
57738
58144
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
57739
58145
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
57740
|
-
const
|
|
57741
|
-
files.push({ path:
|
|
58146
|
+
const path46 = parts2[2];
|
|
58147
|
+
files.push({ path: path46, additions, deletions });
|
|
57742
58148
|
}
|
|
57743
58149
|
}
|
|
57744
58150
|
const contractChanges = [];
|
|
@@ -57833,391 +58239,10 @@ var diff = createSwarmTool({
|
|
|
57833
58239
|
}
|
|
57834
58240
|
}
|
|
57835
58241
|
});
|
|
57836
|
-
|
|
57837
|
-
|
|
57838
|
-
|
|
57839
|
-
|
|
57840
|
-
import * as fs34 from "fs";
|
|
57841
|
-
import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
|
|
57842
|
-
import * as path45 from "path";
|
|
57843
|
-
init_create_tool();
|
|
57844
|
-
var SKIP_DIRECTORIES2 = new Set([
|
|
57845
|
-
"node_modules",
|
|
57846
|
-
".git",
|
|
57847
|
-
".swarm",
|
|
57848
|
-
"dist",
|
|
57849
|
-
"build",
|
|
57850
|
-
".next",
|
|
57851
|
-
"vendor"
|
|
57852
|
-
]);
|
|
57853
|
-
var SKIP_PATTERNS = [/\.test\./, /\.spec\./, /\.d\.ts$/];
|
|
57854
|
-
var MAX_SUMMARY_LENGTH = 200;
|
|
57855
|
-
var MAX_INDEXED_FILES = 100;
|
|
57856
|
-
var READ_LINES_LIMIT = 30;
|
|
57857
|
-
var MIN_LESSON_LENGTH = 15;
|
|
57858
|
-
var MAX_CONSTRAINTS_PER_DOC = 5;
|
|
57859
|
-
var MAX_CONSTRAINT_LENGTH = 200;
|
|
57860
|
-
var RELEVANCE_THRESHOLD = 0.1;
|
|
57861
|
-
var DEDUP_THRESHOLD = 0.6;
|
|
57862
|
-
function normalizeSeparators(filePath) {
|
|
57863
|
-
return filePath.replace(/\\/g, "/");
|
|
57864
|
-
}
|
|
57865
|
-
function matchesDocPattern(filePath, patterns) {
|
|
57866
|
-
const normalizedPath = normalizeSeparators(filePath);
|
|
57867
|
-
const basename5 = path45.basename(filePath);
|
|
57868
|
-
for (const pattern of patterns) {
|
|
57869
|
-
if (!pattern.includes("/") && !pattern.includes("\\")) {
|
|
57870
|
-
if (basename5 === pattern) {
|
|
57871
|
-
return true;
|
|
57872
|
-
}
|
|
57873
|
-
continue;
|
|
57874
|
-
}
|
|
57875
|
-
if (pattern.startsWith("**/")) {
|
|
57876
|
-
const filenamePattern = pattern.slice(3);
|
|
57877
|
-
if (basename5 === filenamePattern) {
|
|
57878
|
-
return true;
|
|
57879
|
-
}
|
|
57880
|
-
continue;
|
|
57881
|
-
}
|
|
57882
|
-
const patternNormalized = normalizeSeparators(pattern);
|
|
57883
|
-
const dirPrefix = patternNormalized.replace(/\/\*\*.*$/, "").replace(/\/\*.*$/, "");
|
|
57884
|
-
if (normalizedPath.startsWith(`${dirPrefix}/`) || normalizedPath === dirPrefix) {
|
|
57885
|
-
return true;
|
|
57886
|
-
}
|
|
57887
|
-
}
|
|
57888
|
-
return false;
|
|
57889
|
-
}
|
|
57890
|
-
function extractTitleAndSummary(content, filename) {
|
|
57891
|
-
const lines = content.split(`
|
|
57892
|
-
`);
|
|
57893
|
-
let title = filename;
|
|
57894
|
-
let summary = "";
|
|
57895
|
-
let foundTitle = false;
|
|
57896
|
-
const potentialSummaryLines = [];
|
|
57897
|
-
for (let i2 = 0;i2 < lines.length && i2 < READ_LINES_LIMIT; i2++) {
|
|
57898
|
-
const line = lines[i2].trim();
|
|
57899
|
-
if (!foundTitle && line.startsWith("# ")) {
|
|
57900
|
-
title = line.slice(2).trim();
|
|
57901
|
-
foundTitle = true;
|
|
57902
|
-
continue;
|
|
57903
|
-
}
|
|
57904
|
-
if (line && !line.startsWith("#")) {
|
|
57905
|
-
potentialSummaryLines.push(line);
|
|
57906
|
-
}
|
|
57907
|
-
}
|
|
57908
|
-
for (const line of potentialSummaryLines) {
|
|
57909
|
-
summary += (summary ? " " : "") + line;
|
|
57910
|
-
if (summary.length >= MAX_SUMMARY_LENGTH) {
|
|
57911
|
-
break;
|
|
57912
|
-
}
|
|
57913
|
-
}
|
|
57914
|
-
if (summary.length > MAX_SUMMARY_LENGTH) {
|
|
57915
|
-
summary = `${summary.slice(0, MAX_SUMMARY_LENGTH - 3)}...`;
|
|
57916
|
-
}
|
|
57917
|
-
return { title, summary };
|
|
57918
|
-
}
|
|
57919
|
-
function stripMarkdown(text) {
|
|
57920
|
-
return text.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/^\s*[-*\u2022]\s+/gm, "").replace(/^\s*\d+\.\s+/gm, "").trim();
|
|
57921
|
-
}
|
|
57922
|
-
async function scanDocIndex(directory) {
|
|
57923
|
-
const manifestPath = path45.join(directory, ".swarm", "doc-manifest.json");
|
|
57924
|
-
const defaultPatterns = DocsConfigSchema.parse({}).doc_patterns;
|
|
57925
|
-
const extraPatterns = [
|
|
57926
|
-
"ARCHITECTURE.md",
|
|
57927
|
-
"CLAUDE.md",
|
|
57928
|
-
"AGENTS.md",
|
|
57929
|
-
".github/*.md",
|
|
57930
|
-
"doc/**/*.md"
|
|
57931
|
-
];
|
|
57932
|
-
const allPatterns = [...defaultPatterns, ...extraPatterns];
|
|
57933
|
-
try {
|
|
57934
|
-
const manifestContent = await readFile6(manifestPath, "utf-8");
|
|
57935
|
-
const existingManifest = JSON.parse(manifestContent);
|
|
57936
|
-
if (existingManifest.schema_version === 1 && existingManifest.files) {
|
|
57937
|
-
let cacheValid = true;
|
|
57938
|
-
for (const file3 of existingManifest.files) {
|
|
57939
|
-
try {
|
|
57940
|
-
const fullPath = path45.join(directory, file3.path);
|
|
57941
|
-
const stat2 = fs34.statSync(fullPath);
|
|
57942
|
-
if (stat2.mtimeMs > new Date(existingManifest.scanned_at).getTime()) {
|
|
57943
|
-
cacheValid = false;
|
|
57944
|
-
break;
|
|
57945
|
-
}
|
|
57946
|
-
} catch {
|
|
57947
|
-
cacheValid = false;
|
|
57948
|
-
break;
|
|
57949
|
-
}
|
|
57950
|
-
}
|
|
57951
|
-
if (cacheValid) {
|
|
57952
|
-
return { manifest: existingManifest, cached: true };
|
|
57953
|
-
}
|
|
57954
|
-
}
|
|
57955
|
-
} catch {}
|
|
57956
|
-
const discoveredFiles = [];
|
|
57957
|
-
let rawEntries;
|
|
57958
|
-
try {
|
|
57959
|
-
rawEntries = fs34.readdirSync(directory, { recursive: true });
|
|
57960
|
-
} catch {
|
|
57961
|
-
const manifest2 = {
|
|
57962
|
-
schema_version: 1,
|
|
57963
|
-
scanned_at: new Date().toISOString(),
|
|
57964
|
-
files: []
|
|
57965
|
-
};
|
|
57966
|
-
return { manifest: manifest2, cached: false };
|
|
57967
|
-
}
|
|
57968
|
-
const entries = rawEntries.filter((e) => typeof e === "string");
|
|
57969
|
-
for (const entry of entries) {
|
|
57970
|
-
const fullPath = path45.join(directory, entry);
|
|
57971
|
-
let stat2;
|
|
57972
|
-
try {
|
|
57973
|
-
stat2 = fs34.statSync(fullPath);
|
|
57974
|
-
} catch {
|
|
57975
|
-
continue;
|
|
57976
|
-
}
|
|
57977
|
-
if (!stat2.isFile())
|
|
57978
|
-
continue;
|
|
57979
|
-
const pathParts = normalizeSeparators(entry).split("/");
|
|
57980
|
-
let skipThisFile = false;
|
|
57981
|
-
for (const part of pathParts) {
|
|
57982
|
-
if (SKIP_DIRECTORIES2.has(part)) {
|
|
57983
|
-
skipThisFile = true;
|
|
57984
|
-
break;
|
|
57985
|
-
}
|
|
57986
|
-
}
|
|
57987
|
-
if (skipThisFile)
|
|
57988
|
-
continue;
|
|
57989
|
-
for (const pattern of SKIP_PATTERNS) {
|
|
57990
|
-
if (pattern.test(entry)) {
|
|
57991
|
-
skipThisFile = true;
|
|
57992
|
-
break;
|
|
57993
|
-
}
|
|
57994
|
-
}
|
|
57995
|
-
if (skipThisFile)
|
|
57996
|
-
continue;
|
|
57997
|
-
if (!matchesDocPattern(entry, allPatterns)) {
|
|
57998
|
-
continue;
|
|
57999
|
-
}
|
|
58000
|
-
let content;
|
|
58001
|
-
try {
|
|
58002
|
-
content = fs34.readFileSync(fullPath, "utf-8");
|
|
58003
|
-
} catch {
|
|
58004
|
-
continue;
|
|
58005
|
-
}
|
|
58006
|
-
const { title, summary } = extractTitleAndSummary(content, path45.basename(entry));
|
|
58007
|
-
const lineCount = content.split(`
|
|
58008
|
-
`).length;
|
|
58009
|
-
discoveredFiles.push({
|
|
58010
|
-
path: entry,
|
|
58011
|
-
title,
|
|
58012
|
-
summary,
|
|
58013
|
-
lines: lineCount,
|
|
58014
|
-
mtime: stat2.mtimeMs
|
|
58015
|
-
});
|
|
58016
|
-
}
|
|
58017
|
-
discoveredFiles.sort((a, b) => a.path.toLowerCase().localeCompare(b.path.toLowerCase()));
|
|
58018
|
-
let truncated = false;
|
|
58019
|
-
if (discoveredFiles.length > MAX_INDEXED_FILES) {
|
|
58020
|
-
discoveredFiles.splice(MAX_INDEXED_FILES);
|
|
58021
|
-
truncated = true;
|
|
58022
|
-
}
|
|
58023
|
-
if (truncated && discoveredFiles.length > 0) {
|
|
58024
|
-
discoveredFiles[0].summary = `[Warning: ${MAX_INDEXED_FILES}+ docs found, listing first ${MAX_INDEXED_FILES}] ` + discoveredFiles[0].summary;
|
|
58025
|
-
}
|
|
58026
|
-
const manifest = {
|
|
58027
|
-
schema_version: 1,
|
|
58028
|
-
scanned_at: new Date().toISOString(),
|
|
58029
|
-
files: discoveredFiles
|
|
58030
|
-
};
|
|
58031
|
-
try {
|
|
58032
|
-
await mkdir6(path45.dirname(manifestPath), { recursive: true });
|
|
58033
|
-
await writeFile5(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
58034
|
-
} catch {}
|
|
58035
|
-
return { manifest, cached: false };
|
|
58036
|
-
}
|
|
58037
|
-
var CONSTRAINT_PATTERNS = [
|
|
58038
|
-
/\bMUST\b/,
|
|
58039
|
-
/\bMUST NOT\b/,
|
|
58040
|
-
/\bSHOULD\b/,
|
|
58041
|
-
/\bSHOULD NOT\b/,
|
|
58042
|
-
/\bDO NOT\b/,
|
|
58043
|
-
/\bALWAYS\b/,
|
|
58044
|
-
/\bNEVER\b/,
|
|
58045
|
-
/\bREQUIRED\b/
|
|
58046
|
-
];
|
|
58047
|
-
var ACTION_WORDS = /\b(must|should|don't|avoid|ensure|use|follow)\b/i;
|
|
58048
|
-
function isConstraintLine(line) {
|
|
58049
|
-
const upperLine = line.toUpperCase();
|
|
58050
|
-
for (const pattern of CONSTRAINT_PATTERNS) {
|
|
58051
|
-
if (pattern.test(upperLine)) {
|
|
58052
|
-
return true;
|
|
58053
|
-
}
|
|
58054
|
-
}
|
|
58055
|
-
if (/^\s*[-*\u2022]/.test(line) && ACTION_WORDS.test(line)) {
|
|
58056
|
-
return true;
|
|
58057
|
-
}
|
|
58058
|
-
return false;
|
|
58059
|
-
}
|
|
58060
|
-
function extractConstraintsFromContent(content) {
|
|
58061
|
-
const lines = content.split(`
|
|
58062
|
-
`);
|
|
58063
|
-
const constraints = [];
|
|
58064
|
-
for (const line of lines) {
|
|
58065
|
-
if (constraints.length >= MAX_CONSTRAINTS_PER_DOC) {
|
|
58066
|
-
break;
|
|
58067
|
-
}
|
|
58068
|
-
const trimmed = line.trim();
|
|
58069
|
-
if (!trimmed)
|
|
58070
|
-
continue;
|
|
58071
|
-
if (isConstraintLine(trimmed)) {
|
|
58072
|
-
const cleaned = stripMarkdown(trimmed);
|
|
58073
|
-
const len = cleaned.length;
|
|
58074
|
-
if (len >= MIN_LESSON_LENGTH && len <= MAX_CONSTRAINT_LENGTH) {
|
|
58075
|
-
constraints.push(cleaned);
|
|
58076
|
-
}
|
|
58077
|
-
}
|
|
58078
|
-
}
|
|
58079
|
-
return constraints;
|
|
58080
|
-
}
|
|
58081
|
-
async function extractDocConstraints(directory, taskFiles, taskDescription) {
|
|
58082
|
-
const manifestPath = path45.join(directory, ".swarm", "doc-manifest.json");
|
|
58083
|
-
let manifest;
|
|
58084
|
-
try {
|
|
58085
|
-
const content = await readFile6(manifestPath, "utf-8");
|
|
58086
|
-
manifest = JSON.parse(content);
|
|
58087
|
-
} catch {
|
|
58088
|
-
const result = await scanDocIndex(directory);
|
|
58089
|
-
manifest = result.manifest;
|
|
58090
|
-
}
|
|
58091
|
-
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
58092
|
-
const existingEntries = await readKnowledge(knowledgePath);
|
|
58093
|
-
const taskContext = [...taskFiles, taskDescription].join(" ");
|
|
58094
|
-
const taskBigrams = wordBigrams(normalize2(taskContext));
|
|
58095
|
-
let extractedCount = 0;
|
|
58096
|
-
let skippedCount = 0;
|
|
58097
|
-
const details = [];
|
|
58098
|
-
for (const docFile of manifest.files) {
|
|
58099
|
-
const docContext = `${docFile.path} ${docFile.title} ${docFile.summary}`;
|
|
58100
|
-
const docBigrams = wordBigrams(normalize2(docContext));
|
|
58101
|
-
const score = jaccardBigram(taskBigrams, docBigrams);
|
|
58102
|
-
if (score <= RELEVANCE_THRESHOLD) {
|
|
58103
|
-
skippedCount++;
|
|
58104
|
-
continue;
|
|
58105
|
-
}
|
|
58106
|
-
let fullContent;
|
|
58107
|
-
try {
|
|
58108
|
-
fullContent = await readFile6(path45.join(directory, docFile.path), "utf-8");
|
|
58109
|
-
} catch {
|
|
58110
|
-
skippedCount++;
|
|
58111
|
-
continue;
|
|
58112
|
-
}
|
|
58113
|
-
const constraints = extractConstraintsFromContent(fullContent);
|
|
58114
|
-
if (constraints.length === 0) {
|
|
58115
|
-
skippedCount++;
|
|
58116
|
-
continue;
|
|
58117
|
-
}
|
|
58118
|
-
const docDetails = {
|
|
58119
|
-
path: docFile.path,
|
|
58120
|
-
score,
|
|
58121
|
-
constraints: []
|
|
58122
|
-
};
|
|
58123
|
-
for (const constraint of constraints) {
|
|
58124
|
-
const duplicate = findNearDuplicate(constraint, existingEntries, DEDUP_THRESHOLD);
|
|
58125
|
-
if (!duplicate) {
|
|
58126
|
-
const entry = {
|
|
58127
|
-
id: crypto4.randomUUID(),
|
|
58128
|
-
tier: "swarm",
|
|
58129
|
-
lesson: constraint,
|
|
58130
|
-
category: "architecture",
|
|
58131
|
-
tags: ["doc-scan", path45.basename(docFile.path)],
|
|
58132
|
-
scope: "global",
|
|
58133
|
-
confidence: 0.5,
|
|
58134
|
-
status: "candidate",
|
|
58135
|
-
confirmed_by: [],
|
|
58136
|
-
project_name: "",
|
|
58137
|
-
retrieval_outcomes: {
|
|
58138
|
-
applied_count: 0,
|
|
58139
|
-
succeeded_after_count: 0,
|
|
58140
|
-
failed_after_count: 0
|
|
58141
|
-
},
|
|
58142
|
-
schema_version: 1,
|
|
58143
|
-
created_at: new Date().toISOString(),
|
|
58144
|
-
updated_at: new Date().toISOString(),
|
|
58145
|
-
auto_generated: true,
|
|
58146
|
-
hive_eligible: false
|
|
58147
|
-
};
|
|
58148
|
-
await appendKnowledge(knowledgePath, entry);
|
|
58149
|
-
existingEntries.push(entry);
|
|
58150
|
-
extractedCount++;
|
|
58151
|
-
docDetails.constraints.push(constraint);
|
|
58152
|
-
}
|
|
58153
|
-
}
|
|
58154
|
-
if (docDetails.constraints.length > 0) {
|
|
58155
|
-
details.push(docDetails);
|
|
58156
|
-
} else {
|
|
58157
|
-
skippedCount++;
|
|
58158
|
-
}
|
|
58159
|
-
}
|
|
58160
|
-
return { extracted: extractedCount, skipped: skippedCount, details };
|
|
58161
|
-
}
|
|
58162
|
-
var doc_scan = createSwarmTool({
|
|
58163
|
-
description: "Scan project documentation files and build an index manifest. Caches results in .swarm/doc-manifest.json for fast subsequent scans.",
|
|
58164
|
-
args: {
|
|
58165
|
-
force: tool.schema.boolean().optional().describe("Force re-scan even if cache is valid")
|
|
58166
|
-
},
|
|
58167
|
-
execute: async (args2, directory) => {
|
|
58168
|
-
let force = false;
|
|
58169
|
-
try {
|
|
58170
|
-
if (args2 && typeof args2 === "object") {
|
|
58171
|
-
const obj = args2;
|
|
58172
|
-
if (obj.force === true)
|
|
58173
|
-
force = true;
|
|
58174
|
-
}
|
|
58175
|
-
} catch {}
|
|
58176
|
-
if (force) {
|
|
58177
|
-
const manifestPath = path45.join(directory, ".swarm", "doc-manifest.json");
|
|
58178
|
-
try {
|
|
58179
|
-
fs34.unlinkSync(manifestPath);
|
|
58180
|
-
} catch {}
|
|
58181
|
-
}
|
|
58182
|
-
const { manifest, cached: cached3 } = await scanDocIndex(directory);
|
|
58183
|
-
return JSON.stringify({
|
|
58184
|
-
success: true,
|
|
58185
|
-
files_count: manifest.files.length,
|
|
58186
|
-
cached: cached3,
|
|
58187
|
-
manifest
|
|
58188
|
-
}, null, 2);
|
|
58189
|
-
}
|
|
58190
|
-
});
|
|
58191
|
-
var doc_extract = createSwarmTool({
|
|
58192
|
-
description: "Extract actionable constraints from project documentation relevant to the current task. Scans docs via doc-manifest, scores relevance via Jaccard bigram similarity, and stores non-duplicate constraints in .swarm/knowledge.jsonl.",
|
|
58193
|
-
args: {
|
|
58194
|
-
task_files: tool.schema.array(tool.schema.string()).describe("List of file paths involved in the current task"),
|
|
58195
|
-
task_description: tool.schema.string().describe("Description of the current task")
|
|
58196
|
-
},
|
|
58197
|
-
execute: async (args2, directory) => {
|
|
58198
|
-
let taskFiles = [];
|
|
58199
|
-
let taskDescription = "";
|
|
58200
|
-
try {
|
|
58201
|
-
if (args2 && typeof args2 === "object") {
|
|
58202
|
-
const obj = args2;
|
|
58203
|
-
if (Array.isArray(obj.task_files)) {
|
|
58204
|
-
taskFiles = obj.task_files.filter((f) => typeof f === "string");
|
|
58205
|
-
}
|
|
58206
|
-
if (typeof obj.task_description === "string") {
|
|
58207
|
-
taskDescription = obj.task_description;
|
|
58208
|
-
}
|
|
58209
|
-
}
|
|
58210
|
-
} catch {}
|
|
58211
|
-
if (taskFiles.length === 0 && !taskDescription) {
|
|
58212
|
-
return JSON.stringify({
|
|
58213
|
-
success: false,
|
|
58214
|
-
error: "task_files or task_description is required"
|
|
58215
|
-
});
|
|
58216
|
-
}
|
|
58217
|
-
const result = await extractDocConstraints(directory, taskFiles, taskDescription);
|
|
58218
|
-
return JSON.stringify({ success: true, ...result }, null, 2);
|
|
58219
|
-
}
|
|
58220
|
-
});
|
|
58242
|
+
|
|
58243
|
+
// src/tools/index.ts
|
|
58244
|
+
init_doc_scan();
|
|
58245
|
+
|
|
58221
58246
|
// src/tools/domain-detector.ts
|
|
58222
58247
|
init_tool();
|
|
58223
58248
|
var DOMAIN_PATTERNS = {
|
|
@@ -58416,11 +58441,8 @@ var LEGACY_EVIDENCE_ALIAS_MAP = {
|
|
|
58416
58441
|
function normalizeEvidenceType(type) {
|
|
58417
58442
|
return LEGACY_EVIDENCE_ALIAS_MAP[type.toLowerCase()] || type;
|
|
58418
58443
|
}
|
|
58419
|
-
function containsControlChars4(str) {
|
|
58420
|
-
return /[\0\t\r\n]/.test(str);
|
|
58421
|
-
}
|
|
58422
58444
|
function validateRequiredTypes(input) {
|
|
58423
|
-
if (
|
|
58445
|
+
if (containsControlChars(input)) {
|
|
58424
58446
|
return "required_types contains control characters";
|
|
58425
58447
|
}
|
|
58426
58448
|
if (SHELL_METACHAR_REGEX2.test(input)) {
|
|
@@ -58859,12 +58881,6 @@ var BINARY_SIGNATURES2 = [
|
|
|
58859
58881
|
var BINARY_PREFIX_BYTES2 = 4;
|
|
58860
58882
|
var BINARY_NULL_CHECK_BYTES2 = 8192;
|
|
58861
58883
|
var BINARY_NULL_THRESHOLD2 = 0.1;
|
|
58862
|
-
function containsPathTraversal3(str) {
|
|
58863
|
-
return /\.\.[/\\]/.test(str);
|
|
58864
|
-
}
|
|
58865
|
-
function containsControlChars5(str) {
|
|
58866
|
-
return /[\0\t\r\n]/.test(str);
|
|
58867
|
-
}
|
|
58868
58884
|
function validateFileInput(file3) {
|
|
58869
58885
|
if (!file3 || file3.length === 0) {
|
|
58870
58886
|
return "file is required";
|
|
@@ -58872,10 +58888,10 @@ function validateFileInput(file3) {
|
|
|
58872
58888
|
if (file3.length > MAX_FILE_PATH_LENGTH2) {
|
|
58873
58889
|
return `file exceeds maximum length of ${MAX_FILE_PATH_LENGTH2}`;
|
|
58874
58890
|
}
|
|
58875
|
-
if (
|
|
58891
|
+
if (containsControlChars(file3)) {
|
|
58876
58892
|
return "file contains control characters";
|
|
58877
58893
|
}
|
|
58878
|
-
if (
|
|
58894
|
+
if (containsPathTraversal(file3)) {
|
|
58879
58895
|
return "file contains path traversal";
|
|
58880
58896
|
}
|
|
58881
58897
|
return null;
|
|
@@ -58887,10 +58903,10 @@ function validateSymbolInput(symbol3) {
|
|
|
58887
58903
|
if (symbol3.length > MAX_SYMBOL_LENGTH) {
|
|
58888
58904
|
return `symbol exceeds maximum length of ${MAX_SYMBOL_LENGTH}`;
|
|
58889
58905
|
}
|
|
58890
|
-
if (
|
|
58906
|
+
if (containsControlChars(symbol3)) {
|
|
58891
58907
|
return "symbol contains control characters";
|
|
58892
58908
|
}
|
|
58893
|
-
if (
|
|
58909
|
+
if (containsPathTraversal(symbol3)) {
|
|
58894
58910
|
return "symbol contains path traversal";
|
|
58895
58911
|
}
|
|
58896
58912
|
return null;
|
|
@@ -59202,6 +59218,7 @@ var imports = createSwarmTool({
|
|
|
59202
59218
|
});
|
|
59203
59219
|
// src/tools/knowledge-add.ts
|
|
59204
59220
|
init_dist();
|
|
59221
|
+
init_knowledge_store();
|
|
59205
59222
|
init_manager2();
|
|
59206
59223
|
init_create_tool();
|
|
59207
59224
|
var VALID_CATEGORIES2 = [
|
|
@@ -59315,8 +59332,9 @@ var knowledgeAdd = createSwarmTool({
|
|
|
59315
59332
|
});
|
|
59316
59333
|
// src/tools/knowledge-query.ts
|
|
59317
59334
|
init_dist();
|
|
59318
|
-
|
|
59335
|
+
init_knowledge_store();
|
|
59319
59336
|
init_create_tool();
|
|
59337
|
+
import { existsSync as existsSync30 } from "fs";
|
|
59320
59338
|
var DEFAULT_LIMIT = 10;
|
|
59321
59339
|
var MAX_LESSON_LENGTH = 200;
|
|
59322
59340
|
var VALID_CATEGORIES3 = [
|
|
@@ -59544,6 +59562,7 @@ var knowledge_query = createSwarmTool({
|
|
|
59544
59562
|
});
|
|
59545
59563
|
// src/tools/knowledge-recall.ts
|
|
59546
59564
|
init_dist();
|
|
59565
|
+
init_knowledge_store();
|
|
59547
59566
|
init_create_tool();
|
|
59548
59567
|
var knowledgeRecall = createSwarmTool({
|
|
59549
59568
|
description: "Search the knowledge base for relevant past decisions, patterns, and lessons learned. Returns ranked results by semantic similarity.",
|
|
@@ -59627,6 +59646,7 @@ var knowledgeRecall = createSwarmTool({
|
|
|
59627
59646
|
});
|
|
59628
59647
|
// src/tools/knowledge-remove.ts
|
|
59629
59648
|
init_dist();
|
|
59649
|
+
init_knowledge_store();
|
|
59630
59650
|
init_create_tool();
|
|
59631
59651
|
var knowledgeRemove = createSwarmTool({
|
|
59632
59652
|
description: "Delete an outdated knowledge entry by ID. Double-deletion is idempotent \u2014 removing a non-existent entry returns a clear message without error.",
|
|
@@ -63340,7 +63360,7 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
63340
63360
|
}
|
|
63341
63361
|
return null;
|
|
63342
63362
|
}
|
|
63343
|
-
function
|
|
63363
|
+
function validateDirectory2(dir, workspaceDir) {
|
|
63344
63364
|
if (!dir || dir.length === 0) {
|
|
63345
63365
|
return "directory is required";
|
|
63346
63366
|
}
|
|
@@ -63697,7 +63717,7 @@ async function runQualityBudgetWrapped(changedFiles, directory, _config) {
|
|
|
63697
63717
|
async function runPreCheckBatch(input, workspaceDir, contextDir) {
|
|
63698
63718
|
const effectiveWorkspaceDir = workspaceDir || input.directory || contextDir;
|
|
63699
63719
|
const { files, directory, sast_threshold = "medium", config: config3 } = input;
|
|
63700
|
-
const dirError =
|
|
63720
|
+
const dirError = validateDirectory2(directory, effectiveWorkspaceDir);
|
|
63701
63721
|
if (dirError) {
|
|
63702
63722
|
warn(`pre_check_batch: Invalid directory: ${dirError}`);
|
|
63703
63723
|
return {
|
|
@@ -63908,7 +63928,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
63908
63928
|
}
|
|
63909
63929
|
const resolvedDirectory = path53.resolve(typedArgs.directory);
|
|
63910
63930
|
const workspaceAnchor = resolvedDirectory;
|
|
63911
|
-
const dirError =
|
|
63931
|
+
const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
|
|
63912
63932
|
if (dirError) {
|
|
63913
63933
|
const errorResult = {
|
|
63914
63934
|
gates_passed: false,
|
|
@@ -65638,15 +65658,6 @@ var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
|
65638
65658
|
function containsControlCharacters(str) {
|
|
65639
65659
|
return /[\0\t\n\r]/.test(str);
|
|
65640
65660
|
}
|
|
65641
|
-
function containsPathTraversal4(str) {
|
|
65642
|
-
if (/^\/|^[A-Za-z]:[/\\]|\.\.[/\\]|\.\.$|~\/|^\\/.test(str)) {
|
|
65643
|
-
return true;
|
|
65644
|
-
}
|
|
65645
|
-
if (str.includes("%2e%2e") || str.includes("%2E%2E")) {
|
|
65646
|
-
return true;
|
|
65647
|
-
}
|
|
65648
|
-
return false;
|
|
65649
|
-
}
|
|
65650
65661
|
function containsWindowsAttacks(str) {
|
|
65651
65662
|
if (/:[^\\/]/.test(str)) {
|
|
65652
65663
|
return true;
|
|
@@ -65920,7 +65931,7 @@ var symbols = createSwarmTool({
|
|
|
65920
65931
|
symbols: []
|
|
65921
65932
|
}, null, 2);
|
|
65922
65933
|
}
|
|
65923
|
-
if (
|
|
65934
|
+
if (containsPathTraversal(file3)) {
|
|
65924
65935
|
return JSON.stringify({
|
|
65925
65936
|
file: file3,
|
|
65926
65937
|
error: "Path contains path traversal sequence",
|
|
@@ -66023,17 +66034,11 @@ var PRIORITY_MAP = {
|
|
|
66023
66034
|
NOTE: "low"
|
|
66024
66035
|
};
|
|
66025
66036
|
var SHELL_METACHAR_REGEX3 = /[;&|%$`\\]/;
|
|
66026
|
-
function containsPathTraversal5(str) {
|
|
66027
|
-
return /\.\.[/\\]/.test(str);
|
|
66028
|
-
}
|
|
66029
|
-
function containsControlChars6(str) {
|
|
66030
|
-
return /[\0\t\r\n]/.test(str);
|
|
66031
|
-
}
|
|
66032
66037
|
function validateTagsInput(tags) {
|
|
66033
66038
|
if (!tags || tags.length === 0) {
|
|
66034
66039
|
return "tags cannot be empty";
|
|
66035
66040
|
}
|
|
66036
|
-
if (
|
|
66041
|
+
if (containsControlChars(tags)) {
|
|
66037
66042
|
return "tags contains control characters";
|
|
66038
66043
|
}
|
|
66039
66044
|
if (SHELL_METACHAR_REGEX3.test(tags)) {
|
|
@@ -66048,10 +66053,10 @@ function validatePathsInput(paths, cwd) {
|
|
|
66048
66053
|
if (!paths || paths.length === 0) {
|
|
66049
66054
|
return { error: null, resolvedPath: cwd };
|
|
66050
66055
|
}
|
|
66051
|
-
if (
|
|
66056
|
+
if (containsControlChars(paths)) {
|
|
66052
66057
|
return { error: "paths contains control characters", resolvedPath: null };
|
|
66053
66058
|
}
|
|
66054
|
-
if (
|
|
66059
|
+
if (containsPathTraversal(paths)) {
|
|
66055
66060
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
66056
66061
|
}
|
|
66057
66062
|
try {
|