opencode-swarm 7.0.0 → 7.0.2
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/README.md +4 -3
- package/dist/__tests__/convene-general-council.test.d.ts +4 -2
- package/dist/agents/council-prompts.d.ts +26 -0
- package/dist/agents/council-prompts.test.d.ts +9 -0
- package/dist/agents/council-registration.test.d.ts +23 -0
- package/dist/agents/index.d.ts +1 -2
- package/dist/cli/index.d.ts +30 -0
- package/dist/cli/index.js +300 -73
- package/dist/commands/registry.d.ts +3 -3
- package/dist/commands/reset.d.ts +1 -1
- package/dist/config/cache-paths.d.ts +6 -0
- package/dist/config/constants.d.ts +2 -2
- package/dist/council/general-council-advisory.d.ts +1 -1
- package/dist/council/general-council-types.d.ts +44 -17
- package/dist/index.js +683 -686
- package/dist/plan/checkpoint.d.ts +2 -2
- package/dist/tools/checkpoint.d.ts +10 -0
- package/dist/tools/convene-general-council.d.ts +5 -4
- package/dist/tools/web-search.d.ts +1 -1
- package/package.json +1 -1
- package/dist/agents/council-member.d.ts +0 -30
- package/dist/agents/council-member.test.d.ts +0 -8
- package/dist/agents/council-moderator.d.ts +0 -20
package/dist/index.js
CHANGED
|
@@ -33,7 +33,7 @@ var package_default;
|
|
|
33
33
|
var init_package = __esm(() => {
|
|
34
34
|
package_default = {
|
|
35
35
|
name: "opencode-swarm",
|
|
36
|
-
version: "7.0.
|
|
36
|
+
version: "7.0.2",
|
|
37
37
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
38
38
|
main: "dist/index.js",
|
|
39
39
|
types: "dist/index.d.ts",
|
|
@@ -245,8 +245,9 @@ var init_constants = __esm(() => {
|
|
|
245
245
|
"critic_hallucination_verifier",
|
|
246
246
|
"curator_init",
|
|
247
247
|
"curator_phase",
|
|
248
|
-
"
|
|
249
|
-
"
|
|
248
|
+
"council_generalist",
|
|
249
|
+
"council_skeptic",
|
|
250
|
+
"council_domain_expert",
|
|
250
251
|
...QA_AGENTS,
|
|
251
252
|
...PIPELINE_AGENTS
|
|
252
253
|
];
|
|
@@ -319,7 +320,8 @@ var init_constants = __esm(() => {
|
|
|
319
320
|
"repo_map",
|
|
320
321
|
"get_qa_gate_profile",
|
|
321
322
|
"set_qa_gates",
|
|
322
|
-
"convene_general_council"
|
|
323
|
+
"convene_general_council",
|
|
324
|
+
"web_search"
|
|
323
325
|
],
|
|
324
326
|
explorer: [
|
|
325
327
|
"complexity_hotspots",
|
|
@@ -470,8 +472,9 @@ var init_constants = __esm(() => {
|
|
|
470
472
|
],
|
|
471
473
|
curator_init: ["knowledge_recall"],
|
|
472
474
|
curator_phase: ["knowledge_recall"],
|
|
473
|
-
|
|
474
|
-
|
|
475
|
+
council_generalist: [],
|
|
476
|
+
council_skeptic: [],
|
|
477
|
+
council_domain_expert: []
|
|
475
478
|
};
|
|
476
479
|
WRITE_TOOL_NAMES = [
|
|
477
480
|
"write",
|
|
@@ -533,8 +536,8 @@ var init_constants = __esm(() => {
|
|
|
533
536
|
gitingest: "fetch a GitHub repository full content via gitingest.com",
|
|
534
537
|
retrieve_summary: "retrieve the full content of a stored tool output summary",
|
|
535
538
|
search: "Workspace-scoped ripgrep-style text search with structured JSON output. Supports literal and regex modes, glob filtering, and result limits. NOTE: This is text search, not structural AST search — use symbols and imports tools for structural queries.",
|
|
536
|
-
web_search: "External web search (Tavily or Brave) for
|
|
537
|
-
convene_general_council: "Synthesize responses from a multi-model General Council. Accepts parallel member responses (Round 1, optionally Round 2), detects disagreements, and returns consensus points, persisting disagreements, a structured synthesis
|
|
539
|
+
web_search: "External web search (Tavily or Brave) for architect-driven council research. Returns titled results with snippets and URLs. Config-gated on council.general.enabled; requires a search API key. Used by the architect in MODE: COUNCIL to gather a RESEARCH CONTEXT before dispatching council agents.",
|
|
540
|
+
convene_general_council: "Synthesize responses from a multi-model General Council. Accepts parallel member responses (Round 1, optionally Round 2), detects disagreements, and returns consensus points, persisting disagreements, and a structured synthesis. Architect-only. Config-gated on council.general.enabled.",
|
|
538
541
|
batch_symbols: "Batched symbol extraction across multiple files. Returns per-file symbol summaries with isolated error handling.",
|
|
539
542
|
suggest_patch: "Reviewer-safe structured patch suggestion tool. Produces context-anchored patch artifacts without file modification. Returns structured diagnostics on context mismatch.",
|
|
540
543
|
lint_spec: "validate .swarm/spec.md format and required fields",
|
|
@@ -565,8 +568,6 @@ var init_constants = __esm(() => {
|
|
|
565
568
|
designer: "opencode/big-pickle",
|
|
566
569
|
curator_init: "opencode/big-pickle",
|
|
567
570
|
curator_phase: "opencode/big-pickle",
|
|
568
|
-
council_member: "opencode/big-pickle",
|
|
569
|
-
council_moderator: "opencode/big-pickle",
|
|
570
571
|
default: "opencode/big-pickle"
|
|
571
572
|
};
|
|
572
573
|
DEFAULT_SCORING_CONFIG = {
|
|
@@ -16750,7 +16751,7 @@ async function loadPlan(directory) {
|
|
|
16750
16751
|
const rebuilt = await replayFromLedger(directory);
|
|
16751
16752
|
if (rebuilt) {
|
|
16752
16753
|
await rebuildPlan(directory, rebuilt);
|
|
16753
|
-
warn("[loadPlan] Rebuilt plan from ledger. Checkpoint available at SWARM_PLAN.md if it exists.");
|
|
16754
|
+
warn("[loadPlan] Rebuilt plan from ledger. Checkpoint available at .swarm/SWARM_PLAN.md if it exists.");
|
|
16754
16755
|
return rebuilt;
|
|
16755
16756
|
}
|
|
16756
16757
|
} catch (replayError) {
|
|
@@ -16771,7 +16772,7 @@ async function loadPlan(directory) {
|
|
|
16771
16772
|
return approved.plan;
|
|
16772
16773
|
}
|
|
16773
16774
|
} catch {}
|
|
16774
|
-
warn(`[loadPlan] Ledger replay failed during hash-mismatch rebuild: ${replayError instanceof Error ? replayError.message : String(replayError)}. Returning stale plan.json. To recover: check SWARM_PLAN.md for a checkpoint, or run /swarm reset-session.`);
|
|
16775
|
+
warn(`[loadPlan] Ledger replay failed during hash-mismatch rebuild: ${replayError instanceof Error ? replayError.message : String(replayError)}. Returning stale plan.json. To recover: check .swarm/SWARM_PLAN.md for a checkpoint, or run /swarm reset-session.`);
|
|
16775
16776
|
}
|
|
16776
16777
|
}
|
|
16777
16778
|
}
|
|
@@ -16817,7 +16818,7 @@ async function loadPlan(directory) {
|
|
|
16817
16818
|
}
|
|
16818
16819
|
return validated;
|
|
16819
16820
|
} catch (error49) {
|
|
16820
|
-
warn(`[loadPlan] plan.json validation failed: ${error49 instanceof Error ? error49.message : String(error49)}. Attempting rebuild from ledger. If rebuild fails, check SWARM_PLAN.md for a checkpoint.`);
|
|
16821
|
+
warn(`[loadPlan] plan.json validation failed: ${error49 instanceof Error ? error49.message : String(error49)}. Attempting rebuild from ledger. If rebuild fails, check .swarm/SWARM_PLAN.md for a checkpoint.`);
|
|
16821
16822
|
let rawPlanId = null;
|
|
16822
16823
|
try {
|
|
16823
16824
|
const rawParsed = JSON.parse(planJsonContent);
|
|
@@ -39463,6 +39464,7 @@ var init_create_tool = __esm(() => {
|
|
|
39463
39464
|
// src/tools/checkpoint.ts
|
|
39464
39465
|
var exports_checkpoint = {};
|
|
39465
39466
|
__export(exports_checkpoint, {
|
|
39467
|
+
saveCheckpointRecord: () => saveCheckpointRecord,
|
|
39466
39468
|
checkpoint: () => checkpoint
|
|
39467
39469
|
});
|
|
39468
39470
|
import * as child_process from "node:child_process";
|
|
@@ -39617,6 +39619,38 @@ function handleSave(label, directory) {
|
|
|
39617
39619
|
}, null, 2);
|
|
39618
39620
|
}
|
|
39619
39621
|
}
|
|
39622
|
+
function saveCheckpointRecord(label, directory) {
|
|
39623
|
+
const labelError = validateLabel(label);
|
|
39624
|
+
if (labelError) {
|
|
39625
|
+
return { success: false, error: labelError };
|
|
39626
|
+
}
|
|
39627
|
+
try {
|
|
39628
|
+
const log2 = readCheckpointLog(directory);
|
|
39629
|
+
if (log2.checkpoints.find((c) => c.label === label)) {
|
|
39630
|
+
return { success: false, error: `duplicate label: "${label}"` };
|
|
39631
|
+
}
|
|
39632
|
+
let sha = "";
|
|
39633
|
+
if (isGitRepo()) {
|
|
39634
|
+
try {
|
|
39635
|
+
sha = getCurrentSha();
|
|
39636
|
+
} catch {
|
|
39637
|
+
sha = "";
|
|
39638
|
+
}
|
|
39639
|
+
}
|
|
39640
|
+
log2.checkpoints.push({
|
|
39641
|
+
label,
|
|
39642
|
+
sha,
|
|
39643
|
+
timestamp: new Date().toISOString()
|
|
39644
|
+
});
|
|
39645
|
+
writeCheckpointLog(log2, directory);
|
|
39646
|
+
return { success: true, sha };
|
|
39647
|
+
} catch (e) {
|
|
39648
|
+
return {
|
|
39649
|
+
success: false,
|
|
39650
|
+
error: e instanceof Error ? e.message : "unknown error"
|
|
39651
|
+
};
|
|
39652
|
+
}
|
|
39653
|
+
}
|
|
39620
39654
|
function handleRestore(label, directory) {
|
|
39621
39655
|
try {
|
|
39622
39656
|
const log2 = readCheckpointLog(directory);
|
|
@@ -41933,7 +41967,7 @@ async function handleCloseCommand(directory, args2) {
|
|
|
41933
41967
|
try {
|
|
41934
41968
|
const evidenceDir = path18.join(swarmDir, "evidence");
|
|
41935
41969
|
const evidenceEntries = await fs12.readdir(evidenceDir);
|
|
41936
|
-
const retroDirs = evidenceEntries.filter((e) => e.startsWith("retro-"));
|
|
41970
|
+
const retroDirs = evidenceEntries.filter((e) => e.startsWith("retro-")).sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
|
|
41937
41971
|
for (const retroDir of retroDirs) {
|
|
41938
41972
|
const evidencePath = path18.join(evidenceDir, retroDir, "evidence.json");
|
|
41939
41973
|
try {
|
|
@@ -42084,22 +42118,20 @@ async function handleCloseCommand(directory, args2) {
|
|
|
42084
42118
|
}
|
|
42085
42119
|
} catch {}
|
|
42086
42120
|
let swarmPlanFilesRemoved = 0;
|
|
42087
|
-
const
|
|
42088
|
-
|
|
42089
|
-
|
|
42090
|
-
|
|
42091
|
-
|
|
42092
|
-
|
|
42093
|
-
|
|
42094
|
-
|
|
42095
|
-
|
|
42096
|
-
|
|
42097
|
-
|
|
42098
|
-
|
|
42099
|
-
|
|
42100
|
-
|
|
42101
|
-
if (err2?.code !== "ENOENT") {
|
|
42102
|
-
warnings.push(`Failed to remove SWARM_PLAN.md: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
42121
|
+
const candidates = [
|
|
42122
|
+
path18.join(directory, ".swarm", "SWARM_PLAN.json"),
|
|
42123
|
+
path18.join(directory, ".swarm", "SWARM_PLAN.md"),
|
|
42124
|
+
path18.join(directory, "SWARM_PLAN.json"),
|
|
42125
|
+
path18.join(directory, "SWARM_PLAN.md")
|
|
42126
|
+
];
|
|
42127
|
+
for (const candidate of candidates) {
|
|
42128
|
+
try {
|
|
42129
|
+
await fs12.unlink(candidate);
|
|
42130
|
+
swarmPlanFilesRemoved++;
|
|
42131
|
+
} catch (err2) {
|
|
42132
|
+
if (err2?.code !== "ENOENT") {
|
|
42133
|
+
warnings.push(`Failed to remove ${path18.basename(candidate)}: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
42134
|
+
}
|
|
42103
42135
|
}
|
|
42104
42136
|
}
|
|
42105
42137
|
clearAllScopes(directory);
|
|
@@ -42174,9 +42206,7 @@ async function handleCloseCommand(directory, args2) {
|
|
|
42174
42206
|
"- Reset context.md for next session",
|
|
42175
42207
|
"- Cleared agent sessions and delegation chains",
|
|
42176
42208
|
...configBackupsRemoved > 0 ? [`- Removed ${configBackupsRemoved} stale config backup file(s)`] : [],
|
|
42177
|
-
...swarmPlanFilesRemoved > 0 ? [
|
|
42178
|
-
`- Removed ${swarmPlanFilesRemoved} root-level SWARM_PLAN checkpoint artifact(s)`
|
|
42179
|
-
] : [],
|
|
42209
|
+
...swarmPlanFilesRemoved > 0 ? [`- Removed ${swarmPlanFilesRemoved} SWARM_PLAN checkpoint artifact(s)`] : [],
|
|
42180
42210
|
...planExists && !planAlreadyDone ? ["- Set non-completed phases/tasks to closed status"] : [],
|
|
42181
42211
|
...curationSucceeded && allLessons.length > 0 ? [`- Committed ${allLessons.length} lesson(s) to knowledge store`] : [],
|
|
42182
42212
|
"",
|
|
@@ -44094,11 +44124,21 @@ function getPluginConfigDir() {
|
|
|
44094
44124
|
function getPluginCachePaths() {
|
|
44095
44125
|
const cacheBase = process.env.XDG_CACHE_HOME || path24.join(os5.homedir(), ".cache");
|
|
44096
44126
|
const configDir = getPluginConfigDir();
|
|
44097
|
-
|
|
44127
|
+
const paths = [
|
|
44128
|
+
path24.join(cacheBase, "opencode", "node_modules", "opencode-swarm"),
|
|
44098
44129
|
path24.join(cacheBase, "opencode", "packages", "opencode-swarm@latest"),
|
|
44099
|
-
path24.join(configDir, "node_modules", "opencode-swarm")
|
|
44100
|
-
path24.join(cacheBase, "opencode", "node_modules", "opencode-swarm")
|
|
44130
|
+
path24.join(configDir, "node_modules", "opencode-swarm")
|
|
44101
44131
|
];
|
|
44132
|
+
if (process.platform === "darwin") {
|
|
44133
|
+
const libCaches = path24.join(os5.homedir(), "Library", "Caches");
|
|
44134
|
+
paths.push(path24.join(libCaches, "opencode", "node_modules", "opencode-swarm"), path24.join(libCaches, "opencode", "packages", "opencode-swarm@latest"));
|
|
44135
|
+
}
|
|
44136
|
+
if (process.platform === "win32") {
|
|
44137
|
+
const localAppData = process.env.LOCALAPPDATA || path24.join(os5.homedir(), "AppData", "Local");
|
|
44138
|
+
const appData = process.env.APPDATA || path24.join(os5.homedir(), "AppData", "Roaming");
|
|
44139
|
+
paths.push(path24.join(localAppData, "opencode", "node_modules", "opencode-swarm"), path24.join(localAppData, "opencode", "packages", "opencode-swarm@latest"), path24.join(appData, "opencode", "node_modules", "opencode-swarm"));
|
|
44140
|
+
}
|
|
44141
|
+
return paths;
|
|
44102
44142
|
}
|
|
44103
44143
|
var init_cache_paths = () => {};
|
|
44104
44144
|
|
|
@@ -49224,6 +49264,13 @@ function parseGitRemoteUrl2(remoteUrl) {
|
|
|
49224
49264
|
repo: sshMatch[2].replace(/\.git$/, "")
|
|
49225
49265
|
};
|
|
49226
49266
|
}
|
|
49267
|
+
const pathMatch = remoteUrl.match(/\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
|
|
49268
|
+
if (pathMatch) {
|
|
49269
|
+
return {
|
|
49270
|
+
owner: pathMatch[1],
|
|
49271
|
+
repo: pathMatch[2].replace(/\.git$/, "")
|
|
49272
|
+
};
|
|
49273
|
+
}
|
|
49227
49274
|
return null;
|
|
49228
49275
|
}
|
|
49229
49276
|
function handlePrReviewCommand(_directory, args2) {
|
|
@@ -53940,13 +53987,14 @@ var init_manager3 = __esm(() => {
|
|
|
53940
53987
|
|
|
53941
53988
|
// src/commands/reset.ts
|
|
53942
53989
|
import * as fs25 from "node:fs";
|
|
53990
|
+
import * as path38 from "node:path";
|
|
53943
53991
|
async function handleResetCommand(directory, args2) {
|
|
53944
53992
|
const hasConfirm = args2.includes("--confirm");
|
|
53945
53993
|
if (!hasConfirm) {
|
|
53946
53994
|
return [
|
|
53947
53995
|
"## Swarm Reset",
|
|
53948
53996
|
"",
|
|
53949
|
-
"⚠️ This will delete
|
|
53997
|
+
"⚠️ This will delete all swarm state from .swarm/ (plan, context, checkpoints, SWARM_PLAN artifacts)",
|
|
53950
53998
|
"",
|
|
53951
53999
|
"**Tip**: Run `/swarm export` first to backup your state.",
|
|
53952
54000
|
"",
|
|
@@ -53954,7 +54002,15 @@ async function handleResetCommand(directory, args2) {
|
|
|
53954
54002
|
].join(`
|
|
53955
54003
|
`);
|
|
53956
54004
|
}
|
|
53957
|
-
const filesToReset = [
|
|
54005
|
+
const filesToReset = [
|
|
54006
|
+
"plan.md",
|
|
54007
|
+
"plan.json",
|
|
54008
|
+
"context.md",
|
|
54009
|
+
"SWARM_PLAN.md",
|
|
54010
|
+
"SWARM_PLAN.json",
|
|
54011
|
+
"checkpoints.json",
|
|
54012
|
+
"events.jsonl"
|
|
54013
|
+
];
|
|
53958
54014
|
const results = [];
|
|
53959
54015
|
for (const filename of filesToReset) {
|
|
53960
54016
|
try {
|
|
@@ -53969,6 +54025,15 @@ async function handleResetCommand(directory, args2) {
|
|
|
53969
54025
|
results.push(`- ❌ Failed to delete ${filename}`);
|
|
53970
54026
|
}
|
|
53971
54027
|
}
|
|
54028
|
+
for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
|
|
54029
|
+
try {
|
|
54030
|
+
const rootPath = path38.join(directory, filename);
|
|
54031
|
+
if (fs25.existsSync(rootPath)) {
|
|
54032
|
+
fs25.unlinkSync(rootPath);
|
|
54033
|
+
results.push(`- ✅ Deleted ${filename} (root)`);
|
|
54034
|
+
}
|
|
54035
|
+
} catch {}
|
|
54036
|
+
}
|
|
53972
54037
|
try {
|
|
53973
54038
|
resetAutomationManager();
|
|
53974
54039
|
results.push("- ✅ Stopped background automation (in-memory queues cleared)");
|
|
@@ -54002,7 +54067,7 @@ var init_reset = __esm(() => {
|
|
|
54002
54067
|
|
|
54003
54068
|
// src/commands/reset-session.ts
|
|
54004
54069
|
import * as fs26 from "node:fs";
|
|
54005
|
-
import * as
|
|
54070
|
+
import * as path39 from "node:path";
|
|
54006
54071
|
async function handleResetSessionCommand(directory, _args) {
|
|
54007
54072
|
const results = [];
|
|
54008
54073
|
try {
|
|
@@ -54017,13 +54082,13 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
54017
54082
|
results.push("❌ Failed to delete state.json");
|
|
54018
54083
|
}
|
|
54019
54084
|
try {
|
|
54020
|
-
const sessionDir =
|
|
54085
|
+
const sessionDir = path39.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
54021
54086
|
if (fs26.existsSync(sessionDir)) {
|
|
54022
54087
|
const files = fs26.readdirSync(sessionDir);
|
|
54023
54088
|
const otherFiles = files.filter((f) => f !== "state.json");
|
|
54024
54089
|
let deletedCount = 0;
|
|
54025
54090
|
for (const file3 of otherFiles) {
|
|
54026
|
-
const filePath =
|
|
54091
|
+
const filePath = path39.join(sessionDir, file3);
|
|
54027
54092
|
if (fs26.lstatSync(filePath).isFile()) {
|
|
54028
54093
|
fs26.unlinkSync(filePath);
|
|
54029
54094
|
deletedCount++;
|
|
@@ -54056,7 +54121,7 @@ var init_reset_session = __esm(() => {
|
|
|
54056
54121
|
|
|
54057
54122
|
// src/summaries/manager.ts
|
|
54058
54123
|
import { mkdirSync as mkdirSync13, readdirSync as readdirSync10, renameSync as renameSync10, rmSync as rmSync4, statSync as statSync10 } from "node:fs";
|
|
54059
|
-
import * as
|
|
54124
|
+
import * as path40 from "node:path";
|
|
54060
54125
|
function sanitizeSummaryId(id) {
|
|
54061
54126
|
if (!id || id.length === 0) {
|
|
54062
54127
|
throw new Error("Invalid summary ID: empty string");
|
|
@@ -54090,9 +54155,9 @@ async function storeSummary(directory, id, fullOutput, summaryText, maxStoredByt
|
|
|
54090
54155
|
if (serializedSize > maxStoredBytes) {
|
|
54091
54156
|
throw new Error(`Summary entry size (${serializedSize} bytes) exceeds maximum (${maxStoredBytes} bytes)`);
|
|
54092
54157
|
}
|
|
54093
|
-
const relativePath =
|
|
54158
|
+
const relativePath = path40.join("summaries", `${sanitizedId}.json`);
|
|
54094
54159
|
const summaryPath = validateSwarmPath(directory, relativePath);
|
|
54095
|
-
const summaryDir =
|
|
54160
|
+
const summaryDir = path40.dirname(summaryPath);
|
|
54096
54161
|
const entry = {
|
|
54097
54162
|
id: sanitizedId,
|
|
54098
54163
|
summaryText,
|
|
@@ -54102,7 +54167,7 @@ async function storeSummary(directory, id, fullOutput, summaryText, maxStoredByt
|
|
|
54102
54167
|
};
|
|
54103
54168
|
const entryJson = JSON.stringify(entry);
|
|
54104
54169
|
mkdirSync13(summaryDir, { recursive: true });
|
|
54105
|
-
const tempPath =
|
|
54170
|
+
const tempPath = path40.join(summaryDir, `${sanitizedId}.json.tmp.${Date.now()}.${process.pid}`);
|
|
54106
54171
|
try {
|
|
54107
54172
|
await Bun.write(tempPath, entryJson);
|
|
54108
54173
|
renameSync10(tempPath, summaryPath);
|
|
@@ -54115,7 +54180,7 @@ async function storeSummary(directory, id, fullOutput, summaryText, maxStoredByt
|
|
|
54115
54180
|
}
|
|
54116
54181
|
async function loadFullOutput(directory, id) {
|
|
54117
54182
|
const sanitizedId = sanitizeSummaryId(id);
|
|
54118
|
-
const relativePath =
|
|
54183
|
+
const relativePath = path40.join("summaries", `${sanitizedId}.json`);
|
|
54119
54184
|
validateSwarmPath(directory, relativePath);
|
|
54120
54185
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
54121
54186
|
if (content === null) {
|
|
@@ -54177,7 +54242,7 @@ var init_retrieve = __esm(() => {
|
|
|
54177
54242
|
|
|
54178
54243
|
// src/commands/rollback.ts
|
|
54179
54244
|
import * as fs27 from "node:fs";
|
|
54180
|
-
import * as
|
|
54245
|
+
import * as path41 from "node:path";
|
|
54181
54246
|
async function handleRollbackCommand(directory, args2) {
|
|
54182
54247
|
const phaseArg = args2[0];
|
|
54183
54248
|
if (!phaseArg) {
|
|
@@ -54242,8 +54307,8 @@ async function handleRollbackCommand(directory, args2) {
|
|
|
54242
54307
|
if (EXCLUDE_FILES.has(file3) || file3.startsWith("plan-ledger.archived-")) {
|
|
54243
54308
|
continue;
|
|
54244
54309
|
}
|
|
54245
|
-
const src =
|
|
54246
|
-
const dest =
|
|
54310
|
+
const src = path41.join(checkpointDir, file3);
|
|
54311
|
+
const dest = path41.join(swarmDir, file3);
|
|
54247
54312
|
try {
|
|
54248
54313
|
fs27.cpSync(src, dest, { recursive: true, force: true });
|
|
54249
54314
|
successes.push(file3);
|
|
@@ -54262,12 +54327,12 @@ async function handleRollbackCommand(directory, args2) {
|
|
|
54262
54327
|
].join(`
|
|
54263
54328
|
`);
|
|
54264
54329
|
}
|
|
54265
|
-
const existingLedgerPath =
|
|
54330
|
+
const existingLedgerPath = path41.join(swarmDir, "plan-ledger.jsonl");
|
|
54266
54331
|
if (fs27.existsSync(existingLedgerPath)) {
|
|
54267
54332
|
fs27.unlinkSync(existingLedgerPath);
|
|
54268
54333
|
}
|
|
54269
54334
|
try {
|
|
54270
|
-
const planJsonPath =
|
|
54335
|
+
const planJsonPath = path41.join(swarmDir, "plan.json");
|
|
54271
54336
|
if (fs27.existsSync(planJsonPath)) {
|
|
54272
54337
|
const planRaw = fs27.readFileSync(planJsonPath, "utf-8");
|
|
54273
54338
|
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
@@ -54345,9 +54410,9 @@ async function handleSimulateCommand(directory, args2) {
|
|
|
54345
54410
|
const report = reportLines.filter(Boolean).join(`
|
|
54346
54411
|
`);
|
|
54347
54412
|
const fs28 = await import("node:fs/promises");
|
|
54348
|
-
const
|
|
54349
|
-
const reportPath =
|
|
54350
|
-
await fs28.mkdir(
|
|
54413
|
+
const path42 = await import("node:path");
|
|
54414
|
+
const reportPath = path42.join(directory, ".swarm", "simulate-report.md");
|
|
54415
|
+
await fs28.mkdir(path42.dirname(reportPath), { recursive: true });
|
|
54351
54416
|
await fs28.writeFile(reportPath, report, "utf-8");
|
|
54352
54417
|
return `${darkMatterPairs.length} hidden coupling pairs detected`;
|
|
54353
54418
|
}
|
|
@@ -54366,7 +54431,7 @@ async function handleSpecifyCommand(_directory, args2) {
|
|
|
54366
54431
|
|
|
54367
54432
|
// src/services/compaction-service.ts
|
|
54368
54433
|
import * as fs28 from "node:fs";
|
|
54369
|
-
import * as
|
|
54434
|
+
import * as path42 from "node:path";
|
|
54370
54435
|
function makeInitialState() {
|
|
54371
54436
|
return {
|
|
54372
54437
|
lastObservationAt: 0,
|
|
@@ -54388,7 +54453,7 @@ function getSessionState(sessionId) {
|
|
|
54388
54453
|
}
|
|
54389
54454
|
function appendSnapshot(directory, tier, budgetPct, message) {
|
|
54390
54455
|
try {
|
|
54391
|
-
const snapshotPath =
|
|
54456
|
+
const snapshotPath = path42.join(directory, ".swarm", "context-snapshot.md");
|
|
54392
54457
|
const timestamp = new Date().toISOString();
|
|
54393
54458
|
const entry = `
|
|
54394
54459
|
## [${tier.toUpperCase()}] ${timestamp} — ${budgetPct.toFixed(1)}% used
|
|
@@ -55060,9 +55125,9 @@ var init_registry = __esm(() => {
|
|
|
55060
55125
|
},
|
|
55061
55126
|
council: {
|
|
55062
55127
|
handler: (ctx) => handleCouncilCommand(ctx.directory, ctx.args),
|
|
55063
|
-
description: "Enter architect MODE: COUNCIL — multi-model deliberation [question] [--
|
|
55064
|
-
args: "<question> [--
|
|
55065
|
-
details: "Triggers the architect to convene a
|
|
55128
|
+
description: "Enter architect MODE: COUNCIL — multi-model deliberation [question] [--spec-review]",
|
|
55129
|
+
args: "<question> [--spec-review]",
|
|
55130
|
+
details: "Triggers the architect to convene a three-agent General Council: " + "Generalist (reviewer model), Skeptic (critic model), and Domain Expert (SME model). " + "The architect first runs 1–3 targeted web searches and passes a compiled RESEARCH CONTEXT " + "to all three agents before dispatching them in parallel. " + "Agents deliberate using the NSED peer-review protocol (Round 1 independent analysis, " + "Round 2 MAINTAIN/CONCEDE/NUANCE for disagreements). " + "The architect synthesizes the final answer directly from convene_general_council output. " + "--spec-review switches to single-pass advisory mode for spec review. " + "Requires council.general.enabled: true and a search API key in opencode-swarm.json."
|
|
55066
55131
|
},
|
|
55067
55132
|
"pr-review": {
|
|
55068
55133
|
handler: async (ctx) => handlePrReviewCommand(ctx.directory, ctx.args),
|
|
@@ -55305,7 +55370,7 @@ Present the ten gates with their defaults (DEFAULT_QA_GATES) as a single user-fa
|
|
|
55305
55370
|
- council_mode (default: OFF) — multi-member council gate (recommended for high-impact architecture, public APIs, schema/data mutation, security-sensitive code)
|
|
55306
55371
|
- hallucination_guard (default: OFF) — when enabled, mandatory per-phase API/signature/claim/citation verification via critic_hallucination_verifier at PHASE-WRAP; phase_complete will REJECT phase completion unless .swarm/evidence/{phase}/hallucination-guard.json exists with an APPROVED verdict (recommended for claim-heavy or research-heavy work)
|
|
55307
55372
|
- mutation_test (default: OFF) — when enabled, runs mutation testing on source files touched this phase via generate_mutants + mutation_test + write_mutation_evidence at PHASE-WRAP; FAIL verdict blocks phase_complete; WARN is non-blocking (recommended for projects with coverage gaps or safety-critical code)
|
|
55308
|
-
- council_general_review (default: OFF) — when enabled, MODE: SPECIFY runs convene_general_council on the draft spec before the critic-gate;
|
|
55373
|
+
- council_general_review (default: OFF) — when enabled, MODE: SPECIFY runs convene_general_council on the draft spec before the critic-gate; the architect runs a curated web_search pass, dispatches council_generalist / council_skeptic / council_domain_expert in parallel with a shared RESEARCH CONTEXT block, deliberates on disagreements, and synthesizes the result directly into the spec (recommended for novel architecture, unclear best practices, or high-risk design decisions). Requires council.general.enabled: true and a configured search API key.
|
|
55309
55374
|
- drift_check (default: ON) — when enabled, mandatory per-phase drift verification via critic_drift_verifier at PHASE-WRAP; compares implemented changes against spec.md intent; hard-blocks phase_complete when spec.md exists and drift evidence is missing or REJECTED; advisory-only when no spec.md exists (recommended for all projects with a specification)
|
|
55310
55375
|
|
|
55311
55376
|
One question, one message, defaults pre-stated. Wait for the user's answer.`;
|
|
@@ -56140,13 +56205,13 @@ Read the elected QA gates (parse the \`## Pending QA Gate Selection\` section fr
|
|
|
56140
56205
|
|
|
56141
56206
|
If \`council_general_review\` is true:
|
|
56142
56207
|
1. Read \`council.general\` config. If \`council.general.enabled\` is not true OR no search API key is configured, surface to the user: "council_general_review gate is enabled but the General Council is not configured. Set council.general.enabled: true and configure a search API key in opencode-swarm.json, or unset council_general_review and re-run." Then stop.
|
|
56143
|
-
2.
|
|
56144
|
-
3.
|
|
56145
|
-
4. Collect all
|
|
56208
|
+
2. Run the Research Phase: formulate 1–3 targeted \`web_search\` queries grounded in the spec's domain, then compile a RESEARCH CONTEXT block (same format as MODE: COUNCIL step 2). If web_search fails, proceed without a context block.
|
|
56209
|
+
3. Dispatch \`{{AGENT_PREFIX}}council_generalist\`, \`{{AGENT_PREFIX}}council_skeptic\`, and \`{{AGENT_PREFIX}}council_domain_expert\` in PARALLEL — one message per agent, then STOP and wait. Pass: the spec text as the question, round number 1, the RESEARCH CONTEXT block, and the instruction "Cite from the RESEARCH CONTEXT for external evidence. Your memberId and role are hardcoded in your system prompt." Do NOT share other agents' perspectives at this stage.
|
|
56210
|
+
4. Collect all three JSON responses.
|
|
56146
56211
|
5. Call \`convene_general_council\` with mode: 'spec_review', the spec as question, and the collected \`round1Responses\`. Omit \`round2Responses\` — spec review is a single-pass advisory, not a full deliberation.
|
|
56147
56212
|
6. Read \`consensusPoints\` — incorporate unambiguous consensus directly into the spec.
|
|
56148
56213
|
7. Read \`disagreements\` — for each: (a) accept one position with rationale, (b) mark as \`[NEEDS CLARIFICATION]\` in the spec, or (c) schedule an SME consultation.
|
|
56149
|
-
8.
|
|
56214
|
+
8. Synthesize the final spec-review answer directly from the \`synthesis\` returned by \`convene_general_council\`. Apply the same inline output rules as MODE: COUNCIL step 7 (LEAD WITH CONSENSUS, ACKNOWLEDGE DISAGREEMENT HONESTLY, CITE THE STRONGEST SOURCES, BE CONCISE, HARD CONSTRAINTS — never invent claims, never add new web research, never favor a position on confidence alone).
|
|
56150
56215
|
9. Revise \`.swarm/spec.md\` to reflect the council input.
|
|
56151
56216
|
|
|
56152
56217
|
<!-- BEHAVIORAL_GUIDANCE_START -->
|
|
@@ -56157,8 +56222,8 @@ SPECIFY-COUNCIL-REVIEW RULES:
|
|
|
56157
56222
|
→ WRONG when gate is true: the user enabled this gate for a reason. Run it regardless.
|
|
56158
56223
|
✗ "I'll include round2Responses for spec_review — more is better"
|
|
56159
56224
|
→ WRONG: spec review is a single advisory pass. Omit \`round2Responses\` for spec_review mode.
|
|
56160
|
-
✗ "I'll skip the
|
|
56161
|
-
→ WRONG
|
|
56225
|
+
✗ "I'll skip the Research Phase to save time"
|
|
56226
|
+
→ WRONG: the council agents have no tools and depend on the architect-supplied RESEARCH CONTEXT for external evidence. Skipping the pre-search degrades every downstream agent's grounding.
|
|
56162
56227
|
<!-- BEHAVIORAL_GUIDANCE_END -->
|
|
56163
56228
|
|
|
56164
56229
|
7. Report a summary to the user (MUST count, SHALL count, scenario count, clarification markers, elected QA gates) and suggest the next step: \`CLARIFY-SPEC\` (if markers exist) or \`PLAN\`.
|
|
@@ -56331,36 +56396,54 @@ GREENFIELD EXEMPTION: If the work is purely greenfield (new project, no existing
|
|
|
56331
56396
|
|
|
56332
56397
|
### MODE: COUNCIL
|
|
56333
56398
|
|
|
56334
|
-
Activates when: user invokes \`/swarm council <question>\` (optionally with \`--
|
|
56399
|
+
Activates when: user invokes \`/swarm council <question>\` (optionally with \`--spec-review\`).
|
|
56335
56400
|
|
|
56336
|
-
Purpose: convene a
|
|
56401
|
+
Purpose: convene a fixed three-agent multi-model General Council (generalist / skeptic / domain expert) for an advisory deliberation. The architect runs a curated web research pass upfront, dispatches the three agents in parallel with the gathered RESEARCH CONTEXT, routes any disagreements back for one targeted reconciliation round, and synthesizes the final user-facing answer directly.
|
|
56337
56402
|
|
|
56338
56403
|
This mode is ADVISORY — it does NOT block any other workflow and does NOT modify code, plans, or specs. The output is for the user (general mode) or for the spec being drafted in MODE: SPECIFY (spec_review mode, gated by \`council_general_review\`).
|
|
56339
56404
|
|
|
56340
56405
|
#### Pre-flight (always run first)
|
|
56341
56406
|
1. Read \`council.general\` config. If \`council.general.enabled\` is not true OR no search API key is configured (neither \`council.general.searchApiKey\` nor the corresponding env var \`TAVILY_API_KEY\` / \`BRAVE_SEARCH_API_KEY\`), surface to the user: "General Council is not enabled. Set council.general.enabled: true and configure a search API key in opencode-swarm.json." Then STOP.
|
|
56342
56407
|
|
|
56343
|
-
####
|
|
56344
|
-
2.
|
|
56345
|
-
|
|
56346
|
-
|
|
56408
|
+
#### Research Phase (always run — before dispatching council agents)
|
|
56409
|
+
2. Formulate 1–3 targeted \`web_search\` queries that best capture the information needed to answer the question. Prefer specific, keyword-focused queries over broad ones. Call \`web_search\` for each query. Compile all results into a RESEARCH CONTEXT block in this format:
|
|
56410
|
+
\`\`\`
|
|
56411
|
+
RESEARCH CONTEXT
|
|
56412
|
+
================
|
|
56413
|
+
[1] <title> — <url>
|
|
56414
|
+
<snippet>
|
|
56415
|
+
|
|
56416
|
+
[2] <title> — <url>
|
|
56417
|
+
<snippet>
|
|
56418
|
+
...
|
|
56419
|
+
\`\`\`
|
|
56420
|
+
If \`web_search\` returns no results or an error (check \`result.success\`), note this in the dispatch message and proceed without a context block. Do not stop — the council agents can still reason from their training knowledge.
|
|
56421
|
+
|
|
56422
|
+
#### Round 1 — Parallel Independent Analysis
|
|
56423
|
+
3. Dispatch \`{{AGENT_PREFIX}}council_generalist\`, \`{{AGENT_PREFIX}}council_skeptic\`, and \`{{AGENT_PREFIX}}council_domain_expert\` in PARALLEL — one message per agent, then STOP and wait for all responses. Each dispatch message must include:
|
|
56424
|
+
- The question
|
|
56425
|
+
- Round number: 1
|
|
56426
|
+
- The full RESEARCH CONTEXT block from step 2
|
|
56427
|
+
- Instruction: "Cite from the RESEARCH CONTEXT for external evidence. Your memberId and role are hardcoded in your system prompt."
|
|
56428
|
+
Do NOT share other agents' responses at this stage.
|
|
56429
|
+
4. Collect all three JSON responses. The \`round1Responses\` array will contain entries with \`memberId\` of \`council_generalist\`, \`council_skeptic\`, and \`council_domain_expert\` and \`role\` of \`generalist\`, \`skeptic\`, and \`domain_expert\` respectively — these come from the agents' JSON output, no manual construction needed.
|
|
56347
56430
|
|
|
56348
56431
|
#### Synthesis and Deliberation (when council.general.deliberate is true; default true)
|
|
56349
56432
|
5. Call \`convene_general_council\` with mode set from the command (\`general\` or \`spec_review\`), \`question\`, and the collected \`round1Responses\` only (omit \`round2Responses\`). Inspect the returned \`disagreementsCount\`.
|
|
56350
56433
|
6. If \`disagreementsCount > 0\`:
|
|
56351
|
-
a. For each disagreement in the tool's response, identify the disputing
|
|
56352
|
-
b. Re-delegate ONLY to the disputing
|
|
56434
|
+
a. For each disagreement in the tool's response, identify the disputing agents (the agents listed in the disagreement's positions, identified by memberId: \`council_generalist\`, \`council_skeptic\`, or \`council_domain_expert\`).
|
|
56435
|
+
b. Re-delegate ONLY to the disputing agents — one message per agent — passing: their Round 1 response, the disagreement topic, the opposing position(s), round number 2, and the same RESEARCH CONTEXT block.
|
|
56353
56436
|
c. Collect the Round 2 responses.
|
|
56354
56437
|
d. Call \`convene_general_council\` AGAIN with both \`round1Responses\` AND \`round2Responses\` populated.
|
|
56355
56438
|
|
|
56356
|
-
#### Moderator Pass (when council.general.moderator is true; default true)
|
|
56357
|
-
7. The most recent \`convene_general_council\` call returned a \`moderatorPrompt\` field. Delegate this prompt to \`{{AGENT_PREFIX}}council_moderator\`. The moderator agent has no tools and no web access — it synthesizes a final user-facing answer from the council output you give it. Collect the moderator's markdown output.
|
|
56358
|
-
|
|
56359
56439
|
#### Output
|
|
56360
|
-
|
|
56361
|
-
-
|
|
56362
|
-
-
|
|
56363
|
-
|
|
56440
|
+
7. Present the final answer to the user from the \`synthesis\` returned by \`convene_general_council\`. Apply these output rules directly:
|
|
56441
|
+
- LEAD WITH CONSENSUS: open with the strongest consensus position. Confidence-weighted: higher-confidence claims from multiple agents rank first, but evidence quality outranks raw confidence. Never elevate a single confident voice over a well-evidenced contrary majority.
|
|
56442
|
+
- ACKNOWLEDGE DISAGREEMENT HONESTLY: for each persisting disagreement, write "experts disagree on X because…" and present the strongest version of each side. Do NOT pretend disagreements are resolved. Do NOT silently pick a winner.
|
|
56443
|
+
- CITE THE STRONGEST SOURCES: link key claims with [title](url) format from the source list in the synthesis. Pick the most reputable source per claim; do not cite duplicates.
|
|
56444
|
+
- BE CONCISE: a few short paragraphs plus a bulleted summary. Expand only when the question genuinely requires it.
|
|
56445
|
+
- HARD CONSTRAINTS: You MUST NOT invent claims not present in the council's responses. You MUST NOT add new web research. You MUST NOT favor a position based on confidence alone.
|
|
56446
|
+
Preface the answer with one line listing the participating models (reviewer model as generalist, critic model as skeptic, SME model as domain expert). Do NOT present raw per-member JSON.
|
|
56364
56447
|
|
|
56365
56448
|
### MODE: ISSUE_INGEST
|
|
56366
56449
|
Activates when: user invokes \`/swarm issue <url>\`; OR architect receives \`[MODE: ISSUE_INGEST issue="<url>"]\` signal.
|
|
@@ -57095,60 +57178,28 @@ META.SUMMARY CONVENTION — When reporting task completion, include:
|
|
|
57095
57178
|
|
|
57096
57179
|
`;
|
|
57097
57180
|
|
|
57098
|
-
// src/agents/council-
|
|
57099
|
-
|
|
57100
|
-
|
|
57101
|
-
if (customPrompt) {
|
|
57102
|
-
prompt = customPrompt;
|
|
57103
|
-
} else if (customAppendPrompt) {
|
|
57104
|
-
prompt = `${COUNCIL_MEMBER_PROMPT}
|
|
57105
|
-
|
|
57106
|
-
${customAppendPrompt}`;
|
|
57107
|
-
}
|
|
57108
|
-
return {
|
|
57109
|
-
name: "council_member",
|
|
57110
|
-
description: "General Council deliberation member. Independently web-searches and answers in Round 1; " + "targeted MAINTAIN/CONCEDE/NUANCE deliberation in Round 2. Tool-restricted to web_search only.",
|
|
57111
|
-
config: {
|
|
57112
|
-
model,
|
|
57113
|
-
temperature: 0.4,
|
|
57114
|
-
prompt,
|
|
57115
|
-
tools: {
|
|
57116
|
-
write: false,
|
|
57117
|
-
edit: false,
|
|
57118
|
-
patch: false
|
|
57119
|
-
}
|
|
57120
|
-
}
|
|
57121
|
-
};
|
|
57122
|
-
}
|
|
57123
|
-
var COUNCIL_MEMBER_PROMPT = `You are Council Member {{MEMBER_ID}} ({{ROLE}}) on a multi-model General Council.
|
|
57124
|
-
|
|
57125
|
-
{{PERSONA_BLOCK}}
|
|
57126
|
-
|
|
57127
|
-
You are participating in Round {{ROUND}} of a structured deliberation. Your job is to give your independent, evidence-grounded perspective — not to agree with the group.
|
|
57128
|
-
|
|
57129
|
-
================================================================
|
|
57130
|
-
ROUND {{ROUND}} PROTOCOL
|
|
57181
|
+
// src/agents/council-prompts.ts
|
|
57182
|
+
var ROUND_PROTOCOL = `================================================================
|
|
57183
|
+
ROUND PROTOCOL
|
|
57131
57184
|
================================================================
|
|
57132
57185
|
|
|
57133
|
-
ROUND 1 — Independent
|
|
57134
|
-
-
|
|
57135
|
-
- Cite EVERY factual claim with a source URL
|
|
57186
|
+
ROUND 1 — Independent Analysis and Answer
|
|
57187
|
+
- Use the RESEARCH CONTEXT block provided by the architect in your dispatch message as your external evidence source. The architect has already gathered the relevant web search results.
|
|
57188
|
+
- Cite EVERY factual claim that depends on external evidence with a source from the RESEARCH CONTEXT (use the title and URL exactly as given).
|
|
57136
57189
|
- State your confidence (0.0–1.0) explicitly. Be honest — overconfident answers hurt the council.
|
|
57137
57190
|
- Enumerate areas of uncertainty so the architect knows where you're guessing vs. where you're sure.
|
|
57138
57191
|
- Do NOT coordinate with other members. You will not see their responses until Round 2.
|
|
57139
57192
|
- Do NOT pad. Be concise. Substance over volume.
|
|
57140
57193
|
|
|
57141
57194
|
ROUND 2 — Targeted Deliberation (ONLY when this round is invoked for you)
|
|
57142
|
-
-
|
|
57143
|
-
-
|
|
57195
|
+
- The architect will pass you the disagreement topic and the opposing position(s) in the dispatch message.
|
|
57196
|
+
- Re-read the RESEARCH CONTEXT for any evidence relevant to the disagreement.
|
|
57144
57197
|
- Declare your stance explicitly using one of these keywords as the FIRST word of a paragraph:
|
|
57145
|
-
MAINTAIN — your Round 1 position holds; cite the
|
|
57198
|
+
MAINTAIN — your Round 1 position holds; cite the evidence supporting it
|
|
57146
57199
|
CONCEDE — the opposing position is correct; state specifically what you got wrong
|
|
57147
57200
|
NUANCE — both positions are partially right; state the boundary condition that distinguishes them
|
|
57148
57201
|
- Never CONCEDE without evidence. Sycophantic capitulation degrades the council below an individual member's baseline (NSED arXiv:2601.16863).
|
|
57149
|
-
- Never MAINTAIN without engaging the opposing argument on its merits
|
|
57150
|
-
|
|
57151
|
-
================================================================
|
|
57202
|
+
- Never MAINTAIN without engaging the opposing argument on its merits.`, RESPONSE_FORMAT = `================================================================
|
|
57152
57203
|
RESPONSE FORMAT (always — both rounds)
|
|
57153
57204
|
================================================================
|
|
57154
57205
|
|
|
@@ -57156,11 +57207,11 @@ Reply with a single fenced JSON block. No prose outside the block.
|
|
|
57156
57207
|
|
|
57157
57208
|
\`\`\`json
|
|
57158
57209
|
{
|
|
57159
|
-
"memberId": "
|
|
57160
|
-
"role": "
|
|
57161
|
-
"round":
|
|
57210
|
+
"memberId": "<your hardcoded memberId>",
|
|
57211
|
+
"role": "<your hardcoded role>",
|
|
57212
|
+
"round": 1,
|
|
57162
57213
|
"response": "Your full answer (Round 1) or stance + reasoning (Round 2). Markdown OK inside the string.",
|
|
57163
|
-
"searchQueries": [
|
|
57214
|
+
"searchQueries": [],
|
|
57164
57215
|
"sources": [
|
|
57165
57216
|
{ "title": "...", "url": "...", "snippet": "...", "query": "..." }
|
|
57166
57217
|
],
|
|
@@ -57172,111 +57223,69 @@ Reply with a single fenced JSON block. No prose outside the block.
|
|
|
57172
57223
|
}
|
|
57173
57224
|
\`\`\`
|
|
57174
57225
|
|
|
57175
|
-
|
|
57176
|
-
|
|
57177
|
-
|
|
57226
|
+
Notes:
|
|
57227
|
+
- \`searchQueries\` is optional — list queries you would have run if you had web access (the architect uses these for audit), or omit / leave empty if none.
|
|
57228
|
+
- \`sources\` MUST come from the RESEARCH CONTEXT only. Copy title/url/snippet/query verbatim. Never invent sources.
|
|
57229
|
+
- For Round 1: leave \`disagreementTopics\` as []. For Round 2: list the specific disagreement topics this response addresses.`, HARD_RULES = `================================================================
|
|
57178
57230
|
HARD RULES
|
|
57179
57231
|
================================================================
|
|
57180
|
-
-
|
|
57181
|
-
- Never invent sources. If
|
|
57232
|
+
- You have no tools. Reason from the provided RESEARCH CONTEXT and your training knowledge.
|
|
57233
|
+
- Never invent sources. If the RESEARCH CONTEXT does not cover a needed claim, say so in \`areasOfUncertainty\`.
|
|
57182
57234
|
- Never echo other members' responses verbatim. Paraphrase or quote with attribution.
|
|
57183
|
-
- Stay within your role and persona. The architect chose you for a specific perspective
|
|
57184
|
-
|
|
57235
|
+
- Stay within your role and persona. The architect chose you for a specific perspective.`, GENERALIST_COUNCIL_PROMPT, SKEPTIC_COUNCIL_PROMPT, DOMAIN_EXPERT_COUNCIL_PROMPT;
|
|
57236
|
+
var init_council_prompts = __esm(() => {
|
|
57237
|
+
GENERALIST_COUNCIL_PROMPT = `You are the GENERALIST voice on a multi-model General Council.
|
|
57185
57238
|
|
|
57186
|
-
|
|
57187
|
-
|
|
57188
|
-
|
|
57189
|
-
|
|
57190
|
-
|
|
57191
|
-
|
|
57192
|
-
prompt = `${COUNCIL_MODERATOR_PROMPT}
|
|
57239
|
+
You are the GENERALIST voice on this council. Your perspective is broad and synthesizing:
|
|
57240
|
+
- You reason from first principles and across disciplines.
|
|
57241
|
+
- You weigh competing considerations without domain bias.
|
|
57242
|
+
- You surface tensions between different valid approaches.
|
|
57243
|
+
- You are the integrating voice — you see what the specialists might miss by being too deep in their domain.
|
|
57244
|
+
Member ID: "council_generalist" | Role: "generalist"
|
|
57193
57245
|
|
|
57194
|
-
|
|
57195
|
-
}
|
|
57196
|
-
return {
|
|
57197
|
-
name: "council_moderator",
|
|
57198
|
-
description: "General Council moderator. Synthesizes a coherent final answer from member " + "responses; no web search (works on already-gathered content).",
|
|
57199
|
-
config: {
|
|
57200
|
-
model,
|
|
57201
|
-
temperature: 0.3,
|
|
57202
|
-
prompt,
|
|
57203
|
-
tools: {
|
|
57204
|
-
write: false,
|
|
57205
|
-
edit: false,
|
|
57206
|
-
patch: false
|
|
57207
|
-
}
|
|
57208
|
-
}
|
|
57209
|
-
};
|
|
57210
|
-
}
|
|
57211
|
-
var COUNCIL_MODERATOR_PROMPT = `You are the General Council Moderator.
|
|
57246
|
+
You are participating in a structured deliberation. Your job is to give your independent, evidence-grounded perspective — not to agree with the group.
|
|
57212
57247
|
|
|
57213
|
-
|
|
57214
|
-
- Question (and mode: general or spec_review)
|
|
57215
|
-
- All member Round 1 responses with sources
|
|
57216
|
-
- Detected disagreements
|
|
57217
|
-
- Round 2 deliberation responses (if any)
|
|
57218
|
-
- Confidence-weighted consensus claims
|
|
57219
|
-
- Persisting disagreements after deliberation
|
|
57248
|
+
${ROUND_PROTOCOL}
|
|
57220
57249
|
|
|
57221
|
-
|
|
57250
|
+
${RESPONSE_FORMAT}
|
|
57222
57251
|
|
|
57223
|
-
|
|
57224
|
-
|
|
57225
|
-
|
|
57226
|
-
|
|
57227
|
-
1. LEAD WITH CONSENSUS — open with the strongest consensus position. Use the
|
|
57228
|
-
confidence-weighted ordering (Quadratic Voting): higher-confidence claims
|
|
57229
|
-
from multiple members rank higher, but evidence quality outranks raw
|
|
57230
|
-
confidence. Never elevate a single confident voice over a well-evidenced
|
|
57231
|
-
contrary majority.
|
|
57232
|
-
|
|
57233
|
-
2. ACKNOWLEDGE DISAGREEMENT HONESTLY — for each persisting disagreement, write
|
|
57234
|
-
"experts disagree on X because…" and present the strongest version of each
|
|
57235
|
-
side. Do NOT pretend disagreements are resolved when they are not. Do NOT
|
|
57236
|
-
silently pick a winner.
|
|
57237
|
-
|
|
57238
|
-
3. CITE THE STRONGEST SOURCES — link key claims with [title](url) format from
|
|
57239
|
-
the deduplicated source list. Pick the most reputable source for each claim;
|
|
57240
|
-
do not cite duplicates.
|
|
57241
|
-
|
|
57242
|
-
4. BE CONCISE — the user wants an answer, not a committee report. Default
|
|
57243
|
-
length: a few short paragraphs plus a bulleted summary. Expand only when
|
|
57244
|
-
the question genuinely requires it.
|
|
57245
|
-
|
|
57246
|
-
================================================================
|
|
57247
|
-
HARD CONSTRAINTS
|
|
57248
|
-
================================================================
|
|
57249
|
-
|
|
57250
|
-
- You MUST NOT invent claims that are not present in the council's responses.
|
|
57251
|
-
- You MUST NOT add new web research. If something was missed, say so.
|
|
57252
|
-
- You MUST NOT favor a position based on member confidence alone — evidence
|
|
57253
|
-
quality is the tie-breaker.
|
|
57254
|
-
- You have NO tools. You write the final synthesis from the input given.
|
|
57252
|
+
${HARD_RULES}
|
|
57253
|
+
`;
|
|
57254
|
+
SKEPTIC_COUNCIL_PROMPT = `You are the SKEPTIC voice on a multi-model General Council.
|
|
57255
57255
|
|
|
57256
|
-
|
|
57257
|
-
|
|
57258
|
-
|
|
57256
|
+
You are the SKEPTIC voice on this council. Your job is rigorous stress-testing:
|
|
57257
|
+
- You challenge assumptions the other members take for granted.
|
|
57258
|
+
- You look for weak points, edge cases, and unstated dependencies.
|
|
57259
|
+
- You are NOT contrarian for its own sake — your pushback must be evidence-grounded.
|
|
57260
|
+
- You make the council's final answer more robust by finding what could go wrong before the user does.
|
|
57261
|
+
Member ID: "council_skeptic" | Role: "skeptic"
|
|
57259
57262
|
|
|
57260
|
-
|
|
57263
|
+
You are participating in a structured deliberation. Your job is to give your independent, evidence-grounded perspective — not to agree with the group.
|
|
57261
57264
|
|
|
57262
|
-
|
|
57265
|
+
${ROUND_PROTOCOL}
|
|
57263
57266
|
|
|
57264
|
-
|
|
57267
|
+
${RESPONSE_FORMAT}
|
|
57265
57268
|
|
|
57266
|
-
|
|
57269
|
+
${HARD_RULES}
|
|
57270
|
+
`;
|
|
57271
|
+
DOMAIN_EXPERT_COUNCIL_PROMPT = `You are the DOMAIN EXPERT voice on a multi-model General Council.
|
|
57267
57272
|
|
|
57268
|
-
|
|
57273
|
+
You are the DOMAIN EXPERT voice on this council. Your perspective is technically precise:
|
|
57274
|
+
- You go deep where others stay broad.
|
|
57275
|
+
- You cite specific mechanisms, constraints, and implementation-level detail.
|
|
57276
|
+
- You surface edge cases and gotchas that only emerge at depth.
|
|
57277
|
+
- Your answers are concrete — no hand-waving, no vague recommendations.
|
|
57278
|
+
Member ID: "council_domain_expert" | Role: "domain_expert"
|
|
57269
57279
|
|
|
57270
|
-
|
|
57271
|
-
- <topic 2>: ...
|
|
57280
|
+
You are participating in a structured deliberation. Your job is to give your independent, evidence-grounded perspective — not to agree with the group.
|
|
57272
57281
|
|
|
57273
|
-
|
|
57282
|
+
${ROUND_PROTOCOL}
|
|
57274
57283
|
|
|
57275
|
-
|
|
57276
|
-
- ...
|
|
57284
|
+
${RESPONSE_FORMAT}
|
|
57277
57285
|
|
|
57278
|
-
|
|
57286
|
+
${HARD_RULES}
|
|
57279
57287
|
`;
|
|
57288
|
+
});
|
|
57280
57289
|
|
|
57281
57290
|
// src/agents/critic.ts
|
|
57282
57291
|
function parseSoundingBoardResponse(raw) {
|
|
@@ -58769,7 +58778,7 @@ COVERAGE REPORTING:
|
|
|
58769
58778
|
|
|
58770
58779
|
// src/agents/index.ts
|
|
58771
58780
|
import { mkdir as mkdir6, writeFile as writeFile6 } from "node:fs/promises";
|
|
58772
|
-
import * as
|
|
58781
|
+
import * as path43 from "node:path";
|
|
58773
58782
|
function stripSwarmPrefix(agentName, swarmPrefix) {
|
|
58774
58783
|
if (!swarmPrefix || !agentName)
|
|
58775
58784
|
return agentName;
|
|
@@ -58951,18 +58960,25 @@ If you call @coder instead of @${swarmId}_coder, the call will FAIL or go to the
|
|
|
58951
58960
|
testEngineer.name = prefixName("test_engineer");
|
|
58952
58961
|
agents.push(applyOverrides(testEngineer, swarmAgents, swarmPrefix, quiet));
|
|
58953
58962
|
}
|
|
58954
|
-
if (pluginConfig?.council?.general?.enabled === true
|
|
58955
|
-
|
|
58956
|
-
|
|
58957
|
-
|
|
58958
|
-
|
|
58959
|
-
|
|
58960
|
-
|
|
58961
|
-
|
|
58962
|
-
|
|
58963
|
-
|
|
58964
|
-
|
|
58965
|
-
|
|
58963
|
+
if (pluginConfig?.council?.general?.enabled === true) {
|
|
58964
|
+
if (!isAgentDisabled("reviewer", swarmAgents, swarmPrefix)) {
|
|
58965
|
+
const councilGeneralist = createReviewerAgent(getModel("reviewer"), GENERALIST_COUNCIL_PROMPT);
|
|
58966
|
+
councilGeneralist.name = prefixName("council_generalist");
|
|
58967
|
+
agents.push(applyOverrides(councilGeneralist, swarmAgents, swarmPrefix, quiet));
|
|
58968
|
+
}
|
|
58969
|
+
if (!isAgentDisabled("critic", swarmAgents, swarmPrefix)) {
|
|
58970
|
+
const councilSkeptic = createCriticAgent(getModel("critic"), SKEPTIC_COUNCIL_PROMPT);
|
|
58971
|
+
councilSkeptic.name = prefixName("council_skeptic");
|
|
58972
|
+
agents.push(applyOverrides(councilSkeptic, swarmAgents, swarmPrefix, quiet));
|
|
58973
|
+
}
|
|
58974
|
+
if (!isAgentDisabled("sme", swarmAgents, swarmPrefix)) {
|
|
58975
|
+
const councilDomainExpert = createSMEAgent(getModel("sme"), DOMAIN_EXPERT_COUNCIL_PROMPT);
|
|
58976
|
+
councilDomainExpert.name = prefixName("council_domain_expert");
|
|
58977
|
+
agents.push(applyOverrides(councilDomainExpert, swarmAgents, swarmPrefix, quiet));
|
|
58978
|
+
}
|
|
58979
|
+
if (pluginConfig?.council?.general?.moderatorModel !== undefined) {
|
|
58980
|
+
addDeferredWarning("[opencode-swarm] council.general.moderatorModel is deprecated and ignored. The architect now synthesizes the final answer directly using inline output rules. Remove this field (and council.general.moderator if set) from opencode-swarm.json to silence this warning.");
|
|
58981
|
+
}
|
|
58966
58982
|
}
|
|
58967
58983
|
if (!isAgentDisabled("docs", swarmAgents, swarmPrefix)) {
|
|
58968
58984
|
const docsPrompts = getPrompts("docs");
|
|
@@ -59080,14 +59096,14 @@ function getAgentConfigs(config3, directory, sessionId) {
|
|
|
59080
59096
|
}));
|
|
59081
59097
|
if (directory) {
|
|
59082
59098
|
const sid = sessionId ?? `init-${Date.now()}`;
|
|
59083
|
-
const evidenceDir =
|
|
59099
|
+
const evidenceDir = path43.join(directory, ".swarm", "evidence");
|
|
59084
59100
|
const filename = `agent-tools-${sid}.json`;
|
|
59085
59101
|
const snapshotData = JSON.stringify({
|
|
59086
59102
|
sessionId: sid,
|
|
59087
59103
|
generatedAt: new Date().toISOString(),
|
|
59088
59104
|
agents: agentToolSnapshot
|
|
59089
59105
|
}, null, 2);
|
|
59090
|
-
mkdir6(evidenceDir, { recursive: true }).then(() => writeFile6(
|
|
59106
|
+
mkdir6(evidenceDir, { recursive: true }).then(() => writeFile6(path43.join(evidenceDir, filename), snapshotData)).catch(() => {});
|
|
59091
59107
|
}
|
|
59092
59108
|
return result;
|
|
59093
59109
|
}
|
|
@@ -59098,9 +59114,11 @@ var init_agents2 = __esm(() => {
|
|
|
59098
59114
|
init_schema();
|
|
59099
59115
|
init_warning_buffer();
|
|
59100
59116
|
init_architect();
|
|
59117
|
+
init_council_prompts();
|
|
59101
59118
|
init_curator_agent();
|
|
59102
59119
|
init_reviewer();
|
|
59103
59120
|
init_architect();
|
|
59121
|
+
init_council_prompts();
|
|
59104
59122
|
init_curator_agent();
|
|
59105
59123
|
init_reviewer();
|
|
59106
59124
|
warnedAgents = new Set;
|
|
@@ -59113,13 +59131,13 @@ __export(exports_evidence_summary_integration, {
|
|
|
59113
59131
|
EvidenceSummaryIntegration: () => EvidenceSummaryIntegration
|
|
59114
59132
|
});
|
|
59115
59133
|
import { existsSync as existsSync24, mkdirSync as mkdirSync14, writeFileSync as writeFileSync6 } from "node:fs";
|
|
59116
|
-
import * as
|
|
59134
|
+
import * as path44 from "node:path";
|
|
59117
59135
|
function persistSummary(projectDir, artifact, filename) {
|
|
59118
|
-
const swarmPath =
|
|
59136
|
+
const swarmPath = path44.join(projectDir, ".swarm");
|
|
59119
59137
|
if (!existsSync24(swarmPath)) {
|
|
59120
59138
|
mkdirSync14(swarmPath, { recursive: true });
|
|
59121
59139
|
}
|
|
59122
|
-
const artifactPath =
|
|
59140
|
+
const artifactPath = path44.join(swarmPath, filename);
|
|
59123
59141
|
const content = JSON.stringify(artifact, null, 2);
|
|
59124
59142
|
writeFileSync6(artifactPath, content, "utf-8");
|
|
59125
59143
|
log("[EvidenceSummaryIntegration] Summary persisted", {
|
|
@@ -59238,7 +59256,7 @@ __export(exports_status_artifact, {
|
|
|
59238
59256
|
AutomationStatusArtifact: () => AutomationStatusArtifact
|
|
59239
59257
|
});
|
|
59240
59258
|
import * as fs30 from "node:fs";
|
|
59241
|
-
import * as
|
|
59259
|
+
import * as path46 from "node:path";
|
|
59242
59260
|
function createEmptySnapshot(mode, capabilities) {
|
|
59243
59261
|
return {
|
|
59244
59262
|
timestamp: Date.now(),
|
|
@@ -59297,7 +59315,7 @@ class AutomationStatusArtifact {
|
|
|
59297
59315
|
});
|
|
59298
59316
|
}
|
|
59299
59317
|
getFilePath() {
|
|
59300
|
-
return
|
|
59318
|
+
return path46.join(this.swarmDir, this.filename);
|
|
59301
59319
|
}
|
|
59302
59320
|
load() {
|
|
59303
59321
|
const filePath = this.getFilePath();
|
|
@@ -59710,12 +59728,12 @@ __export(exports_review_receipt, {
|
|
|
59710
59728
|
});
|
|
59711
59729
|
import * as crypto5 from "node:crypto";
|
|
59712
59730
|
import * as fs34 from "node:fs";
|
|
59713
|
-
import * as
|
|
59731
|
+
import * as path47 from "node:path";
|
|
59714
59732
|
function resolveReceiptsDir(directory) {
|
|
59715
|
-
return
|
|
59733
|
+
return path47.join(directory, ".swarm", "review-receipts");
|
|
59716
59734
|
}
|
|
59717
59735
|
function resolveReceiptIndexPath(directory) {
|
|
59718
|
-
return
|
|
59736
|
+
return path47.join(resolveReceiptsDir(directory), "index.json");
|
|
59719
59737
|
}
|
|
59720
59738
|
function buildReceiptFilename(id, date9) {
|
|
59721
59739
|
const dateStr = date9.toISOString().slice(0, 10);
|
|
@@ -59754,7 +59772,7 @@ async function readReceiptIndex(directory) {
|
|
|
59754
59772
|
}
|
|
59755
59773
|
async function writeReceiptIndex(directory, index) {
|
|
59756
59774
|
const indexPath = resolveReceiptIndexPath(directory);
|
|
59757
|
-
const dir =
|
|
59775
|
+
const dir = path47.dirname(indexPath);
|
|
59758
59776
|
await fs34.promises.mkdir(dir, { recursive: true });
|
|
59759
59777
|
const tmpPath = `${indexPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
59760
59778
|
await fs34.promises.writeFile(tmpPath, JSON.stringify(index, null, 2), "utf-8");
|
|
@@ -59765,7 +59783,7 @@ async function persistReviewReceipt(directory, receipt) {
|
|
|
59765
59783
|
await fs34.promises.mkdir(receiptsDir, { recursive: true });
|
|
59766
59784
|
const now = new Date(receipt.reviewed_at);
|
|
59767
59785
|
const filename = buildReceiptFilename(receipt.id, now);
|
|
59768
|
-
const receiptPath =
|
|
59786
|
+
const receiptPath = path47.join(receiptsDir, filename);
|
|
59769
59787
|
const tmpPath = `${receiptPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
59770
59788
|
await fs34.promises.writeFile(tmpPath, JSON.stringify(receipt, null, 2), "utf-8");
|
|
59771
59789
|
fs34.renameSync(tmpPath, receiptPath);
|
|
@@ -59787,7 +59805,7 @@ async function readReceiptById(directory, receiptId) {
|
|
|
59787
59805
|
const entry = index.entries.find((e) => e.id === receiptId);
|
|
59788
59806
|
if (!entry)
|
|
59789
59807
|
return null;
|
|
59790
|
-
const receiptPath =
|
|
59808
|
+
const receiptPath = path47.join(resolveReceiptsDir(directory), entry.filename);
|
|
59791
59809
|
try {
|
|
59792
59810
|
const content = await fs34.promises.readFile(receiptPath, "utf-8");
|
|
59793
59811
|
return JSON.parse(content);
|
|
@@ -59800,7 +59818,7 @@ async function readReceiptsByScopeHash(directory, scopeHash) {
|
|
|
59800
59818
|
const matching = index.entries.filter((e) => e.scope_hash === scopeHash).sort((a, b) => b.reviewed_at.localeCompare(a.reviewed_at));
|
|
59801
59819
|
const receipts = [];
|
|
59802
59820
|
for (const entry of matching) {
|
|
59803
|
-
const receiptPath =
|
|
59821
|
+
const receiptPath = path47.join(resolveReceiptsDir(directory), entry.filename);
|
|
59804
59822
|
try {
|
|
59805
59823
|
const content = await fs34.promises.readFile(receiptPath, "utf-8");
|
|
59806
59824
|
receipts.push(JSON.parse(content));
|
|
@@ -59813,7 +59831,7 @@ async function readAllReceipts(directory) {
|
|
|
59813
59831
|
const sorted = [...index.entries].sort((a, b) => b.reviewed_at.localeCompare(a.reviewed_at));
|
|
59814
59832
|
const receipts = [];
|
|
59815
59833
|
for (const entry of sorted) {
|
|
59816
|
-
const receiptPath =
|
|
59834
|
+
const receiptPath = path47.join(resolveReceiptsDir(directory), entry.filename);
|
|
59817
59835
|
try {
|
|
59818
59836
|
const content = await fs34.promises.readFile(receiptPath, "utf-8");
|
|
59819
59837
|
receipts.push(JSON.parse(content));
|
|
@@ -61401,11 +61419,11 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
61401
61419
|
throw toThrow;
|
|
61402
61420
|
}, "quit_");
|
|
61403
61421
|
var scriptDirectory = "";
|
|
61404
|
-
function locateFile(
|
|
61422
|
+
function locateFile(path58) {
|
|
61405
61423
|
if (Module["locateFile"]) {
|
|
61406
|
-
return Module["locateFile"](
|
|
61424
|
+
return Module["locateFile"](path58, scriptDirectory);
|
|
61407
61425
|
}
|
|
61408
|
-
return scriptDirectory +
|
|
61426
|
+
return scriptDirectory + path58;
|
|
61409
61427
|
}
|
|
61410
61428
|
__name(locateFile, "locateFile");
|
|
61411
61429
|
var readAsync, readBinary;
|
|
@@ -63154,13 +63172,13 @@ __export(exports_runtime, {
|
|
|
63154
63172
|
getInitializedLanguages: () => getInitializedLanguages,
|
|
63155
63173
|
clearParserCache: () => clearParserCache
|
|
63156
63174
|
});
|
|
63157
|
-
import * as
|
|
63175
|
+
import * as path58 from "node:path";
|
|
63158
63176
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
63159
63177
|
async function initTreeSitter() {
|
|
63160
63178
|
if (treeSitterInitialized) {
|
|
63161
63179
|
return;
|
|
63162
63180
|
}
|
|
63163
|
-
const thisDir =
|
|
63181
|
+
const thisDir = path58.dirname(fileURLToPath2(import.meta.url));
|
|
63164
63182
|
const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/lang");
|
|
63165
63183
|
if (isSource) {
|
|
63166
63184
|
await Parser.init();
|
|
@@ -63168,7 +63186,7 @@ async function initTreeSitter() {
|
|
|
63168
63186
|
const grammarsDir = getGrammarsDirAbsolute();
|
|
63169
63187
|
await Parser.init({
|
|
63170
63188
|
locateFile(scriptName) {
|
|
63171
|
-
return
|
|
63189
|
+
return path58.join(grammarsDir, scriptName);
|
|
63172
63190
|
}
|
|
63173
63191
|
});
|
|
63174
63192
|
}
|
|
@@ -63189,11 +63207,11 @@ function getWasmFileName(languageId) {
|
|
|
63189
63207
|
return `tree-sitter-${sanitized}.wasm`;
|
|
63190
63208
|
}
|
|
63191
63209
|
function getGrammarsDirAbsolute() {
|
|
63192
|
-
const thisDir =
|
|
63210
|
+
const thisDir = path58.dirname(fileURLToPath2(import.meta.url));
|
|
63193
63211
|
const normalized = thisDir.replace(/\\/g, "/");
|
|
63194
63212
|
const isSource = normalized.endsWith("/src/lang");
|
|
63195
63213
|
const isCliBundle = normalized.endsWith("/cli");
|
|
63196
|
-
return isSource ?
|
|
63214
|
+
return isSource ? path58.join(thisDir, "grammars") : isCliBundle ? path58.join(thisDir, "..", "lang", "grammars") : path58.join(thisDir, "lang", "grammars");
|
|
63197
63215
|
}
|
|
63198
63216
|
async function loadGrammar(languageId) {
|
|
63199
63217
|
if (typeof languageId !== "string" || languageId.length > 100) {
|
|
@@ -63209,7 +63227,7 @@ async function loadGrammar(languageId) {
|
|
|
63209
63227
|
await initTreeSitter();
|
|
63210
63228
|
const parser = new Parser;
|
|
63211
63229
|
const wasmFileName = getWasmFileName(normalizedId);
|
|
63212
|
-
const wasmPath =
|
|
63230
|
+
const wasmPath = path58.join(getGrammarsDirAbsolute(), wasmFileName);
|
|
63213
63231
|
const { existsSync: existsSync30 } = await import("node:fs");
|
|
63214
63232
|
if (!existsSync30(wasmPath)) {
|
|
63215
63233
|
throw new Error(`Grammar file not found for ${languageId}: ${wasmPath}
|
|
@@ -63244,7 +63262,7 @@ async function isGrammarAvailable(languageId) {
|
|
|
63244
63262
|
}
|
|
63245
63263
|
try {
|
|
63246
63264
|
const wasmFileName = getWasmFileName(normalizedId);
|
|
63247
|
-
const wasmPath =
|
|
63265
|
+
const wasmPath = path58.join(getGrammarsDirAbsolute(), wasmFileName);
|
|
63248
63266
|
const { statSync: statSync18 } = await import("node:fs");
|
|
63249
63267
|
statSync18(wasmPath);
|
|
63250
63268
|
return true;
|
|
@@ -63303,13 +63321,13 @@ __export(exports_doc_scan, {
|
|
|
63303
63321
|
import * as crypto7 from "node:crypto";
|
|
63304
63322
|
import * as fs43 from "node:fs";
|
|
63305
63323
|
import { mkdir as mkdir9, readFile as readFile8, writeFile as writeFile8 } from "node:fs/promises";
|
|
63306
|
-
import * as
|
|
63324
|
+
import * as path60 from "node:path";
|
|
63307
63325
|
function normalizeSeparators(filePath) {
|
|
63308
63326
|
return filePath.replace(/\\/g, "/");
|
|
63309
63327
|
}
|
|
63310
63328
|
function matchesDocPattern(filePath, patterns) {
|
|
63311
63329
|
const normalizedPath = normalizeSeparators(filePath);
|
|
63312
|
-
const basename8 =
|
|
63330
|
+
const basename8 = path60.basename(filePath);
|
|
63313
63331
|
for (const pattern of patterns) {
|
|
63314
63332
|
if (!pattern.includes("/") && !pattern.includes("\\")) {
|
|
63315
63333
|
if (basename8 === pattern) {
|
|
@@ -63365,7 +63383,7 @@ function stripMarkdown(text) {
|
|
|
63365
63383
|
return text.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/^\s*[-*•]\s+/gm, "").replace(/^\s*\d+\.\s+/gm, "").trim();
|
|
63366
63384
|
}
|
|
63367
63385
|
async function scanDocIndex(directory) {
|
|
63368
|
-
const manifestPath =
|
|
63386
|
+
const manifestPath = path60.join(directory, ".swarm", "doc-manifest.json");
|
|
63369
63387
|
const defaultPatterns = DocsConfigSchema.parse({}).doc_patterns;
|
|
63370
63388
|
const extraPatterns = [
|
|
63371
63389
|
"ARCHITECTURE.md",
|
|
@@ -63382,7 +63400,7 @@ async function scanDocIndex(directory) {
|
|
|
63382
63400
|
let cacheValid = true;
|
|
63383
63401
|
for (const file3 of existingManifest.files) {
|
|
63384
63402
|
try {
|
|
63385
|
-
const fullPath =
|
|
63403
|
+
const fullPath = path60.join(directory, file3.path);
|
|
63386
63404
|
const stat3 = fs43.statSync(fullPath);
|
|
63387
63405
|
if (stat3.mtimeMs > file3.mtime) {
|
|
63388
63406
|
cacheValid = false;
|
|
@@ -63412,7 +63430,7 @@ async function scanDocIndex(directory) {
|
|
|
63412
63430
|
}
|
|
63413
63431
|
const entries = rawEntries.filter((e) => typeof e === "string");
|
|
63414
63432
|
for (const entry of entries) {
|
|
63415
|
-
const fullPath =
|
|
63433
|
+
const fullPath = path60.join(directory, entry);
|
|
63416
63434
|
let stat3;
|
|
63417
63435
|
try {
|
|
63418
63436
|
stat3 = fs43.statSync(fullPath);
|
|
@@ -63448,7 +63466,7 @@ async function scanDocIndex(directory) {
|
|
|
63448
63466
|
} catch {
|
|
63449
63467
|
continue;
|
|
63450
63468
|
}
|
|
63451
|
-
const { title, summary } = extractTitleAndSummary(content,
|
|
63469
|
+
const { title, summary } = extractTitleAndSummary(content, path60.basename(entry));
|
|
63452
63470
|
const lineCount = content.split(`
|
|
63453
63471
|
`).length;
|
|
63454
63472
|
discoveredFiles.push({
|
|
@@ -63474,7 +63492,7 @@ async function scanDocIndex(directory) {
|
|
|
63474
63492
|
files: discoveredFiles
|
|
63475
63493
|
};
|
|
63476
63494
|
try {
|
|
63477
|
-
await mkdir9(
|
|
63495
|
+
await mkdir9(path60.dirname(manifestPath), { recursive: true });
|
|
63478
63496
|
await writeFile8(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
63479
63497
|
} catch {}
|
|
63480
63498
|
return { manifest, cached: false };
|
|
@@ -63513,7 +63531,7 @@ function extractConstraintsFromContent(content) {
|
|
|
63513
63531
|
return constraints;
|
|
63514
63532
|
}
|
|
63515
63533
|
async function extractDocConstraints(directory, taskFiles, taskDescription) {
|
|
63516
|
-
const manifestPath =
|
|
63534
|
+
const manifestPath = path60.join(directory, ".swarm", "doc-manifest.json");
|
|
63517
63535
|
let manifest;
|
|
63518
63536
|
try {
|
|
63519
63537
|
const content = await readFile8(manifestPath, "utf-8");
|
|
@@ -63539,7 +63557,7 @@ async function extractDocConstraints(directory, taskFiles, taskDescription) {
|
|
|
63539
63557
|
}
|
|
63540
63558
|
let fullContent;
|
|
63541
63559
|
try {
|
|
63542
|
-
fullContent = await readFile8(
|
|
63560
|
+
fullContent = await readFile8(path60.join(directory, docFile.path), "utf-8");
|
|
63543
63561
|
} catch {
|
|
63544
63562
|
skippedCount++;
|
|
63545
63563
|
continue;
|
|
@@ -63562,7 +63580,7 @@ async function extractDocConstraints(directory, taskFiles, taskDescription) {
|
|
|
63562
63580
|
tier: "swarm",
|
|
63563
63581
|
lesson: constraint,
|
|
63564
63582
|
category: "architecture",
|
|
63565
|
-
tags: ["doc-scan",
|
|
63583
|
+
tags: ["doc-scan", path60.basename(docFile.path)],
|
|
63566
63584
|
scope: "global",
|
|
63567
63585
|
confidence: 0.5,
|
|
63568
63586
|
status: "candidate",
|
|
@@ -63635,7 +63653,7 @@ var init_doc_scan = __esm(() => {
|
|
|
63635
63653
|
}
|
|
63636
63654
|
} catch {}
|
|
63637
63655
|
if (force) {
|
|
63638
|
-
const manifestPath =
|
|
63656
|
+
const manifestPath = path60.join(directory, ".swarm", "doc-manifest.json");
|
|
63639
63657
|
try {
|
|
63640
63658
|
fs43.unlinkSync(manifestPath);
|
|
63641
63659
|
} catch {}
|
|
@@ -63826,9 +63844,9 @@ __export(exports_curator_drift, {
|
|
|
63826
63844
|
buildDriftInjectionText: () => buildDriftInjectionText
|
|
63827
63845
|
});
|
|
63828
63846
|
import * as fs46 from "node:fs";
|
|
63829
|
-
import * as
|
|
63847
|
+
import * as path63 from "node:path";
|
|
63830
63848
|
async function readPriorDriftReports(directory) {
|
|
63831
|
-
const swarmDir =
|
|
63849
|
+
const swarmDir = path63.join(directory, ".swarm");
|
|
63832
63850
|
const entries = await fs46.promises.readdir(swarmDir).catch(() => null);
|
|
63833
63851
|
if (entries === null)
|
|
63834
63852
|
return [];
|
|
@@ -63855,7 +63873,7 @@ async function readPriorDriftReports(directory) {
|
|
|
63855
63873
|
async function writeDriftReport(directory, report) {
|
|
63856
63874
|
const filename = `${DRIFT_REPORT_PREFIX}${report.phase}.json`;
|
|
63857
63875
|
const filePath = validateSwarmPath(directory, filename);
|
|
63858
|
-
const swarmDir =
|
|
63876
|
+
const swarmDir = path63.dirname(filePath);
|
|
63859
63877
|
await fs46.promises.mkdir(swarmDir, { recursive: true });
|
|
63860
63878
|
try {
|
|
63861
63879
|
await fs46.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
|
|
@@ -63991,7 +64009,7 @@ var init_curator_drift = __esm(() => {
|
|
|
63991
64009
|
init_package();
|
|
63992
64010
|
init_agents2();
|
|
63993
64011
|
import * as fs87 from "node:fs";
|
|
63994
|
-
import * as
|
|
64012
|
+
import * as path106 from "node:path";
|
|
63995
64013
|
|
|
63996
64014
|
// src/background/index.ts
|
|
63997
64015
|
init_event_bus();
|
|
@@ -64002,7 +64020,7 @@ init_manager3();
|
|
|
64002
64020
|
init_manager();
|
|
64003
64021
|
init_utils();
|
|
64004
64022
|
import * as fs29 from "node:fs";
|
|
64005
|
-
import * as
|
|
64023
|
+
import * as path45 from "node:path";
|
|
64006
64024
|
|
|
64007
64025
|
class PlanSyncWorker {
|
|
64008
64026
|
directory;
|
|
@@ -64026,10 +64044,10 @@ class PlanSyncWorker {
|
|
|
64026
64044
|
this.onSyncComplete = options.onSyncComplete;
|
|
64027
64045
|
}
|
|
64028
64046
|
getSwarmDir() {
|
|
64029
|
-
return
|
|
64047
|
+
return path45.resolve(this.directory, ".swarm");
|
|
64030
64048
|
}
|
|
64031
64049
|
getPlanJsonPath() {
|
|
64032
|
-
return
|
|
64050
|
+
return path45.join(this.getSwarmDir(), "plan.json");
|
|
64033
64051
|
}
|
|
64034
64052
|
start() {
|
|
64035
64053
|
if (this.disposed) {
|
|
@@ -64248,8 +64266,8 @@ class PlanSyncWorker {
|
|
|
64248
64266
|
checkForUnauthorizedWrite() {
|
|
64249
64267
|
try {
|
|
64250
64268
|
const swarmDir = this.getSwarmDir();
|
|
64251
|
-
const planJsonPath =
|
|
64252
|
-
const markerPath =
|
|
64269
|
+
const planJsonPath = path45.join(swarmDir, "plan.json");
|
|
64270
|
+
const markerPath = path45.join(swarmDir, ".plan-write-marker");
|
|
64253
64271
|
const planStats = fs29.statSync(planJsonPath);
|
|
64254
64272
|
const planMtimeMs = Math.floor(planStats.mtimeMs);
|
|
64255
64273
|
const markerContent = fs29.readFileSync(markerPath, "utf8");
|
|
@@ -64486,11 +64504,11 @@ async function doFlush(directory) {
|
|
|
64486
64504
|
const activitySection = renderActivitySection();
|
|
64487
64505
|
const updated = replaceOrAppendSection(existing, "## Agent Activity", activitySection);
|
|
64488
64506
|
const flushedCount = swarmState.pendingEvents;
|
|
64489
|
-
const
|
|
64490
|
-
const tempPath = `${
|
|
64507
|
+
const path47 = nodePath2.join(directory, ".swarm", "context.md");
|
|
64508
|
+
const tempPath = `${path47}.tmp`;
|
|
64491
64509
|
try {
|
|
64492
64510
|
await Bun.write(tempPath, updated);
|
|
64493
|
-
renameSync11(tempPath,
|
|
64511
|
+
renameSync11(tempPath, path47);
|
|
64494
64512
|
} catch (writeError) {
|
|
64495
64513
|
try {
|
|
64496
64514
|
unlinkSync8(tempPath);
|
|
@@ -64541,7 +64559,7 @@ ${content.substring(endIndex + 1)}`;
|
|
|
64541
64559
|
init_manager();
|
|
64542
64560
|
init_utils2();
|
|
64543
64561
|
import * as fs31 from "node:fs";
|
|
64544
|
-
import { join as
|
|
64562
|
+
import { join as join43 } from "node:path";
|
|
64545
64563
|
function createCompactionCustomizerHook(config3, directory) {
|
|
64546
64564
|
const enabled = config3.hooks?.compaction !== false;
|
|
64547
64565
|
if (!enabled) {
|
|
@@ -64586,7 +64604,7 @@ function createCompactionCustomizerHook(config3, directory) {
|
|
|
64586
64604
|
}
|
|
64587
64605
|
}
|
|
64588
64606
|
try {
|
|
64589
|
-
const summariesDir =
|
|
64607
|
+
const summariesDir = join43(directory, ".swarm", "summaries");
|
|
64590
64608
|
const files = await fs31.promises.readdir(summariesDir);
|
|
64591
64609
|
if (files.length > 0) {
|
|
64592
64610
|
const count = files.length;
|
|
@@ -65851,7 +65869,7 @@ init_schema();
|
|
|
65851
65869
|
init_manager();
|
|
65852
65870
|
init_curator();
|
|
65853
65871
|
init_utils2();
|
|
65854
|
-
import * as
|
|
65872
|
+
import * as path48 from "node:path";
|
|
65855
65873
|
function createPhaseMonitorHook(directory, preflightManager, curatorRunner, delegateFactory) {
|
|
65856
65874
|
let lastKnownPhase = null;
|
|
65857
65875
|
const handler = async (input, _output) => {
|
|
@@ -65871,9 +65889,9 @@ function createPhaseMonitorHook(directory, preflightManager, curatorRunner, dele
|
|
|
65871
65889
|
const llmDelegate = delegateFactory?.(sessionId);
|
|
65872
65890
|
const initResult = await runner(directory, curatorConfig, llmDelegate);
|
|
65873
65891
|
if (initResult.briefing) {
|
|
65874
|
-
const briefingPath =
|
|
65892
|
+
const briefingPath = path48.join(directory, ".swarm", "curator-briefing.md");
|
|
65875
65893
|
const { mkdir: mkdir7, writeFile: writeFile7 } = await import("node:fs/promises");
|
|
65876
|
-
await mkdir7(
|
|
65894
|
+
await mkdir7(path48.dirname(briefingPath), { recursive: true });
|
|
65877
65895
|
await writeFile7(briefingPath, initResult.briefing, "utf-8");
|
|
65878
65896
|
const { buildApprovedReceipt: buildApprovedReceipt2, persistReviewReceipt: persistReviewReceipt2 } = await Promise.resolve().then(() => (init_review_receipt(), exports_review_receipt));
|
|
65879
65897
|
const initReceipt = buildApprovedReceipt2({
|
|
@@ -65998,7 +66016,7 @@ ${originalText}`;
|
|
|
65998
66016
|
}
|
|
65999
66017
|
// src/hooks/repo-graph-builder.ts
|
|
66000
66018
|
init_constants();
|
|
66001
|
-
import * as
|
|
66019
|
+
import * as path51 from "node:path";
|
|
66002
66020
|
|
|
66003
66021
|
// src/tools/repo-graph.ts
|
|
66004
66022
|
init_utils2();
|
|
@@ -66007,14 +66025,14 @@ init_path_security();
|
|
|
66007
66025
|
import * as fsSync2 from "node:fs";
|
|
66008
66026
|
import { constants as constants3, existsSync as existsSync28, realpathSync as realpathSync6 } from "node:fs";
|
|
66009
66027
|
import * as fsPromises3 from "node:fs/promises";
|
|
66010
|
-
import * as
|
|
66028
|
+
import * as path50 from "node:path";
|
|
66011
66029
|
|
|
66012
66030
|
// src/tools/symbols.ts
|
|
66013
66031
|
init_zod();
|
|
66014
66032
|
init_create_tool();
|
|
66015
66033
|
init_path_security();
|
|
66016
66034
|
import * as fs35 from "node:fs";
|
|
66017
|
-
import * as
|
|
66035
|
+
import * as path49 from "node:path";
|
|
66018
66036
|
var MAX_FILE_SIZE_BYTES2 = 1024 * 1024;
|
|
66019
66037
|
var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
66020
66038
|
function containsWindowsAttacks(str) {
|
|
@@ -66031,11 +66049,11 @@ function containsWindowsAttacks(str) {
|
|
|
66031
66049
|
}
|
|
66032
66050
|
function isPathInWorkspace(filePath, workspace) {
|
|
66033
66051
|
try {
|
|
66034
|
-
const resolvedPath =
|
|
66052
|
+
const resolvedPath = path49.resolve(workspace, filePath);
|
|
66035
66053
|
const realWorkspace = fs35.realpathSync(workspace);
|
|
66036
66054
|
const realResolvedPath = fs35.realpathSync(resolvedPath);
|
|
66037
|
-
const relativePath =
|
|
66038
|
-
if (relativePath.startsWith("..") ||
|
|
66055
|
+
const relativePath = path49.relative(realWorkspace, realResolvedPath);
|
|
66056
|
+
if (relativePath.startsWith("..") || path49.isAbsolute(relativePath)) {
|
|
66039
66057
|
return false;
|
|
66040
66058
|
}
|
|
66041
66059
|
return true;
|
|
@@ -66047,7 +66065,7 @@ function validatePathForRead(filePath, workspace) {
|
|
|
66047
66065
|
return isPathInWorkspace(filePath, workspace);
|
|
66048
66066
|
}
|
|
66049
66067
|
function extractTSSymbols(filePath, cwd) {
|
|
66050
|
-
const fullPath =
|
|
66068
|
+
const fullPath = path49.join(cwd, filePath);
|
|
66051
66069
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
66052
66070
|
return [];
|
|
66053
66071
|
}
|
|
@@ -66199,7 +66217,7 @@ function extractTSSymbols(filePath, cwd) {
|
|
|
66199
66217
|
});
|
|
66200
66218
|
}
|
|
66201
66219
|
function extractPythonSymbols(filePath, cwd) {
|
|
66202
|
-
const fullPath =
|
|
66220
|
+
const fullPath = path49.join(cwd, filePath);
|
|
66203
66221
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
66204
66222
|
return [];
|
|
66205
66223
|
}
|
|
@@ -66282,7 +66300,7 @@ var symbols = createSwarmTool({
|
|
|
66282
66300
|
}, null, 2);
|
|
66283
66301
|
}
|
|
66284
66302
|
const cwd = directory;
|
|
66285
|
-
const ext =
|
|
66303
|
+
const ext = path49.extname(file3);
|
|
66286
66304
|
if (containsControlChars(file3)) {
|
|
66287
66305
|
return JSON.stringify({
|
|
66288
66306
|
file: file3,
|
|
@@ -66346,7 +66364,7 @@ var symbols = createSwarmTool({
|
|
|
66346
66364
|
var WINDOWS_RENAME_MAX_RETRIES = 3;
|
|
66347
66365
|
var WINDOWS_RENAME_RETRY_DELAY_MS = 50;
|
|
66348
66366
|
function normalizeGraphPath(filePath) {
|
|
66349
|
-
return
|
|
66367
|
+
return path50.normalize(filePath).replace(/\\/g, "/");
|
|
66350
66368
|
}
|
|
66351
66369
|
var REPO_GRAPH_FILENAME = "repo-graph.json";
|
|
66352
66370
|
var GRAPH_SCHEMA_VERSION = "1.0.0";
|
|
@@ -66455,8 +66473,8 @@ function resolveModuleSpecifier(workspaceRoot, sourceFile, specifier) {
|
|
|
66455
66473
|
}
|
|
66456
66474
|
try {
|
|
66457
66475
|
if (specifier.startsWith(".")) {
|
|
66458
|
-
const sourceDir =
|
|
66459
|
-
let resolved =
|
|
66476
|
+
const sourceDir = path50.dirname(sourceFile);
|
|
66477
|
+
let resolved = path50.resolve(sourceDir, specifier);
|
|
66460
66478
|
let realResolved;
|
|
66461
66479
|
try {
|
|
66462
66480
|
realResolved = realpathSync6(resolved);
|
|
@@ -66467,7 +66485,7 @@ function resolveModuleSpecifier(workspaceRoot, sourceFile, specifier) {
|
|
|
66467
66485
|
try {
|
|
66468
66486
|
realRoot = realpathSync6(workspaceRoot);
|
|
66469
66487
|
} catch {
|
|
66470
|
-
realRoot =
|
|
66488
|
+
realRoot = path50.normalize(workspaceRoot);
|
|
66471
66489
|
}
|
|
66472
66490
|
if (!existsSync28(resolved)) {
|
|
66473
66491
|
const EXTENSIONS = [
|
|
@@ -66499,9 +66517,9 @@ function resolveModuleSpecifier(workspaceRoot, sourceFile, specifier) {
|
|
|
66499
66517
|
return null;
|
|
66500
66518
|
}
|
|
66501
66519
|
}
|
|
66502
|
-
const normalizedResolved =
|
|
66503
|
-
const normalizedRoot =
|
|
66504
|
-
if (!normalizedResolved.startsWith(normalizedRoot +
|
|
66520
|
+
const normalizedResolved = path50.normalize(realResolved);
|
|
66521
|
+
const normalizedRoot = path50.normalize(realRoot);
|
|
66522
|
+
if (!normalizedResolved.startsWith(normalizedRoot + path50.sep) && normalizedResolved !== normalizedRoot) {
|
|
66505
66523
|
return null;
|
|
66506
66524
|
}
|
|
66507
66525
|
return resolved;
|
|
@@ -66514,7 +66532,7 @@ function resolveModuleSpecifier(workspaceRoot, sourceFile, specifier) {
|
|
|
66514
66532
|
function createEmptyGraph(workspaceRoot) {
|
|
66515
66533
|
return {
|
|
66516
66534
|
schema_version: GRAPH_SCHEMA_VERSION,
|
|
66517
|
-
workspaceRoot:
|
|
66535
|
+
workspaceRoot: path50.normalize(workspaceRoot),
|
|
66518
66536
|
nodes: {},
|
|
66519
66537
|
edges: [],
|
|
66520
66538
|
metadata: {
|
|
@@ -66548,10 +66566,10 @@ function addEdge(graph, edge) {
|
|
|
66548
66566
|
}
|
|
66549
66567
|
}
|
|
66550
66568
|
function getCachedGraph(workspace) {
|
|
66551
|
-
return graphCache.get(
|
|
66569
|
+
return graphCache.get(path50.normalize(workspace));
|
|
66552
66570
|
}
|
|
66553
66571
|
function setCachedGraph(workspace, graph, mtime) {
|
|
66554
|
-
const normalized =
|
|
66572
|
+
const normalized = path50.normalize(workspace);
|
|
66555
66573
|
graphCache.set(normalized, graph);
|
|
66556
66574
|
dirtyFlags.set(normalized, false);
|
|
66557
66575
|
if (mtime !== undefined) {
|
|
@@ -66559,10 +66577,10 @@ function setCachedGraph(workspace, graph, mtime) {
|
|
|
66559
66577
|
}
|
|
66560
66578
|
}
|
|
66561
66579
|
function isDirty(workspace) {
|
|
66562
|
-
return dirtyFlags.get(
|
|
66580
|
+
return dirtyFlags.get(path50.normalize(workspace)) ?? false;
|
|
66563
66581
|
}
|
|
66564
66582
|
function clearCache(workspace) {
|
|
66565
|
-
const normalized =
|
|
66583
|
+
const normalized = path50.normalize(workspace);
|
|
66566
66584
|
graphCache.delete(normalized);
|
|
66567
66585
|
dirtyFlags.delete(normalized);
|
|
66568
66586
|
mtimeCache.delete(normalized);
|
|
@@ -66575,7 +66593,7 @@ function getGraphPath(workspace) {
|
|
|
66575
66593
|
}
|
|
66576
66594
|
async function loadGraph(workspace) {
|
|
66577
66595
|
validateWorkspace(workspace);
|
|
66578
|
-
const normalized =
|
|
66596
|
+
const normalized = path50.normalize(workspace);
|
|
66579
66597
|
const cached3 = getCachedGraph(normalized);
|
|
66580
66598
|
if (cached3 && !isDirty(normalized)) {
|
|
66581
66599
|
try {
|
|
@@ -66669,28 +66687,28 @@ async function saveGraph(workspace, graph, options) {
|
|
|
66669
66687
|
if (!Array.isArray(graph.edges)) {
|
|
66670
66688
|
throw new Error("Graph must have edges array");
|
|
66671
66689
|
}
|
|
66672
|
-
const normalizedWorkspace =
|
|
66690
|
+
const normalizedWorkspace = path50.normalize(workspace);
|
|
66673
66691
|
let realWorkspace;
|
|
66674
66692
|
try {
|
|
66675
66693
|
realWorkspace = realpathSync6(workspace);
|
|
66676
66694
|
} catch {
|
|
66677
66695
|
realWorkspace = normalizedWorkspace;
|
|
66678
66696
|
}
|
|
66679
|
-
const normalizedGraphRoot =
|
|
66697
|
+
const normalizedGraphRoot = path50.normalize(graph.workspaceRoot);
|
|
66680
66698
|
let realGraphRoot;
|
|
66681
66699
|
try {
|
|
66682
66700
|
realGraphRoot = realpathSync6(graph.workspaceRoot);
|
|
66683
66701
|
} catch {
|
|
66684
66702
|
realGraphRoot = normalizedGraphRoot;
|
|
66685
66703
|
}
|
|
66686
|
-
if (
|
|
66704
|
+
if (path50.normalize(realWorkspace) !== path50.normalize(realGraphRoot)) {
|
|
66687
66705
|
throw new Error(`Graph workspaceRoot mismatch: graph was built for "${graph.workspaceRoot}" but save was called for "${workspace}"`);
|
|
66688
66706
|
}
|
|
66689
66707
|
const normalized = normalizedWorkspace;
|
|
66690
66708
|
const graphPath = getGraphPath(workspace);
|
|
66691
66709
|
updateGraphMetadata(graph);
|
|
66692
66710
|
const tempPath = `${graphPath}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`;
|
|
66693
|
-
await fsPromises3.mkdir(
|
|
66711
|
+
await fsPromises3.mkdir(path50.dirname(tempPath), { recursive: true });
|
|
66694
66712
|
let lastError = null;
|
|
66695
66713
|
try {
|
|
66696
66714
|
if (options?.createAtomic) {
|
|
@@ -66821,7 +66839,7 @@ function findSourceFiles(dir, stats) {
|
|
|
66821
66839
|
stats.skippedDirs++;
|
|
66822
66840
|
continue;
|
|
66823
66841
|
}
|
|
66824
|
-
const fullPath =
|
|
66842
|
+
const fullPath = path50.join(dir, entry);
|
|
66825
66843
|
let stat3;
|
|
66826
66844
|
try {
|
|
66827
66845
|
stat3 = fsSync2.statSync(fullPath);
|
|
@@ -66832,7 +66850,7 @@ function findSourceFiles(dir, stats) {
|
|
|
66832
66850
|
const subFiles = findSourceFiles(fullPath, stats);
|
|
66833
66851
|
files.push(...subFiles);
|
|
66834
66852
|
} else if (stat3.isFile()) {
|
|
66835
|
-
const ext =
|
|
66853
|
+
const ext = path50.extname(fullPath).toLowerCase();
|
|
66836
66854
|
if (SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
66837
66855
|
files.push(fullPath);
|
|
66838
66856
|
}
|
|
@@ -66841,11 +66859,11 @@ function findSourceFiles(dir, stats) {
|
|
|
66841
66859
|
return files;
|
|
66842
66860
|
}
|
|
66843
66861
|
function toModuleName(filePath, workspaceRoot) {
|
|
66844
|
-
const relative9 =
|
|
66845
|
-
return relative9.split(
|
|
66862
|
+
const relative9 = path50.relative(workspaceRoot, filePath);
|
|
66863
|
+
return relative9.split(path50.sep).join("/");
|
|
66846
66864
|
}
|
|
66847
66865
|
function getLanguage(filePath) {
|
|
66848
|
-
const ext =
|
|
66866
|
+
const ext = path50.extname(filePath).toLowerCase();
|
|
66849
66867
|
return EXTENSION_TO_LANGUAGE[ext] ?? "unknown";
|
|
66850
66868
|
}
|
|
66851
66869
|
function isBinaryContent(content) {
|
|
@@ -66858,7 +66876,7 @@ function buildWorkspaceGraph(workspaceRoot, options) {
|
|
|
66858
66876
|
validateWorkspace(workspaceRoot);
|
|
66859
66877
|
const maxFileSize = options?.maxFileSizeBytes ?? 1024 * 1024;
|
|
66860
66878
|
const maxFiles = options?.maxFiles ?? 1e4;
|
|
66861
|
-
const absoluteRoot =
|
|
66879
|
+
const absoluteRoot = path50.resolve(workspaceRoot);
|
|
66862
66880
|
if (!existsSync28(absoluteRoot)) {
|
|
66863
66881
|
throw new Error(`Workspace directory does not exist: ${workspaceRoot}`);
|
|
66864
66882
|
}
|
|
@@ -66899,16 +66917,16 @@ function buildWorkspaceGraph(workspaceRoot, options) {
|
|
|
66899
66917
|
continue;
|
|
66900
66918
|
}
|
|
66901
66919
|
stats.filesScanned++;
|
|
66902
|
-
const ext =
|
|
66920
|
+
const ext = path50.extname(filePath).toLowerCase();
|
|
66903
66921
|
let exports = [];
|
|
66904
66922
|
let parsedImports = [];
|
|
66905
66923
|
try {
|
|
66906
66924
|
if ([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"].includes(ext)) {
|
|
66907
|
-
const relativePath =
|
|
66925
|
+
const relativePath = path50.relative(absoluteRoot, filePath);
|
|
66908
66926
|
const symbols2 = extractTSSymbols(relativePath, absoluteRoot);
|
|
66909
66927
|
exports = symbols2.filter((s) => s.exported).map((s) => s.name);
|
|
66910
66928
|
} else if (ext === ".py") {
|
|
66911
|
-
const relativePath =
|
|
66929
|
+
const relativePath = path50.relative(absoluteRoot, filePath);
|
|
66912
66930
|
const symbols2 = extractPythonSymbols(relativePath, absoluteRoot);
|
|
66913
66931
|
exports = symbols2.filter((s) => s.exported).map((s) => s.name);
|
|
66914
66932
|
}
|
|
@@ -66965,15 +66983,15 @@ function scanFile(filePath, absoluteRoot, maxFileSize) {
|
|
|
66965
66983
|
if (isBinaryContent(content)) {
|
|
66966
66984
|
return { node: null, edges: [] };
|
|
66967
66985
|
}
|
|
66968
|
-
const ext =
|
|
66986
|
+
const ext = path50.extname(filePath).toLowerCase();
|
|
66969
66987
|
let exports = [];
|
|
66970
66988
|
try {
|
|
66971
66989
|
if ([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"].includes(ext)) {
|
|
66972
|
-
const relativePath =
|
|
66990
|
+
const relativePath = path50.relative(absoluteRoot, filePath);
|
|
66973
66991
|
const symbols2 = extractTSSymbols(relativePath, absoluteRoot);
|
|
66974
66992
|
exports = symbols2.filter((s) => s.exported).map((s) => s.name);
|
|
66975
66993
|
} else if (ext === ".py") {
|
|
66976
|
-
const relativePath =
|
|
66994
|
+
const relativePath = path50.relative(absoluteRoot, filePath);
|
|
66977
66995
|
const symbols2 = extractPythonSymbols(relativePath, absoluteRoot);
|
|
66978
66996
|
exports = symbols2.filter((s) => s.exported).map((s) => s.name);
|
|
66979
66997
|
}
|
|
@@ -67017,7 +67035,7 @@ async function updateGraphForFiles(workspaceRoot, filePaths, options) {
|
|
|
67017
67035
|
return graph2;
|
|
67018
67036
|
}
|
|
67019
67037
|
const graph = existingGraph;
|
|
67020
|
-
const absoluteRoot =
|
|
67038
|
+
const absoluteRoot = path50.resolve(workspaceRoot);
|
|
67021
67039
|
const maxFileSize = 1024 * 1024;
|
|
67022
67040
|
const updatedPaths = new Set;
|
|
67023
67041
|
for (const rawFilePath of filePaths) {
|
|
@@ -67130,7 +67148,7 @@ function createRepoGraphBuilderHook(workspaceRoot, deps) {
|
|
|
67130
67148
|
if (!isSupportedSourceFile(filePath)) {
|
|
67131
67149
|
return;
|
|
67132
67150
|
}
|
|
67133
|
-
const absoluteFilePath =
|
|
67151
|
+
const absoluteFilePath = path51.isAbsolute(filePath) ? filePath : path51.resolve(workspaceRoot, filePath);
|
|
67134
67152
|
const normalizedAbsolute = absoluteFilePath.replace(/\\/g, "/");
|
|
67135
67153
|
const normalizedWorkspace = workspaceRoot.replace(/\\/g, "/");
|
|
67136
67154
|
if (!normalizedAbsolute.startsWith(`${normalizedWorkspace}/`) && normalizedAbsolute !== normalizedWorkspace) {
|
|
@@ -67138,7 +67156,7 @@ function createRepoGraphBuilderHook(workspaceRoot, deps) {
|
|
|
67138
67156
|
}
|
|
67139
67157
|
try {
|
|
67140
67158
|
await _updateGraphForFiles(workspaceRoot, [absoluteFilePath]);
|
|
67141
|
-
log(`[repo-graph] Incremental update for ${
|
|
67159
|
+
log(`[repo-graph] Incremental update for ${path51.basename(filePath)}`);
|
|
67142
67160
|
} catch (error93) {
|
|
67143
67161
|
const message = error93 instanceof Error ? error93.message : String(error93);
|
|
67144
67162
|
error48(`[repo-graph] Incremental update failed: ${message}`);
|
|
@@ -67157,14 +67175,14 @@ init_manager2();
|
|
|
67157
67175
|
init_detector();
|
|
67158
67176
|
init_manager();
|
|
67159
67177
|
import * as fs44 from "node:fs";
|
|
67160
|
-
import * as
|
|
67178
|
+
import * as path61 from "node:path";
|
|
67161
67179
|
|
|
67162
67180
|
// src/services/decision-drift-analyzer.ts
|
|
67163
67181
|
init_utils2();
|
|
67164
67182
|
init_manager();
|
|
67165
67183
|
init_utils();
|
|
67166
67184
|
import * as fs36 from "node:fs";
|
|
67167
|
-
import * as
|
|
67185
|
+
import * as path52 from "node:path";
|
|
67168
67186
|
var DEFAULT_DRIFT_CONFIG = {
|
|
67169
67187
|
staleThresholdPhases: 1,
|
|
67170
67188
|
detectContradictions: true,
|
|
@@ -67318,7 +67336,7 @@ async function analyzeDecisionDrift(directory, config3 = {}) {
|
|
|
67318
67336
|
currentPhase = legacyPhase;
|
|
67319
67337
|
}
|
|
67320
67338
|
}
|
|
67321
|
-
const contextPath =
|
|
67339
|
+
const contextPath = path52.join(directory, ".swarm", "context.md");
|
|
67322
67340
|
let contextContent = "";
|
|
67323
67341
|
try {
|
|
67324
67342
|
if (fs36.existsSync(contextPath)) {
|
|
@@ -67457,7 +67475,7 @@ init_utils();
|
|
|
67457
67475
|
init_constants();
|
|
67458
67476
|
init_schema();
|
|
67459
67477
|
import * as fs37 from "node:fs/promises";
|
|
67460
|
-
import * as
|
|
67478
|
+
import * as path53 from "node:path";
|
|
67461
67479
|
function safeGet(obj, key) {
|
|
67462
67480
|
if (!obj || !Object.hasOwn(obj, key))
|
|
67463
67481
|
return;
|
|
@@ -67689,23 +67707,18 @@ async function handleDebuggingSpiral(match, taskId, directory) {
|
|
|
67689
67707
|
let eventLogged = false;
|
|
67690
67708
|
let checkpointCreated = false;
|
|
67691
67709
|
try {
|
|
67692
|
-
const swarmDir =
|
|
67710
|
+
const swarmDir = path53.join(directory, ".swarm");
|
|
67693
67711
|
await fs37.mkdir(swarmDir, { recursive: true });
|
|
67694
|
-
const eventsPath =
|
|
67712
|
+
const eventsPath = path53.join(swarmDir, "events.jsonl");
|
|
67695
67713
|
await fs37.appendFile(eventsPath, `${formatDebuggingSpiralEvent(match, taskId)}
|
|
67696
67714
|
`);
|
|
67697
67715
|
eventLogged = true;
|
|
67698
67716
|
} catch {}
|
|
67699
67717
|
const checkpointLabel = `spiral-${taskId}-${Date.now()}`;
|
|
67700
67718
|
try {
|
|
67701
|
-
const {
|
|
67702
|
-
const result =
|
|
67703
|
-
|
|
67704
|
-
const parsed = JSON.parse(result);
|
|
67705
|
-
checkpointCreated = parsed.success === true;
|
|
67706
|
-
} catch {
|
|
67707
|
-
checkpointCreated = false;
|
|
67708
|
-
}
|
|
67719
|
+
const { saveCheckpointRecord: saveCheckpointRecord2 } = await Promise.resolve().then(() => (init_checkpoint(), exports_checkpoint));
|
|
67720
|
+
const result = saveCheckpointRecord2(checkpointLabel, directory);
|
|
67721
|
+
checkpointCreated = result.success === true;
|
|
67709
67722
|
} catch {
|
|
67710
67723
|
checkpointCreated = false;
|
|
67711
67724
|
}
|
|
@@ -67831,7 +67844,7 @@ import * as fs41 from "node:fs";
|
|
|
67831
67844
|
|
|
67832
67845
|
// src/graph/graph-builder.ts
|
|
67833
67846
|
import * as fs39 from "node:fs";
|
|
67834
|
-
import * as
|
|
67847
|
+
import * as path56 from "node:path";
|
|
67835
67848
|
|
|
67836
67849
|
// node_modules/yocto-queue/index.js
|
|
67837
67850
|
class Node {
|
|
@@ -67992,7 +68005,7 @@ function validateConcurrency(concurrency) {
|
|
|
67992
68005
|
// src/graph/import-extractor.ts
|
|
67993
68006
|
init_path_security();
|
|
67994
68007
|
import * as fs38 from "node:fs";
|
|
67995
|
-
import * as
|
|
68008
|
+
import * as path54 from "node:path";
|
|
67996
68009
|
var SOURCE_EXTENSIONS2 = [
|
|
67997
68010
|
".ts",
|
|
67998
68011
|
".tsx",
|
|
@@ -68037,14 +68050,14 @@ function getLanguageFromExtension(ext) {
|
|
|
68037
68050
|
return null;
|
|
68038
68051
|
}
|
|
68039
68052
|
function toRelForwardSlash(absPath, root) {
|
|
68040
|
-
return
|
|
68053
|
+
return path54.relative(root, absPath).replace(/\\/g, "/");
|
|
68041
68054
|
}
|
|
68042
68055
|
function tryResolveTSJS(rawModule, sourceFileAbs) {
|
|
68043
68056
|
if (!rawModule.startsWith(".") && !rawModule.startsWith("/")) {
|
|
68044
68057
|
return null;
|
|
68045
68058
|
}
|
|
68046
|
-
const sourceDir =
|
|
68047
|
-
const baseAbs =
|
|
68059
|
+
const sourceDir = path54.dirname(sourceFileAbs);
|
|
68060
|
+
const baseAbs = path54.resolve(sourceDir, rawModule);
|
|
68048
68061
|
const probe = (basePath) => {
|
|
68049
68062
|
for (const ext of RESOLVE_EXTENSION_CANDIDATES) {
|
|
68050
68063
|
const test = basePath + ext;
|
|
@@ -68055,7 +68068,7 @@ function tryResolveTSJS(rawModule, sourceFileAbs) {
|
|
|
68055
68068
|
} catch {}
|
|
68056
68069
|
}
|
|
68057
68070
|
for (const indexFile of RESOLVE_INDEX_CANDIDATES) {
|
|
68058
|
-
const test =
|
|
68071
|
+
const test = path54.join(basePath, indexFile);
|
|
68059
68072
|
try {
|
|
68060
68073
|
const stat3 = fs38.statSync(test);
|
|
68061
68074
|
if (stat3.isFile())
|
|
@@ -68085,13 +68098,13 @@ function tryResolvePython(rawModule, sourceFileAbs, workspaceRoot) {
|
|
|
68085
68098
|
}
|
|
68086
68099
|
const remainder = rawModule.slice(leadingDots).replace(/\./g, "/");
|
|
68087
68100
|
const upDirs = "../".repeat(Math.max(0, leadingDots - 1));
|
|
68088
|
-
const sourceDir =
|
|
68089
|
-
const baseAbs =
|
|
68101
|
+
const sourceDir = path54.dirname(sourceFileAbs);
|
|
68102
|
+
const baseAbs = path54.resolve(sourceDir, upDirs + remainder);
|
|
68090
68103
|
const accept = (test) => {
|
|
68091
68104
|
try {
|
|
68092
68105
|
const stat3 = fs38.statSync(test);
|
|
68093
68106
|
if (stat3.isFile()) {
|
|
68094
|
-
const rel =
|
|
68107
|
+
const rel = path54.relative(workspaceRoot, test).replace(/\\/g, "/");
|
|
68095
68108
|
if (rel.startsWith(".."))
|
|
68096
68109
|
return null;
|
|
68097
68110
|
return test;
|
|
@@ -68105,7 +68118,7 @@ function tryResolvePython(rawModule, sourceFileAbs, workspaceRoot) {
|
|
|
68105
68118
|
return hit;
|
|
68106
68119
|
}
|
|
68107
68120
|
for (const indexFile of PY_INDEX_CANDIDATES) {
|
|
68108
|
-
const hit = accept(
|
|
68121
|
+
const hit = accept(path54.join(baseAbs, indexFile));
|
|
68109
68122
|
if (hit)
|
|
68110
68123
|
return hit;
|
|
68111
68124
|
}
|
|
@@ -68476,7 +68489,7 @@ function parseRustUses(content) {
|
|
|
68476
68489
|
}
|
|
68477
68490
|
function extractImports2(opts) {
|
|
68478
68491
|
const { absoluteFilePath, workspaceRoot } = opts;
|
|
68479
|
-
const ext =
|
|
68492
|
+
const ext = path54.extname(absoluteFilePath).toLowerCase();
|
|
68480
68493
|
const language = getLanguageFromExtension(ext);
|
|
68481
68494
|
if (!language)
|
|
68482
68495
|
return [];
|
|
@@ -68527,9 +68540,9 @@ function extractImports2(opts) {
|
|
|
68527
68540
|
}
|
|
68528
68541
|
|
|
68529
68542
|
// src/graph/symbol-extractor.ts
|
|
68530
|
-
import * as
|
|
68543
|
+
import * as path55 from "node:path";
|
|
68531
68544
|
function extractExportedSymbols(relativeFilePath, workspaceRoot) {
|
|
68532
|
-
const ext =
|
|
68545
|
+
const ext = path55.extname(relativeFilePath).toLowerCase();
|
|
68533
68546
|
const language = getLanguageFromExtension(ext);
|
|
68534
68547
|
if (!language)
|
|
68535
68548
|
return [];
|
|
@@ -68618,15 +68631,15 @@ function findSourceFiles2(workspaceRoot, skipDirs = DEFAULT_SKIP_DIRS) {
|
|
|
68618
68631
|
if (entry.isDirectory()) {
|
|
68619
68632
|
if (skipDirs.has(entry.name))
|
|
68620
68633
|
continue;
|
|
68621
|
-
stack.push(
|
|
68634
|
+
stack.push(path56.join(dir, entry.name));
|
|
68622
68635
|
continue;
|
|
68623
68636
|
}
|
|
68624
68637
|
if (!entry.isFile())
|
|
68625
68638
|
continue;
|
|
68626
|
-
const ext =
|
|
68639
|
+
const ext = path56.extname(entry.name).toLowerCase();
|
|
68627
68640
|
if (!SOURCE_EXT_SET.has(ext))
|
|
68628
68641
|
continue;
|
|
68629
|
-
out2.push(
|
|
68642
|
+
out2.push(path56.join(dir, entry.name));
|
|
68630
68643
|
}
|
|
68631
68644
|
}
|
|
68632
68645
|
return out2;
|
|
@@ -68654,7 +68667,7 @@ async function buildRepoGraph(workspaceRoot, options = {}) {
|
|
|
68654
68667
|
};
|
|
68655
68668
|
}
|
|
68656
68669
|
async function processFile(absoluteFilePath, workspaceRoot) {
|
|
68657
|
-
const ext =
|
|
68670
|
+
const ext = path56.extname(absoluteFilePath).toLowerCase();
|
|
68658
68671
|
const language = getLanguageFromExtension(ext);
|
|
68659
68672
|
if (!language)
|
|
68660
68673
|
return null;
|
|
@@ -68674,7 +68687,7 @@ async function processFile(absoluteFilePath, workspaceRoot) {
|
|
|
68674
68687
|
} catch {
|
|
68675
68688
|
return null;
|
|
68676
68689
|
}
|
|
68677
|
-
const relPath =
|
|
68690
|
+
const relPath = path56.relative(workspaceRoot, absoluteFilePath).replace(/\\/g, "/");
|
|
68678
68691
|
const imports = extractImports2({
|
|
68679
68692
|
absoluteFilePath,
|
|
68680
68693
|
workspaceRoot,
|
|
@@ -68916,10 +68929,10 @@ function formatSummary(opts) {
|
|
|
68916
68929
|
// src/graph/graph-store.ts
|
|
68917
68930
|
import * as crypto6 from "node:crypto";
|
|
68918
68931
|
import * as fs40 from "node:fs";
|
|
68919
|
-
import * as
|
|
68932
|
+
import * as path57 from "node:path";
|
|
68920
68933
|
var SWARM_DIR = ".swarm";
|
|
68921
68934
|
function getGraphPath2(workspaceRoot) {
|
|
68922
|
-
return
|
|
68935
|
+
return path57.join(workspaceRoot, SWARM_DIR, REPO_GRAPH_FILENAME2);
|
|
68923
68936
|
}
|
|
68924
68937
|
function loadGraph2(workspaceRoot) {
|
|
68925
68938
|
const file3 = getGraphPath2(workspaceRoot);
|
|
@@ -68941,7 +68954,7 @@ function loadGraph2(workspaceRoot) {
|
|
|
68941
68954
|
}
|
|
68942
68955
|
function saveGraph2(workspaceRoot, graph) {
|
|
68943
68956
|
const file3 = getGraphPath2(workspaceRoot);
|
|
68944
|
-
const dir =
|
|
68957
|
+
const dir = path57.dirname(file3);
|
|
68945
68958
|
try {
|
|
68946
68959
|
const stat3 = fs40.lstatSync(dir);
|
|
68947
68960
|
if (stat3.isSymbolicLink()) {
|
|
@@ -69047,7 +69060,7 @@ function buildReviewerBlastRadiusBlock(directory, changedFiles) {
|
|
|
69047
69060
|
// src/hooks/semantic-diff-injection.ts
|
|
69048
69061
|
import * as child_process5 from "node:child_process";
|
|
69049
69062
|
import * as fs42 from "node:fs";
|
|
69050
|
-
import * as
|
|
69063
|
+
import * as path59 from "node:path";
|
|
69051
69064
|
|
|
69052
69065
|
// src/diff/ast-diff.ts
|
|
69053
69066
|
init_tree_sitter();
|
|
@@ -69794,17 +69807,17 @@ async function buildSemanticDiffBlock(directory, changedFiles, maxFiles = 10) {
|
|
|
69794
69807
|
const fileConsumers = {};
|
|
69795
69808
|
if (graph) {
|
|
69796
69809
|
for (const f of filesToProcess) {
|
|
69797
|
-
const relativePath =
|
|
69810
|
+
const relativePath = path59.isAbsolute(f) ? path59.relative(directory, f) : f;
|
|
69798
69811
|
const normalized = normalizeGraphPath2(relativePath);
|
|
69799
69812
|
fileConsumers[normalized] = getImporters(graph, normalized).length;
|
|
69800
69813
|
fileConsumers[f] = fileConsumers[normalized];
|
|
69801
69814
|
}
|
|
69802
69815
|
}
|
|
69803
69816
|
for (const filePath of filesToProcess) {
|
|
69804
|
-
const normalizedPath =
|
|
69805
|
-
const resolvedPath =
|
|
69806
|
-
const relativeToDir =
|
|
69807
|
-
if (relativeToDir.startsWith("..") ||
|
|
69817
|
+
const normalizedPath = path59.normalize(filePath);
|
|
69818
|
+
const resolvedPath = path59.resolve(directory, normalizedPath);
|
|
69819
|
+
const relativeToDir = path59.relative(directory, resolvedPath);
|
|
69820
|
+
if (relativeToDir.startsWith("..") || path59.isAbsolute(relativeToDir)) {
|
|
69808
69821
|
continue;
|
|
69809
69822
|
}
|
|
69810
69823
|
try {
|
|
@@ -69831,7 +69844,7 @@ async function buildSemanticDiffBlock(directory, changedFiles, maxFiles = 10) {
|
|
|
69831
69844
|
stdio: "pipe",
|
|
69832
69845
|
maxBuffer: 5 * 1024 * 1024
|
|
69833
69846
|
}) : "";
|
|
69834
|
-
const newContent = fs42.readFileSync(
|
|
69847
|
+
const newContent = fs42.readFileSync(path59.join(directory, filePath), "utf-8");
|
|
69835
69848
|
const astResult = await computeASTDiff(filePath, oldContent, newContent);
|
|
69836
69849
|
if (astResult && (astResult.changes.length > 0 || astResult.error !== undefined)) {
|
|
69837
69850
|
astDiffs.push(astResult);
|
|
@@ -70173,7 +70186,7 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
70173
70186
|
await fs44.promises.writeFile(darkMatterPath, darkMatterReport, "utf-8");
|
|
70174
70187
|
warn(`[system-enhancer] Dark matter scan complete: ${darkMatter.length} co-change patterns found`);
|
|
70175
70188
|
try {
|
|
70176
|
-
const projectName =
|
|
70189
|
+
const projectName = path61.basename(path61.resolve(directory));
|
|
70177
70190
|
const knowledgeEntries = darkMatterToKnowledgeEntries2(darkMatter, projectName);
|
|
70178
70191
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
70179
70192
|
const existingEntries = await readKnowledge(knowledgePath);
|
|
@@ -70372,7 +70385,7 @@ ${lines.join(`
|
|
|
70372
70385
|
try {
|
|
70373
70386
|
const taskId_ccp = ccpSession?.currentTaskId;
|
|
70374
70387
|
if (taskId_ccp && !taskId_ccp.includes("..") && !taskId_ccp.includes("/") && !taskId_ccp.includes("\\") && !taskId_ccp.includes("\x00")) {
|
|
70375
|
-
const evidencePath =
|
|
70388
|
+
const evidencePath = path61.join(directory, ".swarm", "evidence", `${taskId_ccp}.json`);
|
|
70376
70389
|
if (fs44.existsSync(evidencePath)) {
|
|
70377
70390
|
const evidenceContent = fs44.readFileSync(evidencePath, "utf-8");
|
|
70378
70391
|
const evidenceData = JSON.parse(evidenceContent);
|
|
@@ -71518,7 +71531,7 @@ init_hive_promoter();
|
|
|
71518
71531
|
|
|
71519
71532
|
// src/hooks/incremental-verify.ts
|
|
71520
71533
|
import * as fs45 from "node:fs";
|
|
71521
|
-
import * as
|
|
71534
|
+
import * as path62 from "node:path";
|
|
71522
71535
|
|
|
71523
71536
|
// src/hooks/spawn-helper.ts
|
|
71524
71537
|
import * as child_process6 from "node:child_process";
|
|
@@ -71596,18 +71609,18 @@ function spawnAsync(command, cwd, timeoutMs) {
|
|
|
71596
71609
|
// src/hooks/incremental-verify.ts
|
|
71597
71610
|
var emittedSkipAdvisories = new Set;
|
|
71598
71611
|
function detectPackageManager(projectDir) {
|
|
71599
|
-
if (fs45.existsSync(
|
|
71612
|
+
if (fs45.existsSync(path62.join(projectDir, "bun.lockb")))
|
|
71600
71613
|
return "bun";
|
|
71601
|
-
if (fs45.existsSync(
|
|
71614
|
+
if (fs45.existsSync(path62.join(projectDir, "pnpm-lock.yaml")))
|
|
71602
71615
|
return "pnpm";
|
|
71603
|
-
if (fs45.existsSync(
|
|
71616
|
+
if (fs45.existsSync(path62.join(projectDir, "yarn.lock")))
|
|
71604
71617
|
return "yarn";
|
|
71605
|
-
if (fs45.existsSync(
|
|
71618
|
+
if (fs45.existsSync(path62.join(projectDir, "package-lock.json")))
|
|
71606
71619
|
return "npm";
|
|
71607
71620
|
return "bun";
|
|
71608
71621
|
}
|
|
71609
71622
|
function detectTypecheckCommand(projectDir) {
|
|
71610
|
-
const pkgPath =
|
|
71623
|
+
const pkgPath = path62.join(projectDir, "package.json");
|
|
71611
71624
|
if (fs45.existsSync(pkgPath)) {
|
|
71612
71625
|
try {
|
|
71613
71626
|
const pkg = JSON.parse(fs45.readFileSync(pkgPath, "utf8"));
|
|
@@ -71624,8 +71637,8 @@ function detectTypecheckCommand(projectDir) {
|
|
|
71624
71637
|
...pkg.dependencies,
|
|
71625
71638
|
...pkg.devDependencies
|
|
71626
71639
|
};
|
|
71627
|
-
if (!deps?.typescript && !fs45.existsSync(
|
|
71628
|
-
const hasTSMarkers = deps?.typescript || fs45.existsSync(
|
|
71640
|
+
if (!deps?.typescript && !fs45.existsSync(path62.join(projectDir, "tsconfig.json"))) {}
|
|
71641
|
+
const hasTSMarkers = deps?.typescript || fs45.existsSync(path62.join(projectDir, "tsconfig.json"));
|
|
71629
71642
|
if (hasTSMarkers) {
|
|
71630
71643
|
return { command: ["npx", "tsc", "--noEmit"], language: "typescript" };
|
|
71631
71644
|
}
|
|
@@ -71633,13 +71646,13 @@ function detectTypecheckCommand(projectDir) {
|
|
|
71633
71646
|
return null;
|
|
71634
71647
|
}
|
|
71635
71648
|
}
|
|
71636
|
-
if (fs45.existsSync(
|
|
71649
|
+
if (fs45.existsSync(path62.join(projectDir, "go.mod"))) {
|
|
71637
71650
|
return { command: ["go", "vet", "./..."], language: "go" };
|
|
71638
71651
|
}
|
|
71639
|
-
if (fs45.existsSync(
|
|
71652
|
+
if (fs45.existsSync(path62.join(projectDir, "Cargo.toml"))) {
|
|
71640
71653
|
return { command: ["cargo", "check"], language: "rust" };
|
|
71641
71654
|
}
|
|
71642
|
-
if (fs45.existsSync(
|
|
71655
|
+
if (fs45.existsSync(path62.join(projectDir, "pyproject.toml")) || fs45.existsSync(path62.join(projectDir, "requirements.txt")) || fs45.existsSync(path62.join(projectDir, "setup.py"))) {
|
|
71643
71656
|
return { command: null, language: "python" };
|
|
71644
71657
|
}
|
|
71645
71658
|
try {
|
|
@@ -71989,7 +72002,7 @@ init_scope_persistence();
|
|
|
71989
72002
|
init_state();
|
|
71990
72003
|
init_delegation_gate();
|
|
71991
72004
|
init_normalize_tool_name();
|
|
71992
|
-
import * as
|
|
72005
|
+
import * as path64 from "node:path";
|
|
71993
72006
|
var WRITE_TOOLS = new Set(WRITE_TOOL_NAMES);
|
|
71994
72007
|
function createScopeGuardHook(config3, directory, injectAdvisory) {
|
|
71995
72008
|
const enabled = config3.enabled ?? true;
|
|
@@ -72047,13 +72060,13 @@ function createScopeGuardHook(config3, directory, injectAdvisory) {
|
|
|
72047
72060
|
}
|
|
72048
72061
|
function isFileInScope(filePath, scopeEntries, directory) {
|
|
72049
72062
|
const dir = directory ?? process.cwd();
|
|
72050
|
-
const resolvedFile =
|
|
72063
|
+
const resolvedFile = path64.resolve(dir, filePath);
|
|
72051
72064
|
return scopeEntries.some((scope) => {
|
|
72052
|
-
const resolvedScope =
|
|
72065
|
+
const resolvedScope = path64.resolve(dir, scope);
|
|
72053
72066
|
if (resolvedFile === resolvedScope)
|
|
72054
72067
|
return true;
|
|
72055
|
-
const rel =
|
|
72056
|
-
return rel.length > 0 && !rel.startsWith("..") && !
|
|
72068
|
+
const rel = path64.relative(resolvedScope, resolvedFile);
|
|
72069
|
+
return rel.length > 0 && !rel.startsWith("..") && !path64.isAbsolute(rel);
|
|
72057
72070
|
});
|
|
72058
72071
|
}
|
|
72059
72072
|
|
|
@@ -72105,7 +72118,7 @@ function createSelfReviewHook(config3, injectAdvisory) {
|
|
|
72105
72118
|
|
|
72106
72119
|
// src/hooks/slop-detector.ts
|
|
72107
72120
|
import * as fs47 from "node:fs";
|
|
72108
|
-
import * as
|
|
72121
|
+
import * as path65 from "node:path";
|
|
72109
72122
|
var WRITE_EDIT_TOOLS = new Set([
|
|
72110
72123
|
"write",
|
|
72111
72124
|
"edit",
|
|
@@ -72155,7 +72168,7 @@ function walkFiles(dir, exts, deadline) {
|
|
|
72155
72168
|
break;
|
|
72156
72169
|
if (entry.isSymbolicLink())
|
|
72157
72170
|
continue;
|
|
72158
|
-
const full =
|
|
72171
|
+
const full = path65.join(dir, entry.name);
|
|
72159
72172
|
if (entry.isDirectory()) {
|
|
72160
72173
|
if (entry.name === "node_modules" || entry.name === ".git")
|
|
72161
72174
|
continue;
|
|
@@ -72170,7 +72183,7 @@ function walkFiles(dir, exts, deadline) {
|
|
|
72170
72183
|
return results;
|
|
72171
72184
|
}
|
|
72172
72185
|
function checkDeadExports(content, projectDir, startTime) {
|
|
72173
|
-
const hasPackageJson = fs47.existsSync(
|
|
72186
|
+
const hasPackageJson = fs47.existsSync(path65.join(projectDir, "package.json"));
|
|
72174
72187
|
if (!hasPackageJson)
|
|
72175
72188
|
return null;
|
|
72176
72189
|
const exportMatches = content.matchAll(/^\+(?:export)\s+(?:function|class|const|type|interface)\s+(\w{3,})/gm);
|
|
@@ -72378,14 +72391,14 @@ function createSteeringConsumedHook(directory) {
|
|
|
72378
72391
|
// src/hooks/trajectory-logger.ts
|
|
72379
72392
|
init_manager2();
|
|
72380
72393
|
import * as fs50 from "node:fs/promises";
|
|
72381
|
-
import * as
|
|
72394
|
+
import * as path67 from "node:path";
|
|
72382
72395
|
|
|
72383
72396
|
// src/prm/trajectory-store.ts
|
|
72384
72397
|
init_utils2();
|
|
72385
72398
|
import * as fs49 from "node:fs/promises";
|
|
72386
|
-
import * as
|
|
72399
|
+
import * as path66 from "node:path";
|
|
72387
72400
|
function getTrajectoryPath(sessionId, directory) {
|
|
72388
|
-
const relativePath =
|
|
72401
|
+
const relativePath = path66.join("trajectories", `${sessionId}.jsonl`);
|
|
72389
72402
|
return validateSwarmPath(directory, relativePath);
|
|
72390
72403
|
}
|
|
72391
72404
|
var _inMemoryTrajectoryCache = new Map;
|
|
@@ -72404,7 +72417,7 @@ async function appendTrajectoryEntry(sessionId, entry, directory, maxLines = 100
|
|
|
72404
72417
|
_inMemoryTrajectoryCache.set(sessionId, cached3);
|
|
72405
72418
|
}
|
|
72406
72419
|
const trajectoryPath = getTrajectoryPath(sessionId, directory);
|
|
72407
|
-
await fs49.mkdir(
|
|
72420
|
+
await fs49.mkdir(path66.dirname(trajectoryPath), { recursive: true });
|
|
72408
72421
|
const line = `${JSON.stringify(entry)}
|
|
72409
72422
|
`;
|
|
72410
72423
|
await fs49.appendFile(trajectoryPath, line, "utf-8");
|
|
@@ -72443,7 +72456,7 @@ async function cleanupOldTrajectoryFiles(directory, maxAgeDays = 7) {
|
|
|
72443
72456
|
for (const entry of entries) {
|
|
72444
72457
|
if (!entry.isFile())
|
|
72445
72458
|
continue;
|
|
72446
|
-
const filePath =
|
|
72459
|
+
const filePath = path66.join(dirPath, entry.name);
|
|
72447
72460
|
try {
|
|
72448
72461
|
const stat4 = await fs49.stat(filePath);
|
|
72449
72462
|
if (now - stat4.mtimeMs > cutoffMs) {
|
|
@@ -72635,10 +72648,10 @@ function createTrajectoryLoggerHook(config3, _directory) {
|
|
|
72635
72648
|
elapsed_ms
|
|
72636
72649
|
};
|
|
72637
72650
|
const sanitized = sanitizeTaskId2(taskId);
|
|
72638
|
-
const relativePath =
|
|
72651
|
+
const relativePath = path67.join("evidence", sanitized, "trajectory.jsonl");
|
|
72639
72652
|
const trajectoryPath = validateSwarmPath(_directory, relativePath);
|
|
72640
72653
|
try {
|
|
72641
|
-
await fs50.mkdir(
|
|
72654
|
+
await fs50.mkdir(path67.dirname(trajectoryPath), { recursive: true });
|
|
72642
72655
|
const line = `${JSON.stringify(entry)}
|
|
72643
72656
|
`;
|
|
72644
72657
|
await fs50.appendFile(trajectoryPath, line, "utf-8");
|
|
@@ -73189,16 +73202,16 @@ init_telemetry();
|
|
|
73189
73202
|
|
|
73190
73203
|
// src/prm/replay.ts
|
|
73191
73204
|
import { promises as fs51 } from "node:fs";
|
|
73192
|
-
import
|
|
73205
|
+
import path68 from "node:path";
|
|
73193
73206
|
function isPathSafe2(targetPath, basePath) {
|
|
73194
|
-
const resolvedTarget =
|
|
73195
|
-
const resolvedBase =
|
|
73196
|
-
const rel =
|
|
73197
|
-
return !rel.startsWith("..") && !
|
|
73207
|
+
const resolvedTarget = path68.resolve(targetPath);
|
|
73208
|
+
const resolvedBase = path68.resolve(basePath);
|
|
73209
|
+
const rel = path68.relative(resolvedBase, resolvedTarget);
|
|
73210
|
+
return !rel.startsWith("..") && !path68.isAbsolute(rel);
|
|
73198
73211
|
}
|
|
73199
73212
|
function isWithinReplaysDir(targetPath) {
|
|
73200
|
-
const resolved =
|
|
73201
|
-
const parts2 = resolved.split(
|
|
73213
|
+
const resolved = path68.resolve(targetPath);
|
|
73214
|
+
const parts2 = resolved.split(path68.sep);
|
|
73202
73215
|
for (let i2 = 0;i2 < parts2.length - 1; i2++) {
|
|
73203
73216
|
if (parts2[i2] === ".swarm" && parts2[i2 + 1] === "replays") {
|
|
73204
73217
|
return true;
|
|
@@ -73211,10 +73224,10 @@ function sanitizeFilename(input) {
|
|
|
73211
73224
|
}
|
|
73212
73225
|
async function startReplayRecording(sessionID, directory) {
|
|
73213
73226
|
try {
|
|
73214
|
-
const replayDir =
|
|
73227
|
+
const replayDir = path68.join(directory, ".swarm", "replays");
|
|
73215
73228
|
const safeSessionID = sanitizeFilename(sessionID);
|
|
73216
73229
|
const filename = `${safeSessionID}-${Date.now()}.jsonl`;
|
|
73217
|
-
const filepath =
|
|
73230
|
+
const filepath = path68.join(replayDir, filename);
|
|
73218
73231
|
if (!isPathSafe2(filepath, replayDir)) {
|
|
73219
73232
|
console.warn(`[replay] Invalid path detected - path traversal attempt blocked for session ${sessionID}`);
|
|
73220
73233
|
return null;
|
|
@@ -73587,7 +73600,7 @@ init_telemetry();
|
|
|
73587
73600
|
init_dist();
|
|
73588
73601
|
init_create_tool();
|
|
73589
73602
|
import * as fs52 from "node:fs";
|
|
73590
|
-
import * as
|
|
73603
|
+
import * as path69 from "node:path";
|
|
73591
73604
|
init_path_security();
|
|
73592
73605
|
var WINDOWS_RESERVED_NAMES2 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
73593
73606
|
function containsWindowsAttacks2(str) {
|
|
@@ -73604,14 +73617,14 @@ function containsWindowsAttacks2(str) {
|
|
|
73604
73617
|
}
|
|
73605
73618
|
function isPathInWorkspace2(filePath, workspace) {
|
|
73606
73619
|
try {
|
|
73607
|
-
const resolvedPath =
|
|
73620
|
+
const resolvedPath = path69.resolve(workspace, filePath);
|
|
73608
73621
|
if (!fs52.existsSync(resolvedPath)) {
|
|
73609
73622
|
return true;
|
|
73610
73623
|
}
|
|
73611
73624
|
const realWorkspace = fs52.realpathSync(workspace);
|
|
73612
73625
|
const realResolvedPath = fs52.realpathSync(resolvedPath);
|
|
73613
|
-
const relativePath =
|
|
73614
|
-
if (relativePath.startsWith("..") ||
|
|
73626
|
+
const relativePath = path69.relative(realWorkspace, realResolvedPath);
|
|
73627
|
+
if (relativePath.startsWith("..") || path69.isAbsolute(relativePath)) {
|
|
73615
73628
|
return false;
|
|
73616
73629
|
}
|
|
73617
73630
|
return true;
|
|
@@ -73620,7 +73633,7 @@ function isPathInWorkspace2(filePath, workspace) {
|
|
|
73620
73633
|
}
|
|
73621
73634
|
}
|
|
73622
73635
|
function processFile2(file3, cwd, exportedOnly) {
|
|
73623
|
-
const ext =
|
|
73636
|
+
const ext = path69.extname(file3);
|
|
73624
73637
|
if (containsControlChars(file3)) {
|
|
73625
73638
|
return {
|
|
73626
73639
|
file: file3,
|
|
@@ -73653,7 +73666,7 @@ function processFile2(file3, cwd, exportedOnly) {
|
|
|
73653
73666
|
errorType: "path-outside-workspace"
|
|
73654
73667
|
};
|
|
73655
73668
|
}
|
|
73656
|
-
const fullPath =
|
|
73669
|
+
const fullPath = path69.join(cwd, file3);
|
|
73657
73670
|
if (!fs52.existsSync(fullPath)) {
|
|
73658
73671
|
return {
|
|
73659
73672
|
file: file3,
|
|
@@ -73945,15 +73958,15 @@ init_task_id();
|
|
|
73945
73958
|
init_create_tool();
|
|
73946
73959
|
init_resolve_working_directory();
|
|
73947
73960
|
import * as fs53 from "node:fs";
|
|
73948
|
-
import * as
|
|
73961
|
+
import * as path70 from "node:path";
|
|
73949
73962
|
var EVIDENCE_DIR = ".swarm/evidence";
|
|
73950
73963
|
function isValidTaskId3(taskId) {
|
|
73951
73964
|
return isStrictTaskId(taskId);
|
|
73952
73965
|
}
|
|
73953
73966
|
function isPathWithinSwarm(filePath, workspaceRoot) {
|
|
73954
|
-
const normalizedWorkspace =
|
|
73955
|
-
const swarmPath =
|
|
73956
|
-
const normalizedPath =
|
|
73967
|
+
const normalizedWorkspace = path70.resolve(workspaceRoot);
|
|
73968
|
+
const swarmPath = path70.join(normalizedWorkspace, ".swarm", "evidence");
|
|
73969
|
+
const normalizedPath = path70.resolve(filePath);
|
|
73957
73970
|
return normalizedPath.startsWith(swarmPath);
|
|
73958
73971
|
}
|
|
73959
73972
|
function readEvidenceFile(evidencePath) {
|
|
@@ -74034,7 +74047,7 @@ var check_gate_status = createSwarmTool({
|
|
|
74034
74047
|
};
|
|
74035
74048
|
return JSON.stringify(errorResult, null, 2);
|
|
74036
74049
|
}
|
|
74037
|
-
const evidencePath =
|
|
74050
|
+
const evidencePath = path70.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
|
|
74038
74051
|
if (!isPathWithinSwarm(evidencePath, directory)) {
|
|
74039
74052
|
const errorResult = {
|
|
74040
74053
|
taskId: taskIdInput,
|
|
@@ -74131,7 +74144,7 @@ init_state();
|
|
|
74131
74144
|
init_create_tool();
|
|
74132
74145
|
init_resolve_working_directory();
|
|
74133
74146
|
import * as fs54 from "node:fs";
|
|
74134
|
-
import * as
|
|
74147
|
+
import * as path71 from "node:path";
|
|
74135
74148
|
function extractMatches(regex, text) {
|
|
74136
74149
|
return Array.from(text.matchAll(regex));
|
|
74137
74150
|
}
|
|
@@ -74283,10 +74296,10 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
74283
74296
|
let hasFileReadFailure = false;
|
|
74284
74297
|
for (const filePath of fileTargets) {
|
|
74285
74298
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
74286
|
-
const resolvedPath =
|
|
74287
|
-
const projectRoot =
|
|
74288
|
-
const relative16 =
|
|
74289
|
-
const withinProject = relative16 === "" || !relative16.startsWith("..") && !
|
|
74299
|
+
const resolvedPath = path71.resolve(directory, normalizedPath);
|
|
74300
|
+
const projectRoot = path71.resolve(directory);
|
|
74301
|
+
const relative16 = path71.relative(projectRoot, resolvedPath);
|
|
74302
|
+
const withinProject = relative16 === "" || !relative16.startsWith("..") && !path71.isAbsolute(relative16);
|
|
74290
74303
|
if (!withinProject) {
|
|
74291
74304
|
blockedTasks.push({
|
|
74292
74305
|
task_id: task.id,
|
|
@@ -74341,8 +74354,8 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
74341
74354
|
blockedTasks
|
|
74342
74355
|
};
|
|
74343
74356
|
try {
|
|
74344
|
-
const evidenceDir =
|
|
74345
|
-
const evidencePath =
|
|
74357
|
+
const evidenceDir = path71.join(directory, ".swarm", "evidence", `${phase}`);
|
|
74358
|
+
const evidencePath = path71.join(evidenceDir, "completion-verify.json");
|
|
74346
74359
|
fs54.mkdirSync(evidenceDir, { recursive: true });
|
|
74347
74360
|
const evidenceBundle = {
|
|
74348
74361
|
schema_version: "1.0.0",
|
|
@@ -74419,11 +74432,11 @@ var completion_verify = createSwarmTool({
|
|
|
74419
74432
|
// src/tools/complexity-hotspots.ts
|
|
74420
74433
|
init_zod();
|
|
74421
74434
|
import * as fs56 from "node:fs";
|
|
74422
|
-
import * as
|
|
74435
|
+
import * as path73 from "node:path";
|
|
74423
74436
|
|
|
74424
74437
|
// src/quality/metrics.ts
|
|
74425
74438
|
import * as fs55 from "node:fs";
|
|
74426
|
-
import * as
|
|
74439
|
+
import * as path72 from "node:path";
|
|
74427
74440
|
var MAX_FILE_SIZE_BYTES4 = 256 * 1024;
|
|
74428
74441
|
var MIN_DUPLICATION_LINES = 10;
|
|
74429
74442
|
function estimateCyclomaticComplexity(content) {
|
|
@@ -74475,7 +74488,7 @@ async function computeComplexityDelta(files, workingDir) {
|
|
|
74475
74488
|
let totalComplexity = 0;
|
|
74476
74489
|
const analyzedFiles = [];
|
|
74477
74490
|
for (const file3 of files) {
|
|
74478
|
-
const fullPath =
|
|
74491
|
+
const fullPath = path72.isAbsolute(file3) ? file3 : path72.join(workingDir, file3);
|
|
74479
74492
|
if (!fs55.existsSync(fullPath)) {
|
|
74480
74493
|
continue;
|
|
74481
74494
|
}
|
|
@@ -74598,7 +74611,7 @@ function countGoExports(content) {
|
|
|
74598
74611
|
function getExportCountForFile(filePath) {
|
|
74599
74612
|
try {
|
|
74600
74613
|
const content = fs55.readFileSync(filePath, "utf-8");
|
|
74601
|
-
const ext =
|
|
74614
|
+
const ext = path72.extname(filePath).toLowerCase();
|
|
74602
74615
|
switch (ext) {
|
|
74603
74616
|
case ".ts":
|
|
74604
74617
|
case ".tsx":
|
|
@@ -74624,7 +74637,7 @@ async function computePublicApiDelta(files, workingDir) {
|
|
|
74624
74637
|
let totalExports = 0;
|
|
74625
74638
|
const analyzedFiles = [];
|
|
74626
74639
|
for (const file3 of files) {
|
|
74627
|
-
const fullPath =
|
|
74640
|
+
const fullPath = path72.isAbsolute(file3) ? file3 : path72.join(workingDir, file3);
|
|
74628
74641
|
if (!fs55.existsSync(fullPath)) {
|
|
74629
74642
|
continue;
|
|
74630
74643
|
}
|
|
@@ -74658,7 +74671,7 @@ async function computeDuplicationRatio(files, workingDir) {
|
|
|
74658
74671
|
let duplicateLines = 0;
|
|
74659
74672
|
const analyzedFiles = [];
|
|
74660
74673
|
for (const file3 of files) {
|
|
74661
|
-
const fullPath =
|
|
74674
|
+
const fullPath = path72.isAbsolute(file3) ? file3 : path72.join(workingDir, file3);
|
|
74662
74675
|
if (!fs55.existsSync(fullPath)) {
|
|
74663
74676
|
continue;
|
|
74664
74677
|
}
|
|
@@ -74691,8 +74704,8 @@ function countCodeLines(content) {
|
|
|
74691
74704
|
return lines.length;
|
|
74692
74705
|
}
|
|
74693
74706
|
function isTestFile(filePath) {
|
|
74694
|
-
const basename10 =
|
|
74695
|
-
const _ext =
|
|
74707
|
+
const basename10 = path72.basename(filePath);
|
|
74708
|
+
const _ext = path72.extname(filePath).toLowerCase();
|
|
74696
74709
|
const testPatterns = [
|
|
74697
74710
|
".test.",
|
|
74698
74711
|
".spec.",
|
|
@@ -74773,8 +74786,8 @@ function matchGlobSegment(globSegments, pathSegments) {
|
|
|
74773
74786
|
}
|
|
74774
74787
|
return gIndex === globSegments.length && pIndex === pathSegments.length;
|
|
74775
74788
|
}
|
|
74776
|
-
function matchesGlobSegment(
|
|
74777
|
-
const normalizedPath =
|
|
74789
|
+
function matchesGlobSegment(path73, glob) {
|
|
74790
|
+
const normalizedPath = path73.replace(/\\/g, "/");
|
|
74778
74791
|
const normalizedGlob = glob.replace(/\\/g, "/");
|
|
74779
74792
|
if (normalizedPath.includes("//")) {
|
|
74780
74793
|
return false;
|
|
@@ -74805,8 +74818,8 @@ function simpleGlobToRegex2(glob) {
|
|
|
74805
74818
|
function hasGlobstar(glob) {
|
|
74806
74819
|
return glob.includes("**");
|
|
74807
74820
|
}
|
|
74808
|
-
function globMatches(
|
|
74809
|
-
const normalizedPath =
|
|
74821
|
+
function globMatches(path73, glob) {
|
|
74822
|
+
const normalizedPath = path73.replace(/\\/g, "/");
|
|
74810
74823
|
if (!glob || glob === "") {
|
|
74811
74824
|
if (normalizedPath.includes("//")) {
|
|
74812
74825
|
return false;
|
|
@@ -74842,7 +74855,7 @@ function shouldExcludeFile(filePath, excludeGlobs) {
|
|
|
74842
74855
|
async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
74843
74856
|
let testLines = 0;
|
|
74844
74857
|
let codeLines = 0;
|
|
74845
|
-
const srcDir =
|
|
74858
|
+
const srcDir = path72.join(workingDir, "src");
|
|
74846
74859
|
if (fs55.existsSync(srcDir)) {
|
|
74847
74860
|
await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
74848
74861
|
codeLines += lines;
|
|
@@ -74850,14 +74863,14 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
74850
74863
|
}
|
|
74851
74864
|
const possibleSrcDirs = ["lib", "app", "source", "core"];
|
|
74852
74865
|
for (const dir of possibleSrcDirs) {
|
|
74853
|
-
const dirPath =
|
|
74866
|
+
const dirPath = path72.join(workingDir, dir);
|
|
74854
74867
|
if (fs55.existsSync(dirPath)) {
|
|
74855
74868
|
await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
74856
74869
|
codeLines += lines;
|
|
74857
74870
|
});
|
|
74858
74871
|
}
|
|
74859
74872
|
}
|
|
74860
|
-
const testsDir =
|
|
74873
|
+
const testsDir = path72.join(workingDir, "tests");
|
|
74861
74874
|
if (fs55.existsSync(testsDir)) {
|
|
74862
74875
|
await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
74863
74876
|
testLines += lines;
|
|
@@ -74865,7 +74878,7 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
74865
74878
|
}
|
|
74866
74879
|
const possibleTestDirs = ["test", "__tests__", "specs"];
|
|
74867
74880
|
for (const dir of possibleTestDirs) {
|
|
74868
|
-
const dirPath =
|
|
74881
|
+
const dirPath = path72.join(workingDir, dir);
|
|
74869
74882
|
if (fs55.existsSync(dirPath) && dirPath !== testsDir) {
|
|
74870
74883
|
await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
74871
74884
|
testLines += lines;
|
|
@@ -74880,7 +74893,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
74880
74893
|
try {
|
|
74881
74894
|
const entries = fs55.readdirSync(dirPath, { withFileTypes: true });
|
|
74882
74895
|
for (const entry of entries) {
|
|
74883
|
-
const fullPath =
|
|
74896
|
+
const fullPath = path72.join(dirPath, entry.name);
|
|
74884
74897
|
if (entry.isDirectory()) {
|
|
74885
74898
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
|
|
74886
74899
|
continue;
|
|
@@ -74888,7 +74901,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
74888
74901
|
await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
|
|
74889
74902
|
} else if (entry.isFile()) {
|
|
74890
74903
|
const relativePath = fullPath.replace(`${dirPath}/`, "");
|
|
74891
|
-
const ext =
|
|
74904
|
+
const ext = path72.extname(entry.name).toLowerCase();
|
|
74892
74905
|
const validExts = [
|
|
74893
74906
|
".ts",
|
|
74894
74907
|
".tsx",
|
|
@@ -75141,7 +75154,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
75141
75154
|
const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
|
|
75142
75155
|
const filteredChurn = new Map;
|
|
75143
75156
|
for (const [file3, count] of churnMap) {
|
|
75144
|
-
const ext =
|
|
75157
|
+
const ext = path73.extname(file3).toLowerCase();
|
|
75145
75158
|
if (extSet.has(ext)) {
|
|
75146
75159
|
filteredChurn.set(file3, count);
|
|
75147
75160
|
}
|
|
@@ -75152,7 +75165,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
75152
75165
|
for (const [file3, churnCount] of filteredChurn) {
|
|
75153
75166
|
let fullPath = file3;
|
|
75154
75167
|
if (!fs56.existsSync(fullPath)) {
|
|
75155
|
-
fullPath =
|
|
75168
|
+
fullPath = path73.join(cwd, file3);
|
|
75156
75169
|
}
|
|
75157
75170
|
const complexity = getComplexityForFile2(fullPath);
|
|
75158
75171
|
if (complexity !== null) {
|
|
@@ -75326,7 +75339,7 @@ import {
|
|
|
75326
75339
|
readFileSync as readFileSync36,
|
|
75327
75340
|
writeFileSync as writeFileSync11
|
|
75328
75341
|
} from "node:fs";
|
|
75329
|
-
import { join as
|
|
75342
|
+
import { join as join67 } from "node:path";
|
|
75330
75343
|
var EVIDENCE_DIR2 = ".swarm/evidence";
|
|
75331
75344
|
var VALID_TASK_ID = /^\d+\.\d+(\.\d+)*$/;
|
|
75332
75345
|
var COUNCIL_GATE_NAME = "council";
|
|
@@ -75360,9 +75373,9 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
75360
75373
|
if (!VALID_TASK_ID.test(synthesis.taskId)) {
|
|
75361
75374
|
throw new Error(`writeCouncilEvidence: invalid taskId "${synthesis.taskId}" — must match N.M or N.M.P format`);
|
|
75362
75375
|
}
|
|
75363
|
-
const dir =
|
|
75376
|
+
const dir = join67(workingDir, EVIDENCE_DIR2);
|
|
75364
75377
|
mkdirSync18(dir, { recursive: true });
|
|
75365
|
-
const filePath =
|
|
75378
|
+
const filePath = join67(dir, `${synthesis.taskId}.json`);
|
|
75366
75379
|
const existingRoot = Object.create(null);
|
|
75367
75380
|
if (existsSync37(filePath)) {
|
|
75368
75381
|
try {
|
|
@@ -75396,7 +75409,7 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
75396
75409
|
updated.required_gates = [];
|
|
75397
75410
|
writeFileSync11(filePath, JSON.stringify(updated, null, 2));
|
|
75398
75411
|
try {
|
|
75399
|
-
const councilDir =
|
|
75412
|
+
const councilDir = join67(workingDir, ".swarm", "council");
|
|
75400
75413
|
mkdirSync18(councilDir, { recursive: true });
|
|
75401
75414
|
const auditLine = JSON.stringify({
|
|
75402
75415
|
round: synthesis.roundNumber,
|
|
@@ -75404,7 +75417,7 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
75404
75417
|
timestamp: synthesis.timestamp,
|
|
75405
75418
|
vetoedBy: synthesis.vetoedBy
|
|
75406
75419
|
});
|
|
75407
|
-
appendFileSync6(
|
|
75420
|
+
appendFileSync6(join67(councilDir, `${synthesis.taskId}.rounds.jsonl`), `${auditLine}
|
|
75408
75421
|
`);
|
|
75409
75422
|
} catch (auditError) {
|
|
75410
75423
|
console.warn(`writeCouncilEvidence: failed to append round-history audit log: ${auditError instanceof Error ? auditError.message : String(auditError)}`);
|
|
@@ -75538,20 +75551,20 @@ function buildUnifiedFeedback(taskId, verdict, vetoedBy, requiredFixes, advisory
|
|
|
75538
75551
|
|
|
75539
75552
|
// src/council/criteria-store.ts
|
|
75540
75553
|
import { existsSync as existsSync38, mkdirSync as mkdirSync19, readFileSync as readFileSync37, writeFileSync as writeFileSync12 } from "node:fs";
|
|
75541
|
-
import { join as
|
|
75554
|
+
import { join as join68 } from "node:path";
|
|
75542
75555
|
var COUNCIL_DIR = ".swarm/council";
|
|
75543
75556
|
function writeCriteria(workingDir, taskId, criteria) {
|
|
75544
|
-
const dir =
|
|
75557
|
+
const dir = join68(workingDir, COUNCIL_DIR);
|
|
75545
75558
|
mkdirSync19(dir, { recursive: true });
|
|
75546
75559
|
const payload = {
|
|
75547
75560
|
taskId,
|
|
75548
75561
|
criteria,
|
|
75549
75562
|
declaredAt: new Date().toISOString()
|
|
75550
75563
|
};
|
|
75551
|
-
writeFileSync12(
|
|
75564
|
+
writeFileSync12(join68(dir, `${safeId(taskId)}.json`), JSON.stringify(payload, null, 2));
|
|
75552
75565
|
}
|
|
75553
75566
|
function readCriteria(workingDir, taskId) {
|
|
75554
|
-
const filePath =
|
|
75567
|
+
const filePath = join68(workingDir, COUNCIL_DIR, `${safeId(taskId)}.json`);
|
|
75555
75568
|
if (!existsSync38(filePath))
|
|
75556
75569
|
return null;
|
|
75557
75570
|
try {
|
|
@@ -75704,7 +75717,7 @@ var submit_council_verdicts = createSwarmTool({
|
|
|
75704
75717
|
init_zod();
|
|
75705
75718
|
init_loader();
|
|
75706
75719
|
import * as fs57 from "node:fs";
|
|
75707
|
-
import * as
|
|
75720
|
+
import * as path74 from "node:path";
|
|
75708
75721
|
|
|
75709
75722
|
// src/council/general-council-advisory.ts
|
|
75710
75723
|
var ADVISORY_HEADER = "[general_council] (advisory; not blocking)";
|
|
@@ -75719,12 +75732,7 @@ function pushGeneralCouncilAdvisory(session, result) {
|
|
|
75719
75732
|
${body2}`);
|
|
75720
75733
|
}
|
|
75721
75734
|
function renderAdvisoryBody(result) {
|
|
75722
|
-
|
|
75723
|
-
if (result.moderatorOutput && result.moderatorOutput.trim().length > 0) {
|
|
75724
|
-
parts2.push("", "### Moderator Output", result.moderatorOutput);
|
|
75725
|
-
}
|
|
75726
|
-
return parts2.join(`
|
|
75727
|
-
`).trim();
|
|
75735
|
+
return result.synthesis.trim();
|
|
75728
75736
|
}
|
|
75729
75737
|
|
|
75730
75738
|
// src/council/disagreement-detector.ts
|
|
@@ -76050,23 +76058,8 @@ var ArgsSchema2 = exports_external.object({
|
|
|
76050
76058
|
round2Responses: exports_external.array(Round2ResponseSchema).optional(),
|
|
76051
76059
|
working_directory: exports_external.string().optional()
|
|
76052
76060
|
});
|
|
76053
|
-
function buildModeratorPrompt(question, synthesis) {
|
|
76054
|
-
return [
|
|
76055
|
-
"A multi-model council has deliberated on the following question. Your job is to synthesize",
|
|
76056
|
-
"the council output into a single coherent answer for the user, following the rules in your",
|
|
76057
|
-
"system prompt (lead with consensus, acknowledge persisting disagreement honestly, cite the",
|
|
76058
|
-
"strongest sources, be concise, do not invent claims, do not run new searches).",
|
|
76059
|
-
"",
|
|
76060
|
-
`QUESTION:
|
|
76061
|
-
${question}`,
|
|
76062
|
-
"",
|
|
76063
|
-
"COUNCIL OUTPUT:",
|
|
76064
|
-
synthesis
|
|
76065
|
-
].join(`
|
|
76066
|
-
`);
|
|
76067
|
-
}
|
|
76068
76061
|
var convene_general_council = createSwarmTool({
|
|
76069
|
-
description: "Synthesize responses from a multi-model General Council. Accepts parallel member " + "responses (Round 1, optionally Round 2), detects disagreements, and returns " + "consensus points, persisting disagreements, a structured synthesis
|
|
76062
|
+
description: "Synthesize responses from a multi-model General Council. Accepts parallel member " + "responses (Round 1, optionally Round 2), detects disagreements, and returns " + "consensus points, persisting disagreements, and a structured synthesis. " + "Architect-only. Config-gated on council.general.enabled.",
|
|
76070
76063
|
args: {
|
|
76071
76064
|
question: exports_external.string().min(1).max(8000).describe("The question put to the council, or the spec text to review."),
|
|
76072
76065
|
mode: exports_external.enum(["general", "spec_review"]).optional().describe('"general" for /swarm council; "spec_review" for SPECIFY-COUNCIL-REVIEW gate.'),
|
|
@@ -76152,10 +76145,10 @@ var convene_general_council = createSwarmTool({
|
|
|
76152
76145
|
const round1 = input.round1Responses;
|
|
76153
76146
|
const round2 = input.round2Responses ?? [];
|
|
76154
76147
|
const result = synthesizeGeneralCouncil(input.question, input.mode, round1, round2);
|
|
76155
|
-
const evidenceDir =
|
|
76148
|
+
const evidenceDir = path74.join(workingDir, ".swarm", "council", "general");
|
|
76156
76149
|
const safeTimestamp = result.timestamp.replace(/[:.]/g, "-");
|
|
76157
76150
|
const evidenceFile = `${safeTimestamp}-${input.mode}.json`;
|
|
76158
|
-
const evidencePath =
|
|
76151
|
+
const evidencePath = path74.join(evidenceDir, evidenceFile);
|
|
76159
76152
|
try {
|
|
76160
76153
|
await fs57.promises.mkdir(evidenceDir, { recursive: true });
|
|
76161
76154
|
await fs57.promises.writeFile(evidencePath, JSON.stringify(result, null, 2));
|
|
@@ -76172,7 +76165,6 @@ var convene_general_council = createSwarmTool({
|
|
|
76172
76165
|
}
|
|
76173
76166
|
}
|
|
76174
76167
|
} catch {}
|
|
76175
|
-
const moderatorPrompt = generalConfig.moderator === true ? buildModeratorPrompt(input.question, result.synthesis) : undefined;
|
|
76176
76168
|
const ok = {
|
|
76177
76169
|
success: true,
|
|
76178
76170
|
question: input.question,
|
|
@@ -76183,7 +76175,6 @@ var convene_general_council = createSwarmTool({
|
|
|
76183
76175
|
persistingDisagreements: result.persistingDisagreements,
|
|
76184
76176
|
allSourcesCount: result.allSources.length,
|
|
76185
76177
|
synthesis: result.synthesis,
|
|
76186
|
-
...moderatorPrompt !== undefined && { moderatorPrompt },
|
|
76187
76178
|
evidencePath
|
|
76188
76179
|
};
|
|
76189
76180
|
return JSON.stringify(ok, null, 2);
|
|
@@ -76392,7 +76383,7 @@ init_state();
|
|
|
76392
76383
|
init_task_id();
|
|
76393
76384
|
init_create_tool();
|
|
76394
76385
|
import * as fs58 from "node:fs";
|
|
76395
|
-
import * as
|
|
76386
|
+
import * as path75 from "node:path";
|
|
76396
76387
|
function validateTaskIdFormat2(taskId) {
|
|
76397
76388
|
return validateTaskIdFormat(taskId);
|
|
76398
76389
|
}
|
|
@@ -76466,8 +76457,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
76466
76457
|
};
|
|
76467
76458
|
}
|
|
76468
76459
|
}
|
|
76469
|
-
normalizedDir =
|
|
76470
|
-
const pathParts = normalizedDir.split(
|
|
76460
|
+
normalizedDir = path75.normalize(args2.working_directory);
|
|
76461
|
+
const pathParts = normalizedDir.split(path75.sep);
|
|
76471
76462
|
if (pathParts.includes("..")) {
|
|
76472
76463
|
return {
|
|
76473
76464
|
success: false,
|
|
@@ -76477,10 +76468,10 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
76477
76468
|
]
|
|
76478
76469
|
};
|
|
76479
76470
|
}
|
|
76480
|
-
const resolvedDir =
|
|
76471
|
+
const resolvedDir = path75.resolve(normalizedDir);
|
|
76481
76472
|
try {
|
|
76482
76473
|
const realPath = fs58.realpathSync(resolvedDir);
|
|
76483
|
-
const planPath2 =
|
|
76474
|
+
const planPath2 = path75.join(realPath, ".swarm", "plan.json");
|
|
76484
76475
|
if (!fs58.existsSync(planPath2)) {
|
|
76485
76476
|
return {
|
|
76486
76477
|
success: false,
|
|
@@ -76504,7 +76495,7 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
76504
76495
|
console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
|
|
76505
76496
|
}
|
|
76506
76497
|
const directory = normalizedDir || fallbackDir;
|
|
76507
|
-
const planPath =
|
|
76498
|
+
const planPath = path75.resolve(directory, ".swarm", "plan.json");
|
|
76508
76499
|
if (!fs58.existsSync(planPath)) {
|
|
76509
76500
|
return {
|
|
76510
76501
|
success: false,
|
|
@@ -76544,8 +76535,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
76544
76535
|
const normalizeErrors = [];
|
|
76545
76536
|
const dir = normalizedDir || fallbackDir || process.cwd();
|
|
76546
76537
|
const mergedFiles = rawMergedFiles.map((file3) => {
|
|
76547
|
-
if (
|
|
76548
|
-
const relativePath =
|
|
76538
|
+
if (path75.isAbsolute(file3)) {
|
|
76539
|
+
const relativePath = path75.relative(dir, file3).replace(/\\/g, "/");
|
|
76549
76540
|
if (relativePath.startsWith("..")) {
|
|
76550
76541
|
normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
|
|
76551
76542
|
return file3;
|
|
@@ -76606,7 +76597,7 @@ var declare_scope = createSwarmTool({
|
|
|
76606
76597
|
init_zod();
|
|
76607
76598
|
import * as child_process7 from "node:child_process";
|
|
76608
76599
|
import * as fs59 from "node:fs";
|
|
76609
|
-
import * as
|
|
76600
|
+
import * as path76 from "node:path";
|
|
76610
76601
|
init_create_tool();
|
|
76611
76602
|
var MAX_DIFF_LINES = 500;
|
|
76612
76603
|
var DIFF_TIMEOUT_MS = 30000;
|
|
@@ -76635,20 +76626,20 @@ function validateBase(base) {
|
|
|
76635
76626
|
function validatePaths(paths) {
|
|
76636
76627
|
if (!paths)
|
|
76637
76628
|
return null;
|
|
76638
|
-
for (const
|
|
76639
|
-
if (!
|
|
76629
|
+
for (const path77 of paths) {
|
|
76630
|
+
if (!path77 || path77.length === 0) {
|
|
76640
76631
|
return "empty path not allowed";
|
|
76641
76632
|
}
|
|
76642
|
-
if (
|
|
76633
|
+
if (path77.length > MAX_PATH_LENGTH) {
|
|
76643
76634
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
76644
76635
|
}
|
|
76645
|
-
if (SHELL_METACHARACTERS2.test(
|
|
76636
|
+
if (SHELL_METACHARACTERS2.test(path77)) {
|
|
76646
76637
|
return "path contains shell metacharacters";
|
|
76647
76638
|
}
|
|
76648
|
-
if (
|
|
76639
|
+
if (path77.startsWith("-")) {
|
|
76649
76640
|
return 'path cannot start with "-" (option-like arguments not allowed)';
|
|
76650
76641
|
}
|
|
76651
|
-
if (CONTROL_CHAR_PATTERN2.test(
|
|
76642
|
+
if (CONTROL_CHAR_PATTERN2.test(path77)) {
|
|
76652
76643
|
return "path contains control characters";
|
|
76653
76644
|
}
|
|
76654
76645
|
}
|
|
@@ -76754,8 +76745,8 @@ var diff = createSwarmTool({
|
|
|
76754
76745
|
if (parts2.length >= 3) {
|
|
76755
76746
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
76756
76747
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
76757
|
-
const
|
|
76758
|
-
files.push({ path:
|
|
76748
|
+
const path77 = parts2[2];
|
|
76749
|
+
files.push({ path: path77, additions, deletions });
|
|
76759
76750
|
}
|
|
76760
76751
|
}
|
|
76761
76752
|
const contractChanges = [];
|
|
@@ -76795,7 +76786,7 @@ var diff = createSwarmTool({
|
|
|
76795
76786
|
} else if (base === "unstaged") {
|
|
76796
76787
|
const oldRef = `:${file3.path}`;
|
|
76797
76788
|
oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
|
|
76798
|
-
newContent = fs59.readFileSync(
|
|
76789
|
+
newContent = fs59.readFileSync(path76.join(directory, file3.path), "utf-8");
|
|
76799
76790
|
} else {
|
|
76800
76791
|
const oldRef = `${base}:${file3.path}`;
|
|
76801
76792
|
oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
|
|
@@ -76870,7 +76861,7 @@ var diff = createSwarmTool({
|
|
|
76870
76861
|
init_zod();
|
|
76871
76862
|
import * as child_process8 from "node:child_process";
|
|
76872
76863
|
import * as fs60 from "node:fs";
|
|
76873
|
-
import * as
|
|
76864
|
+
import * as path77 from "node:path";
|
|
76874
76865
|
init_create_tool();
|
|
76875
76866
|
var diff_summary = createSwarmTool({
|
|
76876
76867
|
description: "Generate a filtered semantic diff summary from AST analysis. Returns SemanticDiffSummary with optional filtering by classification or riskLevel.",
|
|
@@ -76918,7 +76909,7 @@ var diff_summary = createSwarmTool({
|
|
|
76918
76909
|
}
|
|
76919
76910
|
try {
|
|
76920
76911
|
let oldContent;
|
|
76921
|
-
const newContent = fs60.readFileSync(
|
|
76912
|
+
const newContent = fs60.readFileSync(path77.join(workingDir, filePath), "utf-8");
|
|
76922
76913
|
if (fileExistsInHead) {
|
|
76923
76914
|
oldContent = child_process8.execFileSync("git", ["show", `HEAD:${filePath}`], {
|
|
76924
76915
|
encoding: "utf-8",
|
|
@@ -77147,7 +77138,7 @@ init_zod();
|
|
|
77147
77138
|
init_create_tool();
|
|
77148
77139
|
init_path_security();
|
|
77149
77140
|
import * as fs61 from "node:fs";
|
|
77150
|
-
import * as
|
|
77141
|
+
import * as path78 from "node:path";
|
|
77151
77142
|
var MAX_FILE_SIZE_BYTES6 = 1024 * 1024;
|
|
77152
77143
|
var MAX_EVIDENCE_FILES = 1000;
|
|
77153
77144
|
var EVIDENCE_DIR3 = ".swarm/evidence";
|
|
@@ -77174,9 +77165,9 @@ function validateRequiredTypes(input) {
|
|
|
77174
77165
|
return null;
|
|
77175
77166
|
}
|
|
77176
77167
|
function isPathWithinSwarm2(filePath, cwd) {
|
|
77177
|
-
const normalizedCwd =
|
|
77178
|
-
const swarmPath =
|
|
77179
|
-
const normalizedPath =
|
|
77168
|
+
const normalizedCwd = path78.resolve(cwd);
|
|
77169
|
+
const swarmPath = path78.join(normalizedCwd, ".swarm");
|
|
77170
|
+
const normalizedPath = path78.resolve(filePath);
|
|
77180
77171
|
return normalizedPath.startsWith(swarmPath);
|
|
77181
77172
|
}
|
|
77182
77173
|
function parseCompletedTasks(planContent) {
|
|
@@ -77206,10 +77197,10 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
77206
77197
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
77207
77198
|
continue;
|
|
77208
77199
|
}
|
|
77209
|
-
const filePath =
|
|
77200
|
+
const filePath = path78.join(evidenceDir, filename);
|
|
77210
77201
|
try {
|
|
77211
|
-
const resolvedPath =
|
|
77212
|
-
const evidenceDirResolved =
|
|
77202
|
+
const resolvedPath = path78.resolve(filePath);
|
|
77203
|
+
const evidenceDirResolved = path78.resolve(evidenceDir);
|
|
77213
77204
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
77214
77205
|
continue;
|
|
77215
77206
|
}
|
|
@@ -77327,7 +77318,7 @@ var evidence_check = createSwarmTool({
|
|
|
77327
77318
|
return JSON.stringify(errorResult, null, 2);
|
|
77328
77319
|
}
|
|
77329
77320
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
|
|
77330
|
-
const planPath =
|
|
77321
|
+
const planPath = path78.join(cwd, PLAN_FILE);
|
|
77331
77322
|
if (!isPathWithinSwarm2(planPath, cwd)) {
|
|
77332
77323
|
const errorResult = {
|
|
77333
77324
|
error: "plan file path validation failed",
|
|
@@ -77359,7 +77350,7 @@ var evidence_check = createSwarmTool({
|
|
|
77359
77350
|
};
|
|
77360
77351
|
return JSON.stringify(result2, null, 2);
|
|
77361
77352
|
}
|
|
77362
|
-
const evidenceDir =
|
|
77353
|
+
const evidenceDir = path78.join(cwd, EVIDENCE_DIR3);
|
|
77363
77354
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
77364
77355
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
77365
77356
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -77377,7 +77368,7 @@ var evidence_check = createSwarmTool({
|
|
|
77377
77368
|
init_zod();
|
|
77378
77369
|
init_create_tool();
|
|
77379
77370
|
import * as fs62 from "node:fs";
|
|
77380
|
-
import * as
|
|
77371
|
+
import * as path79 from "node:path";
|
|
77381
77372
|
var EXT_MAP = {
|
|
77382
77373
|
python: ".py",
|
|
77383
77374
|
py: ".py",
|
|
@@ -77458,12 +77449,12 @@ var extract_code_blocks = createSwarmTool({
|
|
|
77458
77449
|
if (prefix) {
|
|
77459
77450
|
filename = `${prefix}_${filename}`;
|
|
77460
77451
|
}
|
|
77461
|
-
let filepath =
|
|
77462
|
-
const base =
|
|
77463
|
-
const ext =
|
|
77452
|
+
let filepath = path79.join(targetDir, filename);
|
|
77453
|
+
const base = path79.basename(filepath, path79.extname(filepath));
|
|
77454
|
+
const ext = path79.extname(filepath);
|
|
77464
77455
|
let counter = 1;
|
|
77465
77456
|
while (fs62.existsSync(filepath)) {
|
|
77466
|
-
filepath =
|
|
77457
|
+
filepath = path79.join(targetDir, `${base}_${counter}${ext}`);
|
|
77467
77458
|
counter++;
|
|
77468
77459
|
}
|
|
77469
77460
|
try {
|
|
@@ -77727,7 +77718,7 @@ init_zod();
|
|
|
77727
77718
|
init_create_tool();
|
|
77728
77719
|
init_path_security();
|
|
77729
77720
|
import * as fs63 from "node:fs";
|
|
77730
|
-
import * as
|
|
77721
|
+
import * as path80 from "node:path";
|
|
77731
77722
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
77732
77723
|
var MAX_SYMBOL_LENGTH = 256;
|
|
77733
77724
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
@@ -77775,7 +77766,7 @@ function validateSymbolInput(symbol3) {
|
|
|
77775
77766
|
return null;
|
|
77776
77767
|
}
|
|
77777
77768
|
function isBinaryFile2(filePath, buffer) {
|
|
77778
|
-
const ext =
|
|
77769
|
+
const ext = path80.extname(filePath).toLowerCase();
|
|
77779
77770
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
77780
77771
|
return false;
|
|
77781
77772
|
}
|
|
@@ -77799,15 +77790,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
77799
77790
|
const imports = [];
|
|
77800
77791
|
let _resolvedTarget;
|
|
77801
77792
|
try {
|
|
77802
|
-
_resolvedTarget =
|
|
77793
|
+
_resolvedTarget = path80.resolve(targetFile);
|
|
77803
77794
|
} catch {
|
|
77804
77795
|
_resolvedTarget = targetFile;
|
|
77805
77796
|
}
|
|
77806
|
-
const targetBasename =
|
|
77797
|
+
const targetBasename = path80.basename(targetFile, path80.extname(targetFile));
|
|
77807
77798
|
const targetWithExt = targetFile;
|
|
77808
77799
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
77809
|
-
const normalizedTargetWithExt =
|
|
77810
|
-
const normalizedTargetWithoutExt =
|
|
77800
|
+
const normalizedTargetWithExt = path80.normalize(targetWithExt).replace(/\\/g, "/");
|
|
77801
|
+
const normalizedTargetWithoutExt = path80.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
77811
77802
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
77812
77803
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
77813
77804
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -77830,9 +77821,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
77830
77821
|
}
|
|
77831
77822
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
77832
77823
|
let isMatch = false;
|
|
77833
|
-
const _targetDir =
|
|
77834
|
-
const targetExt =
|
|
77835
|
-
const targetBasenameNoExt =
|
|
77824
|
+
const _targetDir = path80.dirname(targetFile);
|
|
77825
|
+
const targetExt = path80.extname(targetFile);
|
|
77826
|
+
const targetBasenameNoExt = path80.basename(targetFile, targetExt);
|
|
77836
77827
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
77837
77828
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
77838
77829
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -77900,10 +77891,10 @@ function findSourceFiles3(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
77900
77891
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
77901
77892
|
for (const entry of entries) {
|
|
77902
77893
|
if (SKIP_DIRECTORIES4.has(entry)) {
|
|
77903
|
-
stats.skippedDirs.push(
|
|
77894
|
+
stats.skippedDirs.push(path80.join(dir, entry));
|
|
77904
77895
|
continue;
|
|
77905
77896
|
}
|
|
77906
|
-
const fullPath =
|
|
77897
|
+
const fullPath = path80.join(dir, entry);
|
|
77907
77898
|
let stat4;
|
|
77908
77899
|
try {
|
|
77909
77900
|
stat4 = fs63.statSync(fullPath);
|
|
@@ -77917,7 +77908,7 @@ function findSourceFiles3(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
77917
77908
|
if (stat4.isDirectory()) {
|
|
77918
77909
|
findSourceFiles3(fullPath, files, stats);
|
|
77919
77910
|
} else if (stat4.isFile()) {
|
|
77920
|
-
const ext =
|
|
77911
|
+
const ext = path80.extname(fullPath).toLowerCase();
|
|
77921
77912
|
if (SUPPORTED_EXTENSIONS3.includes(ext)) {
|
|
77922
77913
|
files.push(fullPath);
|
|
77923
77914
|
}
|
|
@@ -77974,7 +77965,7 @@ var imports = createSwarmTool({
|
|
|
77974
77965
|
return JSON.stringify(errorResult, null, 2);
|
|
77975
77966
|
}
|
|
77976
77967
|
try {
|
|
77977
|
-
const targetFile =
|
|
77968
|
+
const targetFile = path80.resolve(file3);
|
|
77978
77969
|
if (!fs63.existsSync(targetFile)) {
|
|
77979
77970
|
const errorResult = {
|
|
77980
77971
|
error: `target file not found: ${file3}`,
|
|
@@ -77996,7 +77987,7 @@ var imports = createSwarmTool({
|
|
|
77996
77987
|
};
|
|
77997
77988
|
return JSON.stringify(errorResult, null, 2);
|
|
77998
77989
|
}
|
|
77999
|
-
const baseDir =
|
|
77990
|
+
const baseDir = path80.dirname(targetFile);
|
|
78000
77991
|
const scanStats = {
|
|
78001
77992
|
skippedDirs: [],
|
|
78002
77993
|
skippedFiles: 0,
|
|
@@ -78542,7 +78533,7 @@ init_qa_gate_profile();
|
|
|
78542
78533
|
init_manager2();
|
|
78543
78534
|
init_curator();
|
|
78544
78535
|
import * as fs65 from "node:fs";
|
|
78545
|
-
import * as
|
|
78536
|
+
import * as path82 from "node:path";
|
|
78546
78537
|
init_knowledge_curator();
|
|
78547
78538
|
init_knowledge_reader();
|
|
78548
78539
|
init_knowledge_store();
|
|
@@ -78555,14 +78546,16 @@ init_plan_schema();
|
|
|
78555
78546
|
init_ledger();
|
|
78556
78547
|
init_manager();
|
|
78557
78548
|
import * as fs64 from "node:fs";
|
|
78558
|
-
import * as
|
|
78549
|
+
import * as path81 from "node:path";
|
|
78559
78550
|
async function writeCheckpoint(directory) {
|
|
78560
78551
|
try {
|
|
78561
78552
|
const plan = await loadPlan(directory);
|
|
78562
78553
|
if (!plan)
|
|
78563
78554
|
return;
|
|
78564
|
-
const
|
|
78565
|
-
|
|
78555
|
+
const swarmDir = path81.join(directory, ".swarm");
|
|
78556
|
+
fs64.mkdirSync(swarmDir, { recursive: true });
|
|
78557
|
+
const jsonPath = path81.join(swarmDir, "SWARM_PLAN.json");
|
|
78558
|
+
const mdPath = path81.join(swarmDir, "SWARM_PLAN.md");
|
|
78566
78559
|
fs64.writeFileSync(jsonPath, JSON.stringify(plan, null, 2), "utf8");
|
|
78567
78560
|
const md = derivePlanMarkdown(plan);
|
|
78568
78561
|
fs64.writeFileSync(mdPath, md, "utf8");
|
|
@@ -78797,7 +78790,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
78797
78790
|
let driftCheckEnabled = true;
|
|
78798
78791
|
let driftHasSpecMd = false;
|
|
78799
78792
|
try {
|
|
78800
|
-
const specMdPath =
|
|
78793
|
+
const specMdPath = path82.join(dir, ".swarm", "spec.md");
|
|
78801
78794
|
driftHasSpecMd = fs65.existsSync(specMdPath);
|
|
78802
78795
|
const gatePlan = await loadPlan(dir);
|
|
78803
78796
|
if (gatePlan) {
|
|
@@ -78819,7 +78812,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
78819
78812
|
} else {
|
|
78820
78813
|
let phaseType;
|
|
78821
78814
|
try {
|
|
78822
|
-
const planPath =
|
|
78815
|
+
const planPath = path82.join(dir, ".swarm", "plan.json");
|
|
78823
78816
|
if (fs65.existsSync(planPath)) {
|
|
78824
78817
|
const planRaw = fs65.readFileSync(planPath, "utf-8");
|
|
78825
78818
|
const plan = JSON.parse(planRaw);
|
|
@@ -78832,7 +78825,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
78832
78825
|
warnings.push(`Phase ${phase} is annotated as 'non-code'. Drift verification was skipped per phase type annotation.`);
|
|
78833
78826
|
} else {
|
|
78834
78827
|
try {
|
|
78835
|
-
const driftEvidencePath =
|
|
78828
|
+
const driftEvidencePath = path82.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
|
|
78836
78829
|
let driftVerdictFound = false;
|
|
78837
78830
|
let driftVerdictApproved = false;
|
|
78838
78831
|
try {
|
|
@@ -78870,7 +78863,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
78870
78863
|
let incompleteTaskCount = 0;
|
|
78871
78864
|
let planParseable = false;
|
|
78872
78865
|
try {
|
|
78873
|
-
const planPath =
|
|
78866
|
+
const planPath = path82.join(dir, ".swarm", "plan.json");
|
|
78874
78867
|
if (fs65.existsSync(planPath)) {
|
|
78875
78868
|
const planRaw = fs65.readFileSync(planPath, "utf-8");
|
|
78876
78869
|
const plan = JSON.parse(planRaw);
|
|
@@ -78937,7 +78930,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
78937
78930
|
const overrides = session2?.qaGateSessionOverrides ?? {};
|
|
78938
78931
|
const effective = getEffectiveGates(profile, overrides);
|
|
78939
78932
|
if (effective.hallucination_guard === true) {
|
|
78940
|
-
const hgPath =
|
|
78933
|
+
const hgPath = path82.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
|
|
78941
78934
|
let hgVerdictFound = false;
|
|
78942
78935
|
let hgVerdictApproved = false;
|
|
78943
78936
|
try {
|
|
@@ -79009,7 +79002,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
79009
79002
|
const overrides = session2?.qaGateSessionOverrides ?? {};
|
|
79010
79003
|
const effective = getEffectiveGates(profile, overrides);
|
|
79011
79004
|
if (effective.mutation_test === true) {
|
|
79012
|
-
const mgPath =
|
|
79005
|
+
const mgPath = path82.join(dir, ".swarm", "evidence", String(phase), "mutation-gate.json");
|
|
79013
79006
|
let mgVerdictFound = false;
|
|
79014
79007
|
let mgVerdict;
|
|
79015
79008
|
try {
|
|
@@ -79083,7 +79076,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
79083
79076
|
const effective = getEffectiveGates(profile, overrides);
|
|
79084
79077
|
if (effective.council_mode === true) {
|
|
79085
79078
|
councilModeEnabled = true;
|
|
79086
|
-
const pcPath =
|
|
79079
|
+
const pcPath = path82.join(dir, ".swarm", "evidence", String(phase), "phase-council.json");
|
|
79087
79080
|
let pcVerdictFound = false;
|
|
79088
79081
|
let _pcVerdict;
|
|
79089
79082
|
let pcQuorumSize;
|
|
@@ -79285,7 +79278,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
79285
79278
|
}
|
|
79286
79279
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
79287
79280
|
try {
|
|
79288
|
-
const projectName =
|
|
79281
|
+
const projectName = path82.basename(dir);
|
|
79289
79282
|
const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
|
|
79290
79283
|
if (curationResult) {
|
|
79291
79284
|
const sessionState = swarmState.agentSessions.get(sessionID);
|
|
@@ -79654,7 +79647,7 @@ init_discovery();
|
|
|
79654
79647
|
init_utils();
|
|
79655
79648
|
init_create_tool();
|
|
79656
79649
|
import * as fs66 from "node:fs";
|
|
79657
|
-
import * as
|
|
79650
|
+
import * as path83 from "node:path";
|
|
79658
79651
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
79659
79652
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
79660
79653
|
function isValidEcosystem(value) {
|
|
@@ -79682,16 +79675,16 @@ function validateArgs3(args2) {
|
|
|
79682
79675
|
function detectEcosystems(directory) {
|
|
79683
79676
|
const ecosystems = [];
|
|
79684
79677
|
const cwd = directory;
|
|
79685
|
-
if (fs66.existsSync(
|
|
79678
|
+
if (fs66.existsSync(path83.join(cwd, "package.json"))) {
|
|
79686
79679
|
ecosystems.push("npm");
|
|
79687
79680
|
}
|
|
79688
|
-
if (fs66.existsSync(
|
|
79681
|
+
if (fs66.existsSync(path83.join(cwd, "pyproject.toml")) || fs66.existsSync(path83.join(cwd, "requirements.txt"))) {
|
|
79689
79682
|
ecosystems.push("pip");
|
|
79690
79683
|
}
|
|
79691
|
-
if (fs66.existsSync(
|
|
79684
|
+
if (fs66.existsSync(path83.join(cwd, "Cargo.toml"))) {
|
|
79692
79685
|
ecosystems.push("cargo");
|
|
79693
79686
|
}
|
|
79694
|
-
if (fs66.existsSync(
|
|
79687
|
+
if (fs66.existsSync(path83.join(cwd, "go.mod"))) {
|
|
79695
79688
|
ecosystems.push("go");
|
|
79696
79689
|
}
|
|
79697
79690
|
try {
|
|
@@ -79700,13 +79693,13 @@ function detectEcosystems(directory) {
|
|
|
79700
79693
|
ecosystems.push("dotnet");
|
|
79701
79694
|
}
|
|
79702
79695
|
} catch {}
|
|
79703
|
-
if (fs66.existsSync(
|
|
79696
|
+
if (fs66.existsSync(path83.join(cwd, "Gemfile")) || fs66.existsSync(path83.join(cwd, "Gemfile.lock"))) {
|
|
79704
79697
|
ecosystems.push("ruby");
|
|
79705
79698
|
}
|
|
79706
|
-
if (fs66.existsSync(
|
|
79699
|
+
if (fs66.existsSync(path83.join(cwd, "pubspec.yaml"))) {
|
|
79707
79700
|
ecosystems.push("dart");
|
|
79708
79701
|
}
|
|
79709
|
-
if (fs66.existsSync(
|
|
79702
|
+
if (fs66.existsSync(path83.join(cwd, "composer.lock"))) {
|
|
79710
79703
|
ecosystems.push("composer");
|
|
79711
79704
|
}
|
|
79712
79705
|
return ecosystems;
|
|
@@ -80866,7 +80859,7 @@ var pkg_audit = createSwarmTool({
|
|
|
80866
80859
|
init_zod();
|
|
80867
80860
|
init_manager2();
|
|
80868
80861
|
import * as fs67 from "node:fs";
|
|
80869
|
-
import * as
|
|
80862
|
+
import * as path84 from "node:path";
|
|
80870
80863
|
init_utils();
|
|
80871
80864
|
init_create_tool();
|
|
80872
80865
|
var MAX_FILE_SIZE = 1024 * 1024;
|
|
@@ -80989,7 +80982,7 @@ function isScaffoldFile(filePath) {
|
|
|
80989
80982
|
if (SCAFFOLD_PATH_PATTERNS.some((pattern) => pattern.test(normalizedPath))) {
|
|
80990
80983
|
return true;
|
|
80991
80984
|
}
|
|
80992
|
-
const filename =
|
|
80985
|
+
const filename = path84.basename(filePath);
|
|
80993
80986
|
if (SCAFFOLD_FILENAME_PATTERNS.some((pattern) => pattern.test(filename))) {
|
|
80994
80987
|
return true;
|
|
80995
80988
|
}
|
|
@@ -81006,7 +80999,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
|
|
|
81006
80999
|
if (regex.test(normalizedPath)) {
|
|
81007
81000
|
return true;
|
|
81008
81001
|
}
|
|
81009
|
-
const filename =
|
|
81002
|
+
const filename = path84.basename(filePath);
|
|
81010
81003
|
const filenameRegex = new RegExp(`^${regexPattern}$`, "i");
|
|
81011
81004
|
if (filenameRegex.test(filename)) {
|
|
81012
81005
|
return true;
|
|
@@ -81015,7 +81008,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
|
|
|
81015
81008
|
return false;
|
|
81016
81009
|
}
|
|
81017
81010
|
function isParserSupported(filePath) {
|
|
81018
|
-
const ext =
|
|
81011
|
+
const ext = path84.extname(filePath).toLowerCase();
|
|
81019
81012
|
return SUPPORTED_PARSER_EXTENSIONS.has(ext);
|
|
81020
81013
|
}
|
|
81021
81014
|
function isPlanFile(filePath) {
|
|
@@ -81262,9 +81255,9 @@ async function placeholderScan(input, directory) {
|
|
|
81262
81255
|
let filesScanned = 0;
|
|
81263
81256
|
const filesWithFindings = new Set;
|
|
81264
81257
|
for (const filePath of changed_files) {
|
|
81265
|
-
const fullPath =
|
|
81266
|
-
const resolvedDirectory =
|
|
81267
|
-
if (!fullPath.startsWith(resolvedDirectory +
|
|
81258
|
+
const fullPath = path84.isAbsolute(filePath) ? filePath : path84.resolve(directory, filePath);
|
|
81259
|
+
const resolvedDirectory = path84.resolve(directory);
|
|
81260
|
+
if (!fullPath.startsWith(resolvedDirectory + path84.sep) && fullPath !== resolvedDirectory) {
|
|
81268
81261
|
continue;
|
|
81269
81262
|
}
|
|
81270
81263
|
if (!fs67.existsSync(fullPath)) {
|
|
@@ -81273,7 +81266,7 @@ async function placeholderScan(input, directory) {
|
|
|
81273
81266
|
if (isAllowedByGlobs(filePath, allow_globs)) {
|
|
81274
81267
|
continue;
|
|
81275
81268
|
}
|
|
81276
|
-
const relativeFilePath =
|
|
81269
|
+
const relativeFilePath = path84.relative(directory, fullPath).replace(/\\/g, "/");
|
|
81277
81270
|
if (FILE_ALLOWLIST.some((allowed) => relativeFilePath.endsWith(allowed))) {
|
|
81278
81271
|
continue;
|
|
81279
81272
|
}
|
|
@@ -81345,7 +81338,7 @@ var placeholder_scan = createSwarmTool({
|
|
|
81345
81338
|
});
|
|
81346
81339
|
// src/tools/pre-check-batch.ts
|
|
81347
81340
|
import * as fs70 from "node:fs";
|
|
81348
|
-
import * as
|
|
81341
|
+
import * as path87 from "node:path";
|
|
81349
81342
|
init_zod();
|
|
81350
81343
|
init_manager2();
|
|
81351
81344
|
init_utils();
|
|
@@ -81482,7 +81475,7 @@ init_zod();
|
|
|
81482
81475
|
init_manager2();
|
|
81483
81476
|
init_detector();
|
|
81484
81477
|
import * as fs69 from "node:fs";
|
|
81485
|
-
import * as
|
|
81478
|
+
import * as path86 from "node:path";
|
|
81486
81479
|
import { extname as extname18 } from "node:path";
|
|
81487
81480
|
|
|
81488
81481
|
// src/sast/rules/c.ts
|
|
@@ -82376,24 +82369,24 @@ init_create_tool();
|
|
|
82376
82369
|
init_utils2();
|
|
82377
82370
|
import * as crypto8 from "node:crypto";
|
|
82378
82371
|
import * as fs68 from "node:fs";
|
|
82379
|
-
import * as
|
|
82372
|
+
import * as path85 from "node:path";
|
|
82380
82373
|
var BASELINE_SCHEMA_VERSION = "1.0.0";
|
|
82381
82374
|
var MAX_BASELINE_FINDINGS = 2000;
|
|
82382
82375
|
var MAX_BASELINE_BYTES = 2 * 1048576;
|
|
82383
82376
|
var LOCK_RETRY_DELAYS_MS = [50, 100, 200, 400, 800];
|
|
82384
82377
|
function normalizeFindingPath(directory, file3) {
|
|
82385
|
-
const resolved =
|
|
82386
|
-
const rel =
|
|
82378
|
+
const resolved = path85.isAbsolute(file3) ? file3 : path85.resolve(directory, file3);
|
|
82379
|
+
const rel = path85.relative(path85.resolve(directory), resolved);
|
|
82387
82380
|
return rel.replace(/\\/g, "/");
|
|
82388
82381
|
}
|
|
82389
82382
|
function baselineRelPath(phase) {
|
|
82390
|
-
return
|
|
82383
|
+
return path85.join("evidence", String(phase), "sast-baseline.json");
|
|
82391
82384
|
}
|
|
82392
82385
|
function tempRelPath(phase) {
|
|
82393
|
-
return
|
|
82386
|
+
return path85.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
|
|
82394
82387
|
}
|
|
82395
82388
|
function lockRelPath(phase) {
|
|
82396
|
-
return
|
|
82389
|
+
return path85.join("evidence", String(phase), "sast-baseline.json.lock");
|
|
82397
82390
|
}
|
|
82398
82391
|
function getLine(lines, idx) {
|
|
82399
82392
|
if (idx < 0 || idx >= lines.length)
|
|
@@ -82514,8 +82507,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
82514
82507
|
message: e instanceof Error ? e.message : "Path validation failed"
|
|
82515
82508
|
};
|
|
82516
82509
|
}
|
|
82517
|
-
fs68.mkdirSync(
|
|
82518
|
-
fs68.mkdirSync(
|
|
82510
|
+
fs68.mkdirSync(path85.dirname(baselinePath), { recursive: true });
|
|
82511
|
+
fs68.mkdirSync(path85.dirname(tempPath), { recursive: true });
|
|
82519
82512
|
const releaseLock = await acquireLock(lockPath);
|
|
82520
82513
|
try {
|
|
82521
82514
|
let existing = null;
|
|
@@ -82782,9 +82775,9 @@ async function sastScan(input, directory, config3) {
|
|
|
82782
82775
|
_filesSkipped++;
|
|
82783
82776
|
continue;
|
|
82784
82777
|
}
|
|
82785
|
-
const resolvedPath =
|
|
82786
|
-
const resolvedDirectory =
|
|
82787
|
-
if (!resolvedPath.startsWith(resolvedDirectory +
|
|
82778
|
+
const resolvedPath = path86.isAbsolute(filePath) ? filePath : path86.resolve(directory, filePath);
|
|
82779
|
+
const resolvedDirectory = path86.resolve(directory);
|
|
82780
|
+
if (!resolvedPath.startsWith(resolvedDirectory + path86.sep) && resolvedPath !== resolvedDirectory) {
|
|
82788
82781
|
_filesSkipped++;
|
|
82789
82782
|
continue;
|
|
82790
82783
|
}
|
|
@@ -83095,18 +83088,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
83095
83088
|
let resolved;
|
|
83096
83089
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
83097
83090
|
if (isWinAbs) {
|
|
83098
|
-
resolved =
|
|
83099
|
-
} else if (
|
|
83100
|
-
resolved =
|
|
83091
|
+
resolved = path87.win32.resolve(inputPath);
|
|
83092
|
+
} else if (path87.isAbsolute(inputPath)) {
|
|
83093
|
+
resolved = path87.resolve(inputPath);
|
|
83101
83094
|
} else {
|
|
83102
|
-
resolved =
|
|
83095
|
+
resolved = path87.resolve(baseDir, inputPath);
|
|
83103
83096
|
}
|
|
83104
|
-
const workspaceResolved =
|
|
83097
|
+
const workspaceResolved = path87.resolve(workspaceDir);
|
|
83105
83098
|
let relative20;
|
|
83106
83099
|
if (isWinAbs) {
|
|
83107
|
-
relative20 =
|
|
83100
|
+
relative20 = path87.win32.relative(workspaceResolved, resolved);
|
|
83108
83101
|
} else {
|
|
83109
|
-
relative20 =
|
|
83102
|
+
relative20 = path87.relative(workspaceResolved, resolved);
|
|
83110
83103
|
}
|
|
83111
83104
|
if (relative20.startsWith("..")) {
|
|
83112
83105
|
return "path traversal detected";
|
|
@@ -83171,7 +83164,7 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
83171
83164
|
if (typeof file3 !== "string") {
|
|
83172
83165
|
continue;
|
|
83173
83166
|
}
|
|
83174
|
-
const resolvedPath =
|
|
83167
|
+
const resolvedPath = path87.resolve(file3);
|
|
83175
83168
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
83176
83169
|
if (validationError) {
|
|
83177
83170
|
continue;
|
|
@@ -83328,7 +83321,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
83328
83321
|
skippedFiles++;
|
|
83329
83322
|
continue;
|
|
83330
83323
|
}
|
|
83331
|
-
const resolvedPath =
|
|
83324
|
+
const resolvedPath = path87.resolve(file3);
|
|
83332
83325
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
83333
83326
|
if (validationError) {
|
|
83334
83327
|
skippedFiles++;
|
|
@@ -83346,7 +83339,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
83346
83339
|
};
|
|
83347
83340
|
}
|
|
83348
83341
|
for (const file3 of validatedFiles) {
|
|
83349
|
-
const ext =
|
|
83342
|
+
const ext = path87.extname(file3).toLowerCase();
|
|
83350
83343
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
83351
83344
|
skippedFiles++;
|
|
83352
83345
|
continue;
|
|
@@ -83565,7 +83558,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
|
|
|
83565
83558
|
const preexistingFindings = [];
|
|
83566
83559
|
for (const finding of findings) {
|
|
83567
83560
|
const filePath = finding.location.file;
|
|
83568
|
-
const normalised =
|
|
83561
|
+
const normalised = path87.relative(directory, filePath).replace(/\\/g, "/");
|
|
83569
83562
|
const changedLines = changedLineRanges.get(normalised);
|
|
83570
83563
|
if (changedLines?.has(finding.location.line)) {
|
|
83571
83564
|
newFindings.push(finding);
|
|
@@ -83616,7 +83609,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
|
|
|
83616
83609
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
83617
83610
|
continue;
|
|
83618
83611
|
}
|
|
83619
|
-
changedFiles.push(
|
|
83612
|
+
changedFiles.push(path87.resolve(directory, file3));
|
|
83620
83613
|
}
|
|
83621
83614
|
if (changedFiles.length === 0) {
|
|
83622
83615
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -83817,7 +83810,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
83817
83810
|
};
|
|
83818
83811
|
return JSON.stringify(errorResult, null, 2);
|
|
83819
83812
|
}
|
|
83820
|
-
const resolvedDirectory =
|
|
83813
|
+
const resolvedDirectory = path87.resolve(typedArgs.directory);
|
|
83821
83814
|
const workspaceAnchor = resolvedDirectory;
|
|
83822
83815
|
const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
|
|
83823
83816
|
if (dirError) {
|
|
@@ -83858,7 +83851,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
83858
83851
|
});
|
|
83859
83852
|
// src/tools/repo-map.ts
|
|
83860
83853
|
init_zod();
|
|
83861
|
-
import * as
|
|
83854
|
+
import * as path88 from "node:path";
|
|
83862
83855
|
init_path_security();
|
|
83863
83856
|
init_create_tool();
|
|
83864
83857
|
var VALID_ACTIONS = [
|
|
@@ -83883,7 +83876,7 @@ function validateFile(p) {
|
|
|
83883
83876
|
return "file contains control characters";
|
|
83884
83877
|
if (containsPathTraversal(p))
|
|
83885
83878
|
return "file contains path traversal";
|
|
83886
|
-
if (
|
|
83879
|
+
if (path88.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
|
|
83887
83880
|
return "file must be a workspace-relative path, not absolute";
|
|
83888
83881
|
}
|
|
83889
83882
|
return null;
|
|
@@ -83906,8 +83899,8 @@ function ok(action, payload) {
|
|
|
83906
83899
|
}
|
|
83907
83900
|
function toRelativeGraphPath(input, workspaceRoot) {
|
|
83908
83901
|
const normalized = input.replace(/\\/g, "/");
|
|
83909
|
-
if (
|
|
83910
|
-
const rel =
|
|
83902
|
+
if (path88.isAbsolute(normalized)) {
|
|
83903
|
+
const rel = path88.relative(workspaceRoot, normalized).replace(/\\/g, "/");
|
|
83911
83904
|
return normalizeGraphPath2(rel);
|
|
83912
83905
|
}
|
|
83913
83906
|
return normalizeGraphPath2(normalized);
|
|
@@ -84052,7 +84045,7 @@ var repo_map = createSwarmTool({
|
|
|
84052
84045
|
init_zod();
|
|
84053
84046
|
init_create_tool();
|
|
84054
84047
|
import * as fs71 from "node:fs";
|
|
84055
|
-
import * as
|
|
84048
|
+
import * as path89 from "node:path";
|
|
84056
84049
|
var SPEC_FILE = ".swarm/spec.md";
|
|
84057
84050
|
var EVIDENCE_DIR4 = ".swarm/evidence";
|
|
84058
84051
|
var OBLIGATION_KEYWORDS = ["MUST", "SHOULD", "SHALL"];
|
|
@@ -84121,7 +84114,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
84121
84114
|
return [];
|
|
84122
84115
|
}
|
|
84123
84116
|
for (const entry of entries) {
|
|
84124
|
-
const entryPath =
|
|
84117
|
+
const entryPath = path89.join(evidenceDir, entry);
|
|
84125
84118
|
try {
|
|
84126
84119
|
const stat4 = fs71.statSync(entryPath);
|
|
84127
84120
|
if (!stat4.isDirectory()) {
|
|
@@ -84137,11 +84130,11 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
84137
84130
|
if (entryPhase !== String(phase)) {
|
|
84138
84131
|
continue;
|
|
84139
84132
|
}
|
|
84140
|
-
const evidenceFilePath =
|
|
84133
|
+
const evidenceFilePath = path89.join(entryPath, "evidence.json");
|
|
84141
84134
|
try {
|
|
84142
|
-
const resolvedPath =
|
|
84143
|
-
const evidenceDirResolved =
|
|
84144
|
-
if (!resolvedPath.startsWith(evidenceDirResolved +
|
|
84135
|
+
const resolvedPath = path89.resolve(evidenceFilePath);
|
|
84136
|
+
const evidenceDirResolved = path89.resolve(evidenceDir);
|
|
84137
|
+
if (!resolvedPath.startsWith(evidenceDirResolved + path89.sep)) {
|
|
84145
84138
|
continue;
|
|
84146
84139
|
}
|
|
84147
84140
|
const stat4 = fs71.lstatSync(evidenceFilePath);
|
|
@@ -84175,7 +84168,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
84175
84168
|
if (Array.isArray(diffEntry.files_changed)) {
|
|
84176
84169
|
for (const file3 of diffEntry.files_changed) {
|
|
84177
84170
|
if (typeof file3 === "string") {
|
|
84178
|
-
touchedFiles.add(
|
|
84171
|
+
touchedFiles.add(path89.resolve(cwd, file3));
|
|
84179
84172
|
}
|
|
84180
84173
|
}
|
|
84181
84174
|
}
|
|
@@ -84188,8 +84181,8 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
84188
84181
|
}
|
|
84189
84182
|
function searchFileForKeywords(filePath, keywords, cwd) {
|
|
84190
84183
|
try {
|
|
84191
|
-
const resolvedPath =
|
|
84192
|
-
const cwdResolved =
|
|
84184
|
+
const resolvedPath = path89.resolve(filePath);
|
|
84185
|
+
const cwdResolved = path89.resolve(cwd);
|
|
84193
84186
|
if (!resolvedPath.startsWith(cwdResolved)) {
|
|
84194
84187
|
return false;
|
|
84195
84188
|
}
|
|
@@ -84323,7 +84316,7 @@ var req_coverage = createSwarmTool({
|
|
|
84323
84316
|
}, null, 2);
|
|
84324
84317
|
}
|
|
84325
84318
|
const cwd = inputDirectory || directory;
|
|
84326
|
-
const specPath =
|
|
84319
|
+
const specPath = path89.join(cwd, SPEC_FILE);
|
|
84327
84320
|
let specContent;
|
|
84328
84321
|
try {
|
|
84329
84322
|
specContent = fs71.readFileSync(specPath, "utf-8");
|
|
@@ -84350,7 +84343,7 @@ var req_coverage = createSwarmTool({
|
|
|
84350
84343
|
message: "No FR requirements found in spec.md"
|
|
84351
84344
|
}, null, 2);
|
|
84352
84345
|
}
|
|
84353
|
-
const evidenceDir =
|
|
84346
|
+
const evidenceDir = path89.join(cwd, EVIDENCE_DIR4);
|
|
84354
84347
|
const touchedFiles = readTouchedFiles(evidenceDir, phase, cwd);
|
|
84355
84348
|
const analyzedRequirements = [];
|
|
84356
84349
|
let coveredCount = 0;
|
|
@@ -84376,7 +84369,7 @@ var req_coverage = createSwarmTool({
|
|
|
84376
84369
|
requirements: analyzedRequirements
|
|
84377
84370
|
};
|
|
84378
84371
|
const reportFilename = `req-coverage-phase-${phase}.json`;
|
|
84379
|
-
const reportPath =
|
|
84372
|
+
const reportPath = path89.join(evidenceDir, reportFilename);
|
|
84380
84373
|
try {
|
|
84381
84374
|
if (!fs71.existsSync(evidenceDir)) {
|
|
84382
84375
|
fs71.mkdirSync(evidenceDir, { recursive: true });
|
|
@@ -84464,7 +84457,7 @@ init_qa_gate_profile();
|
|
|
84464
84457
|
init_file_locks();
|
|
84465
84458
|
import * as crypto9 from "node:crypto";
|
|
84466
84459
|
import * as fs72 from "node:fs";
|
|
84467
|
-
import * as
|
|
84460
|
+
import * as path90 from "node:path";
|
|
84468
84461
|
init_ledger();
|
|
84469
84462
|
init_manager();
|
|
84470
84463
|
init_state();
|
|
@@ -84542,8 +84535,8 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
84542
84535
|
};
|
|
84543
84536
|
}
|
|
84544
84537
|
if (args2.working_directory && fallbackDir) {
|
|
84545
|
-
const resolvedTarget =
|
|
84546
|
-
const resolvedRoot =
|
|
84538
|
+
const resolvedTarget = path90.resolve(args2.working_directory);
|
|
84539
|
+
const resolvedRoot = path90.resolve(fallbackDir);
|
|
84547
84540
|
let fallbackExists = false;
|
|
84548
84541
|
try {
|
|
84549
84542
|
fs72.accessSync(resolvedRoot, fs72.constants.F_OK);
|
|
@@ -84552,7 +84545,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
84552
84545
|
fallbackExists = false;
|
|
84553
84546
|
}
|
|
84554
84547
|
if (fallbackExists) {
|
|
84555
|
-
const isSubdirectory = resolvedTarget.startsWith(resolvedRoot +
|
|
84548
|
+
const isSubdirectory = resolvedTarget.startsWith(resolvedRoot + path90.sep);
|
|
84556
84549
|
if (isSubdirectory) {
|
|
84557
84550
|
return {
|
|
84558
84551
|
success: false,
|
|
@@ -84568,7 +84561,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
84568
84561
|
let specMtime;
|
|
84569
84562
|
let specHash;
|
|
84570
84563
|
if (process.env.SWARM_SKIP_SPEC_GATE !== "1") {
|
|
84571
|
-
const specPath =
|
|
84564
|
+
const specPath = path90.join(targetWorkspace, ".swarm", "spec.md");
|
|
84572
84565
|
try {
|
|
84573
84566
|
const stat4 = await fs72.promises.stat(specPath);
|
|
84574
84567
|
specMtime = stat4.mtime.toISOString();
|
|
@@ -84584,7 +84577,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
84584
84577
|
}
|
|
84585
84578
|
}
|
|
84586
84579
|
if (process.env.SWARM_SKIP_GATE_SELECTION !== "1") {
|
|
84587
|
-
const contextPath =
|
|
84580
|
+
const contextPath = path90.join(targetWorkspace, ".swarm", "context.md");
|
|
84588
84581
|
let contextContent = "";
|
|
84589
84582
|
try {
|
|
84590
84583
|
contextContent = await fs72.promises.readFile(contextPath, "utf8");
|
|
@@ -84734,7 +84727,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
84734
84727
|
}
|
|
84735
84728
|
await writeCheckpoint(dir).catch(() => {});
|
|
84736
84729
|
try {
|
|
84737
|
-
const markerPath =
|
|
84730
|
+
const markerPath = path90.join(dir, ".swarm", ".plan-write-marker");
|
|
84738
84731
|
const marker = JSON.stringify({
|
|
84739
84732
|
source: "save_plan",
|
|
84740
84733
|
timestamp: new Date().toISOString(),
|
|
@@ -84757,7 +84750,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
84757
84750
|
return {
|
|
84758
84751
|
success: true,
|
|
84759
84752
|
message: "Plan saved successfully",
|
|
84760
|
-
plan_path:
|
|
84753
|
+
plan_path: path90.join(dir, ".swarm", "plan.json"),
|
|
84761
84754
|
phases_count: plan.phases.length,
|
|
84762
84755
|
tasks_count: tasksCount,
|
|
84763
84756
|
...resolvedProfile !== undefined ? { execution_profile: resolvedProfile } : {},
|
|
@@ -84810,7 +84803,7 @@ var save_plan = createSwarmTool({
|
|
|
84810
84803
|
init_zod();
|
|
84811
84804
|
init_manager2();
|
|
84812
84805
|
import * as fs73 from "node:fs";
|
|
84813
|
-
import * as
|
|
84806
|
+
import * as path91 from "node:path";
|
|
84814
84807
|
|
|
84815
84808
|
// src/sbom/detectors/index.ts
|
|
84816
84809
|
init_utils();
|
|
@@ -85660,7 +85653,7 @@ function findManifestFiles(rootDir) {
|
|
|
85660
85653
|
try {
|
|
85661
85654
|
const entries = fs73.readdirSync(dir, { withFileTypes: true });
|
|
85662
85655
|
for (const entry of entries) {
|
|
85663
|
-
const fullPath =
|
|
85656
|
+
const fullPath = path91.join(dir, entry.name);
|
|
85664
85657
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
85665
85658
|
continue;
|
|
85666
85659
|
}
|
|
@@ -85669,7 +85662,7 @@ function findManifestFiles(rootDir) {
|
|
|
85669
85662
|
} else if (entry.isFile()) {
|
|
85670
85663
|
for (const pattern of patterns) {
|
|
85671
85664
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
85672
|
-
manifestFiles.push(
|
|
85665
|
+
manifestFiles.push(path91.relative(rootDir, fullPath));
|
|
85673
85666
|
break;
|
|
85674
85667
|
}
|
|
85675
85668
|
}
|
|
@@ -85687,11 +85680,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
85687
85680
|
try {
|
|
85688
85681
|
const entries = fs73.readdirSync(dir, { withFileTypes: true });
|
|
85689
85682
|
for (const entry of entries) {
|
|
85690
|
-
const fullPath =
|
|
85683
|
+
const fullPath = path91.join(dir, entry.name);
|
|
85691
85684
|
if (entry.isFile()) {
|
|
85692
85685
|
for (const pattern of patterns) {
|
|
85693
85686
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
85694
|
-
found.push(
|
|
85687
|
+
found.push(path91.relative(workingDir, fullPath));
|
|
85695
85688
|
break;
|
|
85696
85689
|
}
|
|
85697
85690
|
}
|
|
@@ -85704,11 +85697,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
85704
85697
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
85705
85698
|
const dirs = new Set;
|
|
85706
85699
|
for (const file3 of changedFiles) {
|
|
85707
|
-
let currentDir =
|
|
85700
|
+
let currentDir = path91.dirname(file3);
|
|
85708
85701
|
while (true) {
|
|
85709
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
85710
|
-
dirs.add(
|
|
85711
|
-
const parent =
|
|
85702
|
+
if (currentDir && currentDir !== "." && currentDir !== path91.sep) {
|
|
85703
|
+
dirs.add(path91.join(workingDir, currentDir));
|
|
85704
|
+
const parent = path91.dirname(currentDir);
|
|
85712
85705
|
if (parent === currentDir)
|
|
85713
85706
|
break;
|
|
85714
85707
|
currentDir = parent;
|
|
@@ -85792,7 +85785,7 @@ var sbom_generate = createSwarmTool({
|
|
|
85792
85785
|
const changedFiles = obj.changed_files;
|
|
85793
85786
|
const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
|
|
85794
85787
|
const workingDir = directory;
|
|
85795
|
-
const outputDir =
|
|
85788
|
+
const outputDir = path91.isAbsolute(relativeOutputDir) ? relativeOutputDir : path91.join(workingDir, relativeOutputDir);
|
|
85796
85789
|
let manifestFiles = [];
|
|
85797
85790
|
if (scope === "all") {
|
|
85798
85791
|
manifestFiles = findManifestFiles(workingDir);
|
|
@@ -85815,7 +85808,7 @@ var sbom_generate = createSwarmTool({
|
|
|
85815
85808
|
const processedFiles = [];
|
|
85816
85809
|
for (const manifestFile of manifestFiles) {
|
|
85817
85810
|
try {
|
|
85818
|
-
const fullPath =
|
|
85811
|
+
const fullPath = path91.isAbsolute(manifestFile) ? manifestFile : path91.join(workingDir, manifestFile);
|
|
85819
85812
|
if (!fs73.existsSync(fullPath)) {
|
|
85820
85813
|
continue;
|
|
85821
85814
|
}
|
|
@@ -85832,7 +85825,7 @@ var sbom_generate = createSwarmTool({
|
|
|
85832
85825
|
const bom = generateCycloneDX(allComponents);
|
|
85833
85826
|
const bomJson = serializeCycloneDX(bom);
|
|
85834
85827
|
const filename = generateSbomFilename();
|
|
85835
|
-
const outputPath =
|
|
85828
|
+
const outputPath = path91.join(outputDir, filename);
|
|
85836
85829
|
fs73.writeFileSync(outputPath, bomJson, "utf-8");
|
|
85837
85830
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
85838
85831
|
try {
|
|
@@ -85876,7 +85869,7 @@ var sbom_generate = createSwarmTool({
|
|
|
85876
85869
|
init_zod();
|
|
85877
85870
|
init_create_tool();
|
|
85878
85871
|
import * as fs74 from "node:fs";
|
|
85879
|
-
import * as
|
|
85872
|
+
import * as path92 from "node:path";
|
|
85880
85873
|
var SPEC_CANDIDATES = [
|
|
85881
85874
|
"openapi.json",
|
|
85882
85875
|
"openapi.yaml",
|
|
@@ -85908,12 +85901,12 @@ function normalizePath3(p) {
|
|
|
85908
85901
|
}
|
|
85909
85902
|
function discoverSpecFile(cwd, specFileArg) {
|
|
85910
85903
|
if (specFileArg) {
|
|
85911
|
-
const resolvedPath =
|
|
85912
|
-
const normalizedCwd = cwd.endsWith(
|
|
85904
|
+
const resolvedPath = path92.resolve(cwd, specFileArg);
|
|
85905
|
+
const normalizedCwd = cwd.endsWith(path92.sep) ? cwd : cwd + path92.sep;
|
|
85913
85906
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
85914
85907
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
85915
85908
|
}
|
|
85916
|
-
const ext =
|
|
85909
|
+
const ext = path92.extname(resolvedPath).toLowerCase();
|
|
85917
85910
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
85918
85911
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
85919
85912
|
}
|
|
@@ -85927,7 +85920,7 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
85927
85920
|
return resolvedPath;
|
|
85928
85921
|
}
|
|
85929
85922
|
for (const candidate of SPEC_CANDIDATES) {
|
|
85930
|
-
const candidatePath =
|
|
85923
|
+
const candidatePath = path92.resolve(cwd, candidate);
|
|
85931
85924
|
if (fs74.existsSync(candidatePath)) {
|
|
85932
85925
|
const stats = fs74.statSync(candidatePath);
|
|
85933
85926
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
@@ -85939,7 +85932,7 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
85939
85932
|
}
|
|
85940
85933
|
function parseSpec(specFile) {
|
|
85941
85934
|
const content = fs74.readFileSync(specFile, "utf-8");
|
|
85942
|
-
const ext =
|
|
85935
|
+
const ext = path92.extname(specFile).toLowerCase();
|
|
85943
85936
|
if (ext === ".json") {
|
|
85944
85937
|
return parseJsonSpec(content);
|
|
85945
85938
|
}
|
|
@@ -86015,7 +86008,7 @@ function extractRoutes(cwd) {
|
|
|
86015
86008
|
return;
|
|
86016
86009
|
}
|
|
86017
86010
|
for (const entry of entries) {
|
|
86018
|
-
const fullPath =
|
|
86011
|
+
const fullPath = path92.join(dir, entry.name);
|
|
86019
86012
|
if (entry.isSymbolicLink()) {
|
|
86020
86013
|
continue;
|
|
86021
86014
|
}
|
|
@@ -86025,7 +86018,7 @@ function extractRoutes(cwd) {
|
|
|
86025
86018
|
}
|
|
86026
86019
|
walkDir(fullPath);
|
|
86027
86020
|
} else if (entry.isFile()) {
|
|
86028
|
-
const ext =
|
|
86021
|
+
const ext = path92.extname(entry.name).toLowerCase();
|
|
86029
86022
|
const baseName = entry.name.toLowerCase();
|
|
86030
86023
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
86031
86024
|
continue;
|
|
@@ -86192,7 +86185,7 @@ init_zod();
|
|
|
86192
86185
|
init_path_security();
|
|
86193
86186
|
init_create_tool();
|
|
86194
86187
|
import * as fs75 from "node:fs";
|
|
86195
|
-
import * as
|
|
86188
|
+
import * as path93 from "node:path";
|
|
86196
86189
|
var DEFAULT_MAX_RESULTS = 100;
|
|
86197
86190
|
var DEFAULT_MAX_LINES = 200;
|
|
86198
86191
|
var REGEX_TIMEOUT_MS = 5000;
|
|
@@ -86228,11 +86221,11 @@ function containsWindowsAttacks3(str) {
|
|
|
86228
86221
|
}
|
|
86229
86222
|
function isPathInWorkspace3(filePath, workspace) {
|
|
86230
86223
|
try {
|
|
86231
|
-
const resolvedPath =
|
|
86224
|
+
const resolvedPath = path93.resolve(workspace, filePath);
|
|
86232
86225
|
const realWorkspace = fs75.realpathSync(workspace);
|
|
86233
86226
|
const realResolvedPath = fs75.realpathSync(resolvedPath);
|
|
86234
|
-
const relativePath =
|
|
86235
|
-
if (relativePath.startsWith("..") ||
|
|
86227
|
+
const relativePath = path93.relative(realWorkspace, realResolvedPath);
|
|
86228
|
+
if (relativePath.startsWith("..") || path93.isAbsolute(relativePath)) {
|
|
86236
86229
|
return false;
|
|
86237
86230
|
}
|
|
86238
86231
|
return true;
|
|
@@ -86245,11 +86238,11 @@ function validatePathForRead2(filePath, workspace) {
|
|
|
86245
86238
|
}
|
|
86246
86239
|
function findRgInEnvPath() {
|
|
86247
86240
|
const searchPath = process.env.PATH ?? "";
|
|
86248
|
-
for (const dir of searchPath.split(
|
|
86241
|
+
for (const dir of searchPath.split(path93.delimiter)) {
|
|
86249
86242
|
if (!dir)
|
|
86250
86243
|
continue;
|
|
86251
86244
|
const isWindows = process.platform === "win32";
|
|
86252
|
-
const candidate =
|
|
86245
|
+
const candidate = path93.join(dir, isWindows ? "rg.exe" : "rg");
|
|
86253
86246
|
if (fs75.existsSync(candidate))
|
|
86254
86247
|
return candidate;
|
|
86255
86248
|
}
|
|
@@ -86379,8 +86372,8 @@ function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
|
|
|
86379
86372
|
try {
|
|
86380
86373
|
const entries = fs75.readdirSync(dir, { withFileTypes: true });
|
|
86381
86374
|
for (const entry of entries) {
|
|
86382
|
-
const fullPath =
|
|
86383
|
-
const relativePath =
|
|
86375
|
+
const fullPath = path93.join(dir, entry.name);
|
|
86376
|
+
const relativePath = path93.relative(workspace, fullPath);
|
|
86384
86377
|
if (!validatePathForRead2(fullPath, workspace)) {
|
|
86385
86378
|
continue;
|
|
86386
86379
|
}
|
|
@@ -86421,7 +86414,7 @@ async function fallbackSearch(opts) {
|
|
|
86421
86414
|
const matches = [];
|
|
86422
86415
|
let total = 0;
|
|
86423
86416
|
for (const file3 of files) {
|
|
86424
|
-
const fullPath =
|
|
86417
|
+
const fullPath = path93.join(opts.workspace, file3);
|
|
86425
86418
|
if (!validatePathForRead2(fullPath, opts.workspace)) {
|
|
86426
86419
|
continue;
|
|
86427
86420
|
}
|
|
@@ -86678,7 +86671,7 @@ init_zod();
|
|
|
86678
86671
|
init_path_security();
|
|
86679
86672
|
init_create_tool();
|
|
86680
86673
|
import * as fs76 from "node:fs";
|
|
86681
|
-
import * as
|
|
86674
|
+
import * as path94 from "node:path";
|
|
86682
86675
|
var WINDOWS_RESERVED_NAMES4 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
86683
86676
|
function containsWindowsAttacks4(str) {
|
|
86684
86677
|
if (/:[^\\/]/.test(str))
|
|
@@ -86692,14 +86685,14 @@ function containsWindowsAttacks4(str) {
|
|
|
86692
86685
|
}
|
|
86693
86686
|
function isPathInWorkspace4(filePath, workspace) {
|
|
86694
86687
|
try {
|
|
86695
|
-
const resolvedPath =
|
|
86688
|
+
const resolvedPath = path94.resolve(workspace, filePath);
|
|
86696
86689
|
if (!fs76.existsSync(resolvedPath)) {
|
|
86697
86690
|
return true;
|
|
86698
86691
|
}
|
|
86699
86692
|
const realWorkspace = fs76.realpathSync(workspace);
|
|
86700
86693
|
const realResolvedPath = fs76.realpathSync(resolvedPath);
|
|
86701
|
-
const relativePath =
|
|
86702
|
-
if (relativePath.startsWith("..") ||
|
|
86694
|
+
const relativePath = path94.relative(realWorkspace, realResolvedPath);
|
|
86695
|
+
if (relativePath.startsWith("..") || path94.isAbsolute(relativePath)) {
|
|
86703
86696
|
return false;
|
|
86704
86697
|
}
|
|
86705
86698
|
return true;
|
|
@@ -86907,7 +86900,7 @@ var suggestPatch = createSwarmTool({
|
|
|
86907
86900
|
});
|
|
86908
86901
|
continue;
|
|
86909
86902
|
}
|
|
86910
|
-
const fullPath =
|
|
86903
|
+
const fullPath = path94.resolve(directory, change.file);
|
|
86911
86904
|
if (!fs76.existsSync(fullPath)) {
|
|
86912
86905
|
errors5.push({
|
|
86913
86906
|
success: false,
|
|
@@ -87170,7 +87163,7 @@ var generate_mutants = createSwarmTool({
|
|
|
87170
87163
|
init_spec_schema();
|
|
87171
87164
|
init_create_tool();
|
|
87172
87165
|
import * as fs77 from "node:fs";
|
|
87173
|
-
import * as
|
|
87166
|
+
import * as path95 from "node:path";
|
|
87174
87167
|
var SPEC_FILE_NAME = "spec.md";
|
|
87175
87168
|
var SWARM_DIR2 = ".swarm";
|
|
87176
87169
|
var OBLIGATION_KEYWORDS2 = ["MUST", "SHALL", "SHOULD", "MAY"];
|
|
@@ -87223,7 +87216,7 @@ var lint_spec = createSwarmTool({
|
|
|
87223
87216
|
async execute(_args, directory) {
|
|
87224
87217
|
const errors5 = [];
|
|
87225
87218
|
const warnings = [];
|
|
87226
|
-
const specPath =
|
|
87219
|
+
const specPath = path95.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
|
|
87227
87220
|
if (!fs77.existsSync(specPath)) {
|
|
87228
87221
|
const result2 = {
|
|
87229
87222
|
valid: false,
|
|
@@ -87294,12 +87287,12 @@ var lint_spec = createSwarmTool({
|
|
|
87294
87287
|
// src/tools/mutation-test.ts
|
|
87295
87288
|
init_zod();
|
|
87296
87289
|
import * as fs78 from "node:fs";
|
|
87297
|
-
import * as
|
|
87290
|
+
import * as path97 from "node:path";
|
|
87298
87291
|
|
|
87299
87292
|
// src/mutation/engine.ts
|
|
87300
87293
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
87301
87294
|
import { unlinkSync as unlinkSync13, writeFileSync as writeFileSync19 } from "node:fs";
|
|
87302
|
-
import * as
|
|
87295
|
+
import * as path96 from "node:path";
|
|
87303
87296
|
|
|
87304
87297
|
// src/mutation/equivalence.ts
|
|
87305
87298
|
function isStaticallyEquivalent(originalCode, mutatedCode) {
|
|
@@ -87434,7 +87427,7 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
|
|
|
87434
87427
|
let patchFile;
|
|
87435
87428
|
try {
|
|
87436
87429
|
const safeId2 = patch.id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
87437
|
-
patchFile =
|
|
87430
|
+
patchFile = path96.join(workingDir, `.mutation_patch_${safeId2}.diff`);
|
|
87438
87431
|
try {
|
|
87439
87432
|
writeFileSync19(patchFile, patch.patch);
|
|
87440
87433
|
} catch (writeErr) {
|
|
@@ -87828,7 +87821,7 @@ var mutation_test = createSwarmTool({
|
|
|
87828
87821
|
];
|
|
87829
87822
|
for (const filePath of uniquePaths) {
|
|
87830
87823
|
try {
|
|
87831
|
-
const resolvedPath =
|
|
87824
|
+
const resolvedPath = path97.resolve(cwd, filePath);
|
|
87832
87825
|
sourceFiles.set(filePath, fs78.readFileSync(resolvedPath, "utf-8"));
|
|
87833
87826
|
} catch {}
|
|
87834
87827
|
}
|
|
@@ -87848,7 +87841,7 @@ init_zod();
|
|
|
87848
87841
|
init_manager2();
|
|
87849
87842
|
init_detector();
|
|
87850
87843
|
import * as fs79 from "node:fs";
|
|
87851
|
-
import * as
|
|
87844
|
+
import * as path98 from "node:path";
|
|
87852
87845
|
init_create_tool();
|
|
87853
87846
|
var MAX_FILE_SIZE2 = 2 * 1024 * 1024;
|
|
87854
87847
|
var BINARY_CHECK_BYTES = 8192;
|
|
@@ -87914,7 +87907,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
87914
87907
|
if (languages?.length) {
|
|
87915
87908
|
const lowerLangs = languages.map((l) => l.toLowerCase());
|
|
87916
87909
|
filesToCheck = filesToCheck.filter((file3) => {
|
|
87917
|
-
const ext =
|
|
87910
|
+
const ext = path98.extname(file3.path).toLowerCase();
|
|
87918
87911
|
const langDef = getLanguageForExtension(ext);
|
|
87919
87912
|
const fileProfile = getProfileForFile(file3.path);
|
|
87920
87913
|
const langId = fileProfile?.id || langDef?.id;
|
|
@@ -87927,7 +87920,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
87927
87920
|
let skippedCount = 0;
|
|
87928
87921
|
for (const fileInfo of filesToCheck) {
|
|
87929
87922
|
const { path: filePath } = fileInfo;
|
|
87930
|
-
const fullPath =
|
|
87923
|
+
const fullPath = path98.isAbsolute(filePath) ? filePath : path98.join(directory, filePath);
|
|
87931
87924
|
const result = {
|
|
87932
87925
|
path: filePath,
|
|
87933
87926
|
language: "",
|
|
@@ -87976,7 +87969,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
87976
87969
|
results.push(result);
|
|
87977
87970
|
continue;
|
|
87978
87971
|
}
|
|
87979
|
-
const ext =
|
|
87972
|
+
const ext = path98.extname(filePath).toLowerCase();
|
|
87980
87973
|
const langDef = getLanguageForExtension(ext);
|
|
87981
87974
|
result.language = profile?.id || langDef?.id || "unknown";
|
|
87982
87975
|
const errors5 = extractSyntaxErrors(parser, content);
|
|
@@ -88069,7 +88062,7 @@ init_utils();
|
|
|
88069
88062
|
init_create_tool();
|
|
88070
88063
|
init_path_security();
|
|
88071
88064
|
import * as fs80 from "node:fs";
|
|
88072
|
-
import * as
|
|
88065
|
+
import * as path99 from "node:path";
|
|
88073
88066
|
var MAX_TEXT_LENGTH = 200;
|
|
88074
88067
|
var MAX_FILE_SIZE_BYTES11 = 1024 * 1024;
|
|
88075
88068
|
var SUPPORTED_EXTENSIONS4 = new Set([
|
|
@@ -88135,9 +88128,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
88135
88128
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
88136
88129
|
}
|
|
88137
88130
|
try {
|
|
88138
|
-
const resolvedPath =
|
|
88139
|
-
const normalizedCwd =
|
|
88140
|
-
const normalizedResolved =
|
|
88131
|
+
const resolvedPath = path99.resolve(paths);
|
|
88132
|
+
const normalizedCwd = path99.resolve(cwd);
|
|
88133
|
+
const normalizedResolved = path99.resolve(resolvedPath);
|
|
88141
88134
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
88142
88135
|
return {
|
|
88143
88136
|
error: "paths must be within the current working directory",
|
|
@@ -88153,7 +88146,7 @@ function validatePathsInput(paths, cwd) {
|
|
|
88153
88146
|
}
|
|
88154
88147
|
}
|
|
88155
88148
|
function isSupportedExtension(filePath) {
|
|
88156
|
-
const ext =
|
|
88149
|
+
const ext = path99.extname(filePath).toLowerCase();
|
|
88157
88150
|
return SUPPORTED_EXTENSIONS4.has(ext);
|
|
88158
88151
|
}
|
|
88159
88152
|
function findSourceFiles4(dir, files = []) {
|
|
@@ -88168,7 +88161,7 @@ function findSourceFiles4(dir, files = []) {
|
|
|
88168
88161
|
if (SKIP_DIRECTORIES5.has(entry)) {
|
|
88169
88162
|
continue;
|
|
88170
88163
|
}
|
|
88171
|
-
const fullPath =
|
|
88164
|
+
const fullPath = path99.join(dir, entry);
|
|
88172
88165
|
let stat4;
|
|
88173
88166
|
try {
|
|
88174
88167
|
stat4 = fs80.statSync(fullPath);
|
|
@@ -88280,7 +88273,7 @@ var todo_extract = createSwarmTool({
|
|
|
88280
88273
|
filesToScan.push(scanPath);
|
|
88281
88274
|
} else {
|
|
88282
88275
|
const errorResult = {
|
|
88283
|
-
error: `unsupported file extension: ${
|
|
88276
|
+
error: `unsupported file extension: ${path99.extname(scanPath)}`,
|
|
88284
88277
|
total: 0,
|
|
88285
88278
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
88286
88279
|
entries: []
|
|
@@ -88329,14 +88322,14 @@ init_schema();
|
|
|
88329
88322
|
init_qa_gate_profile();
|
|
88330
88323
|
init_gate_evidence();
|
|
88331
88324
|
import * as fs82 from "node:fs";
|
|
88332
|
-
import * as
|
|
88325
|
+
import * as path101 from "node:path";
|
|
88333
88326
|
|
|
88334
88327
|
// src/hooks/diff-scope.ts
|
|
88335
88328
|
import * as fs81 from "node:fs";
|
|
88336
|
-
import * as
|
|
88329
|
+
import * as path100 from "node:path";
|
|
88337
88330
|
function getDeclaredScope(taskId, directory) {
|
|
88338
88331
|
try {
|
|
88339
|
-
const planPath =
|
|
88332
|
+
const planPath = path100.join(directory, ".swarm", "plan.json");
|
|
88340
88333
|
if (!fs81.existsSync(planPath))
|
|
88341
88334
|
return null;
|
|
88342
88335
|
const raw = fs81.readFileSync(planPath, "utf-8");
|
|
@@ -88455,7 +88448,7 @@ var TIER_3_PATTERNS = [
|
|
|
88455
88448
|
];
|
|
88456
88449
|
function matchesTier3Pattern(files) {
|
|
88457
88450
|
for (const file3 of files) {
|
|
88458
|
-
const fileName =
|
|
88451
|
+
const fileName = path101.basename(file3);
|
|
88459
88452
|
for (const pattern of TIER_3_PATTERNS) {
|
|
88460
88453
|
if (pattern.test(fileName)) {
|
|
88461
88454
|
return true;
|
|
@@ -88469,7 +88462,7 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
88469
88462
|
if (hasActiveTurboMode()) {
|
|
88470
88463
|
const resolvedDir2 = workingDirectory;
|
|
88471
88464
|
try {
|
|
88472
|
-
const planPath =
|
|
88465
|
+
const planPath = path101.join(resolvedDir2, ".swarm", "plan.json");
|
|
88473
88466
|
const planRaw = fs82.readFileSync(planPath, "utf-8");
|
|
88474
88467
|
const plan = JSON.parse(planRaw);
|
|
88475
88468
|
for (const planPhase of plan.phases ?? []) {
|
|
@@ -88539,7 +88532,7 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
88539
88532
|
}
|
|
88540
88533
|
try {
|
|
88541
88534
|
const resolvedDir2 = workingDirectory;
|
|
88542
|
-
const planPath =
|
|
88535
|
+
const planPath = path101.join(resolvedDir2, ".swarm", "plan.json");
|
|
88543
88536
|
const planRaw = fs82.readFileSync(planPath, "utf-8");
|
|
88544
88537
|
const plan = JSON.parse(planRaw);
|
|
88545
88538
|
for (const planPhase of plan.phases ?? []) {
|
|
@@ -88697,7 +88690,7 @@ function checkCouncilGate(workingDirectory, taskId) {
|
|
|
88697
88690
|
return { blocked: false, reason: "" };
|
|
88698
88691
|
}
|
|
88699
88692
|
try {
|
|
88700
|
-
const planPath =
|
|
88693
|
+
const planPath = path101.join(workingDirectory, ".swarm", "plan.json");
|
|
88701
88694
|
const planRaw = fs82.readFileSync(planPath, "utf-8");
|
|
88702
88695
|
const planObj = JSON.parse(planRaw);
|
|
88703
88696
|
if (planObj.swarm && planObj.title) {
|
|
@@ -88788,8 +88781,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
88788
88781
|
};
|
|
88789
88782
|
}
|
|
88790
88783
|
}
|
|
88791
|
-
normalizedDir =
|
|
88792
|
-
const pathParts = normalizedDir.split(
|
|
88784
|
+
normalizedDir = path101.normalize(args2.working_directory);
|
|
88785
|
+
const pathParts = normalizedDir.split(path101.sep);
|
|
88793
88786
|
if (pathParts.includes("..")) {
|
|
88794
88787
|
return {
|
|
88795
88788
|
success: false,
|
|
@@ -88799,10 +88792,10 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
88799
88792
|
]
|
|
88800
88793
|
};
|
|
88801
88794
|
}
|
|
88802
|
-
const resolvedDir =
|
|
88795
|
+
const resolvedDir = path101.resolve(normalizedDir);
|
|
88803
88796
|
try {
|
|
88804
88797
|
const realPath = fs82.realpathSync(resolvedDir);
|
|
88805
|
-
const planPath =
|
|
88798
|
+
const planPath = path101.join(realPath, ".swarm", "plan.json");
|
|
88806
88799
|
if (!fs82.existsSync(planPath)) {
|
|
88807
88800
|
return {
|
|
88808
88801
|
success: false,
|
|
@@ -88834,8 +88827,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
88834
88827
|
}
|
|
88835
88828
|
if (args2.status === "in_progress") {
|
|
88836
88829
|
try {
|
|
88837
|
-
const evidencePath =
|
|
88838
|
-
fs82.mkdirSync(
|
|
88830
|
+
const evidencePath = path101.join(directory, ".swarm", "evidence", `${args2.task_id}.json`);
|
|
88831
|
+
fs82.mkdirSync(path101.dirname(evidencePath), { recursive: true });
|
|
88839
88832
|
const fd = fs82.openSync(evidencePath, "wx");
|
|
88840
88833
|
let writeOk = false;
|
|
88841
88834
|
try {
|
|
@@ -88859,7 +88852,7 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
88859
88852
|
recoverTaskStateFromDelegations(args2.task_id);
|
|
88860
88853
|
let phaseRequiresReviewer = true;
|
|
88861
88854
|
try {
|
|
88862
|
-
const planPath =
|
|
88855
|
+
const planPath = path101.join(directory, ".swarm", "plan.json");
|
|
88863
88856
|
const planRaw = fs82.readFileSync(planPath, "utf-8");
|
|
88864
88857
|
const plan = JSON.parse(planRaw);
|
|
88865
88858
|
const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
|
|
@@ -89100,7 +89093,7 @@ var ArgsSchema4 = exports_external.object({
|
|
|
89100
89093
|
working_directory: exports_external.string().optional()
|
|
89101
89094
|
});
|
|
89102
89095
|
var web_search = createSwarmTool({
|
|
89103
|
-
description: "External web search for council
|
|
89096
|
+
description: "External web search for architect-driven council research. Returns titled results with snippets and URLs. " + "Used by the architect in MODE: COUNCIL to gather a RESEARCH CONTEXT before dispatching council agents. " + "Requires council.general.enabled and a configured search API key (Tavily or Brave). max_results is capped at 10 with default from council.general.maxSourcesPerMember.",
|
|
89104
89097
|
args: {
|
|
89105
89098
|
query: exports_external.string().min(1).max(500).describe("Search query string (1–500 characters)."),
|
|
89106
89099
|
max_results: exports_external.number().int().min(1).max(20).optional().describe(`Number of results to request (1–20). Hard-capped at ${MAX_RESULTS_HARD_CAP}. Defaults to council.general.maxSourcesPerMember.`),
|
|
@@ -89179,7 +89172,7 @@ init_ledger();
|
|
|
89179
89172
|
init_manager();
|
|
89180
89173
|
init_create_tool();
|
|
89181
89174
|
import fs83 from "node:fs";
|
|
89182
|
-
import
|
|
89175
|
+
import path102 from "node:path";
|
|
89183
89176
|
function derivePlanId5(plan) {
|
|
89184
89177
|
return `${plan.swarm}-${plan.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
|
|
89185
89178
|
}
|
|
@@ -89230,7 +89223,7 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
89230
89223
|
entries: [evidenceEntry]
|
|
89231
89224
|
};
|
|
89232
89225
|
const filename = "drift-verifier.json";
|
|
89233
|
-
const relativePath =
|
|
89226
|
+
const relativePath = path102.join("evidence", String(phase), filename);
|
|
89234
89227
|
let validatedPath;
|
|
89235
89228
|
try {
|
|
89236
89229
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -89241,10 +89234,10 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
89241
89234
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
89242
89235
|
}, null, 2);
|
|
89243
89236
|
}
|
|
89244
|
-
const evidenceDir =
|
|
89237
|
+
const evidenceDir = path102.dirname(validatedPath);
|
|
89245
89238
|
try {
|
|
89246
89239
|
await fs83.promises.mkdir(evidenceDir, { recursive: true });
|
|
89247
|
-
const tempPath =
|
|
89240
|
+
const tempPath = path102.join(evidenceDir, `.${filename}.tmp`);
|
|
89248
89241
|
await fs83.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
89249
89242
|
await fs83.promises.rename(tempPath, validatedPath);
|
|
89250
89243
|
let snapshotInfo;
|
|
@@ -89341,7 +89334,7 @@ init_zod();
|
|
|
89341
89334
|
init_utils2();
|
|
89342
89335
|
init_create_tool();
|
|
89343
89336
|
import fs84 from "node:fs";
|
|
89344
|
-
import
|
|
89337
|
+
import path103 from "node:path";
|
|
89345
89338
|
function normalizeVerdict2(verdict) {
|
|
89346
89339
|
switch (verdict) {
|
|
89347
89340
|
case "APPROVED":
|
|
@@ -89389,7 +89382,7 @@ async function executeWriteHallucinationEvidence(args2, directory) {
|
|
|
89389
89382
|
entries: [evidenceEntry]
|
|
89390
89383
|
};
|
|
89391
89384
|
const filename = "hallucination-guard.json";
|
|
89392
|
-
const relativePath =
|
|
89385
|
+
const relativePath = path103.join("evidence", String(phase), filename);
|
|
89393
89386
|
let validatedPath;
|
|
89394
89387
|
try {
|
|
89395
89388
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -89400,10 +89393,10 @@ async function executeWriteHallucinationEvidence(args2, directory) {
|
|
|
89400
89393
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
89401
89394
|
}, null, 2);
|
|
89402
89395
|
}
|
|
89403
|
-
const evidenceDir =
|
|
89396
|
+
const evidenceDir = path103.dirname(validatedPath);
|
|
89404
89397
|
try {
|
|
89405
89398
|
await fs84.promises.mkdir(evidenceDir, { recursive: true });
|
|
89406
|
-
const tempPath =
|
|
89399
|
+
const tempPath = path103.join(evidenceDir, `.${filename}.tmp`);
|
|
89407
89400
|
await fs84.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
89408
89401
|
await fs84.promises.rename(tempPath, validatedPath);
|
|
89409
89402
|
return JSON.stringify({
|
|
@@ -89452,7 +89445,7 @@ init_zod();
|
|
|
89452
89445
|
init_utils2();
|
|
89453
89446
|
init_create_tool();
|
|
89454
89447
|
import fs85 from "node:fs";
|
|
89455
|
-
import
|
|
89448
|
+
import path104 from "node:path";
|
|
89456
89449
|
function normalizeVerdict3(verdict) {
|
|
89457
89450
|
switch (verdict) {
|
|
89458
89451
|
case "PASS":
|
|
@@ -89526,7 +89519,7 @@ async function executeWriteMutationEvidence(args2, directory) {
|
|
|
89526
89519
|
entries: [evidenceEntry]
|
|
89527
89520
|
};
|
|
89528
89521
|
const filename = "mutation-gate.json";
|
|
89529
|
-
const relativePath =
|
|
89522
|
+
const relativePath = path104.join("evidence", String(phase), filename);
|
|
89530
89523
|
let validatedPath;
|
|
89531
89524
|
try {
|
|
89532
89525
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -89537,10 +89530,10 @@ async function executeWriteMutationEvidence(args2, directory) {
|
|
|
89537
89530
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
89538
89531
|
}, null, 2);
|
|
89539
89532
|
}
|
|
89540
|
-
const evidenceDir =
|
|
89533
|
+
const evidenceDir = path104.dirname(validatedPath);
|
|
89541
89534
|
try {
|
|
89542
89535
|
await fs85.promises.mkdir(evidenceDir, { recursive: true });
|
|
89543
|
-
const tempPath =
|
|
89536
|
+
const tempPath = path104.join(evidenceDir, `.${filename}.tmp`);
|
|
89544
89537
|
await fs85.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
89545
89538
|
await fs85.promises.rename(tempPath, validatedPath);
|
|
89546
89539
|
return JSON.stringify({
|
|
@@ -89597,19 +89590,19 @@ init_utils();
|
|
|
89597
89590
|
|
|
89598
89591
|
// src/utils/gitignore-warning.ts
|
|
89599
89592
|
import * as fs86 from "node:fs";
|
|
89600
|
-
import * as
|
|
89593
|
+
import * as path105 from "node:path";
|
|
89601
89594
|
var _gitignoreWarningEmitted = false;
|
|
89602
89595
|
function findGitRoot(startDir) {
|
|
89603
89596
|
let current = startDir;
|
|
89604
89597
|
while (true) {
|
|
89605
89598
|
try {
|
|
89606
|
-
const gitPath =
|
|
89599
|
+
const gitPath = path105.join(current, ".git");
|
|
89607
89600
|
const stat4 = fs86.statSync(gitPath);
|
|
89608
89601
|
if (stat4.isDirectory()) {
|
|
89609
89602
|
return current;
|
|
89610
89603
|
}
|
|
89611
89604
|
} catch {}
|
|
89612
|
-
const parent =
|
|
89605
|
+
const parent = path105.dirname(current);
|
|
89613
89606
|
if (parent === current) {
|
|
89614
89607
|
return null;
|
|
89615
89608
|
}
|
|
@@ -89641,12 +89634,12 @@ function warnIfSwarmNotGitignored(directory, quiet = false) {
|
|
|
89641
89634
|
const gitRoot = findGitRoot(directory);
|
|
89642
89635
|
if (!gitRoot)
|
|
89643
89636
|
return;
|
|
89644
|
-
const gitignoreContent = readFileSafe(
|
|
89637
|
+
const gitignoreContent = readFileSafe(path105.join(gitRoot, ".gitignore"));
|
|
89645
89638
|
if (gitignoreContent !== null && fileCoversSwarm(gitignoreContent)) {
|
|
89646
89639
|
_gitignoreWarningEmitted = true;
|
|
89647
89640
|
return;
|
|
89648
89641
|
}
|
|
89649
|
-
const excludeContent = readFileSafe(
|
|
89642
|
+
const excludeContent = readFileSafe(path105.join(gitRoot, ".git", "info", "exclude"));
|
|
89650
89643
|
if (excludeContent !== null && fileCoversSwarm(excludeContent)) {
|
|
89651
89644
|
_gitignoreWarningEmitted = true;
|
|
89652
89645
|
return;
|
|
@@ -89694,8 +89687,8 @@ init_warning_buffer();
|
|
|
89694
89687
|
var _heartbeatTimers = new Map;
|
|
89695
89688
|
function writeSwarmConfigExampleIfNew(projectDirectory) {
|
|
89696
89689
|
try {
|
|
89697
|
-
const swarmDir =
|
|
89698
|
-
const dest =
|
|
89690
|
+
const swarmDir = path106.join(projectDirectory, ".swarm");
|
|
89691
|
+
const dest = path106.join(swarmDir, "config.example.json");
|
|
89699
89692
|
if (fs87.existsSync(dest))
|
|
89700
89693
|
return;
|
|
89701
89694
|
const example = {
|
|
@@ -89899,7 +89892,7 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
89899
89892
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
89900
89893
|
preflightTriggerManager = new PTM(automationConfig);
|
|
89901
89894
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
89902
|
-
const swarmDir =
|
|
89895
|
+
const swarmDir = path106.resolve(ctx.directory, ".swarm");
|
|
89903
89896
|
statusArtifact = new ASA(swarmDir);
|
|
89904
89897
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
89905
89898
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|
|
@@ -90069,7 +90062,7 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
90069
90062
|
...opencodeConfig.command || {},
|
|
90070
90063
|
swarm: {
|
|
90071
90064
|
template: "/swarm $ARGUMENTS",
|
|
90072
|
-
description: "Swarm management commands: /swarm [status|plan|agents|history|config|evidence|handoff|archive|diagnose|diagnosis|preflight|sync-plan|benchmark|export|reset|rollback|retrieve|clarify|analyze|specify|brainstorm|qa-gates|dark-matter|knowledge|curate|turbo|full-auto|write-retro|reset-session|simulate|promote|checkpoint|acknowledge-spec-drift|doctor-tools|close]"
|
|
90065
|
+
description: "Swarm management commands: /swarm [status|plan|agents|history|config|evidence|handoff|archive|diagnose|diagnosis|preflight|sync-plan|benchmark|export|reset|rollback|retrieve|clarify|analyze|specify|brainstorm|council|qa-gates|dark-matter|knowledge|curate|turbo|full-auto|write-retro|reset-session|simulate|promote|checkpoint|acknowledge-spec-drift|doctor-tools|close]"
|
|
90073
90066
|
},
|
|
90074
90067
|
"swarm-status": {
|
|
90075
90068
|
template: "/swarm status",
|
|
@@ -90155,6 +90148,10 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
90155
90148
|
template: "/swarm brainstorm $ARGUMENTS",
|
|
90156
90149
|
description: "Use /swarm brainstorm to enter the architect MODE: BRAINSTORM planning workflow"
|
|
90157
90150
|
},
|
|
90151
|
+
"swarm-council": {
|
|
90152
|
+
template: "/swarm council $ARGUMENTS",
|
|
90153
|
+
description: "Use /swarm council <question> to convene a multi-model General Council deliberation (generalist / skeptic / domain expert) [--spec-review]"
|
|
90154
|
+
},
|
|
90158
90155
|
"swarm-qa-gates": {
|
|
90159
90156
|
template: "/swarm qa-gates $ARGUMENTS",
|
|
90160
90157
|
description: "Use /swarm qa-gates to view or modify QA gate profile for the current plan"
|