opencode-swarm 7.47.0 → 7.48.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +3 -7
- package/dist/commands/tool-policy.d.ts +1 -1
- package/dist/index.js +1287 -1161
- package/dist/tools/phase-complete/gates/architecture-supervisor-gate.d.ts +9 -0
- package/dist/tools/phase-complete/gates/completion-verify-gate.d.ts +6 -0
- package/dist/tools/phase-complete/gates/drift-gate.d.ts +7 -0
- package/dist/tools/phase-complete/gates/final-council-gate.d.ts +7 -0
- package/dist/tools/phase-complete/gates/hallucination-gate.d.ts +6 -0
- package/dist/tools/phase-complete/gates/index.d.ts +12 -0
- package/dist/tools/phase-complete/gates/mutation-gate.d.ts +6 -0
- package/dist/tools/phase-complete/gates/phase-council-gate.d.ts +6 -0
- package/dist/tools/phase-complete/gates/types.d.ts +39 -0
- package/dist/tools/phase-complete.d.ts +14 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -69,7 +69,7 @@ var package_default;
|
|
|
69
69
|
var init_package = __esm(() => {
|
|
70
70
|
package_default = {
|
|
71
71
|
name: "opencode-swarm",
|
|
72
|
-
version: "7.
|
|
72
|
+
version: "7.48.1",
|
|
73
73
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
74
74
|
main: "dist/index.js",
|
|
75
75
|
types: "dist/index.d.ts",
|
|
@@ -616,6 +616,7 @@ var init_constants = __esm(() => {
|
|
|
616
616
|
"syntax_check",
|
|
617
617
|
"search",
|
|
618
618
|
"summarize_work",
|
|
619
|
+
"knowledge_recall",
|
|
619
620
|
"swarm_command"
|
|
620
621
|
],
|
|
621
622
|
sme: [
|
|
@@ -36016,12 +36017,13 @@ import { spawn, spawnSync } from "node:child_process";
|
|
|
36016
36017
|
import * as fs8 from "node:fs";
|
|
36017
36018
|
import * as os3 from "node:os";
|
|
36018
36019
|
import * as path11 from "node:path";
|
|
36020
|
+
import { fileURLToPath } from "node:url";
|
|
36019
36021
|
function findRunnerBinary() {
|
|
36020
36022
|
const arch = process.arch === "x64" ? "x64" : "arm64";
|
|
36021
36023
|
const platform = "win32";
|
|
36022
36024
|
const packagePaths = [
|
|
36023
|
-
path11.resolve(
|
|
36024
|
-
path11.resolve(
|
|
36025
|
+
path11.resolve(_runtimeDir, "..", "..", "..", "binaries", `${platform}-${arch}`, "swarm-sandbox-runner.exe"),
|
|
36026
|
+
path11.resolve(_runtimeDir, "..", "..", "..", "..", "binaries", `${platform}-${arch}`, "swarm-sandbox-runner.exe")
|
|
36025
36027
|
];
|
|
36026
36028
|
for (const p of packagePaths) {
|
|
36027
36029
|
try {
|
|
@@ -36225,9 +36227,10 @@ function buildDefaultPolicy(workspaceRoot, runId) {
|
|
|
36225
36227
|
deny_symlink_egress: true
|
|
36226
36228
|
};
|
|
36227
36229
|
}
|
|
36228
|
-
var
|
|
36230
|
+
var _runtimeDir, RUNNER_EXIT_CODES, _cachedProbe, _internals10;
|
|
36229
36231
|
var init_runner_client = __esm(() => {
|
|
36230
36232
|
init_logger();
|
|
36233
|
+
_runtimeDir = fileURLToPath(new URL(".", import.meta.url));
|
|
36231
36234
|
RUNNER_EXIT_CODES = {
|
|
36232
36235
|
SUCCESS: 0,
|
|
36233
36236
|
CHILD_NON_ZERO: 1,
|
|
@@ -62993,7 +62996,7 @@ var init_knowledge_diagnostics = __esm(() => {
|
|
|
62993
62996
|
import * as child_process4 from "node:child_process";
|
|
62994
62997
|
import { existsSync as existsSync21, readdirSync as readdirSync4, readFileSync as readFileSync9, statSync as statSync8 } from "node:fs";
|
|
62995
62998
|
import path36 from "node:path";
|
|
62996
|
-
import { fileURLToPath } from "node:url";
|
|
62999
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
62997
63000
|
function validateTaskDag(plan) {
|
|
62998
63001
|
const allTaskIds = new Set;
|
|
62999
63002
|
for (const phase of plan.phases) {
|
|
@@ -63356,7 +63359,7 @@ async function checkGrammarWasmFiles() {
|
|
|
63356
63359
|
"tree-sitter-ini.wasm",
|
|
63357
63360
|
"tree-sitter-regex.wasm"
|
|
63358
63361
|
];
|
|
63359
|
-
const thisDir = path36.dirname(
|
|
63362
|
+
const thisDir = path36.dirname(fileURLToPath2(import.meta.url));
|
|
63360
63363
|
const grammarDir = resolveGrammarDir(thisDir);
|
|
63361
63364
|
const missing = [];
|
|
63362
63365
|
if (!existsSync21(path36.join(grammarDir, "tree-sitter.wasm"))) {
|
|
@@ -72485,7 +72488,7 @@ var init_memory = __esm(() => {
|
|
|
72485
72488
|
// src/commands/memory.ts
|
|
72486
72489
|
import { existsSync as existsSync30 } from "node:fs";
|
|
72487
72490
|
import * as path49 from "node:path";
|
|
72488
|
-
import { fileURLToPath as
|
|
72491
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
72489
72492
|
async function handleMemoryCommand(_directory, _args) {
|
|
72490
72493
|
return [
|
|
72491
72494
|
"## Swarm Memory",
|
|
@@ -72928,7 +72931,7 @@ var PACKAGE_ROOT;
|
|
|
72928
72931
|
var init_memory2 = __esm(() => {
|
|
72929
72932
|
init_loader();
|
|
72930
72933
|
init_memory();
|
|
72931
|
-
PACKAGE_ROOT = path49.resolve(resolvePackageRootFromModule(
|
|
72934
|
+
PACKAGE_ROOT = path49.resolve(resolvePackageRootFromModule(fileURLToPath3(import.meta.url)));
|
|
72932
72935
|
});
|
|
72933
72936
|
|
|
72934
72937
|
// src/services/plan-service.ts
|
|
@@ -81429,17 +81432,13 @@ var init_tool_policy = __esm(() => {
|
|
|
81429
81432
|
"agents",
|
|
81430
81433
|
"config",
|
|
81431
81434
|
"config doctor",
|
|
81432
|
-
"config-doctor",
|
|
81433
|
-
"doctor",
|
|
81434
81435
|
"doctor tools",
|
|
81435
81436
|
"status",
|
|
81436
81437
|
"show-plan",
|
|
81437
|
-
"plan",
|
|
81438
81438
|
"help",
|
|
81439
81439
|
"history",
|
|
81440
81440
|
"evidence",
|
|
81441
81441
|
"evidence summary",
|
|
81442
|
-
"evidence-summary",
|
|
81443
81442
|
"retrieve",
|
|
81444
81443
|
"diagnose",
|
|
81445
81444
|
"preflight",
|
|
@@ -81456,8 +81455,7 @@ var init_tool_policy = __esm(() => {
|
|
|
81456
81455
|
"memory import",
|
|
81457
81456
|
"memory migrate",
|
|
81458
81457
|
"sync-plan",
|
|
81459
|
-
"export"
|
|
81460
|
-
"list-agents"
|
|
81458
|
+
"export"
|
|
81461
81459
|
];
|
|
81462
81460
|
SWARM_COMMAND_TOOL_ALLOWLIST = new Set([
|
|
81463
81461
|
"agents",
|
|
@@ -82979,9 +82977,11 @@ ${archBlock}`;
|
|
|
82979
82977
|
if (!uiReview?.enabled) {
|
|
82980
82978
|
prompt = prompt?.replace(", {{AGENT_PREFIX}}designer", "")?.replace(/\n 9\. \*\*UI\/UX DESIGN GATE\*\*:[\s\S]*?(?=\n10\. \*\*)/, `
|
|
82981
82979
|
`)?.replace(`
|
|
82982
|
-
{{AGENT_PREFIX}}designer - UI/UX design specs (scaffold generation for UI components — runs BEFORE coder on UI tasks)`, "")?.replace(/\n\{\{AGENT_PREFIX\}\}designer\nTASK: Design specification[\s\S]*?
|
|
82983
|
-
|
|
82984
|
-
|
|
82980
|
+
{{AGENT_PREFIX}}designer - UI/UX design specs (scaffold generation for UI components — runs BEFORE coder on UI tasks)`, "")?.replace(/\n\{\{AGENT_PREFIX\}\}designer\nTASK: Design specification[\s\S]*?(?=\n\n## WORKFLOW)/, "")?.replace(/, or designer/g, "")?.replace(`- the active swarm's designer agent = @{{AGENT_PREFIX}}designer
|
|
82981
|
+
`, "");
|
|
82982
|
+
if (/(?:@(?:\{\{AGENT_PREFIX\}\})?designer\b|\{\{AGENT_PREFIX\}\}designer\b)/i.test(prompt ?? "")) {
|
|
82983
|
+
console.warn("[swarm] WARNING: Custom architect prompt may still contain designer references after stripping. " + "Verify your custom prompt does not reference @designer when ui_review is disabled.");
|
|
82984
|
+
}
|
|
82985
82985
|
}
|
|
82986
82986
|
if (!designDocsEnabled) {
|
|
82987
82987
|
prompt = prompt?.replace(", {{AGENT_PREFIX}}docs_design", "")?.replace(/### MODE: DESIGN_DOCS\n[\s\S]*?(?=### MODE: ISSUE_INGEST)/, "")?.replace(`- the active swarm's docs_design agent = @{{AGENT_PREFIX}}docs_design
|
|
@@ -83441,7 +83441,7 @@ the safe \`spec_write\` tool. Use it when:
|
|
|
83441
83441
|
- requirements decomposition is non-trivial,
|
|
83442
83442
|
- you would otherwise inline-author \`.swarm/spec.md\` yourself.
|
|
83443
83443
|
|
|
83444
|
-
Continue handling small touch-ups (typos, cross-references)
|
|
83444
|
+
Continue handling small touch-ups (typos, cross-references) via the spec_writer agent — the architect lacks the spec_write tool and must delegate all spec changes.
|
|
83445
83445
|
|
|
83446
83446
|
### ANTI-RATIONALIZATION
|
|
83447
83447
|
- ✗ "The coder already knows these conventions" → Skills contain project-specific rules the model cannot know from training. Always pass.
|
|
@@ -83745,6 +83745,24 @@ HARD CONSTRAINTS (apply regardless of skill load success):
|
|
|
83745
83745
|
- Do NOT touch .swarm/spec.md, CHANGELOG.md, or docs/releases/pending/* in this mode.
|
|
83746
83746
|
- Requires design_docs.enabled: true — if the docs_design agent is not registered, instruct the user to enable it and stop.
|
|
83747
83747
|
|
|
83748
|
+
### MODE: PR_REVIEW
|
|
83749
|
+
Activates when: architect receives \`[MODE: PR_REVIEW pr="https://github.com/..." council=true/false]\` signal from the pr-review command handler.
|
|
83750
|
+
|
|
83751
|
+
Purpose: Read-only structured PR review using parallel explorer lanes, independent reviewer validation, critic challenge, and synthesis. Does NOT mutate source code. Does NOT delegate to coder.
|
|
83752
|
+
|
|
83753
|
+
ACTION: Load skill file:.opencode/skills/swarm-pr-review/SKILL.md immediately and follow its protocol.
|
|
83754
|
+
|
|
83755
|
+
HARD CONSTRAINTS (apply regardless of skill load success):
|
|
83756
|
+
- Do NOT delegate to coder
|
|
83757
|
+
- Do NOT call declare_scope
|
|
83758
|
+
- Do NOT mutate source code
|
|
83759
|
+
- Do NOT create or modify files outside .swarm/
|
|
83760
|
+
- The orchestrator MUST NOT classify, confirm, disprove, or judge explorer candidates — validation is exclusively the reviewer's job
|
|
83761
|
+
- Explorers produce candidates only — reviewers verify or reject — critics challenge HIGH/CRITICAL and borderline findings
|
|
83762
|
+
- No finding may appear as CONFIRMED in the final report without reviewer validation provenance
|
|
83763
|
+
- Test execution, explorer lanes, reviewer dispatch, and critic challenge are all permitted within this mode
|
|
83764
|
+
- Quality is the only metric — time, tokens, and agent dispatches are irrelevant to correctness
|
|
83765
|
+
|
|
83748
83766
|
### MODE: ISSUE_INGEST
|
|
83749
83767
|
Activates when the user invokes /swarm issue <url> or the architect receives an ISSUE_INGEST signal.
|
|
83750
83768
|
|
|
@@ -90942,11 +90960,11 @@ __export(exports_runtime, {
|
|
|
90942
90960
|
_internals: () => _internals45
|
|
90943
90961
|
});
|
|
90944
90962
|
import * as path93 from "node:path";
|
|
90945
|
-
import { fileURLToPath as
|
|
90963
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
90946
90964
|
async function initTreeSitter() {
|
|
90947
90965
|
if (!treeSitterInitPromise) {
|
|
90948
90966
|
treeSitterInitPromise = (async () => {
|
|
90949
|
-
const thisDir = path93.dirname(
|
|
90967
|
+
const thisDir = path93.dirname(fileURLToPath4(import.meta.url));
|
|
90950
90968
|
const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/lang");
|
|
90951
90969
|
if (isSource) {
|
|
90952
90970
|
await _internals45.parserInit();
|
|
@@ -90980,7 +90998,7 @@ function getWasmFileName(languageId) {
|
|
|
90980
90998
|
return `tree-sitter-${sanitized}.wasm`;
|
|
90981
90999
|
}
|
|
90982
91000
|
function getGrammarsDirAbsolute() {
|
|
90983
|
-
const thisDir = path93.dirname(
|
|
91001
|
+
const thisDir = path93.dirname(fileURLToPath4(import.meta.url));
|
|
90984
91002
|
const normalized = thisDir.replace(/\\/g, "/");
|
|
90985
91003
|
const isSource = normalized.endsWith("/src/lang");
|
|
90986
91004
|
const isCliBundle = normalized.endsWith("/cli");
|
|
@@ -92278,11 +92296,11 @@ __export(exports_design_doc_drift, {
|
|
|
92278
92296
|
runDesignDocDriftCheck: () => runDesignDocDriftCheck,
|
|
92279
92297
|
_internals: () => _internals55
|
|
92280
92298
|
});
|
|
92281
|
-
import * as
|
|
92282
|
-
import * as
|
|
92299
|
+
import * as fs94 from "node:fs";
|
|
92300
|
+
import * as path131 from "node:path";
|
|
92283
92301
|
function mtimeMsOrNull(absPath) {
|
|
92284
92302
|
try {
|
|
92285
|
-
return
|
|
92303
|
+
return fs94.statSync(absPath).mtimeMs;
|
|
92286
92304
|
} catch {
|
|
92287
92305
|
return null;
|
|
92288
92306
|
}
|
|
@@ -92290,40 +92308,40 @@ function mtimeMsOrNull(absPath) {
|
|
|
92290
92308
|
function resolveAnchorWithin(directory, anchor) {
|
|
92291
92309
|
if (!anchor || typeof anchor !== "string")
|
|
92292
92310
|
return null;
|
|
92293
|
-
const root =
|
|
92294
|
-
const resolved =
|
|
92295
|
-
const rel =
|
|
92296
|
-
if (rel.startsWith("..") ||
|
|
92311
|
+
const root = path131.resolve(directory);
|
|
92312
|
+
const resolved = path131.resolve(root, anchor);
|
|
92313
|
+
const rel = path131.relative(root, resolved);
|
|
92314
|
+
if (rel.startsWith("..") || path131.isAbsolute(rel))
|
|
92297
92315
|
return null;
|
|
92298
92316
|
return resolved;
|
|
92299
92317
|
}
|
|
92300
92318
|
async function runDesignDocDriftCheck(directory, phase, outDir) {
|
|
92301
92319
|
try {
|
|
92302
|
-
const root =
|
|
92303
|
-
const outAbs =
|
|
92304
|
-
const outRel =
|
|
92305
|
-
if (outRel.startsWith("..") ||
|
|
92320
|
+
const root = path131.resolve(directory);
|
|
92321
|
+
const outAbs = path131.resolve(root, outDir);
|
|
92322
|
+
const outRel = path131.relative(root, outAbs);
|
|
92323
|
+
if (outRel.startsWith("..") || path131.isAbsolute(outRel)) {
|
|
92306
92324
|
return null;
|
|
92307
92325
|
}
|
|
92308
92326
|
const docMtimes = new Map;
|
|
92309
92327
|
const checkedDocs = [];
|
|
92310
92328
|
const missingDocs = [];
|
|
92311
92329
|
for (const [docName, relFile] of Object.entries(DESIGN_DOC_FILES)) {
|
|
92312
|
-
const abs =
|
|
92330
|
+
const abs = path131.join(outAbs, relFile);
|
|
92313
92331
|
const mtime = mtimeMsOrNull(abs);
|
|
92314
92332
|
docMtimes.set(docName, mtime);
|
|
92315
92333
|
if (mtime === null) {
|
|
92316
|
-
missingDocs.push(
|
|
92334
|
+
missingDocs.push(path131.join(outDir, relFile));
|
|
92317
92335
|
} else {
|
|
92318
|
-
checkedDocs.push(
|
|
92336
|
+
checkedDocs.push(path131.join(outDir, relFile));
|
|
92319
92337
|
}
|
|
92320
92338
|
}
|
|
92321
|
-
const traceabilityAbs =
|
|
92339
|
+
const traceabilityAbs = path131.join(outAbs, TRACEABILITY_REL);
|
|
92322
92340
|
let registry3 = null;
|
|
92323
92341
|
try {
|
|
92324
|
-
const stat9 = await
|
|
92342
|
+
const stat9 = await fs94.promises.stat(traceabilityAbs);
|
|
92325
92343
|
if (stat9.size <= MAX_TRACEABILITY_BYTES) {
|
|
92326
|
-
const raw = await
|
|
92344
|
+
const raw = await fs94.promises.readFile(traceabilityAbs, "utf-8");
|
|
92327
92345
|
const parsed = JSON.parse(raw);
|
|
92328
92346
|
registry3 = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
92329
92347
|
}
|
|
@@ -92331,7 +92349,7 @@ async function runDesignDocDriftCheck(directory, phase, outDir) {
|
|
|
92331
92349
|
registry3 = null;
|
|
92332
92350
|
}
|
|
92333
92351
|
const noDocs = checkedDocs.length === 0 || registry3 === null;
|
|
92334
|
-
const specMtime = mtimeMsOrNull(
|
|
92352
|
+
const specMtime = mtimeMsOrNull(path131.join(root, ".swarm", "spec.md"));
|
|
92335
92353
|
const staleSections = [];
|
|
92336
92354
|
if (!noDocs && Array.isArray(registry3?.sections)) {
|
|
92337
92355
|
for (const section of registry3.sections) {
|
|
@@ -92387,8 +92405,8 @@ async function runDesignDocDriftCheck(directory, phase, outDir) {
|
|
|
92387
92405
|
};
|
|
92388
92406
|
const filename = `${DOC_DRIFT_REPORT_PREFIX}${phase}.json`;
|
|
92389
92407
|
const filePath = validateSwarmPath(directory, filename);
|
|
92390
|
-
await
|
|
92391
|
-
await
|
|
92408
|
+
await fs94.promises.mkdir(path131.dirname(filePath), { recursive: true });
|
|
92409
|
+
await fs94.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
|
|
92392
92410
|
getGlobalEventBus().publish("curator.docdrift.completed", {
|
|
92393
92411
|
phase,
|
|
92394
92412
|
verdict,
|
|
@@ -92418,10 +92436,10 @@ var init_design_doc_drift = __esm(() => {
|
|
|
92418
92436
|
domain: "domain.md",
|
|
92419
92437
|
"technical-spec": "technical-spec.md",
|
|
92420
92438
|
"behavior-spec": "behavior-spec.md",
|
|
92421
|
-
"reference-impl":
|
|
92422
|
-
"idiom-notes":
|
|
92439
|
+
"reference-impl": path131.join("reference", "reference-impl.md"),
|
|
92440
|
+
"idiom-notes": path131.join("reference", "idiom-notes.md")
|
|
92423
92441
|
};
|
|
92424
|
-
TRACEABILITY_REL =
|
|
92442
|
+
TRACEABILITY_REL = path131.join("reference", "traceability.json");
|
|
92425
92443
|
_internals55 = {
|
|
92426
92444
|
mtimeMsOrNull,
|
|
92427
92445
|
resolveAnchorWithin,
|
|
@@ -92436,12 +92454,12 @@ __export(exports_project_context, {
|
|
|
92436
92454
|
_internals: () => _internals71,
|
|
92437
92455
|
LANG_BACKEND_DETECTION_TIMEOUT_MS: () => LANG_BACKEND_DETECTION_TIMEOUT_MS
|
|
92438
92456
|
});
|
|
92439
|
-
import * as
|
|
92440
|
-
import * as
|
|
92457
|
+
import * as fs123 from "node:fs";
|
|
92458
|
+
import * as path166 from "node:path";
|
|
92441
92459
|
function detectFileExists2(directory, pattern) {
|
|
92442
92460
|
if (pattern.includes("*") || pattern.includes("?")) {
|
|
92443
92461
|
try {
|
|
92444
|
-
const files =
|
|
92462
|
+
const files = fs123.readdirSync(directory);
|
|
92445
92463
|
const regex = new RegExp(`^${pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".")}$`);
|
|
92446
92464
|
return files.some((f) => regex.test(f));
|
|
92447
92465
|
} catch {
|
|
@@ -92449,7 +92467,7 @@ function detectFileExists2(directory, pattern) {
|
|
|
92449
92467
|
}
|
|
92450
92468
|
}
|
|
92451
92469
|
try {
|
|
92452
|
-
|
|
92470
|
+
fs123.accessSync(path166.join(directory, pattern));
|
|
92453
92471
|
return true;
|
|
92454
92472
|
} catch {
|
|
92455
92473
|
return false;
|
|
@@ -92458,7 +92476,7 @@ function detectFileExists2(directory, pattern) {
|
|
|
92458
92476
|
function selectTestCommandFromScriptsTest(backend, directory) {
|
|
92459
92477
|
let pkgRaw;
|
|
92460
92478
|
try {
|
|
92461
|
-
pkgRaw =
|
|
92479
|
+
pkgRaw = fs123.readFileSync(path166.join(directory, "package.json"), "utf-8");
|
|
92462
92480
|
} catch {
|
|
92463
92481
|
return null;
|
|
92464
92482
|
}
|
|
@@ -92567,7 +92585,7 @@ var init_project_context = __esm(() => {
|
|
|
92567
92585
|
init_package();
|
|
92568
92586
|
init_agents2();
|
|
92569
92587
|
init_critic();
|
|
92570
|
-
import * as
|
|
92588
|
+
import * as path167 from "node:path";
|
|
92571
92589
|
|
|
92572
92590
|
// src/background/index.ts
|
|
92573
92591
|
init_event_bus();
|
|
@@ -111461,10 +111479,9 @@ init_lint();
|
|
|
111461
111479
|
init_zod();
|
|
111462
111480
|
init_config();
|
|
111463
111481
|
init_schema();
|
|
111464
|
-
init_qa_gate_profile();
|
|
111465
111482
|
init_manager2();
|
|
111466
|
-
import * as
|
|
111467
|
-
import * as
|
|
111483
|
+
import * as fs95 from "node:fs";
|
|
111484
|
+
import * as path132 from "node:path";
|
|
111468
111485
|
|
|
111469
111486
|
// src/full-auto/phase-approval.ts
|
|
111470
111487
|
init_utils2();
|
|
@@ -111643,7 +111660,6 @@ init_ledger();
|
|
|
111643
111660
|
init_manager();
|
|
111644
111661
|
init_snapshot_writer();
|
|
111645
111662
|
init_state();
|
|
111646
|
-
init_store();
|
|
111647
111663
|
init_telemetry();
|
|
111648
111664
|
|
|
111649
111665
|
// src/turbo/lean/phase-ready.ts
|
|
@@ -112137,12 +112153,765 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
112137
112153
|
// src/tools/phase-complete.ts
|
|
112138
112154
|
init_logger();
|
|
112139
112155
|
init_create_tool();
|
|
112156
|
+
|
|
112157
|
+
// src/tools/phase-complete/gates/architecture-supervisor-gate.ts
|
|
112158
|
+
init_store();
|
|
112159
|
+
async function runArchitectureSupervisorGate(ctx) {
|
|
112160
|
+
const { phase, dir, pluginConfig, agentsDispatched, safeWarn } = ctx;
|
|
112161
|
+
const asConfig = pluginConfig.architectural_supervision;
|
|
112162
|
+
const summarizeFindings = (findings) => {
|
|
112163
|
+
if (!Array.isArray(findings) || findings.length === 0)
|
|
112164
|
+
return "";
|
|
112165
|
+
const details = findings.map((f) => f && typeof f === "object" && typeof f.description === "string" ? f.description : undefined).filter((d) => Boolean(d));
|
|
112166
|
+
return details.length > 0 ? `
|
|
112167
|
+
Findings: ${details.join("; ")}` : "";
|
|
112168
|
+
};
|
|
112169
|
+
const asBlocked = (reason, message) => ({
|
|
112170
|
+
blocked: true,
|
|
112171
|
+
reason,
|
|
112172
|
+
message,
|
|
112173
|
+
agentsDispatched,
|
|
112174
|
+
agentsMissing: [],
|
|
112175
|
+
warnings: []
|
|
112176
|
+
});
|
|
112177
|
+
let asEntry = null;
|
|
112178
|
+
try {
|
|
112179
|
+
asEntry = readSupervisorReportRaw(dir, phase);
|
|
112180
|
+
} catch (asError) {
|
|
112181
|
+
return asBlocked("ARCH_SUPERVISOR_ERROR", `Phase ${phase} cannot be completed: architecture supervisor gate encountered an error. Error: ${String(asError)}`);
|
|
112182
|
+
}
|
|
112183
|
+
if (!asEntry) {
|
|
112184
|
+
return asBlocked("ARCH_SUPERVISOR_REQUIRED", `Phase ${phase} cannot be completed: architectural_supervision gate mode is enabled and no architecture supervisor evidence was found at .swarm/evidence/${phase}/architecture-supervisor.json. Dispatch critic_architecture_supervisor with the phase + agent summaries, then call write_architecture_supervisor_evidence.`);
|
|
112185
|
+
}
|
|
112186
|
+
const now = new Date;
|
|
112187
|
+
const asTime = asEntry.timestamp ? new Date(asEntry.timestamp) : null;
|
|
112188
|
+
if (!asTime || Number.isNaN(asTime.getTime())) {
|
|
112189
|
+
return asBlocked("ARCH_SUPERVISOR_INVALID_TIMESTAMP", `Phase ${phase} cannot be completed: architecture supervisor evidence has a missing or invalid timestamp.`);
|
|
112190
|
+
}
|
|
112191
|
+
if (asTime.getTime() > now.getTime()) {
|
|
112192
|
+
return asBlocked("ARCH_SUPERVISOR_FUTURE_TIMESTAMP", `Phase ${phase} cannot be completed: architecture supervisor evidence timestamp is in the future.`);
|
|
112193
|
+
}
|
|
112194
|
+
if (now.getTime() - asTime.getTime() > 24 * 60 * 60 * 1000) {
|
|
112195
|
+
return asBlocked("ARCH_SUPERVISOR_STALE_EVIDENCE", `Phase ${phase} cannot be completed: architecture supervisor evidence is older than 24 hours. Re-run the supervisor for fresh review.`);
|
|
112196
|
+
}
|
|
112197
|
+
if (typeof asEntry.phase_number !== "number" || asEntry.phase_number !== phase) {
|
|
112198
|
+
return asBlocked("ARCH_SUPERVISOR_PHASE_MISMATCH", `Phase ${phase} cannot be completed: architecture supervisor evidence is for phase ${String(asEntry.phase_number)}, not phase ${phase}.`);
|
|
112199
|
+
}
|
|
112200
|
+
const asVerdict = asEntry.verdict;
|
|
112201
|
+
if (asVerdict === "REJECT") {
|
|
112202
|
+
return asBlocked("ARCH_SUPERVISOR_REJECTED", `Phase ${phase} cannot be completed: architecture supervisor returned verdict 'REJECT'. Address the system-level findings before completing the phase.${summarizeFindings(asEntry.findings)}`);
|
|
112203
|
+
}
|
|
112204
|
+
if (asVerdict === "CONCERNS") {
|
|
112205
|
+
if (asConfig?.allow_concerns_to_complete === false) {
|
|
112206
|
+
return asBlocked("ARCH_SUPERVISOR_CONCERNS", `Phase ${phase} cannot be completed: architecture supervisor returned verdict 'CONCERNS' and allow_concerns_to_complete is disabled.${summarizeFindings(asEntry.findings)}`);
|
|
112207
|
+
}
|
|
112208
|
+
safeWarn(`[phase_complete] Architecture supervisor returned CONCERNS for phase ${phase} — proceeding (allow_concerns_to_complete is enabled)`, undefined);
|
|
112209
|
+
} else if (asVerdict !== "APPROVE") {
|
|
112210
|
+
return asBlocked("ARCH_SUPERVISOR_INVALID", `Phase ${phase} cannot be completed: architecture supervisor evidence contains unrecognized verdict '${String(asVerdict)}'. Expected one of: APPROVE, CONCERNS, REJECT.`);
|
|
112211
|
+
}
|
|
112212
|
+
return { blocked: false, agentsDispatched, agentsMissing: [], warnings: [] };
|
|
112213
|
+
}
|
|
112214
|
+
// src/tools/phase-complete/gates/completion-verify-gate.ts
|
|
112215
|
+
async function runCompletionVerifyGate(ctx) {
|
|
112216
|
+
const { phase, dir, agentsDispatched, safeWarn } = ctx;
|
|
112217
|
+
try {
|
|
112218
|
+
const completionResultRaw = await executeCompletionVerify({ phase }, dir);
|
|
112219
|
+
const completionResult = JSON.parse(completionResultRaw);
|
|
112220
|
+
if (completionResult.status === "blocked") {
|
|
112221
|
+
return {
|
|
112222
|
+
blocked: true,
|
|
112223
|
+
reason: "COMPLETION_INCOMPLETE",
|
|
112224
|
+
message: `Phase ${phase} cannot be completed: ${completionResult.reason}`,
|
|
112225
|
+
agentsDispatched,
|
|
112226
|
+
agentsMissing: [],
|
|
112227
|
+
warnings: completionResult.blockedTasks ? [
|
|
112228
|
+
`Blocked tasks: ${completionResult.blockedTasks.map((t) => t.task_id).join(", ")}`
|
|
112229
|
+
] : []
|
|
112230
|
+
};
|
|
112231
|
+
}
|
|
112232
|
+
return {
|
|
112233
|
+
blocked: false,
|
|
112234
|
+
agentsDispatched,
|
|
112235
|
+
agentsMissing: [],
|
|
112236
|
+
warnings: []
|
|
112237
|
+
};
|
|
112238
|
+
} catch (completionError) {
|
|
112239
|
+
safeWarn(`[phase_complete] Completion verify error (non-blocking):`, completionError);
|
|
112240
|
+
return {
|
|
112241
|
+
blocked: false,
|
|
112242
|
+
agentsDispatched,
|
|
112243
|
+
agentsMissing: [],
|
|
112244
|
+
warnings: []
|
|
112245
|
+
};
|
|
112246
|
+
}
|
|
112247
|
+
}
|
|
112248
|
+
// src/tools/phase-complete/gates/drift-gate.ts
|
|
112249
|
+
init_qa_gate_profile();
|
|
112250
|
+
init_manager();
|
|
112251
|
+
init_state();
|
|
112252
|
+
import * as fs89 from "node:fs";
|
|
112253
|
+
import * as path126 from "node:path";
|
|
112254
|
+
async function runDriftGate(ctx) {
|
|
112255
|
+
const { phase, dir, sessionID, agentsDispatched, safeWarn } = ctx;
|
|
112256
|
+
let driftCheckEnabled = true;
|
|
112257
|
+
let driftHasSpecMd = false;
|
|
112258
|
+
try {
|
|
112259
|
+
const specMdPath = path126.join(dir, ".swarm", "spec.md");
|
|
112260
|
+
driftHasSpecMd = fs89.existsSync(specMdPath);
|
|
112261
|
+
const gatePlan = await loadPlan(dir);
|
|
112262
|
+
if (gatePlan) {
|
|
112263
|
+
const gatePlanId = derivePlanId(gatePlan);
|
|
112264
|
+
const gateProfile = getProfile(dir, gatePlanId);
|
|
112265
|
+
if (gateProfile) {
|
|
112266
|
+
const gateSession = sessionID ? swarmState.agentSessions.get(sessionID) : undefined;
|
|
112267
|
+
const gateOverrides = gateSession?.qaGateSessionOverrides ?? {};
|
|
112268
|
+
const gateEffective = getEffectiveGates(gateProfile, gateOverrides);
|
|
112269
|
+
driftCheckEnabled = gateEffective.drift_check === true;
|
|
112270
|
+
}
|
|
112271
|
+
}
|
|
112272
|
+
} catch (gateLoadError) {
|
|
112273
|
+
safeWarn(`[phase_complete] QA gate profile load error, drift_check defaults to enabled:`, gateLoadError);
|
|
112274
|
+
}
|
|
112275
|
+
if (!driftCheckEnabled) {
|
|
112276
|
+
return {
|
|
112277
|
+
blocked: false,
|
|
112278
|
+
agentsDispatched,
|
|
112279
|
+
agentsMissing: [],
|
|
112280
|
+
warnings: [
|
|
112281
|
+
`drift_check gate is disabled. Drift verification was skipped for phase ${phase}.`
|
|
112282
|
+
]
|
|
112283
|
+
};
|
|
112284
|
+
}
|
|
112285
|
+
let phaseType;
|
|
112286
|
+
try {
|
|
112287
|
+
const planPath = path126.join(dir, ".swarm", "plan.json");
|
|
112288
|
+
if (fs89.existsSync(planPath)) {
|
|
112289
|
+
const planRaw = fs89.readFileSync(planPath, "utf-8");
|
|
112290
|
+
const plan = JSON.parse(planRaw);
|
|
112291
|
+
const targetPhase = plan.phases?.find((p) => p.id === phase);
|
|
112292
|
+
phaseType = targetPhase?.type;
|
|
112293
|
+
}
|
|
112294
|
+
} catch {}
|
|
112295
|
+
if (phaseType === "non-code") {
|
|
112296
|
+
return {
|
|
112297
|
+
blocked: false,
|
|
112298
|
+
agentsDispatched,
|
|
112299
|
+
agentsMissing: [],
|
|
112300
|
+
warnings: [
|
|
112301
|
+
`Phase ${phase} is annotated as 'non-code'. Drift verification was skipped per phase type annotation.`
|
|
112302
|
+
]
|
|
112303
|
+
};
|
|
112304
|
+
}
|
|
112305
|
+
try {
|
|
112306
|
+
const driftEvidencePath = path126.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
|
|
112307
|
+
let driftVerdictFound = false;
|
|
112308
|
+
let driftVerdictApproved = false;
|
|
112309
|
+
try {
|
|
112310
|
+
const driftEvidenceContent = fs89.readFileSync(driftEvidencePath, "utf-8");
|
|
112311
|
+
const driftEvidence = JSON.parse(driftEvidenceContent);
|
|
112312
|
+
const entries = driftEvidence.entries ?? [];
|
|
112313
|
+
for (const entry of entries) {
|
|
112314
|
+
if (typeof entry.type === "string" && entry.type.includes("drift") && typeof entry.verdict === "string") {
|
|
112315
|
+
driftVerdictFound = true;
|
|
112316
|
+
if (entry.verdict === "approved") {
|
|
112317
|
+
driftVerdictApproved = true;
|
|
112318
|
+
}
|
|
112319
|
+
if (entry.verdict === "rejected" || typeof entry.summary === "string" && entry.summary.includes("NEEDS_REVISION")) {
|
|
112320
|
+
return {
|
|
112321
|
+
blocked: true,
|
|
112322
|
+
reason: "DRIFT_VERIFICATION_REJECTED",
|
|
112323
|
+
message: `Phase ${phase} cannot be completed: drift verifier returned verdict '${entry.verdict}'. Address the drift issues before completing the phase.`,
|
|
112324
|
+
agentsDispatched,
|
|
112325
|
+
agentsMissing: [],
|
|
112326
|
+
warnings: []
|
|
112327
|
+
};
|
|
112328
|
+
}
|
|
112329
|
+
}
|
|
112330
|
+
}
|
|
112331
|
+
} catch (readError) {
|
|
112332
|
+
if (readError.code !== "ENOENT") {
|
|
112333
|
+
safeWarn(`[phase_complete] Drift verifier evidence unreadable:`, readError);
|
|
112334
|
+
}
|
|
112335
|
+
driftVerdictFound = false;
|
|
112336
|
+
}
|
|
112337
|
+
if (!driftVerdictFound) {
|
|
112338
|
+
if (!driftHasSpecMd) {
|
|
112339
|
+
let incompleteTaskCount = 0;
|
|
112340
|
+
let planParseable = false;
|
|
112341
|
+
try {
|
|
112342
|
+
const planPath = path126.join(dir, ".swarm", "plan.json");
|
|
112343
|
+
if (fs89.existsSync(planPath)) {
|
|
112344
|
+
const planRaw = fs89.readFileSync(planPath, "utf-8");
|
|
112345
|
+
const plan = JSON.parse(planRaw);
|
|
112346
|
+
planParseable = true;
|
|
112347
|
+
const planPhase = plan.phases?.find((p) => p.id === phase);
|
|
112348
|
+
if (planPhase?.tasks) {
|
|
112349
|
+
incompleteTaskCount = planPhase.tasks.filter((t) => t.status !== "completed" && t.status !== "closed").length;
|
|
112350
|
+
}
|
|
112351
|
+
}
|
|
112352
|
+
} catch {}
|
|
112353
|
+
if (!planParseable) {
|
|
112354
|
+
return {
|
|
112355
|
+
blocked: false,
|
|
112356
|
+
agentsDispatched,
|
|
112357
|
+
agentsMissing: [],
|
|
112358
|
+
warnings: [
|
|
112359
|
+
`No spec.md found and drift verification evidence missing — consider running critic_drift_verifier before phase completion.`
|
|
112360
|
+
]
|
|
112361
|
+
};
|
|
112362
|
+
} else if (incompleteTaskCount > 0) {
|
|
112363
|
+
return {
|
|
112364
|
+
blocked: false,
|
|
112365
|
+
agentsDispatched,
|
|
112366
|
+
agentsMissing: [],
|
|
112367
|
+
warnings: [
|
|
112368
|
+
`No spec.md found and drift verification evidence missing. Phase ${phase} has ${incompleteTaskCount} incomplete task(s) in plan.json — consider running critic_drift_verifier before phase completion.`
|
|
112369
|
+
]
|
|
112370
|
+
};
|
|
112371
|
+
} else {
|
|
112372
|
+
return {
|
|
112373
|
+
blocked: false,
|
|
112374
|
+
agentsDispatched,
|
|
112375
|
+
agentsMissing: [],
|
|
112376
|
+
warnings: [
|
|
112377
|
+
`No spec.md found. Phase ${phase} tasks are all completed in plan.json. Drift verification was skipped.`
|
|
112378
|
+
]
|
|
112379
|
+
};
|
|
112380
|
+
}
|
|
112381
|
+
} else {
|
|
112382
|
+
return {
|
|
112383
|
+
blocked: true,
|
|
112384
|
+
reason: "DRIFT_VERIFICATION_MISSING",
|
|
112385
|
+
message: `Phase ${phase} cannot be completed: drift_check is enabled and drift verifier evidence not found at .swarm/evidence/${phase}/drift-verifier.json. Run drift verification before completing the phase.`,
|
|
112386
|
+
agentsDispatched,
|
|
112387
|
+
agentsMissing: [],
|
|
112388
|
+
warnings: []
|
|
112389
|
+
};
|
|
112390
|
+
}
|
|
112391
|
+
}
|
|
112392
|
+
if (!driftVerdictApproved && driftVerdictFound) {
|
|
112393
|
+
return {
|
|
112394
|
+
blocked: true,
|
|
112395
|
+
reason: "DRIFT_VERIFICATION_REJECTED",
|
|
112396
|
+
message: `Phase ${phase} cannot be completed: drift verifier verdict is not approved.`,
|
|
112397
|
+
agentsDispatched,
|
|
112398
|
+
agentsMissing: [],
|
|
112399
|
+
warnings: []
|
|
112400
|
+
};
|
|
112401
|
+
}
|
|
112402
|
+
return {
|
|
112403
|
+
blocked: false,
|
|
112404
|
+
agentsDispatched,
|
|
112405
|
+
agentsMissing: [],
|
|
112406
|
+
warnings: []
|
|
112407
|
+
};
|
|
112408
|
+
} catch (driftError) {
|
|
112409
|
+
return {
|
|
112410
|
+
blocked: true,
|
|
112411
|
+
reason: "DRIFT_VERIFICATION_ERROR",
|
|
112412
|
+
message: `Phase ${phase} cannot be completed: drift verification encountered an error: ${driftError instanceof Error ? driftError.message : String(driftError)}. This is a hard block — resolve the error before completing the phase.`,
|
|
112413
|
+
agentsDispatched,
|
|
112414
|
+
agentsMissing: [],
|
|
112415
|
+
warnings: []
|
|
112416
|
+
};
|
|
112417
|
+
}
|
|
112418
|
+
}
|
|
112419
|
+
// src/tools/phase-complete/gates/final-council-gate.ts
|
|
112420
|
+
init_qa_gate_profile();
|
|
112421
|
+
init_manager();
|
|
112422
|
+
init_state();
|
|
112423
|
+
import * as fs90 from "node:fs";
|
|
112424
|
+
import * as path127 from "node:path";
|
|
112425
|
+
async function runFinalCouncilGate(ctx) {
|
|
112426
|
+
const { phase, dir, sessionID, agentsDispatched, safeWarn } = ctx;
|
|
112427
|
+
let finalCouncilEnabled = false;
|
|
112428
|
+
try {
|
|
112429
|
+
const plan = await loadPlan(dir);
|
|
112430
|
+
if (plan) {
|
|
112431
|
+
const lastPhaseId = plan.phases[plan.phases.length - 1]?.id;
|
|
112432
|
+
if (lastPhaseId !== undefined && phase === lastPhaseId) {
|
|
112433
|
+
const planId = derivePlanId(plan);
|
|
112434
|
+
const profile = getProfile(dir, planId);
|
|
112435
|
+
if (profile) {
|
|
112436
|
+
const session = sessionID ? swarmState.agentSessions.get(sessionID) : undefined;
|
|
112437
|
+
const overrides = session?.qaGateSessionOverrides ?? {};
|
|
112438
|
+
const effective = getEffectiveGates(profile, overrides);
|
|
112439
|
+
if (effective.final_council === true) {
|
|
112440
|
+
finalCouncilEnabled = true;
|
|
112441
|
+
const fcPath = path127.join(dir, ".swarm", "evidence", "final-council.json");
|
|
112442
|
+
let fcVerdictFound = false;
|
|
112443
|
+
let _fcVerdict;
|
|
112444
|
+
try {
|
|
112445
|
+
const fcContent = fs90.readFileSync(fcPath, "utf-8");
|
|
112446
|
+
const fcBundle = JSON.parse(fcContent);
|
|
112447
|
+
for (const entry of fcBundle.entries ?? []) {
|
|
112448
|
+
if (typeof entry.type === "string" && entry.type === "final-council" && typeof entry.verdict === "string") {
|
|
112449
|
+
fcVerdictFound = true;
|
|
112450
|
+
_fcVerdict = entry.verdict;
|
|
112451
|
+
if (plan) {
|
|
112452
|
+
const currentPlanId = derivePlanId(plan);
|
|
112453
|
+
if (entry.plan_id && entry.plan_id !== currentPlanId) {
|
|
112454
|
+
return {
|
|
112455
|
+
blocked: true,
|
|
112456
|
+
reason: "final_council_plan_mismatch",
|
|
112457
|
+
message: `Final council evidence belongs to a different plan (evidence: ${entry.plan_id}, current: ${currentPlanId}). Re-run the final council.`,
|
|
112458
|
+
agentsDispatched,
|
|
112459
|
+
agentsMissing: [],
|
|
112460
|
+
warnings: []
|
|
112461
|
+
};
|
|
112462
|
+
}
|
|
112463
|
+
if (!entry.plan_id) {
|
|
112464
|
+
return {
|
|
112465
|
+
blocked: true,
|
|
112466
|
+
reason: "FINAL_COUNCIL_PLAN_ID_REQUIRED",
|
|
112467
|
+
message: `Phase ${phase} (last phase) cannot be completed: final council evidence is missing plan_id binding. Re-run the final council to generate evidence with plan identity.`,
|
|
112468
|
+
agentsDispatched,
|
|
112469
|
+
agentsMissing: [],
|
|
112470
|
+
warnings: []
|
|
112471
|
+
};
|
|
112472
|
+
}
|
|
112473
|
+
}
|
|
112474
|
+
if (typeof entry.quorumSize !== "number" || !Number.isFinite(entry.quorumSize) || entry.quorumSize < 5) {
|
|
112475
|
+
return {
|
|
112476
|
+
blocked: true,
|
|
112477
|
+
reason: "FINAL_COUNCIL_MISSING_QUORUM",
|
|
112478
|
+
message: `Phase ${phase} (last phase) cannot be completed: final council evidence is missing valid quorum metadata. Re-run the project-scoped five-member final council and call write_final_council_evidence to generate quorumed evidence.`,
|
|
112479
|
+
agentsDispatched,
|
|
112480
|
+
agentsMissing: [],
|
|
112481
|
+
warnings: []
|
|
112482
|
+
};
|
|
112483
|
+
}
|
|
112484
|
+
const requiredFinalCouncilMembers = [
|
|
112485
|
+
"critic",
|
|
112486
|
+
"reviewer",
|
|
112487
|
+
"sme",
|
|
112488
|
+
"test_engineer",
|
|
112489
|
+
"explorer"
|
|
112490
|
+
];
|
|
112491
|
+
const membersVoted = Array.isArray(entry.membersVoted) ? entry.membersVoted.filter((member) => typeof member === "string") : [];
|
|
112492
|
+
const membersAbsent = Array.isArray(entry.membersAbsent) ? entry.membersAbsent.filter((member) => typeof member === "string") : [];
|
|
112493
|
+
const distinctMembersVoted = new Set(membersVoted);
|
|
112494
|
+
const hasAllRequiredMembers = requiredFinalCouncilMembers.every((member) => distinctMembersVoted.has(member)) && distinctMembersVoted.size === requiredFinalCouncilMembers.length && membersAbsent.length === 0;
|
|
112495
|
+
if (!hasAllRequiredMembers) {
|
|
112496
|
+
return {
|
|
112497
|
+
blocked: true,
|
|
112498
|
+
reason: "FINAL_COUNCIL_MISSING_QUORUM",
|
|
112499
|
+
message: `Phase ${phase} (last phase) cannot be completed: final council evidence does not prove all five required members voted. Re-run the project-scoped five-member final council and call write_final_council_evidence to generate complete evidence.`,
|
|
112500
|
+
agentsDispatched,
|
|
112501
|
+
agentsMissing: [],
|
|
112502
|
+
warnings: []
|
|
112503
|
+
};
|
|
112504
|
+
}
|
|
112505
|
+
if (entry.verdict === "rejected" || entry.verdict === "REJECTED") {
|
|
112506
|
+
return {
|
|
112507
|
+
blocked: true,
|
|
112508
|
+
reason: "FINAL_COUNCIL_REJECTED",
|
|
112509
|
+
message: `Phase ${phase} (last phase) cannot be completed: final council returned verdict 'REJECTED'. Address the required fixes before completing the project.`,
|
|
112510
|
+
agentsDispatched,
|
|
112511
|
+
agentsMissing: [],
|
|
112512
|
+
warnings: []
|
|
112513
|
+
};
|
|
112514
|
+
}
|
|
112515
|
+
if (entry.verdict !== "approved" && entry.verdict !== "APPROVED") {
|
|
112516
|
+
return {
|
|
112517
|
+
blocked: true,
|
|
112518
|
+
reason: "FINAL_COUNCIL_INVALID_VERDICT",
|
|
112519
|
+
message: `Phase ${phase} (last phase) cannot be completed: final council evidence contains unrecognized verdict '${entry.verdict}'. Expected 'approved'.`,
|
|
112520
|
+
agentsDispatched,
|
|
112521
|
+
agentsMissing: [],
|
|
112522
|
+
warnings: []
|
|
112523
|
+
};
|
|
112524
|
+
}
|
|
112525
|
+
}
|
|
112526
|
+
}
|
|
112527
|
+
} catch (readErr) {
|
|
112528
|
+
if (readErr.code !== "ENOENT") {
|
|
112529
|
+
safeWarn(`[phase_complete] Final council evidence unreadable:`, readErr);
|
|
112530
|
+
}
|
|
112531
|
+
fcVerdictFound = false;
|
|
112532
|
+
}
|
|
112533
|
+
if (!fcVerdictFound) {
|
|
112534
|
+
return {
|
|
112535
|
+
blocked: true,
|
|
112536
|
+
reason: "FINAL_COUNCIL_REQUIRED",
|
|
112537
|
+
final_council_required: true,
|
|
112538
|
+
message: `Phase ${phase} (last phase) cannot be completed: final_council is enabled and final council evidence not found at .swarm/evidence/final-council.json. Dispatch critic, reviewer, sme, test_engineer, and explorer with project-scoped context, collect their CouncilMemberVerdict JSON, and call write_final_council_evidence before completing the project. Do not use convene_general_council for this gate.`,
|
|
112539
|
+
agentsDispatched,
|
|
112540
|
+
agentsMissing: [],
|
|
112541
|
+
warnings: [
|
|
112542
|
+
`Final council required - dispatch the five project-scoped council members, then call write_final_council_evidence to persist quorumed evidence.`
|
|
112543
|
+
]
|
|
112544
|
+
};
|
|
112545
|
+
}
|
|
112546
|
+
}
|
|
112547
|
+
}
|
|
112548
|
+
}
|
|
112549
|
+
}
|
|
112550
|
+
} catch (fcError) {
|
|
112551
|
+
if (finalCouncilEnabled) {
|
|
112552
|
+
return {
|
|
112553
|
+
blocked: true,
|
|
112554
|
+
reason: "FINAL_COUNCIL_ERROR",
|
|
112555
|
+
message: `Phase ${phase} (last phase) cannot be completed: final council gate encountered an error. Error: ${String(fcError)}`,
|
|
112556
|
+
agentsDispatched,
|
|
112557
|
+
agentsMissing: [],
|
|
112558
|
+
warnings: [`FINAL_COUNCIL_ERROR: ${String(fcError)}`]
|
|
112559
|
+
};
|
|
112560
|
+
} else {
|
|
112561
|
+
safeWarn(`[phase_complete] Final council gate error (non-blocking):`, fcError);
|
|
112562
|
+
}
|
|
112563
|
+
}
|
|
112564
|
+
return { blocked: false, agentsDispatched, agentsMissing: [], warnings: [] };
|
|
112565
|
+
}
|
|
112566
|
+
// src/tools/phase-complete/gates/hallucination-gate.ts
|
|
112567
|
+
init_qa_gate_profile();
|
|
112568
|
+
init_manager();
|
|
112569
|
+
init_state();
|
|
112570
|
+
import * as fs91 from "node:fs";
|
|
112571
|
+
import * as path128 from "node:path";
|
|
112572
|
+
async function runHallucinationGate(ctx) {
|
|
112573
|
+
const { phase, dir, sessionID, agentsDispatched, safeWarn } = ctx;
|
|
112574
|
+
try {
|
|
112575
|
+
const plan = await loadPlan(dir);
|
|
112576
|
+
if (plan) {
|
|
112577
|
+
const planId = derivePlanId(plan);
|
|
112578
|
+
const profile = getProfile(dir, planId);
|
|
112579
|
+
if (profile) {
|
|
112580
|
+
const session = sessionID ? swarmState.agentSessions.get(sessionID) : undefined;
|
|
112581
|
+
const overrides = session?.qaGateSessionOverrides ?? {};
|
|
112582
|
+
const effective = getEffectiveGates(profile, overrides);
|
|
112583
|
+
if (effective.hallucination_guard === true) {
|
|
112584
|
+
const hgPath = path128.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
|
|
112585
|
+
let hgVerdictFound = false;
|
|
112586
|
+
let hgVerdictApproved = false;
|
|
112587
|
+
try {
|
|
112588
|
+
const hgContent = fs91.readFileSync(hgPath, "utf-8");
|
|
112589
|
+
const hgBundle = JSON.parse(hgContent);
|
|
112590
|
+
for (const entry of hgBundle.entries ?? []) {
|
|
112591
|
+
if (typeof entry.type === "string" && entry.type.includes("hallucination") && typeof entry.verdict === "string") {
|
|
112592
|
+
hgVerdictFound = true;
|
|
112593
|
+
if (entry.verdict === "approved") {
|
|
112594
|
+
hgVerdictApproved = true;
|
|
112595
|
+
}
|
|
112596
|
+
if (entry.verdict === "rejected" || typeof entry.summary === "string" && entry.summary.includes("NEEDS_REVISION")) {
|
|
112597
|
+
return {
|
|
112598
|
+
blocked: true,
|
|
112599
|
+
reason: "HALLUCINATION_VERIFICATION_REJECTED",
|
|
112600
|
+
message: `Phase ${phase} cannot be completed: hallucination verifier returned verdict '${entry.verdict}'. Remove fabricated APIs/signatures and fix broken citations before completing the phase.`,
|
|
112601
|
+
agentsDispatched,
|
|
112602
|
+
agentsMissing: [],
|
|
112603
|
+
warnings: []
|
|
112604
|
+
};
|
|
112605
|
+
}
|
|
112606
|
+
}
|
|
112607
|
+
}
|
|
112608
|
+
} catch (readErr) {
|
|
112609
|
+
if (readErr.code !== "ENOENT") {
|
|
112610
|
+
safeWarn(`[phase_complete] Hallucination guard evidence unreadable:`, readErr);
|
|
112611
|
+
}
|
|
112612
|
+
hgVerdictFound = false;
|
|
112613
|
+
}
|
|
112614
|
+
if (!hgVerdictFound) {
|
|
112615
|
+
return {
|
|
112616
|
+
blocked: true,
|
|
112617
|
+
reason: "HALLUCINATION_VERIFICATION_MISSING",
|
|
112618
|
+
message: `Phase ${phase} cannot be completed: hallucination_guard is enabled and evidence not found at .swarm/evidence/${phase}/hallucination-guard.json. Delegate to critic_hallucination_verifier and call write_hallucination_evidence before completing the phase.`,
|
|
112619
|
+
agentsDispatched,
|
|
112620
|
+
agentsMissing: [],
|
|
112621
|
+
warnings: []
|
|
112622
|
+
};
|
|
112623
|
+
}
|
|
112624
|
+
if (!hgVerdictApproved) {
|
|
112625
|
+
return {
|
|
112626
|
+
blocked: true,
|
|
112627
|
+
reason: "HALLUCINATION_VERIFICATION_REJECTED",
|
|
112628
|
+
message: `Phase ${phase} cannot be completed: hallucination verifier verdict is not approved.`,
|
|
112629
|
+
agentsDispatched,
|
|
112630
|
+
agentsMissing: [],
|
|
112631
|
+
warnings: []
|
|
112632
|
+
};
|
|
112633
|
+
}
|
|
112634
|
+
}
|
|
112635
|
+
}
|
|
112636
|
+
}
|
|
112637
|
+
} catch (hgError) {
|
|
112638
|
+
safeWarn(`[phase_complete] Hallucination guard error (non-blocking):`, hgError);
|
|
112639
|
+
}
|
|
112640
|
+
return { blocked: false, agentsDispatched, agentsMissing: [], warnings: [] };
|
|
112641
|
+
}
|
|
112642
|
+
// src/tools/phase-complete/gates/mutation-gate.ts
|
|
112643
|
+
init_qa_gate_profile();
|
|
112644
|
+
init_manager();
|
|
112645
|
+
init_state();
|
|
112646
|
+
import * as fs92 from "node:fs";
|
|
112647
|
+
import * as path129 from "node:path";
|
|
112648
|
+
async function runMutationGate(ctx) {
|
|
112649
|
+
const { phase, dir, sessionID, agentsDispatched, safeWarn } = ctx;
|
|
112650
|
+
try {
|
|
112651
|
+
const plan = await loadPlan(dir);
|
|
112652
|
+
if (plan) {
|
|
112653
|
+
const planId = derivePlanId(plan);
|
|
112654
|
+
const profile = getProfile(dir, planId);
|
|
112655
|
+
if (profile) {
|
|
112656
|
+
const session = sessionID ? swarmState.agentSessions.get(sessionID) : undefined;
|
|
112657
|
+
const overrides = session?.qaGateSessionOverrides ?? {};
|
|
112658
|
+
const effective = getEffectiveGates(profile, overrides);
|
|
112659
|
+
if (effective.mutation_test === true) {
|
|
112660
|
+
const mgPath = path129.join(dir, ".swarm", "evidence", String(phase), "mutation-gate.json");
|
|
112661
|
+
let mgVerdictFound = false;
|
|
112662
|
+
let mgVerdict;
|
|
112663
|
+
try {
|
|
112664
|
+
const mgContent = fs92.readFileSync(mgPath, "utf-8");
|
|
112665
|
+
const mgBundle = JSON.parse(mgContent);
|
|
112666
|
+
for (const entry of mgBundle.entries ?? []) {
|
|
112667
|
+
if (typeof entry.type === "string" && entry.type === "mutation-gate" && typeof entry.verdict === "string") {
|
|
112668
|
+
mgVerdictFound = true;
|
|
112669
|
+
mgVerdict = entry.verdict;
|
|
112670
|
+
if (entry.verdict === "fail") {
|
|
112671
|
+
return {
|
|
112672
|
+
blocked: true,
|
|
112673
|
+
reason: "MUTATION_GATE_FAIL",
|
|
112674
|
+
message: `Phase ${phase} cannot be completed: mutation gate returned verdict 'fail'. Resolve surviving mutants or lower the kill-rate threshold before completing the phase.`,
|
|
112675
|
+
agentsDispatched,
|
|
112676
|
+
agentsMissing: [],
|
|
112677
|
+
warnings: []
|
|
112678
|
+
};
|
|
112679
|
+
} else if (!["pass", "warn", "skip"].includes(entry.verdict)) {
|
|
112680
|
+
return {
|
|
112681
|
+
blocked: true,
|
|
112682
|
+
reason: "MUTATION_GATE_FAIL",
|
|
112683
|
+
message: `Phase ${phase} cannot be completed: mutation gate evidence contains unrecognized verdict '${entry.verdict}'. Expected one of: pass, warn, fail, skip.`,
|
|
112684
|
+
agentsDispatched,
|
|
112685
|
+
agentsMissing: [],
|
|
112686
|
+
warnings: []
|
|
112687
|
+
};
|
|
112688
|
+
}
|
|
112689
|
+
}
|
|
112690
|
+
}
|
|
112691
|
+
} catch (readErr) {
|
|
112692
|
+
if (readErr.code !== "ENOENT") {
|
|
112693
|
+
safeWarn(`[phase_complete] Mutation gate evidence unreadable:`, readErr);
|
|
112694
|
+
}
|
|
112695
|
+
mgVerdictFound = false;
|
|
112696
|
+
}
|
|
112697
|
+
if (!mgVerdictFound) {
|
|
112698
|
+
return {
|
|
112699
|
+
blocked: true,
|
|
112700
|
+
reason: "MUTATION_GATE_MISSING",
|
|
112701
|
+
message: `Phase ${phase} cannot be completed: mutation_test is enabled and evidence not found at .swarm/evidence/${phase}/mutation-gate.json. Run mutation_test, then call write_mutation_evidence before completing the phase.`,
|
|
112702
|
+
agentsDispatched,
|
|
112703
|
+
agentsMissing: [],
|
|
112704
|
+
warnings: []
|
|
112705
|
+
};
|
|
112706
|
+
}
|
|
112707
|
+
if (mgVerdict === "warn") {
|
|
112708
|
+
safeWarn(`[phase_complete] Mutation gate verdict is 'warn' for phase ${phase} — proceeding with warning`, undefined);
|
|
112709
|
+
}
|
|
112710
|
+
}
|
|
112711
|
+
}
|
|
112712
|
+
}
|
|
112713
|
+
} catch (mgError) {
|
|
112714
|
+
safeWarn(`[phase_complete] Mutation gate error (non-blocking):`, mgError);
|
|
112715
|
+
}
|
|
112716
|
+
return { blocked: false, agentsDispatched, agentsMissing: [], warnings: [] };
|
|
112717
|
+
}
|
|
112718
|
+
// src/tools/phase-complete/gates/phase-council-gate.ts
|
|
112719
|
+
init_qa_gate_profile();
|
|
112720
|
+
init_manager();
|
|
112721
|
+
init_state();
|
|
112722
|
+
import * as fs93 from "node:fs";
|
|
112723
|
+
import * as path130 from "node:path";
|
|
112724
|
+
async function runPhaseCouncilGate(ctx) {
|
|
112725
|
+
const { phase, dir, sessionID, pluginConfig, agentsDispatched, safeWarn } = ctx;
|
|
112726
|
+
let councilModeEnabled = false;
|
|
112727
|
+
try {
|
|
112728
|
+
const plan = await loadPlan(dir);
|
|
112729
|
+
if (plan) {
|
|
112730
|
+
const planId = derivePlanId(plan);
|
|
112731
|
+
const profile = getProfile(dir, planId);
|
|
112732
|
+
if (profile) {
|
|
112733
|
+
const session = sessionID ? swarmState.agentSessions.get(sessionID) : undefined;
|
|
112734
|
+
const overrides = session?.qaGateSessionOverrides ?? {};
|
|
112735
|
+
const effective = getEffectiveGates(profile, overrides);
|
|
112736
|
+
if (effective.council_mode === true) {
|
|
112737
|
+
councilModeEnabled = true;
|
|
112738
|
+
const pcPath = path130.join(dir, ".swarm", "evidence", String(phase), "phase-council.json");
|
|
112739
|
+
let pcVerdictFound = false;
|
|
112740
|
+
let _pcVerdict;
|
|
112741
|
+
let pcQuorumSize;
|
|
112742
|
+
let pcTimestamp;
|
|
112743
|
+
let pcPhaseNumber;
|
|
112744
|
+
try {
|
|
112745
|
+
const pcContent = fs93.readFileSync(pcPath, "utf-8");
|
|
112746
|
+
const pcBundle = JSON.parse(pcContent);
|
|
112747
|
+
for (const entry of pcBundle.entries ?? []) {
|
|
112748
|
+
if (typeof entry.type === "string" && entry.type === "phase-council" && typeof entry.verdict === "string") {
|
|
112749
|
+
pcVerdictFound = true;
|
|
112750
|
+
_pcVerdict = entry.verdict;
|
|
112751
|
+
pcQuorumSize = typeof entry.quorumSize === "number" ? entry.quorumSize : undefined;
|
|
112752
|
+
pcTimestamp = typeof entry.timestamp === "string" ? entry.timestamp : undefined;
|
|
112753
|
+
pcPhaseNumber = typeof entry.phase_number === "number" ? entry.phase_number : typeof entry.phase === "number" ? entry.phase : undefined;
|
|
112754
|
+
const now = new Date;
|
|
112755
|
+
const pcTime = pcTimestamp ? new Date(pcTimestamp) : null;
|
|
112756
|
+
if (!pcTime || Number.isNaN(pcTime.getTime())) {
|
|
112757
|
+
return {
|
|
112758
|
+
blocked: true,
|
|
112759
|
+
reason: "PHASE_COUNCIL_INVALID_TIMESTAMP",
|
|
112760
|
+
message: `Phase ${phase} cannot be completed: phase council evidence has missing or invalid timestamp.`,
|
|
112761
|
+
agentsDispatched,
|
|
112762
|
+
agentsMissing: [],
|
|
112763
|
+
warnings: []
|
|
112764
|
+
};
|
|
112765
|
+
}
|
|
112766
|
+
const maxAge = 24 * 60 * 60 * 1000;
|
|
112767
|
+
if (pcTime.getTime() > now.getTime()) {
|
|
112768
|
+
return {
|
|
112769
|
+
blocked: true,
|
|
112770
|
+
reason: "PHASE_COUNCIL_FUTURE_TIMESTAMP",
|
|
112771
|
+
message: `Phase ${phase} cannot be completed: phase council evidence timestamp is in the future.`,
|
|
112772
|
+
agentsDispatched,
|
|
112773
|
+
agentsMissing: [],
|
|
112774
|
+
warnings: []
|
|
112775
|
+
};
|
|
112776
|
+
}
|
|
112777
|
+
if (now.getTime() - pcTime.getTime() > maxAge) {
|
|
112778
|
+
return {
|
|
112779
|
+
blocked: true,
|
|
112780
|
+
reason: "PHASE_COUNCIL_STALE_EVIDENCE",
|
|
112781
|
+
message: `Phase ${phase} cannot be completed: phase council evidence is older than 24 hours. Re-convene council for fresh review.`,
|
|
112782
|
+
agentsDispatched,
|
|
112783
|
+
agentsMissing: [],
|
|
112784
|
+
warnings: []
|
|
112785
|
+
};
|
|
112786
|
+
}
|
|
112787
|
+
if (entry.verdict === "REJECT" || entry.verdict === "reject") {
|
|
112788
|
+
const requiredFixes = entry.requiredFixes ?? entry.required_fixes ?? [];
|
|
112789
|
+
const fixesDetail = Array.isArray(requiredFixes) && requiredFixes.length > 0 ? `
|
|
112790
|
+
Required fixes: ${requiredFixes.map((f) => f.detail ?? JSON.stringify(f)).join("; ")}` : "";
|
|
112791
|
+
return {
|
|
112792
|
+
blocked: true,
|
|
112793
|
+
reason: "PHASE_COUNCIL_REJECTED",
|
|
112794
|
+
message: `Phase ${phase} cannot be completed: phase council returned verdict 'REJECT'. Address the required fixes before completing the phase.${fixesDetail}`,
|
|
112795
|
+
agentsDispatched,
|
|
112796
|
+
agentsMissing: [],
|
|
112797
|
+
warnings: []
|
|
112798
|
+
};
|
|
112799
|
+
}
|
|
112800
|
+
if (entry.verdict === "CONCERNS" || entry.verdict === "concerns") {
|
|
112801
|
+
const phaseConcernsAllow = pluginConfig.council?.phaseConcernsAllowComplete ?? true;
|
|
112802
|
+
if (!phaseConcernsAllow) {
|
|
112803
|
+
const advisoryNotes = entry.advisoryNotes ?? entry.advisory_notes ?? [];
|
|
112804
|
+
const notesDetail = Array.isArray(advisoryNotes) && advisoryNotes.length > 0 ? `
|
|
112805
|
+
Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
112806
|
+
return {
|
|
112807
|
+
blocked: true,
|
|
112808
|
+
reason: "PHASE_COUNCIL_CONCERNS",
|
|
112809
|
+
message: `Phase ${phase} cannot be completed: phase council returned verdict 'CONCERNS'.${notesDetail}`,
|
|
112810
|
+
agentsDispatched,
|
|
112811
|
+
agentsMissing: [],
|
|
112812
|
+
warnings: []
|
|
112813
|
+
};
|
|
112814
|
+
}
|
|
112815
|
+
safeWarn(`[phase_complete] Phase council returned CONCERNS for phase ${phase} — proceeding (phaseConcernsAllowComplete is enabled)`, undefined);
|
|
112816
|
+
}
|
|
112817
|
+
if (entry.verdict !== "APPROVE" && entry.verdict !== "approve" && entry.verdict !== "CONCERNS" && entry.verdict !== "concerns") {
|
|
112818
|
+
return {
|
|
112819
|
+
blocked: true,
|
|
112820
|
+
reason: "PHASE_COUNCIL_INVALID",
|
|
112821
|
+
message: `Phase ${phase} cannot be completed: phase council evidence contains unrecognized verdict '${entry.verdict}'. Expected one of: APPROVE, CONCERNS, REJECT.`,
|
|
112822
|
+
agentsDispatched,
|
|
112823
|
+
agentsMissing: [],
|
|
112824
|
+
warnings: []
|
|
112825
|
+
};
|
|
112826
|
+
}
|
|
112827
|
+
}
|
|
112828
|
+
}
|
|
112829
|
+
} catch (readErr) {
|
|
112830
|
+
if (readErr.code !== "ENOENT") {
|
|
112831
|
+
safeWarn(`[phase_complete] Phase council evidence unreadable:`, readErr);
|
|
112832
|
+
}
|
|
112833
|
+
pcVerdictFound = false;
|
|
112834
|
+
}
|
|
112835
|
+
if (!pcVerdictFound) {
|
|
112836
|
+
return {
|
|
112837
|
+
blocked: true,
|
|
112838
|
+
reason: "PHASE_COUNCIL_REQUIRED",
|
|
112839
|
+
phase_council_required: true,
|
|
112840
|
+
message: `Phase ${phase} cannot be completed: council_mode is enabled and phase council evidence not found at .swarm/evidence/${phase}/phase-council.json. Convene a phase-level council (dispatch 5 members, collect verdicts, call submit_phase_council_verdicts) before completing the phase.`,
|
|
112841
|
+
agentsDispatched,
|
|
112842
|
+
agentsMissing: [],
|
|
112843
|
+
warnings: [
|
|
112844
|
+
`Phase council required — convene 5 council members (critic, reviewer, sme, test_engineer, explorer) for holistic phase review. Call submit_phase_council_verdicts to synthesize verdicts and write phase-council.json evidence.`
|
|
112845
|
+
]
|
|
112846
|
+
};
|
|
112847
|
+
}
|
|
112848
|
+
if (pcQuorumSize === undefined || typeof pcQuorumSize !== "number") {
|
|
112849
|
+
return {
|
|
112850
|
+
blocked: true,
|
|
112851
|
+
reason: "PHASE_COUNCIL_MISSING_QUORUM",
|
|
112852
|
+
message: `Phase ${phase} cannot be completed: phase council evidence is missing quorumSize field.`,
|
|
112853
|
+
agentsDispatched,
|
|
112854
|
+
agentsMissing: [],
|
|
112855
|
+
warnings: []
|
|
112856
|
+
};
|
|
112857
|
+
}
|
|
112858
|
+
if (pcQuorumSize < 3) {
|
|
112859
|
+
return {
|
|
112860
|
+
blocked: true,
|
|
112861
|
+
reason: "PHASE_COUNCIL_INSUFFICIENT_QUORUM",
|
|
112862
|
+
message: `Phase ${phase} cannot be completed: phase council quorum (${pcQuorumSize}) is below minimum (3). Re-convene council with sufficient members.`,
|
|
112863
|
+
agentsDispatched,
|
|
112864
|
+
agentsMissing: [],
|
|
112865
|
+
warnings: []
|
|
112866
|
+
};
|
|
112867
|
+
}
|
|
112868
|
+
if (pcPhaseNumber === undefined || typeof pcPhaseNumber !== "number") {
|
|
112869
|
+
return {
|
|
112870
|
+
blocked: true,
|
|
112871
|
+
reason: "PHASE_COUNCIL_MISSING_PHASE",
|
|
112872
|
+
message: `Phase ${phase} cannot be completed: phase council evidence is missing phase_number field.`,
|
|
112873
|
+
agentsDispatched,
|
|
112874
|
+
agentsMissing: [],
|
|
112875
|
+
warnings: []
|
|
112876
|
+
};
|
|
112877
|
+
}
|
|
112878
|
+
if (pcPhaseNumber !== phase) {
|
|
112879
|
+
return {
|
|
112880
|
+
blocked: true,
|
|
112881
|
+
reason: "PHASE_COUNCIL_PHASE_MISMATCH",
|
|
112882
|
+
message: `Phase ${phase} cannot be completed: phase council evidence is for phase ${pcPhaseNumber}, not phase ${phase}. Run council for the correct phase.`,
|
|
112883
|
+
agentsDispatched,
|
|
112884
|
+
agentsMissing: [],
|
|
112885
|
+
warnings: []
|
|
112886
|
+
};
|
|
112887
|
+
}
|
|
112888
|
+
}
|
|
112889
|
+
}
|
|
112890
|
+
}
|
|
112891
|
+
} catch (pcError) {
|
|
112892
|
+
if (councilModeEnabled) {
|
|
112893
|
+
return {
|
|
112894
|
+
blocked: true,
|
|
112895
|
+
reason: "PHASE_COUNCIL_ERROR",
|
|
112896
|
+
message: `Phase ${phase} cannot be completed: phase council gate encountered an error when council_mode was enabled. Error: ${String(pcError)}`,
|
|
112897
|
+
agentsDispatched,
|
|
112898
|
+
agentsMissing: [],
|
|
112899
|
+
warnings: [`PHASE_COUNCIL_ERROR: ${String(pcError)}`]
|
|
112900
|
+
};
|
|
112901
|
+
} else {
|
|
112902
|
+
safeWarn(`[phase_complete] Phase council gate error (non-blocking):`, pcError);
|
|
112903
|
+
}
|
|
112904
|
+
}
|
|
112905
|
+
return { blocked: false, agentsDispatched, agentsMissing: [], warnings: [] };
|
|
112906
|
+
}
|
|
112907
|
+
// src/tools/phase-complete.ts
|
|
112140
112908
|
init_resolve_working_directory();
|
|
112141
112909
|
function safeWarn(message, error93) {
|
|
112142
112910
|
try {
|
|
112143
112911
|
warn(message, error93 instanceof Error ? error93.message : String(error93));
|
|
112144
112912
|
} catch {}
|
|
112145
112913
|
}
|
|
112914
|
+
var MAX_OUTPUT_BYTES5 = 512000;
|
|
112146
112915
|
var TASK_GATE_INFERABLE_AGENTS = new Set([
|
|
112147
112916
|
"coder",
|
|
112148
112917
|
"reviewer",
|
|
@@ -112213,6 +112982,28 @@ function _getDelegationsSince(sessionID, sinceTimestamp) {
|
|
|
112213
112982
|
function isValidRetroEntry(entry, phase) {
|
|
112214
112983
|
return entry.type === "retrospective" && "phase_number" in entry && entry.phase_number === phase && "verdict" in entry && entry.verdict === "pass";
|
|
112215
112984
|
}
|
|
112985
|
+
function blockedResult(phase, gateResult) {
|
|
112986
|
+
const {
|
|
112987
|
+
reason,
|
|
112988
|
+
message,
|
|
112989
|
+
agentsDispatched,
|
|
112990
|
+
agentsMissing,
|
|
112991
|
+
warnings,
|
|
112992
|
+
blocked: _blocked,
|
|
112993
|
+
...extra
|
|
112994
|
+
} = gateResult;
|
|
112995
|
+
return JSON.stringify({
|
|
112996
|
+
success: false,
|
|
112997
|
+
phase,
|
|
112998
|
+
status: "blocked",
|
|
112999
|
+
reason,
|
|
113000
|
+
message,
|
|
113001
|
+
agentsDispatched,
|
|
113002
|
+
agentsMissing,
|
|
113003
|
+
warnings,
|
|
113004
|
+
...extra
|
|
113005
|
+
}, null, 2);
|
|
113006
|
+
}
|
|
112216
113007
|
async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
112217
113008
|
const phase = Number(args2.phase);
|
|
112218
113009
|
const summary = args2.summary;
|
|
@@ -112351,719 +113142,66 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
112351
113142
|
]
|
|
112352
113143
|
}, null, 2);
|
|
112353
113144
|
}
|
|
113145
|
+
const gateCtx = {
|
|
113146
|
+
phase,
|
|
113147
|
+
dir,
|
|
113148
|
+
sessionID,
|
|
113149
|
+
pluginConfig: config3,
|
|
113150
|
+
agentsDispatched,
|
|
113151
|
+
safeWarn
|
|
113152
|
+
};
|
|
112354
113153
|
if (hasActiveTurboMode(sessionID)) {
|
|
112355
113154
|
warnings.push(`Turbo mode active — skipped completion-verify, drift-verifier, hallucination-guard, mutation-gate, phase-council, and final-council gates for phase ${phase}.`);
|
|
112356
113155
|
} else {
|
|
112357
|
-
|
|
112358
|
-
const
|
|
112359
|
-
|
|
112360
|
-
|
|
112361
|
-
return JSON.stringify({
|
|
112362
|
-
success: false,
|
|
112363
|
-
phase,
|
|
112364
|
-
status: "blocked",
|
|
112365
|
-
reason: "COMPLETION_INCOMPLETE",
|
|
112366
|
-
message: `Phase ${phase} cannot be completed: ${completionResult.reason}`,
|
|
112367
|
-
agentsDispatched,
|
|
112368
|
-
agentsMissing: [],
|
|
112369
|
-
warnings: completionResult.blockedTasks ? [
|
|
112370
|
-
`Blocked tasks: ${completionResult.blockedTasks.map((t) => t.task_id).join(", ")}`
|
|
112371
|
-
] : []
|
|
112372
|
-
}, null, 2);
|
|
113156
|
+
{
|
|
113157
|
+
const gateResult = await runCompletionVerifyGate(gateCtx);
|
|
113158
|
+
if (gateResult.blocked) {
|
|
113159
|
+
return blockedResult(phase, gateResult);
|
|
112373
113160
|
}
|
|
112374
|
-
|
|
112375
|
-
safeWarn(`[phase_complete] Completion verify error (non-blocking):`, completionError);
|
|
113161
|
+
warnings.push(...gateResult.warnings);
|
|
112376
113162
|
}
|
|
112377
|
-
|
|
112378
|
-
|
|
112379
|
-
|
|
112380
|
-
|
|
112381
|
-
driftHasSpecMd = fs90.existsSync(specMdPath);
|
|
112382
|
-
const gatePlan = await loadPlan(dir);
|
|
112383
|
-
if (gatePlan) {
|
|
112384
|
-
const gatePlanId = derivePlanId(gatePlan);
|
|
112385
|
-
const gateProfile = getProfile(dir, gatePlanId);
|
|
112386
|
-
if (gateProfile) {
|
|
112387
|
-
const gateSession = sessionID ? swarmState.agentSessions.get(sessionID) : undefined;
|
|
112388
|
-
const gateOverrides = gateSession?.qaGateSessionOverrides ?? {};
|
|
112389
|
-
const gateEffective = getEffectiveGates(gateProfile, gateOverrides);
|
|
112390
|
-
driftCheckEnabled = gateEffective.drift_check === true;
|
|
112391
|
-
}
|
|
112392
|
-
}
|
|
112393
|
-
} catch (gateLoadError) {
|
|
112394
|
-
safeWarn(`[phase_complete] QA gate profile load error, drift_check defaults to enabled:`, gateLoadError);
|
|
112395
|
-
}
|
|
112396
|
-
if (!driftCheckEnabled) {
|
|
112397
|
-
warnings.push(`drift_check gate is disabled. Drift verification was skipped for phase ${phase}.`);
|
|
112398
|
-
} else {
|
|
112399
|
-
let phaseType;
|
|
112400
|
-
try {
|
|
112401
|
-
const planPath = path127.join(dir, ".swarm", "plan.json");
|
|
112402
|
-
if (fs90.existsSync(planPath)) {
|
|
112403
|
-
const planRaw = fs90.readFileSync(planPath, "utf-8");
|
|
112404
|
-
const plan = JSON.parse(planRaw);
|
|
112405
|
-
const targetPhase = plan.phases?.find((p) => p.id === phase);
|
|
112406
|
-
phaseType = targetPhase?.type;
|
|
112407
|
-
}
|
|
112408
|
-
} catch {}
|
|
112409
|
-
if (phaseType === "non-code") {
|
|
112410
|
-
warnings.push(`Phase ${phase} is annotated as 'non-code'. Drift verification was skipped per phase type annotation.`);
|
|
112411
|
-
} else {
|
|
112412
|
-
try {
|
|
112413
|
-
const driftEvidencePath = path127.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
|
|
112414
|
-
let driftVerdictFound = false;
|
|
112415
|
-
let driftVerdictApproved = false;
|
|
112416
|
-
try {
|
|
112417
|
-
const driftEvidenceContent = fs90.readFileSync(driftEvidencePath, "utf-8");
|
|
112418
|
-
const driftEvidence = JSON.parse(driftEvidenceContent);
|
|
112419
|
-
const entries = driftEvidence.entries ?? [];
|
|
112420
|
-
for (const entry of entries) {
|
|
112421
|
-
if (typeof entry.type === "string" && entry.type.includes("drift") && typeof entry.verdict === "string") {
|
|
112422
|
-
driftVerdictFound = true;
|
|
112423
|
-
if (entry.verdict === "approved") {
|
|
112424
|
-
driftVerdictApproved = true;
|
|
112425
|
-
}
|
|
112426
|
-
if (entry.verdict === "rejected" || typeof entry.summary === "string" && entry.summary.includes("NEEDS_REVISION")) {
|
|
112427
|
-
return JSON.stringify({
|
|
112428
|
-
success: false,
|
|
112429
|
-
phase,
|
|
112430
|
-
status: "blocked",
|
|
112431
|
-
reason: "DRIFT_VERIFICATION_REJECTED",
|
|
112432
|
-
message: `Phase ${phase} cannot be completed: drift verifier returned verdict '${entry.verdict}'. Address the drift issues before completing the phase.`,
|
|
112433
|
-
agentsDispatched,
|
|
112434
|
-
agentsMissing: [],
|
|
112435
|
-
warnings: []
|
|
112436
|
-
}, null, 2);
|
|
112437
|
-
}
|
|
112438
|
-
}
|
|
112439
|
-
}
|
|
112440
|
-
} catch (readError) {
|
|
112441
|
-
if (readError.code !== "ENOENT") {
|
|
112442
|
-
safeWarn(`[phase_complete] Drift verifier evidence unreadable:`, readError);
|
|
112443
|
-
}
|
|
112444
|
-
driftVerdictFound = false;
|
|
112445
|
-
}
|
|
112446
|
-
if (!driftVerdictFound) {
|
|
112447
|
-
if (!driftHasSpecMd) {
|
|
112448
|
-
let incompleteTaskCount = 0;
|
|
112449
|
-
let planParseable = false;
|
|
112450
|
-
try {
|
|
112451
|
-
const planPath = path127.join(dir, ".swarm", "plan.json");
|
|
112452
|
-
if (fs90.existsSync(planPath)) {
|
|
112453
|
-
const planRaw = fs90.readFileSync(planPath, "utf-8");
|
|
112454
|
-
const plan = JSON.parse(planRaw);
|
|
112455
|
-
planParseable = true;
|
|
112456
|
-
const planPhase = plan.phases?.find((p) => p.id === phase);
|
|
112457
|
-
if (planPhase?.tasks) {
|
|
112458
|
-
incompleteTaskCount = planPhase.tasks.filter((t) => t.status !== "completed" && t.status !== "closed").length;
|
|
112459
|
-
}
|
|
112460
|
-
}
|
|
112461
|
-
} catch {}
|
|
112462
|
-
if (!planParseable) {
|
|
112463
|
-
warnings.push(`No spec.md found and drift verification evidence missing — consider running critic_drift_verifier before phase completion.`);
|
|
112464
|
-
} else if (incompleteTaskCount > 0) {
|
|
112465
|
-
warnings.push(`No spec.md found and drift verification evidence missing. Phase ${phase} has ${incompleteTaskCount} incomplete task(s) in plan.json — consider running critic_drift_verifier before phase completion.`);
|
|
112466
|
-
} else {
|
|
112467
|
-
warnings.push(`No spec.md found. Phase ${phase} tasks are all completed in plan.json. Drift verification was skipped.`);
|
|
112468
|
-
}
|
|
112469
|
-
} else {
|
|
112470
|
-
return JSON.stringify({
|
|
112471
|
-
success: false,
|
|
112472
|
-
phase,
|
|
112473
|
-
status: "blocked",
|
|
112474
|
-
reason: "DRIFT_VERIFICATION_MISSING",
|
|
112475
|
-
message: `Phase ${phase} cannot be completed: drift_check is enabled and drift verifier evidence not found at .swarm/evidence/${phase}/drift-verifier.json. Run drift verification before completing the phase.`,
|
|
112476
|
-
agentsDispatched,
|
|
112477
|
-
agentsMissing: [],
|
|
112478
|
-
warnings: []
|
|
112479
|
-
}, null, 2);
|
|
112480
|
-
}
|
|
112481
|
-
}
|
|
112482
|
-
if (!driftVerdictApproved && driftVerdictFound) {
|
|
112483
|
-
return JSON.stringify({
|
|
112484
|
-
success: false,
|
|
112485
|
-
phase,
|
|
112486
|
-
status: "blocked",
|
|
112487
|
-
reason: "DRIFT_VERIFICATION_REJECTED",
|
|
112488
|
-
message: `Phase ${phase} cannot be completed: drift verifier verdict is not approved.`,
|
|
112489
|
-
agentsDispatched,
|
|
112490
|
-
agentsMissing: [],
|
|
112491
|
-
warnings: []
|
|
112492
|
-
}, null, 2);
|
|
112493
|
-
}
|
|
112494
|
-
} catch (driftError) {
|
|
112495
|
-
return JSON.stringify({
|
|
112496
|
-
success: false,
|
|
112497
|
-
phase,
|
|
112498
|
-
status: "blocked",
|
|
112499
|
-
reason: "DRIFT_VERIFICATION_ERROR",
|
|
112500
|
-
message: `Phase ${phase} cannot be completed: drift verification encountered an error: ${driftError instanceof Error ? driftError.message : String(driftError)}. This is a hard block — resolve the error before completing the phase.`,
|
|
112501
|
-
agentsDispatched,
|
|
112502
|
-
agentsMissing: [],
|
|
112503
|
-
warnings: []
|
|
112504
|
-
}, null, 2);
|
|
112505
|
-
}
|
|
113163
|
+
{
|
|
113164
|
+
const gateResult = await runDriftGate(gateCtx);
|
|
113165
|
+
if (gateResult.blocked) {
|
|
113166
|
+
return blockedResult(phase, gateResult);
|
|
112506
113167
|
}
|
|
113168
|
+
warnings.push(...gateResult.warnings);
|
|
112507
113169
|
}
|
|
112508
|
-
|
|
112509
|
-
const
|
|
112510
|
-
if (
|
|
112511
|
-
|
|
112512
|
-
const profile = getProfile(dir, planId);
|
|
112513
|
-
if (profile) {
|
|
112514
|
-
const session2 = sessionID ? swarmState.agentSessions.get(sessionID) : undefined;
|
|
112515
|
-
const overrides = session2?.qaGateSessionOverrides ?? {};
|
|
112516
|
-
const effective = getEffectiveGates(profile, overrides);
|
|
112517
|
-
if (effective.hallucination_guard === true) {
|
|
112518
|
-
const hgPath = path127.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
|
|
112519
|
-
let hgVerdictFound = false;
|
|
112520
|
-
let hgVerdictApproved = false;
|
|
112521
|
-
try {
|
|
112522
|
-
const hgContent = fs90.readFileSync(hgPath, "utf-8");
|
|
112523
|
-
const hgBundle = JSON.parse(hgContent);
|
|
112524
|
-
for (const entry of hgBundle.entries ?? []) {
|
|
112525
|
-
if (typeof entry.type === "string" && entry.type.includes("hallucination") && typeof entry.verdict === "string") {
|
|
112526
|
-
hgVerdictFound = true;
|
|
112527
|
-
if (entry.verdict === "approved") {
|
|
112528
|
-
hgVerdictApproved = true;
|
|
112529
|
-
}
|
|
112530
|
-
if (entry.verdict === "rejected" || typeof entry.summary === "string" && entry.summary.includes("NEEDS_REVISION")) {
|
|
112531
|
-
return JSON.stringify({
|
|
112532
|
-
success: false,
|
|
112533
|
-
phase,
|
|
112534
|
-
status: "blocked",
|
|
112535
|
-
reason: "HALLUCINATION_VERIFICATION_REJECTED",
|
|
112536
|
-
message: `Phase ${phase} cannot be completed: hallucination verifier returned verdict '${entry.verdict}'. Remove fabricated APIs/signatures and fix broken citations before completing the phase.`,
|
|
112537
|
-
agentsDispatched,
|
|
112538
|
-
agentsMissing: [],
|
|
112539
|
-
warnings: []
|
|
112540
|
-
}, null, 2);
|
|
112541
|
-
}
|
|
112542
|
-
}
|
|
112543
|
-
}
|
|
112544
|
-
} catch (readErr) {
|
|
112545
|
-
if (readErr.code !== "ENOENT") {
|
|
112546
|
-
safeWarn(`[phase_complete] Hallucination guard evidence unreadable:`, readErr);
|
|
112547
|
-
}
|
|
112548
|
-
hgVerdictFound = false;
|
|
112549
|
-
}
|
|
112550
|
-
if (!hgVerdictFound) {
|
|
112551
|
-
return JSON.stringify({
|
|
112552
|
-
success: false,
|
|
112553
|
-
phase,
|
|
112554
|
-
status: "blocked",
|
|
112555
|
-
reason: "HALLUCINATION_VERIFICATION_MISSING",
|
|
112556
|
-
message: `Phase ${phase} cannot be completed: hallucination_guard is enabled and evidence not found at .swarm/evidence/${phase}/hallucination-guard.json. Delegate to critic_hallucination_verifier and call write_hallucination_evidence before completing the phase.`,
|
|
112557
|
-
agentsDispatched,
|
|
112558
|
-
agentsMissing: [],
|
|
112559
|
-
warnings: []
|
|
112560
|
-
}, null, 2);
|
|
112561
|
-
}
|
|
112562
|
-
if (!hgVerdictApproved) {
|
|
112563
|
-
return JSON.stringify({
|
|
112564
|
-
success: false,
|
|
112565
|
-
phase,
|
|
112566
|
-
status: "blocked",
|
|
112567
|
-
reason: "HALLUCINATION_VERIFICATION_REJECTED",
|
|
112568
|
-
message: `Phase ${phase} cannot be completed: hallucination verifier verdict is not approved.`,
|
|
112569
|
-
agentsDispatched,
|
|
112570
|
-
agentsMissing: [],
|
|
112571
|
-
warnings: []
|
|
112572
|
-
}, null, 2);
|
|
112573
|
-
}
|
|
112574
|
-
}
|
|
112575
|
-
}
|
|
113170
|
+
{
|
|
113171
|
+
const gateResult = await runHallucinationGate(gateCtx);
|
|
113172
|
+
if (gateResult.blocked) {
|
|
113173
|
+
return blockedResult(phase, gateResult);
|
|
112576
113174
|
}
|
|
112577
|
-
|
|
112578
|
-
safeWarn(`[phase_complete] Hallucination guard error (non-blocking):`, hgError);
|
|
113175
|
+
warnings.push(...gateResult.warnings);
|
|
112579
113176
|
}
|
|
112580
|
-
|
|
112581
|
-
const
|
|
112582
|
-
if (
|
|
112583
|
-
|
|
112584
|
-
const profile = getProfile(dir, planId);
|
|
112585
|
-
if (profile) {
|
|
112586
|
-
const session2 = sessionID ? swarmState.agentSessions.get(sessionID) : undefined;
|
|
112587
|
-
const overrides = session2?.qaGateSessionOverrides ?? {};
|
|
112588
|
-
const effective = getEffectiveGates(profile, overrides);
|
|
112589
|
-
if (effective.mutation_test === true) {
|
|
112590
|
-
const mgPath = path127.join(dir, ".swarm", "evidence", String(phase), "mutation-gate.json");
|
|
112591
|
-
let mgVerdictFound = false;
|
|
112592
|
-
let mgVerdict;
|
|
112593
|
-
try {
|
|
112594
|
-
const mgContent = fs90.readFileSync(mgPath, "utf-8");
|
|
112595
|
-
const mgBundle = JSON.parse(mgContent);
|
|
112596
|
-
for (const entry of mgBundle.entries ?? []) {
|
|
112597
|
-
if (typeof entry.type === "string" && entry.type === "mutation-gate" && typeof entry.verdict === "string") {
|
|
112598
|
-
mgVerdictFound = true;
|
|
112599
|
-
mgVerdict = entry.verdict;
|
|
112600
|
-
if (entry.verdict === "fail") {
|
|
112601
|
-
return JSON.stringify({
|
|
112602
|
-
success: false,
|
|
112603
|
-
phase,
|
|
112604
|
-
status: "blocked",
|
|
112605
|
-
reason: "MUTATION_GATE_FAIL",
|
|
112606
|
-
message: `Phase ${phase} cannot be completed: mutation gate returned verdict 'fail'. Resolve surviving mutants or lower the kill-rate threshold before completing the phase.`,
|
|
112607
|
-
agentsDispatched,
|
|
112608
|
-
agentsMissing: [],
|
|
112609
|
-
warnings: []
|
|
112610
|
-
}, null, 2);
|
|
112611
|
-
} else if (!["pass", "warn", "skip"].includes(entry.verdict)) {
|
|
112612
|
-
return JSON.stringify({
|
|
112613
|
-
success: false,
|
|
112614
|
-
phase,
|
|
112615
|
-
status: "blocked",
|
|
112616
|
-
reason: "MUTATION_GATE_FAIL",
|
|
112617
|
-
message: `Phase ${phase} cannot be completed: mutation gate evidence contains unrecognized verdict '${entry.verdict}'. Expected one of: pass, warn, fail, skip.`,
|
|
112618
|
-
agentsDispatched,
|
|
112619
|
-
agentsMissing: [],
|
|
112620
|
-
warnings: []
|
|
112621
|
-
}, null, 2);
|
|
112622
|
-
}
|
|
112623
|
-
}
|
|
112624
|
-
}
|
|
112625
|
-
} catch (readErr) {
|
|
112626
|
-
if (readErr.code !== "ENOENT") {
|
|
112627
|
-
safeWarn(`[phase_complete] Mutation gate evidence unreadable:`, readErr);
|
|
112628
|
-
}
|
|
112629
|
-
mgVerdictFound = false;
|
|
112630
|
-
}
|
|
112631
|
-
if (!mgVerdictFound) {
|
|
112632
|
-
return JSON.stringify({
|
|
112633
|
-
success: false,
|
|
112634
|
-
phase,
|
|
112635
|
-
status: "blocked",
|
|
112636
|
-
reason: "MUTATION_GATE_MISSING",
|
|
112637
|
-
message: `Phase ${phase} cannot be completed: mutation_test is enabled and evidence not found at .swarm/evidence/${phase}/mutation-gate.json. Run mutation_test, then call write_mutation_evidence before completing the phase.`,
|
|
112638
|
-
agentsDispatched,
|
|
112639
|
-
agentsMissing: [],
|
|
112640
|
-
warnings: []
|
|
112641
|
-
}, null, 2);
|
|
112642
|
-
}
|
|
112643
|
-
if (mgVerdict === "warn") {
|
|
112644
|
-
safeWarn(`[phase_complete] Mutation gate verdict is 'warn' for phase ${phase} — proceeding with warning`, undefined);
|
|
112645
|
-
}
|
|
112646
|
-
}
|
|
112647
|
-
}
|
|
113177
|
+
{
|
|
113178
|
+
const gateResult = await runMutationGate(gateCtx);
|
|
113179
|
+
if (gateResult.blocked) {
|
|
113180
|
+
return blockedResult(phase, gateResult);
|
|
112648
113181
|
}
|
|
112649
|
-
|
|
112650
|
-
safeWarn(`[phase_complete] Mutation gate error (non-blocking):`, mgError);
|
|
113182
|
+
warnings.push(...gateResult.warnings);
|
|
112651
113183
|
}
|
|
112652
|
-
|
|
112653
|
-
|
|
112654
|
-
|
|
112655
|
-
|
|
112656
|
-
const planId = derivePlanId(plan);
|
|
112657
|
-
const profile = getProfile(dir, planId);
|
|
112658
|
-
if (profile) {
|
|
112659
|
-
const session2 = sessionID ? swarmState.agentSessions.get(sessionID) : undefined;
|
|
112660
|
-
const overrides = session2?.qaGateSessionOverrides ?? {};
|
|
112661
|
-
const effective = getEffectiveGates(profile, overrides);
|
|
112662
|
-
if (effective.council_mode === true) {
|
|
112663
|
-
councilModeEnabled = true;
|
|
112664
|
-
const pcPath = path127.join(dir, ".swarm", "evidence", String(phase), "phase-council.json");
|
|
112665
|
-
let pcVerdictFound = false;
|
|
112666
|
-
let _pcVerdict;
|
|
112667
|
-
let pcQuorumSize;
|
|
112668
|
-
let pcTimestamp;
|
|
112669
|
-
let pcPhaseNumber;
|
|
112670
|
-
try {
|
|
112671
|
-
const pcContent = fs90.readFileSync(pcPath, "utf-8");
|
|
112672
|
-
const pcBundle = JSON.parse(pcContent);
|
|
112673
|
-
for (const entry of pcBundle.entries ?? []) {
|
|
112674
|
-
if (typeof entry.type === "string" && entry.type === "phase-council" && typeof entry.verdict === "string") {
|
|
112675
|
-
pcVerdictFound = true;
|
|
112676
|
-
_pcVerdict = entry.verdict;
|
|
112677
|
-
pcQuorumSize = typeof entry.quorumSize === "number" ? entry.quorumSize : undefined;
|
|
112678
|
-
pcTimestamp = typeof entry.timestamp === "string" ? entry.timestamp : undefined;
|
|
112679
|
-
pcPhaseNumber = typeof entry.phase_number === "number" ? entry.phase_number : typeof entry.phase === "number" ? entry.phase : undefined;
|
|
112680
|
-
const now2 = new Date;
|
|
112681
|
-
const pcTime = pcTimestamp ? new Date(pcTimestamp) : null;
|
|
112682
|
-
if (!pcTime || Number.isNaN(pcTime.getTime())) {
|
|
112683
|
-
return JSON.stringify({
|
|
112684
|
-
success: false,
|
|
112685
|
-
phase,
|
|
112686
|
-
status: "blocked",
|
|
112687
|
-
reason: "PHASE_COUNCIL_INVALID_TIMESTAMP",
|
|
112688
|
-
message: `Phase ${phase} cannot be completed: phase council evidence has missing or invalid timestamp.`,
|
|
112689
|
-
agentsDispatched,
|
|
112690
|
-
agentsMissing: [],
|
|
112691
|
-
warnings: []
|
|
112692
|
-
}, null, 2);
|
|
112693
|
-
}
|
|
112694
|
-
const maxAge = 24 * 60 * 60 * 1000;
|
|
112695
|
-
if (pcTime.getTime() > now2.getTime()) {
|
|
112696
|
-
return JSON.stringify({
|
|
112697
|
-
success: false,
|
|
112698
|
-
phase,
|
|
112699
|
-
status: "blocked",
|
|
112700
|
-
reason: "PHASE_COUNCIL_FUTURE_TIMESTAMP",
|
|
112701
|
-
message: `Phase ${phase} cannot be completed: phase council evidence timestamp is in the future.`,
|
|
112702
|
-
agentsDispatched,
|
|
112703
|
-
agentsMissing: [],
|
|
112704
|
-
warnings: []
|
|
112705
|
-
}, null, 2);
|
|
112706
|
-
}
|
|
112707
|
-
if (now2.getTime() - pcTime.getTime() > maxAge) {
|
|
112708
|
-
return JSON.stringify({
|
|
112709
|
-
success: false,
|
|
112710
|
-
phase,
|
|
112711
|
-
status: "blocked",
|
|
112712
|
-
reason: "PHASE_COUNCIL_STALE_EVIDENCE",
|
|
112713
|
-
message: `Phase ${phase} cannot be completed: phase council evidence is older than 24 hours. Re-convene council for fresh review.`,
|
|
112714
|
-
agentsDispatched,
|
|
112715
|
-
agentsMissing: [],
|
|
112716
|
-
warnings: []
|
|
112717
|
-
}, null, 2);
|
|
112718
|
-
}
|
|
112719
|
-
if (entry.verdict === "REJECT" || entry.verdict === "reject") {
|
|
112720
|
-
const requiredFixes = entry.requiredFixes ?? entry.required_fixes ?? [];
|
|
112721
|
-
const fixesDetail = Array.isArray(requiredFixes) && requiredFixes.length > 0 ? `
|
|
112722
|
-
Required fixes: ${requiredFixes.map((f) => f.detail ?? JSON.stringify(f)).join("; ")}` : "";
|
|
112723
|
-
return JSON.stringify({
|
|
112724
|
-
success: false,
|
|
112725
|
-
phase,
|
|
112726
|
-
status: "blocked",
|
|
112727
|
-
reason: "PHASE_COUNCIL_REJECTED",
|
|
112728
|
-
message: `Phase ${phase} cannot be completed: phase council returned verdict 'REJECT'. Address the required fixes before completing the phase.${fixesDetail}`,
|
|
112729
|
-
agentsDispatched,
|
|
112730
|
-
agentsMissing: [],
|
|
112731
|
-
warnings: []
|
|
112732
|
-
}, null, 2);
|
|
112733
|
-
}
|
|
112734
|
-
if (entry.verdict === "CONCERNS" || entry.verdict === "concerns") {
|
|
112735
|
-
const phaseConcernsAllow = config3.council?.phaseConcernsAllowComplete ?? true;
|
|
112736
|
-
if (!phaseConcernsAllow) {
|
|
112737
|
-
const advisoryNotes = entry.advisoryNotes ?? entry.advisory_notes ?? [];
|
|
112738
|
-
const notesDetail = Array.isArray(advisoryNotes) && advisoryNotes.length > 0 ? `
|
|
112739
|
-
Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
112740
|
-
return JSON.stringify({
|
|
112741
|
-
success: false,
|
|
112742
|
-
phase,
|
|
112743
|
-
status: "blocked",
|
|
112744
|
-
reason: "PHASE_COUNCIL_CONCERNS",
|
|
112745
|
-
message: `Phase ${phase} cannot be completed: phase council returned verdict 'CONCERNS'.${notesDetail}`,
|
|
112746
|
-
agentsDispatched,
|
|
112747
|
-
agentsMissing: [],
|
|
112748
|
-
warnings: []
|
|
112749
|
-
}, null, 2);
|
|
112750
|
-
}
|
|
112751
|
-
safeWarn(`[phase_complete] Phase council returned CONCERNS for phase ${phase} — proceeding (phaseConcernsAllowComplete is enabled)`, undefined);
|
|
112752
|
-
}
|
|
112753
|
-
if (entry.verdict !== "APPROVE" && entry.verdict !== "approve" && entry.verdict !== "CONCERNS" && entry.verdict !== "concerns") {
|
|
112754
|
-
return JSON.stringify({
|
|
112755
|
-
success: false,
|
|
112756
|
-
phase,
|
|
112757
|
-
status: "blocked",
|
|
112758
|
-
reason: "PHASE_COUNCIL_INVALID",
|
|
112759
|
-
message: `Phase ${phase} cannot be completed: phase council evidence contains unrecognized verdict '${entry.verdict}'. Expected one of: APPROVE, CONCERNS, REJECT.`,
|
|
112760
|
-
agentsDispatched,
|
|
112761
|
-
agentsMissing: [],
|
|
112762
|
-
warnings: []
|
|
112763
|
-
}, null, 2);
|
|
112764
|
-
}
|
|
112765
|
-
}
|
|
112766
|
-
}
|
|
112767
|
-
} catch (readErr) {
|
|
112768
|
-
if (readErr.code !== "ENOENT") {
|
|
112769
|
-
safeWarn(`[phase_complete] Phase council evidence unreadable:`, readErr);
|
|
112770
|
-
}
|
|
112771
|
-
pcVerdictFound = false;
|
|
112772
|
-
}
|
|
112773
|
-
if (!pcVerdictFound) {
|
|
112774
|
-
return JSON.stringify({
|
|
112775
|
-
success: false,
|
|
112776
|
-
phase,
|
|
112777
|
-
status: "blocked",
|
|
112778
|
-
reason: "PHASE_COUNCIL_REQUIRED",
|
|
112779
|
-
phase_council_required: true,
|
|
112780
|
-
message: `Phase ${phase} cannot be completed: council_mode is enabled and phase council evidence not found at .swarm/evidence/${phase}/phase-council.json. Convene a phase-level council (dispatch 5 members, collect verdicts, call submit_phase_council_verdicts) before completing the phase.`,
|
|
112781
|
-
agentsDispatched,
|
|
112782
|
-
agentsMissing: [],
|
|
112783
|
-
warnings: [
|
|
112784
|
-
`Phase council required — convene 5 council members (critic, reviewer, sme, test_engineer, explorer) for holistic phase review. Call submit_phase_council_verdicts to synthesize verdicts and write phase-council.json evidence.`
|
|
112785
|
-
]
|
|
112786
|
-
}, null, 2);
|
|
112787
|
-
}
|
|
112788
|
-
if (pcQuorumSize === undefined || typeof pcQuorumSize !== "number") {
|
|
112789
|
-
return JSON.stringify({
|
|
112790
|
-
success: false,
|
|
112791
|
-
phase,
|
|
112792
|
-
status: "blocked",
|
|
112793
|
-
reason: "PHASE_COUNCIL_MISSING_QUORUM",
|
|
112794
|
-
message: `Phase ${phase} cannot be completed: phase council evidence is missing quorumSize field.`,
|
|
112795
|
-
agentsDispatched,
|
|
112796
|
-
agentsMissing: [],
|
|
112797
|
-
warnings: []
|
|
112798
|
-
}, null, 2);
|
|
112799
|
-
}
|
|
112800
|
-
if (pcQuorumSize < 3) {
|
|
112801
|
-
return JSON.stringify({
|
|
112802
|
-
success: false,
|
|
112803
|
-
phase,
|
|
112804
|
-
status: "blocked",
|
|
112805
|
-
reason: "PHASE_COUNCIL_INSUFFICIENT_QUORUM",
|
|
112806
|
-
message: `Phase ${phase} cannot be completed: phase council quorum (${pcQuorumSize}) is below minimum (3). Re-convene council with sufficient members.`,
|
|
112807
|
-
agentsDispatched,
|
|
112808
|
-
agentsMissing: [],
|
|
112809
|
-
warnings: []
|
|
112810
|
-
}, null, 2);
|
|
112811
|
-
}
|
|
112812
|
-
if (pcPhaseNumber === undefined || typeof pcPhaseNumber !== "number") {
|
|
112813
|
-
return JSON.stringify({
|
|
112814
|
-
success: false,
|
|
112815
|
-
phase,
|
|
112816
|
-
status: "blocked",
|
|
112817
|
-
reason: "PHASE_COUNCIL_MISSING_PHASE",
|
|
112818
|
-
message: `Phase ${phase} cannot be completed: phase council evidence is missing phase_number field.`,
|
|
112819
|
-
agentsDispatched,
|
|
112820
|
-
agentsMissing: [],
|
|
112821
|
-
warnings: []
|
|
112822
|
-
}, null, 2);
|
|
112823
|
-
}
|
|
112824
|
-
if (pcPhaseNumber !== phase) {
|
|
112825
|
-
return JSON.stringify({
|
|
112826
|
-
success: false,
|
|
112827
|
-
phase,
|
|
112828
|
-
status: "blocked",
|
|
112829
|
-
reason: "PHASE_COUNCIL_PHASE_MISMATCH",
|
|
112830
|
-
message: `Phase ${phase} cannot be completed: phase council evidence is for phase ${pcPhaseNumber}, not phase ${phase}. Run council for the correct phase.`,
|
|
112831
|
-
agentsDispatched,
|
|
112832
|
-
agentsMissing: [],
|
|
112833
|
-
warnings: []
|
|
112834
|
-
}, null, 2);
|
|
112835
|
-
}
|
|
112836
|
-
}
|
|
112837
|
-
}
|
|
112838
|
-
}
|
|
112839
|
-
} catch (pcError) {
|
|
112840
|
-
if (councilModeEnabled) {
|
|
112841
|
-
warnings.push(`PHASE_COUNCIL_ERROR: ${String(pcError)}`);
|
|
112842
|
-
return JSON.stringify({
|
|
112843
|
-
success: false,
|
|
112844
|
-
phase,
|
|
112845
|
-
status: "blocked",
|
|
112846
|
-
reason: "PHASE_COUNCIL_ERROR",
|
|
112847
|
-
message: `Phase ${phase} cannot be completed: phase council gate encountered an error when council_mode was enabled. Error: ${String(pcError)}`,
|
|
112848
|
-
agentsDispatched,
|
|
112849
|
-
agentsMissing: [],
|
|
112850
|
-
warnings: [`PHASE_COUNCIL_ERROR: ${String(pcError)}`]
|
|
112851
|
-
}, null, 2);
|
|
112852
|
-
} else {
|
|
112853
|
-
safeWarn(`[phase_complete] Phase council gate error (non-blocking):`, pcError);
|
|
113184
|
+
{
|
|
113185
|
+
const gateResult = await runPhaseCouncilGate(gateCtx);
|
|
113186
|
+
if (gateResult.blocked) {
|
|
113187
|
+
return blockedResult(phase, gateResult);
|
|
112854
113188
|
}
|
|
113189
|
+
warnings.push(...gateResult.warnings);
|
|
112855
113190
|
}
|
|
112856
113191
|
}
|
|
112857
113192
|
if (config3.architectural_supervision?.enabled && config3.architectural_supervision.mode === "gate") {
|
|
112858
|
-
const
|
|
112859
|
-
|
|
112860
|
-
|
|
112861
|
-
return "";
|
|
112862
|
-
const details = findings.map((f) => f && typeof f === "object" && typeof f.description === "string" ? f.description : undefined).filter((d) => Boolean(d));
|
|
112863
|
-
return details.length > 0 ? `
|
|
112864
|
-
Findings: ${details.join("; ")}` : "";
|
|
112865
|
-
};
|
|
112866
|
-
const asBlocked = (reason, message2) => JSON.stringify({
|
|
112867
|
-
success: false,
|
|
112868
|
-
phase,
|
|
112869
|
-
status: "blocked",
|
|
112870
|
-
reason,
|
|
112871
|
-
message: message2,
|
|
112872
|
-
agentsDispatched,
|
|
112873
|
-
agentsMissing: [],
|
|
112874
|
-
warnings: []
|
|
112875
|
-
}, null, 2);
|
|
112876
|
-
let asEntry = null;
|
|
112877
|
-
try {
|
|
112878
|
-
asEntry = readSupervisorReportRaw(dir, phase);
|
|
112879
|
-
} catch (asError) {
|
|
112880
|
-
return asBlocked("ARCH_SUPERVISOR_ERROR", `Phase ${phase} cannot be completed: architecture supervisor gate encountered an error. Error: ${String(asError)}`);
|
|
112881
|
-
}
|
|
112882
|
-
if (!asEntry) {
|
|
112883
|
-
return asBlocked("ARCH_SUPERVISOR_REQUIRED", `Phase ${phase} cannot be completed: architectural_supervision gate mode is enabled and no architecture supervisor evidence was found at .swarm/evidence/${phase}/architecture-supervisor.json. Dispatch critic_architecture_supervisor with the phase + agent summaries, then call write_architecture_supervisor_evidence.`);
|
|
112884
|
-
}
|
|
112885
|
-
const now2 = new Date;
|
|
112886
|
-
const asTime = asEntry.timestamp ? new Date(asEntry.timestamp) : null;
|
|
112887
|
-
if (!asTime || Number.isNaN(asTime.getTime())) {
|
|
112888
|
-
return asBlocked("ARCH_SUPERVISOR_INVALID_TIMESTAMP", `Phase ${phase} cannot be completed: architecture supervisor evidence has a missing or invalid timestamp.`);
|
|
112889
|
-
}
|
|
112890
|
-
if (asTime.getTime() > now2.getTime()) {
|
|
112891
|
-
return asBlocked("ARCH_SUPERVISOR_FUTURE_TIMESTAMP", `Phase ${phase} cannot be completed: architecture supervisor evidence timestamp is in the future.`);
|
|
112892
|
-
}
|
|
112893
|
-
if (now2.getTime() - asTime.getTime() > 24 * 60 * 60 * 1000) {
|
|
112894
|
-
return asBlocked("ARCH_SUPERVISOR_STALE_EVIDENCE", `Phase ${phase} cannot be completed: architecture supervisor evidence is older than 24 hours. Re-run the supervisor for fresh review.`);
|
|
112895
|
-
}
|
|
112896
|
-
if (typeof asEntry.phase_number !== "number" || asEntry.phase_number !== phase) {
|
|
112897
|
-
return asBlocked("ARCH_SUPERVISOR_PHASE_MISMATCH", `Phase ${phase} cannot be completed: architecture supervisor evidence is for phase ${String(asEntry.phase_number)}, not phase ${phase}.`);
|
|
112898
|
-
}
|
|
112899
|
-
const asVerdict = asEntry.verdict;
|
|
112900
|
-
if (asVerdict === "REJECT") {
|
|
112901
|
-
return asBlocked("ARCH_SUPERVISOR_REJECTED", `Phase ${phase} cannot be completed: architecture supervisor returned verdict 'REJECT'. Address the system-level findings before completing the phase.${summarizeFindings(asEntry.findings)}`);
|
|
112902
|
-
}
|
|
112903
|
-
if (asVerdict === "CONCERNS") {
|
|
112904
|
-
if (asConfig.allow_concerns_to_complete === false) {
|
|
112905
|
-
return asBlocked("ARCH_SUPERVISOR_CONCERNS", `Phase ${phase} cannot be completed: architecture supervisor returned verdict 'CONCERNS' and allow_concerns_to_complete is disabled.${summarizeFindings(asEntry.findings)}`);
|
|
112906
|
-
}
|
|
112907
|
-
safeWarn(`[phase_complete] Architecture supervisor returned CONCERNS for phase ${phase} — proceeding (allow_concerns_to_complete is enabled)`, undefined);
|
|
112908
|
-
} else if (asVerdict !== "APPROVE") {
|
|
112909
|
-
return asBlocked("ARCH_SUPERVISOR_INVALID", `Phase ${phase} cannot be completed: architecture supervisor evidence contains unrecognized verdict '${String(asVerdict)}'. Expected one of: APPROVE, CONCERNS, REJECT.`);
|
|
113193
|
+
const gateResult = await runArchitectureSupervisorGate(gateCtx);
|
|
113194
|
+
if (gateResult.blocked) {
|
|
113195
|
+
return blockedResult(phase, gateResult);
|
|
112910
113196
|
}
|
|
113197
|
+
warnings.push(...gateResult.warnings);
|
|
112911
113198
|
}
|
|
112912
113199
|
if (!hasActiveTurboMode(sessionID)) {
|
|
112913
|
-
|
|
112914
|
-
|
|
112915
|
-
|
|
112916
|
-
if (plan) {
|
|
112917
|
-
const lastPhaseId = plan.phases[plan.phases.length - 1]?.id;
|
|
112918
|
-
if (lastPhaseId !== undefined && phase === lastPhaseId) {
|
|
112919
|
-
const planId = derivePlanId(plan);
|
|
112920
|
-
const profile = getProfile(dir, planId);
|
|
112921
|
-
if (profile) {
|
|
112922
|
-
const session2 = sessionID ? swarmState.agentSessions.get(sessionID) : undefined;
|
|
112923
|
-
const overrides = session2?.qaGateSessionOverrides ?? {};
|
|
112924
|
-
const effective = getEffectiveGates(profile, overrides);
|
|
112925
|
-
if (effective.final_council === true) {
|
|
112926
|
-
finalCouncilEnabled = true;
|
|
112927
|
-
const fcPath = path127.join(dir, ".swarm", "evidence", "final-council.json");
|
|
112928
|
-
let fcVerdictFound = false;
|
|
112929
|
-
let _fcVerdict;
|
|
112930
|
-
try {
|
|
112931
|
-
const fcContent = fs90.readFileSync(fcPath, "utf-8");
|
|
112932
|
-
const fcBundle = JSON.parse(fcContent);
|
|
112933
|
-
for (const entry of fcBundle.entries ?? []) {
|
|
112934
|
-
if (typeof entry.type === "string" && entry.type === "final-council" && typeof entry.verdict === "string") {
|
|
112935
|
-
fcVerdictFound = true;
|
|
112936
|
-
_fcVerdict = entry.verdict;
|
|
112937
|
-
if (plan) {
|
|
112938
|
-
const currentPlanId = derivePlanId(plan);
|
|
112939
|
-
if (entry.plan_id && entry.plan_id !== currentPlanId) {
|
|
112940
|
-
return JSON.stringify({
|
|
112941
|
-
success: false,
|
|
112942
|
-
phase,
|
|
112943
|
-
status: "blocked",
|
|
112944
|
-
reason: "final_council_plan_mismatch",
|
|
112945
|
-
message: `Final council evidence belongs to a different plan (evidence: ${entry.plan_id}, current: ${currentPlanId}). Re-run the final council.`,
|
|
112946
|
-
agentsDispatched,
|
|
112947
|
-
agentsMissing: [],
|
|
112948
|
-
warnings: []
|
|
112949
|
-
}, null, 2);
|
|
112950
|
-
}
|
|
112951
|
-
if (!entry.plan_id) {
|
|
112952
|
-
return JSON.stringify({
|
|
112953
|
-
success: false,
|
|
112954
|
-
phase,
|
|
112955
|
-
status: "blocked",
|
|
112956
|
-
reason: "FINAL_COUNCIL_PLAN_ID_REQUIRED",
|
|
112957
|
-
message: `Phase ${phase} (last phase) cannot be completed: final council evidence is missing plan_id binding. Re-run the final council to generate evidence with plan identity.`,
|
|
112958
|
-
agentsDispatched,
|
|
112959
|
-
agentsMissing: [],
|
|
112960
|
-
warnings: []
|
|
112961
|
-
}, null, 2);
|
|
112962
|
-
}
|
|
112963
|
-
}
|
|
112964
|
-
if (typeof entry.quorumSize !== "number" || !Number.isFinite(entry.quorumSize) || entry.quorumSize < 5) {
|
|
112965
|
-
return JSON.stringify({
|
|
112966
|
-
success: false,
|
|
112967
|
-
phase,
|
|
112968
|
-
status: "blocked",
|
|
112969
|
-
reason: "FINAL_COUNCIL_MISSING_QUORUM",
|
|
112970
|
-
message: `Phase ${phase} (last phase) cannot be completed: final council evidence is missing valid quorum metadata. Re-run the project-scoped five-member final council and call write_final_council_evidence to generate quorumed evidence.`,
|
|
112971
|
-
agentsDispatched,
|
|
112972
|
-
agentsMissing: [],
|
|
112973
|
-
warnings: []
|
|
112974
|
-
}, null, 2);
|
|
112975
|
-
}
|
|
112976
|
-
const requiredFinalCouncilMembers = [
|
|
112977
|
-
"critic",
|
|
112978
|
-
"reviewer",
|
|
112979
|
-
"sme",
|
|
112980
|
-
"test_engineer",
|
|
112981
|
-
"explorer"
|
|
112982
|
-
];
|
|
112983
|
-
const membersVoted = Array.isArray(entry.membersVoted) ? entry.membersVoted.filter((member) => typeof member === "string") : [];
|
|
112984
|
-
const membersAbsent = Array.isArray(entry.membersAbsent) ? entry.membersAbsent.filter((member) => typeof member === "string") : [];
|
|
112985
|
-
const distinctMembersVoted = new Set(membersVoted);
|
|
112986
|
-
const hasAllRequiredMembers = requiredFinalCouncilMembers.every((member) => distinctMembersVoted.has(member)) && distinctMembersVoted.size === requiredFinalCouncilMembers.length && membersAbsent.length === 0;
|
|
112987
|
-
if (!hasAllRequiredMembers) {
|
|
112988
|
-
return JSON.stringify({
|
|
112989
|
-
success: false,
|
|
112990
|
-
phase,
|
|
112991
|
-
status: "blocked",
|
|
112992
|
-
reason: "FINAL_COUNCIL_MISSING_QUORUM",
|
|
112993
|
-
message: `Phase ${phase} (last phase) cannot be completed: final council evidence does not prove all five required members voted. Re-run the project-scoped five-member final council and call write_final_council_evidence to generate complete evidence.`,
|
|
112994
|
-
agentsDispatched,
|
|
112995
|
-
agentsMissing: [],
|
|
112996
|
-
warnings: []
|
|
112997
|
-
}, null, 2);
|
|
112998
|
-
}
|
|
112999
|
-
if (entry.verdict === "rejected" || entry.verdict === "REJECTED") {
|
|
113000
|
-
return JSON.stringify({
|
|
113001
|
-
success: false,
|
|
113002
|
-
phase,
|
|
113003
|
-
status: "blocked",
|
|
113004
|
-
reason: "FINAL_COUNCIL_REJECTED",
|
|
113005
|
-
message: `Phase ${phase} (last phase) cannot be completed: final council returned verdict 'REJECTED'. Address the required fixes before completing the project.`,
|
|
113006
|
-
agentsDispatched,
|
|
113007
|
-
agentsMissing: [],
|
|
113008
|
-
warnings: []
|
|
113009
|
-
}, null, 2);
|
|
113010
|
-
}
|
|
113011
|
-
if (entry.verdict !== "approved" && entry.verdict !== "APPROVED") {
|
|
113012
|
-
return JSON.stringify({
|
|
113013
|
-
success: false,
|
|
113014
|
-
phase,
|
|
113015
|
-
status: "blocked",
|
|
113016
|
-
reason: "FINAL_COUNCIL_INVALID_VERDICT",
|
|
113017
|
-
message: `Phase ${phase} (last phase) cannot be completed: final council evidence contains unrecognized verdict '${entry.verdict}'. Expected 'approved'.`,
|
|
113018
|
-
agentsDispatched,
|
|
113019
|
-
agentsMissing: [],
|
|
113020
|
-
warnings: []
|
|
113021
|
-
}, null, 2);
|
|
113022
|
-
}
|
|
113023
|
-
}
|
|
113024
|
-
}
|
|
113025
|
-
} catch (readErr) {
|
|
113026
|
-
if (readErr.code !== "ENOENT") {
|
|
113027
|
-
safeWarn(`[phase_complete] Final council evidence unreadable:`, readErr);
|
|
113028
|
-
}
|
|
113029
|
-
fcVerdictFound = false;
|
|
113030
|
-
}
|
|
113031
|
-
if (!fcVerdictFound) {
|
|
113032
|
-
return JSON.stringify({
|
|
113033
|
-
success: false,
|
|
113034
|
-
phase,
|
|
113035
|
-
status: "blocked",
|
|
113036
|
-
reason: "FINAL_COUNCIL_REQUIRED",
|
|
113037
|
-
final_council_required: true,
|
|
113038
|
-
message: `Phase ${phase} (last phase) cannot be completed: final_council is enabled and final council evidence not found at .swarm/evidence/final-council.json. Dispatch critic, reviewer, sme, test_engineer, and explorer with project-scoped context, collect their CouncilMemberVerdict JSON, and call write_final_council_evidence before completing the project. Do not use convene_general_council for this gate.`,
|
|
113039
|
-
agentsDispatched,
|
|
113040
|
-
agentsMissing: [],
|
|
113041
|
-
warnings: [
|
|
113042
|
-
`Final council required - dispatch the five project-scoped council members, then call write_final_council_evidence to persist quorumed evidence.`
|
|
113043
|
-
]
|
|
113044
|
-
}, null, 2);
|
|
113045
|
-
}
|
|
113046
|
-
}
|
|
113047
|
-
}
|
|
113048
|
-
}
|
|
113049
|
-
}
|
|
113050
|
-
} catch (fcError) {
|
|
113051
|
-
if (finalCouncilEnabled) {
|
|
113052
|
-
warnings.push(`FINAL_COUNCIL_ERROR: ${String(fcError)}`);
|
|
113053
|
-
return JSON.stringify({
|
|
113054
|
-
success: false,
|
|
113055
|
-
phase,
|
|
113056
|
-
status: "blocked",
|
|
113057
|
-
reason: "FINAL_COUNCIL_ERROR",
|
|
113058
|
-
message: `Phase ${phase} (last phase) cannot be completed: final council gate encountered an error. Error: ${String(fcError)}`,
|
|
113059
|
-
agentsDispatched,
|
|
113060
|
-
agentsMissing: [],
|
|
113061
|
-
warnings: [`FINAL_COUNCIL_ERROR: ${String(fcError)}`]
|
|
113062
|
-
}, null, 2);
|
|
113063
|
-
} else {
|
|
113064
|
-
safeWarn(`[phase_complete] Final council gate error (non-blocking):`, fcError);
|
|
113065
|
-
}
|
|
113200
|
+
const gateResult = await runFinalCouncilGate(gateCtx);
|
|
113201
|
+
if (gateResult.blocked) {
|
|
113202
|
+
return blockedResult(phase, gateResult);
|
|
113066
113203
|
}
|
|
113204
|
+
warnings.push(...gateResult.warnings);
|
|
113067
113205
|
}
|
|
113068
113206
|
{
|
|
113069
113207
|
const approval = verifyFullAutoPhaseApproval(dir, sessionID, phase, config3);
|
|
@@ -113112,7 +113250,7 @@ Findings: ${details.join("; ")}` : "";
|
|
|
113112
113250
|
}
|
|
113113
113251
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
113114
113252
|
try {
|
|
113115
|
-
const projectName =
|
|
113253
|
+
const projectName = path132.basename(dir);
|
|
113116
113254
|
const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
|
|
113117
113255
|
if (curationResult) {
|
|
113118
113256
|
const sessionState = swarmState.agentSessions.get(sessionID);
|
|
@@ -113212,14 +113350,14 @@ Findings: ${details.join("; ")}` : "";
|
|
|
113212
113350
|
const markerPath = validateSwarmPath(dir, "skill-usage-last-processed.json");
|
|
113213
113351
|
let sinceTimestamp;
|
|
113214
113352
|
try {
|
|
113215
|
-
const markerData = JSON.parse(
|
|
113353
|
+
const markerData = JSON.parse(fs95.readFileSync(markerPath, "utf-8"));
|
|
113216
113354
|
sinceTimestamp = markerData.lastProcessedTimestamp;
|
|
113217
113355
|
} catch {}
|
|
113218
113356
|
const feedbackResult = await applySkillUsageFeedback(dir, {
|
|
113219
113357
|
sinceTimestamp
|
|
113220
113358
|
});
|
|
113221
113359
|
try {
|
|
113222
|
-
|
|
113360
|
+
fs95.writeFileSync(markerPath, JSON.stringify({ lastProcessedTimestamp: new Date().toISOString() }), "utf-8");
|
|
113223
113361
|
} catch {}
|
|
113224
113362
|
if (feedbackResult.processed > 0) {
|
|
113225
113363
|
const sessionState = swarmState.agentSessions.get(sessionID);
|
|
@@ -113239,7 +113377,7 @@ Findings: ${details.join("; ")}` : "";
|
|
|
113239
113377
|
let phaseRequiredAgents;
|
|
113240
113378
|
try {
|
|
113241
113379
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
113242
|
-
const planRaw =
|
|
113380
|
+
const planRaw = fs95.readFileSync(planPath, "utf-8");
|
|
113243
113381
|
const plan = JSON.parse(planRaw);
|
|
113244
113382
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
113245
113383
|
phaseRequiredAgents = phaseObj?.required_agents;
|
|
@@ -113254,7 +113392,7 @@ Findings: ${details.join("; ")}` : "";
|
|
|
113254
113392
|
if (agentsMissing.length > 0) {
|
|
113255
113393
|
try {
|
|
113256
113394
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
113257
|
-
const planRaw =
|
|
113395
|
+
const planRaw = fs95.readFileSync(planPath, "utf-8");
|
|
113258
113396
|
const plan = JSON.parse(planRaw);
|
|
113259
113397
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
113260
113398
|
if (targetPhase && targetPhase.tasks.length > 0 && canInferMissingAgentsFromTaskGates(agentsMissing) && await allCompletedTasksHavePassedGateEvidence(dir, targetPhase.tasks)) {
|
|
@@ -113294,7 +113432,7 @@ Findings: ${details.join("; ")}` : "";
|
|
|
113294
113432
|
if (phaseCompleteConfig.regression_sweep?.enforce) {
|
|
113295
113433
|
try {
|
|
113296
113434
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
113297
|
-
const planRaw =
|
|
113435
|
+
const planRaw = fs95.readFileSync(planPath, "utf-8");
|
|
113298
113436
|
const plan = JSON.parse(planRaw);
|
|
113299
113437
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
113300
113438
|
if (targetPhase) {
|
|
@@ -113348,7 +113486,7 @@ Findings: ${details.join("; ")}` : "";
|
|
|
113348
113486
|
}
|
|
113349
113487
|
try {
|
|
113350
113488
|
const eventsPath = validateSwarmPath(dir, "events.jsonl");
|
|
113351
|
-
|
|
113489
|
+
fs95.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
113352
113490
|
`, "utf-8");
|
|
113353
113491
|
} catch (writeError) {
|
|
113354
113492
|
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -113423,12 +113561,12 @@ Findings: ${details.join("; ")}` : "";
|
|
|
113423
113561
|
warnings.push(`Warning: failed to update plan.json phase status`);
|
|
113424
113562
|
try {
|
|
113425
113563
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
113426
|
-
const planRaw =
|
|
113564
|
+
const planRaw = fs95.readFileSync(planPath, "utf-8");
|
|
113427
113565
|
const plan2 = JSON.parse(planRaw);
|
|
113428
113566
|
const phaseObj = plan2.phases.find((p) => p.id === phase);
|
|
113429
113567
|
if (phaseObj) {
|
|
113430
113568
|
phaseObj.status = "complete";
|
|
113431
|
-
|
|
113569
|
+
fs95.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
|
|
113432
113570
|
}
|
|
113433
113571
|
} catch {}
|
|
113434
113572
|
} else if (plan) {
|
|
@@ -113465,12 +113603,12 @@ Findings: ${details.join("; ")}` : "";
|
|
|
113465
113603
|
warnings.push(`Warning: failed to update plan.json phase status`);
|
|
113466
113604
|
try {
|
|
113467
113605
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
113468
|
-
const planRaw =
|
|
113606
|
+
const planRaw = fs95.readFileSync(planPath, "utf-8");
|
|
113469
113607
|
const plan = JSON.parse(planRaw);
|
|
113470
113608
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
113471
113609
|
if (phaseObj) {
|
|
113472
113610
|
phaseObj.status = "complete";
|
|
113473
|
-
|
|
113611
|
+
fs95.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
|
|
113474
113612
|
}
|
|
113475
113613
|
} catch {}
|
|
113476
113614
|
}
|
|
@@ -113480,7 +113618,32 @@ Findings: ${details.join("; ")}` : "";
|
|
|
113480
113618
|
}
|
|
113481
113619
|
await flushPendingSnapshot(dir);
|
|
113482
113620
|
await writeCheckpoint(dir).catch(() => {});
|
|
113483
|
-
|
|
113621
|
+
const outputData = {
|
|
113622
|
+
...result,
|
|
113623
|
+
timestamp: event.timestamp,
|
|
113624
|
+
duration_ms: durationMs
|
|
113625
|
+
};
|
|
113626
|
+
return _buildOutputJson(outputData);
|
|
113627
|
+
}
|
|
113628
|
+
function _buildOutputJson(outputData) {
|
|
113629
|
+
let json3 = JSON.stringify(outputData, null, 2);
|
|
113630
|
+
if (json3.length > MAX_OUTPUT_BYTES5) {
|
|
113631
|
+
const truncated = {
|
|
113632
|
+
_truncated: true,
|
|
113633
|
+
_truncation_reason: `Output exceeded MAX_OUTPUT_BYTES (${MAX_OUTPUT_BYTES5}) limit`,
|
|
113634
|
+
phase: outputData.phase,
|
|
113635
|
+
success: outputData.success,
|
|
113636
|
+
status: outputData.status,
|
|
113637
|
+
message: outputData.message,
|
|
113638
|
+
agentsDispatched: outputData.agentsDispatched?.slice(0, 10),
|
|
113639
|
+
agentsMissing: outputData.agentsMissing?.slice(0, 10),
|
|
113640
|
+
warnings: ["(output truncated — full output exceeded size limit)"],
|
|
113641
|
+
timestamp: outputData.timestamp,
|
|
113642
|
+
duration_ms: outputData.duration_ms
|
|
113643
|
+
};
|
|
113644
|
+
json3 = JSON.stringify(truncated, null, 2);
|
|
113645
|
+
}
|
|
113646
|
+
return json3;
|
|
113484
113647
|
}
|
|
113485
113648
|
var phase_complete = createSwarmTool({
|
|
113486
113649
|
description: "Mark a phase as complete and track which agents were dispatched. Used for phase completion gating and tracking. Accepts phase number and optional summary. Returns list of agents that were dispatched.",
|
|
@@ -113528,9 +113691,9 @@ init_discovery();
|
|
|
113528
113691
|
init_utils();
|
|
113529
113692
|
init_bun_compat();
|
|
113530
113693
|
init_create_tool();
|
|
113531
|
-
import * as
|
|
113532
|
-
import * as
|
|
113533
|
-
var
|
|
113694
|
+
import * as fs96 from "node:fs";
|
|
113695
|
+
import * as path133 from "node:path";
|
|
113696
|
+
var MAX_OUTPUT_BYTES6 = 52428800;
|
|
113534
113697
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
113535
113698
|
function isValidEcosystem(value) {
|
|
113536
113699
|
return typeof value === "string" && [
|
|
@@ -113557,31 +113720,31 @@ function validateArgs3(args2) {
|
|
|
113557
113720
|
function detectEcosystems(directory) {
|
|
113558
113721
|
const ecosystems = [];
|
|
113559
113722
|
const cwd = directory;
|
|
113560
|
-
if (
|
|
113723
|
+
if (fs96.existsSync(path133.join(cwd, "package.json"))) {
|
|
113561
113724
|
ecosystems.push("npm");
|
|
113562
113725
|
}
|
|
113563
|
-
if (
|
|
113726
|
+
if (fs96.existsSync(path133.join(cwd, "pyproject.toml")) || fs96.existsSync(path133.join(cwd, "requirements.txt"))) {
|
|
113564
113727
|
ecosystems.push("pip");
|
|
113565
113728
|
}
|
|
113566
|
-
if (
|
|
113729
|
+
if (fs96.existsSync(path133.join(cwd, "Cargo.toml"))) {
|
|
113567
113730
|
ecosystems.push("cargo");
|
|
113568
113731
|
}
|
|
113569
|
-
if (
|
|
113732
|
+
if (fs96.existsSync(path133.join(cwd, "go.mod"))) {
|
|
113570
113733
|
ecosystems.push("go");
|
|
113571
113734
|
}
|
|
113572
113735
|
try {
|
|
113573
|
-
const files =
|
|
113736
|
+
const files = fs96.readdirSync(cwd);
|
|
113574
113737
|
if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
113575
113738
|
ecosystems.push("dotnet");
|
|
113576
113739
|
}
|
|
113577
113740
|
} catch {}
|
|
113578
|
-
if (
|
|
113741
|
+
if (fs96.existsSync(path133.join(cwd, "Gemfile")) || fs96.existsSync(path133.join(cwd, "Gemfile.lock"))) {
|
|
113579
113742
|
ecosystems.push("ruby");
|
|
113580
113743
|
}
|
|
113581
|
-
if (
|
|
113744
|
+
if (fs96.existsSync(path133.join(cwd, "pubspec.yaml"))) {
|
|
113582
113745
|
ecosystems.push("dart");
|
|
113583
113746
|
}
|
|
113584
|
-
if (
|
|
113747
|
+
if (fs96.existsSync(path133.join(cwd, "composer.lock"))) {
|
|
113585
113748
|
ecosystems.push("composer");
|
|
113586
113749
|
}
|
|
113587
113750
|
return ecosystems;
|
|
@@ -113613,8 +113776,8 @@ async function runNpmAudit(directory) {
|
|
|
113613
113776
|
};
|
|
113614
113777
|
}
|
|
113615
113778
|
let { stdout, stderr } = result;
|
|
113616
|
-
if (stdout.length >
|
|
113617
|
-
stdout = stdout.slice(0,
|
|
113779
|
+
if (stdout.length > MAX_OUTPUT_BYTES6) {
|
|
113780
|
+
stdout = stdout.slice(0, MAX_OUTPUT_BYTES6);
|
|
113618
113781
|
}
|
|
113619
113782
|
const exitCode = await proc.exited;
|
|
113620
113783
|
if (exitCode === 0) {
|
|
@@ -113733,8 +113896,8 @@ async function runPipAudit(directory) {
|
|
|
113733
113896
|
};
|
|
113734
113897
|
}
|
|
113735
113898
|
let { stdout, stderr } = result;
|
|
113736
|
-
if (stdout.length >
|
|
113737
|
-
stdout = stdout.slice(0,
|
|
113899
|
+
if (stdout.length > MAX_OUTPUT_BYTES6) {
|
|
113900
|
+
stdout = stdout.slice(0, MAX_OUTPUT_BYTES6);
|
|
113738
113901
|
}
|
|
113739
113902
|
const exitCode = await proc.exited;
|
|
113740
113903
|
if (exitCode === 0 && !stdout.trim()) {
|
|
@@ -113861,8 +114024,8 @@ async function runCargoAudit(directory) {
|
|
|
113861
114024
|
};
|
|
113862
114025
|
}
|
|
113863
114026
|
let { stdout, stderr: _stderr } = result;
|
|
113864
|
-
if (stdout.length >
|
|
113865
|
-
stdout = stdout.slice(0,
|
|
114027
|
+
if (stdout.length > MAX_OUTPUT_BYTES6) {
|
|
114028
|
+
stdout = stdout.slice(0, MAX_OUTPUT_BYTES6);
|
|
113866
114029
|
}
|
|
113867
114030
|
const exitCode = await proc.exited;
|
|
113868
114031
|
if (exitCode === 0) {
|
|
@@ -113985,8 +114148,8 @@ async function runGoAudit(directory) {
|
|
|
113985
114148
|
};
|
|
113986
114149
|
}
|
|
113987
114150
|
let { stdout } = result;
|
|
113988
|
-
if (stdout.length >
|
|
113989
|
-
stdout = stdout.slice(0,
|
|
114151
|
+
if (stdout.length > MAX_OUTPUT_BYTES6) {
|
|
114152
|
+
stdout = stdout.slice(0, MAX_OUTPUT_BYTES6);
|
|
113990
114153
|
}
|
|
113991
114154
|
const exitCode = await proc.exited;
|
|
113992
114155
|
if (exitCode !== 0 && exitCode !== 3) {
|
|
@@ -114118,8 +114281,8 @@ async function runDotnetAudit(directory) {
|
|
|
114118
114281
|
};
|
|
114119
114282
|
}
|
|
114120
114283
|
let { stdout } = result;
|
|
114121
|
-
if (stdout.length >
|
|
114122
|
-
stdout = stdout.slice(0,
|
|
114284
|
+
if (stdout.length > MAX_OUTPUT_BYTES6) {
|
|
114285
|
+
stdout = stdout.slice(0, MAX_OUTPUT_BYTES6);
|
|
114123
114286
|
}
|
|
114124
114287
|
const exitCode = await proc.exited;
|
|
114125
114288
|
if (exitCode !== 0 && !stdout.includes("has the following vulnerable packages")) {
|
|
@@ -114234,8 +114397,8 @@ async function runBundleAudit(directory) {
|
|
|
114234
114397
|
};
|
|
114235
114398
|
}
|
|
114236
114399
|
let { stdout } = result;
|
|
114237
|
-
if (stdout.length >
|
|
114238
|
-
stdout = stdout.slice(0,
|
|
114400
|
+
if (stdout.length > MAX_OUTPUT_BYTES6) {
|
|
114401
|
+
stdout = stdout.slice(0, MAX_OUTPUT_BYTES6);
|
|
114239
114402
|
}
|
|
114240
114403
|
const exitCode = await proc.exited;
|
|
114241
114404
|
if (exitCode !== 0 && exitCode !== 1) {
|
|
@@ -114379,8 +114542,8 @@ async function runDartAudit(directory) {
|
|
|
114379
114542
|
};
|
|
114380
114543
|
}
|
|
114381
114544
|
let { stdout } = result;
|
|
114382
|
-
if (stdout.length >
|
|
114383
|
-
stdout = stdout.slice(0,
|
|
114545
|
+
if (stdout.length > MAX_OUTPUT_BYTES6) {
|
|
114546
|
+
stdout = stdout.slice(0, MAX_OUTPUT_BYTES6);
|
|
114384
114547
|
}
|
|
114385
114548
|
const exitCode = await proc.exited;
|
|
114386
114549
|
if (exitCode !== 0) {
|
|
@@ -114494,8 +114657,8 @@ async function runComposerAudit(directory) {
|
|
|
114494
114657
|
};
|
|
114495
114658
|
}
|
|
114496
114659
|
let { stdout } = result;
|
|
114497
|
-
if (stdout.length >
|
|
114498
|
-
stdout = stdout.slice(0,
|
|
114660
|
+
if (stdout.length > MAX_OUTPUT_BYTES6) {
|
|
114661
|
+
stdout = stdout.slice(0, MAX_OUTPUT_BYTES6);
|
|
114499
114662
|
}
|
|
114500
114663
|
const exitCode = await proc.exited;
|
|
114501
114664
|
const hasVulnerabilities = (exitCode & 1) !== 0;
|
|
@@ -114716,8 +114879,8 @@ var pkg_audit = createSwarmTool({
|
|
|
114716
114879
|
// src/tools/placeholder-scan.ts
|
|
114717
114880
|
init_zod();
|
|
114718
114881
|
init_manager2();
|
|
114719
|
-
import * as
|
|
114720
|
-
import * as
|
|
114882
|
+
import * as fs97 from "node:fs";
|
|
114883
|
+
import * as path134 from "node:path";
|
|
114721
114884
|
init_utils();
|
|
114722
114885
|
init_create_tool();
|
|
114723
114886
|
var MAX_FILE_SIZE = 1024 * 1024;
|
|
@@ -114840,7 +115003,7 @@ function isScaffoldFile(filePath) {
|
|
|
114840
115003
|
if (SCAFFOLD_PATH_PATTERNS.some((pattern) => pattern.test(normalizedPath))) {
|
|
114841
115004
|
return true;
|
|
114842
115005
|
}
|
|
114843
|
-
const filename =
|
|
115006
|
+
const filename = path134.basename(filePath);
|
|
114844
115007
|
if (SCAFFOLD_FILENAME_PATTERNS.some((pattern) => pattern.test(filename))) {
|
|
114845
115008
|
return true;
|
|
114846
115009
|
}
|
|
@@ -114857,7 +115020,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
|
|
|
114857
115020
|
if (regex.test(normalizedPath)) {
|
|
114858
115021
|
return true;
|
|
114859
115022
|
}
|
|
114860
|
-
const filename =
|
|
115023
|
+
const filename = path134.basename(filePath);
|
|
114861
115024
|
const filenameRegex = new RegExp(`^${regexPattern}$`, "i");
|
|
114862
115025
|
if (filenameRegex.test(filename)) {
|
|
114863
115026
|
return true;
|
|
@@ -114866,7 +115029,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
|
|
|
114866
115029
|
return false;
|
|
114867
115030
|
}
|
|
114868
115031
|
function isParserSupported(filePath) {
|
|
114869
|
-
const ext =
|
|
115032
|
+
const ext = path134.extname(filePath).toLowerCase();
|
|
114870
115033
|
return SUPPORTED_PARSER_EXTENSIONS.has(ext);
|
|
114871
115034
|
}
|
|
114872
115035
|
function isPlanFile(filePath) {
|
|
@@ -115113,28 +115276,28 @@ async function placeholderScan(input, directory) {
|
|
|
115113
115276
|
let filesScanned = 0;
|
|
115114
115277
|
const filesWithFindings = new Set;
|
|
115115
115278
|
for (const filePath of changed_files) {
|
|
115116
|
-
const fullPath =
|
|
115117
|
-
const resolvedDirectory =
|
|
115118
|
-
if (!fullPath.startsWith(resolvedDirectory +
|
|
115279
|
+
const fullPath = path134.isAbsolute(filePath) ? filePath : path134.resolve(directory, filePath);
|
|
115280
|
+
const resolvedDirectory = path134.resolve(directory);
|
|
115281
|
+
if (!fullPath.startsWith(resolvedDirectory + path134.sep) && fullPath !== resolvedDirectory) {
|
|
115119
115282
|
continue;
|
|
115120
115283
|
}
|
|
115121
|
-
if (!
|
|
115284
|
+
if (!fs97.existsSync(fullPath)) {
|
|
115122
115285
|
continue;
|
|
115123
115286
|
}
|
|
115124
115287
|
if (isAllowedByGlobs(filePath, allow_globs)) {
|
|
115125
115288
|
continue;
|
|
115126
115289
|
}
|
|
115127
|
-
const relativeFilePath =
|
|
115290
|
+
const relativeFilePath = path134.relative(directory, fullPath).replace(/\\/g, "/");
|
|
115128
115291
|
if (FILE_ALLOWLIST.some((allowed) => relativeFilePath.endsWith(allowed))) {
|
|
115129
115292
|
continue;
|
|
115130
115293
|
}
|
|
115131
115294
|
let content;
|
|
115132
115295
|
try {
|
|
115133
|
-
const stat9 =
|
|
115296
|
+
const stat9 = fs97.statSync(fullPath);
|
|
115134
115297
|
if (stat9.size > MAX_FILE_SIZE) {
|
|
115135
115298
|
continue;
|
|
115136
115299
|
}
|
|
115137
|
-
content =
|
|
115300
|
+
content = fs97.readFileSync(fullPath, "utf-8");
|
|
115138
115301
|
} catch {
|
|
115139
115302
|
continue;
|
|
115140
115303
|
}
|
|
@@ -115195,8 +115358,8 @@ var placeholder_scan = createSwarmTool({
|
|
|
115195
115358
|
}
|
|
115196
115359
|
});
|
|
115197
115360
|
// src/tools/pre-check-batch.ts
|
|
115198
|
-
import * as
|
|
115199
|
-
import * as
|
|
115361
|
+
import * as fs101 from "node:fs";
|
|
115362
|
+
import * as path138 from "node:path";
|
|
115200
115363
|
init_zod();
|
|
115201
115364
|
init_manager2();
|
|
115202
115365
|
init_utils();
|
|
@@ -115336,8 +115499,8 @@ var _internals56 = {
|
|
|
115336
115499
|
init_zod();
|
|
115337
115500
|
init_manager2();
|
|
115338
115501
|
init_detector();
|
|
115339
|
-
import * as
|
|
115340
|
-
import * as
|
|
115502
|
+
import * as fs100 from "node:fs";
|
|
115503
|
+
import * as path137 from "node:path";
|
|
115341
115504
|
import { extname as extname20 } from "node:path";
|
|
115342
115505
|
|
|
115343
115506
|
// src/sast/rules/c.ts
|
|
@@ -116052,8 +116215,8 @@ function executeRulesSync(filePath, content, language) {
|
|
|
116052
116215
|
|
|
116053
116216
|
// src/sast/semgrep.ts
|
|
116054
116217
|
import * as child_process9 from "node:child_process";
|
|
116055
|
-
import * as
|
|
116056
|
-
import * as
|
|
116218
|
+
import * as fs98 from "node:fs";
|
|
116219
|
+
import * as path135 from "node:path";
|
|
116057
116220
|
var semgrepAvailableCache = null;
|
|
116058
116221
|
var DEFAULT_RULES_DIR = ".swarm/semgrep-rules";
|
|
116059
116222
|
var DEFAULT_TIMEOUT_MS3 = 30000;
|
|
@@ -116240,14 +116403,14 @@ async function runSemgrep(options) {
|
|
|
116240
116403
|
}
|
|
116241
116404
|
function getRulesDirectory(projectRoot) {
|
|
116242
116405
|
if (projectRoot) {
|
|
116243
|
-
return
|
|
116406
|
+
return path135.resolve(projectRoot, DEFAULT_RULES_DIR);
|
|
116244
116407
|
}
|
|
116245
116408
|
return DEFAULT_RULES_DIR;
|
|
116246
116409
|
}
|
|
116247
116410
|
function hasBundledRules(projectRoot) {
|
|
116248
116411
|
const rulesDir = getRulesDirectory(projectRoot);
|
|
116249
116412
|
try {
|
|
116250
|
-
return
|
|
116413
|
+
return fs98.existsSync(rulesDir);
|
|
116251
116414
|
} catch {
|
|
116252
116415
|
return false;
|
|
116253
116416
|
}
|
|
@@ -116260,25 +116423,25 @@ init_create_tool();
|
|
|
116260
116423
|
// src/tools/sast-baseline.ts
|
|
116261
116424
|
init_utils2();
|
|
116262
116425
|
import * as crypto11 from "node:crypto";
|
|
116263
|
-
import * as
|
|
116264
|
-
import * as
|
|
116426
|
+
import * as fs99 from "node:fs";
|
|
116427
|
+
import * as path136 from "node:path";
|
|
116265
116428
|
var BASELINE_SCHEMA_VERSION = "1.0.0";
|
|
116266
116429
|
var MAX_BASELINE_FINDINGS = 2000;
|
|
116267
116430
|
var MAX_BASELINE_BYTES = 2 * 1048576;
|
|
116268
116431
|
var LOCK_RETRY_DELAYS_MS = [50, 100, 200, 400, 800];
|
|
116269
116432
|
function normalizeFindingPath(directory, file3) {
|
|
116270
|
-
const resolved =
|
|
116271
|
-
const rel =
|
|
116433
|
+
const resolved = path136.isAbsolute(file3) ? file3 : path136.resolve(directory, file3);
|
|
116434
|
+
const rel = path136.relative(path136.resolve(directory), resolved);
|
|
116272
116435
|
return rel.replace(/\\/g, "/");
|
|
116273
116436
|
}
|
|
116274
116437
|
function baselineRelPath(phase) {
|
|
116275
|
-
return
|
|
116438
|
+
return path136.join("evidence", String(phase), "sast-baseline.json");
|
|
116276
116439
|
}
|
|
116277
116440
|
function tempRelPath(phase) {
|
|
116278
|
-
return
|
|
116441
|
+
return path136.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
|
|
116279
116442
|
}
|
|
116280
116443
|
function lockRelPath(phase) {
|
|
116281
|
-
return
|
|
116444
|
+
return path136.join("evidence", String(phase), "sast-baseline.json.lock");
|
|
116282
116445
|
}
|
|
116283
116446
|
function getLine(lines, idx) {
|
|
116284
116447
|
if (idx < 0 || idx >= lines.length)
|
|
@@ -116295,7 +116458,7 @@ function fingerprintFinding(finding, directory, occurrenceIndex) {
|
|
|
116295
116458
|
}
|
|
116296
116459
|
const lineNum = finding.location.line;
|
|
116297
116460
|
try {
|
|
116298
|
-
const content =
|
|
116461
|
+
const content = fs99.readFileSync(finding.location.file, "utf-8");
|
|
116299
116462
|
const lines = content.split(`
|
|
116300
116463
|
`);
|
|
116301
116464
|
const idx = lineNum - 1;
|
|
@@ -116326,7 +116489,7 @@ function assignOccurrenceIndices(findings, directory) {
|
|
|
116326
116489
|
try {
|
|
116327
116490
|
if (relFile.startsWith(".."))
|
|
116328
116491
|
throw new Error("escapes workspace");
|
|
116329
|
-
const content =
|
|
116492
|
+
const content = fs99.readFileSync(finding.location.file, "utf-8");
|
|
116330
116493
|
const lines = content.split(`
|
|
116331
116494
|
`);
|
|
116332
116495
|
const idx = lineNum - 1;
|
|
@@ -116355,11 +116518,11 @@ function assignOccurrenceIndices(findings, directory) {
|
|
|
116355
116518
|
async function acquireLock2(lockPath) {
|
|
116356
116519
|
for (let attempt = 0;attempt <= LOCK_RETRY_DELAYS_MS.length; attempt++) {
|
|
116357
116520
|
try {
|
|
116358
|
-
const fd =
|
|
116359
|
-
|
|
116521
|
+
const fd = fs99.openSync(lockPath, "wx");
|
|
116522
|
+
fs99.closeSync(fd);
|
|
116360
116523
|
return () => {
|
|
116361
116524
|
try {
|
|
116362
|
-
|
|
116525
|
+
fs99.unlinkSync(lockPath);
|
|
116363
116526
|
} catch {}
|
|
116364
116527
|
};
|
|
116365
116528
|
} catch {
|
|
@@ -116399,13 +116562,13 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
116399
116562
|
message: e instanceof Error ? e.message : "Path validation failed"
|
|
116400
116563
|
};
|
|
116401
116564
|
}
|
|
116402
|
-
|
|
116403
|
-
|
|
116565
|
+
fs99.mkdirSync(path136.dirname(baselinePath), { recursive: true });
|
|
116566
|
+
fs99.mkdirSync(path136.dirname(tempPath), { recursive: true });
|
|
116404
116567
|
const releaseLock = await acquireLock2(lockPath);
|
|
116405
116568
|
try {
|
|
116406
116569
|
let existing = null;
|
|
116407
116570
|
try {
|
|
116408
|
-
const raw =
|
|
116571
|
+
const raw = fs99.readFileSync(baselinePath, "utf-8");
|
|
116409
116572
|
const parsed = JSON.parse(raw);
|
|
116410
116573
|
if (parsed.schema_version === BASELINE_SCHEMA_VERSION) {
|
|
116411
116574
|
existing = parsed;
|
|
@@ -116465,8 +116628,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
116465
116628
|
message: `Baseline would exceed size cap (${json4.length} bytes > ${MAX_BASELINE_BYTES})`
|
|
116466
116629
|
};
|
|
116467
116630
|
}
|
|
116468
|
-
|
|
116469
|
-
|
|
116631
|
+
fs99.writeFileSync(tempPath, json4, "utf-8");
|
|
116632
|
+
fs99.renameSync(tempPath, baselinePath);
|
|
116470
116633
|
return {
|
|
116471
116634
|
status: "merged",
|
|
116472
116635
|
path: baselinePath,
|
|
@@ -116497,8 +116660,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
116497
116660
|
message: `Baseline would exceed size cap (${json3.length} bytes > ${MAX_BASELINE_BYTES})`
|
|
116498
116661
|
};
|
|
116499
116662
|
}
|
|
116500
|
-
|
|
116501
|
-
|
|
116663
|
+
fs99.writeFileSync(tempPath, json3, "utf-8");
|
|
116664
|
+
fs99.renameSync(tempPath, baselinePath);
|
|
116502
116665
|
return {
|
|
116503
116666
|
status: "written",
|
|
116504
116667
|
path: baselinePath,
|
|
@@ -116523,7 +116686,7 @@ function loadBaseline(directory, phase) {
|
|
|
116523
116686
|
};
|
|
116524
116687
|
}
|
|
116525
116688
|
try {
|
|
116526
|
-
const raw =
|
|
116689
|
+
const raw = fs99.readFileSync(baselinePath, "utf-8");
|
|
116527
116690
|
const parsed = JSON.parse(raw);
|
|
116528
116691
|
if (parsed.schema_version !== BASELINE_SCHEMA_VERSION) {
|
|
116529
116692
|
return {
|
|
@@ -116571,17 +116734,17 @@ var SEVERITY_ORDER = {
|
|
|
116571
116734
|
};
|
|
116572
116735
|
function shouldSkipFile(filePath) {
|
|
116573
116736
|
try {
|
|
116574
|
-
const stats =
|
|
116737
|
+
const stats = fs100.statSync(filePath);
|
|
116575
116738
|
if (stats.size > MAX_FILE_SIZE_BYTES8) {
|
|
116576
116739
|
return { skip: true, reason: "file too large" };
|
|
116577
116740
|
}
|
|
116578
116741
|
if (stats.size === 0) {
|
|
116579
116742
|
return { skip: true, reason: "empty file" };
|
|
116580
116743
|
}
|
|
116581
|
-
const fd =
|
|
116744
|
+
const fd = fs100.openSync(filePath, "r");
|
|
116582
116745
|
const buffer = Buffer.alloc(8192);
|
|
116583
|
-
const bytesRead =
|
|
116584
|
-
|
|
116746
|
+
const bytesRead = fs100.readSync(fd, buffer, 0, 8192, 0);
|
|
116747
|
+
fs100.closeSync(fd);
|
|
116585
116748
|
if (bytesRead > 0) {
|
|
116586
116749
|
let nullCount = 0;
|
|
116587
116750
|
for (let i2 = 0;i2 < bytesRead; i2++) {
|
|
@@ -116620,7 +116783,7 @@ function countBySeverity(findings) {
|
|
|
116620
116783
|
}
|
|
116621
116784
|
function scanFileWithTierA(filePath, language) {
|
|
116622
116785
|
try {
|
|
116623
|
-
const content =
|
|
116786
|
+
const content = fs100.readFileSync(filePath, "utf-8");
|
|
116624
116787
|
const findings = executeRulesSync(filePath, content, language);
|
|
116625
116788
|
return findings.map((f) => ({
|
|
116626
116789
|
rule_id: f.rule_id,
|
|
@@ -116673,13 +116836,13 @@ async function sastScan(input, directory, config3) {
|
|
|
116673
116836
|
_filesSkipped++;
|
|
116674
116837
|
continue;
|
|
116675
116838
|
}
|
|
116676
|
-
const resolvedPath =
|
|
116677
|
-
const resolvedDirectory =
|
|
116678
|
-
if (!resolvedPath.startsWith(resolvedDirectory +
|
|
116839
|
+
const resolvedPath = path137.isAbsolute(filePath) ? filePath : path137.resolve(directory, filePath);
|
|
116840
|
+
const resolvedDirectory = path137.resolve(directory);
|
|
116841
|
+
if (!resolvedPath.startsWith(resolvedDirectory + path137.sep) && resolvedPath !== resolvedDirectory) {
|
|
116679
116842
|
_filesSkipped++;
|
|
116680
116843
|
continue;
|
|
116681
116844
|
}
|
|
116682
|
-
if (!
|
|
116845
|
+
if (!fs100.existsSync(resolvedPath)) {
|
|
116683
116846
|
_filesSkipped++;
|
|
116684
116847
|
continue;
|
|
116685
116848
|
}
|
|
@@ -116990,18 +117153,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
116990
117153
|
let resolved;
|
|
116991
117154
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
116992
117155
|
if (isWinAbs) {
|
|
116993
|
-
resolved =
|
|
116994
|
-
} else if (
|
|
116995
|
-
resolved =
|
|
117156
|
+
resolved = path138.win32.resolve(inputPath);
|
|
117157
|
+
} else if (path138.isAbsolute(inputPath)) {
|
|
117158
|
+
resolved = path138.resolve(inputPath);
|
|
116996
117159
|
} else {
|
|
116997
|
-
resolved =
|
|
117160
|
+
resolved = path138.resolve(baseDir, inputPath);
|
|
116998
117161
|
}
|
|
116999
|
-
const workspaceResolved =
|
|
117162
|
+
const workspaceResolved = path138.resolve(workspaceDir);
|
|
117000
117163
|
let relative27;
|
|
117001
117164
|
if (isWinAbs) {
|
|
117002
|
-
relative27 =
|
|
117165
|
+
relative27 = path138.win32.relative(workspaceResolved, resolved);
|
|
117003
117166
|
} else {
|
|
117004
|
-
relative27 =
|
|
117167
|
+
relative27 = path138.relative(workspaceResolved, resolved);
|
|
117005
117168
|
}
|
|
117006
117169
|
if (relative27.startsWith("..")) {
|
|
117007
117170
|
return "path traversal detected";
|
|
@@ -117066,7 +117229,7 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
117066
117229
|
if (typeof file3 !== "string") {
|
|
117067
117230
|
continue;
|
|
117068
117231
|
}
|
|
117069
|
-
const resolvedPath =
|
|
117232
|
+
const resolvedPath = path138.resolve(file3);
|
|
117070
117233
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
117071
117234
|
if (validationError) {
|
|
117072
117235
|
continue;
|
|
@@ -117223,7 +117386,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
117223
117386
|
skippedFiles++;
|
|
117224
117387
|
continue;
|
|
117225
117388
|
}
|
|
117226
|
-
const resolvedPath =
|
|
117389
|
+
const resolvedPath = path138.resolve(file3);
|
|
117227
117390
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
117228
117391
|
if (validationError) {
|
|
117229
117392
|
skippedFiles++;
|
|
@@ -117241,14 +117404,14 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
117241
117404
|
};
|
|
117242
117405
|
}
|
|
117243
117406
|
for (const file3 of validatedFiles) {
|
|
117244
|
-
const ext =
|
|
117407
|
+
const ext = path138.extname(file3).toLowerCase();
|
|
117245
117408
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
117246
117409
|
skippedFiles++;
|
|
117247
117410
|
continue;
|
|
117248
117411
|
}
|
|
117249
117412
|
let stat9;
|
|
117250
117413
|
try {
|
|
117251
|
-
stat9 =
|
|
117414
|
+
stat9 = fs101.statSync(file3);
|
|
117252
117415
|
} catch {
|
|
117253
117416
|
skippedFiles++;
|
|
117254
117417
|
continue;
|
|
@@ -117259,7 +117422,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
117259
117422
|
}
|
|
117260
117423
|
let content;
|
|
117261
117424
|
try {
|
|
117262
|
-
const buffer =
|
|
117425
|
+
const buffer = fs101.readFileSync(file3);
|
|
117263
117426
|
if (buffer.includes(0)) {
|
|
117264
117427
|
skippedFiles++;
|
|
117265
117428
|
continue;
|
|
@@ -117460,7 +117623,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
|
|
|
117460
117623
|
const preexistingFindings = [];
|
|
117461
117624
|
for (const finding of findings) {
|
|
117462
117625
|
const filePath = finding.location.file;
|
|
117463
|
-
const normalised =
|
|
117626
|
+
const normalised = path138.relative(directory, filePath).replace(/\\/g, "/");
|
|
117464
117627
|
const changedLines = changedLineRanges.get(normalised);
|
|
117465
117628
|
if (changedLines?.has(finding.location.line)) {
|
|
117466
117629
|
newFindings.push(finding);
|
|
@@ -117511,7 +117674,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
|
|
|
117511
117674
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
117512
117675
|
continue;
|
|
117513
117676
|
}
|
|
117514
|
-
changedFiles.push(
|
|
117677
|
+
changedFiles.push(path138.resolve(directory, file3));
|
|
117515
117678
|
}
|
|
117516
117679
|
if (changedFiles.length === 0) {
|
|
117517
117680
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -117712,9 +117875,9 @@ var pre_check_batch = createSwarmTool({
|
|
|
117712
117875
|
};
|
|
117713
117876
|
return JSON.stringify(errorResult, null, 2);
|
|
117714
117877
|
}
|
|
117715
|
-
const resolvedDirectory =
|
|
117716
|
-
const workspaceAnchor =
|
|
117717
|
-
if (resolvedDirectory !== workspaceAnchor && resolvedDirectory.startsWith(workspaceAnchor +
|
|
117878
|
+
const resolvedDirectory = path138.resolve(typedArgs.directory);
|
|
117879
|
+
const workspaceAnchor = path138.resolve(directory);
|
|
117880
|
+
if (resolvedDirectory !== workspaceAnchor && resolvedDirectory.startsWith(workspaceAnchor + path138.sep)) {
|
|
117718
117881
|
const subDirError = `directory "${typedArgs.directory}" is a subdirectory of the project root — pre_check_batch requires the project root directory "${workspaceAnchor}"`;
|
|
117719
117882
|
const subDirResult = {
|
|
117720
117883
|
gates_passed: false,
|
|
@@ -117765,7 +117928,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
117765
117928
|
});
|
|
117766
117929
|
// src/tools/repo-map.ts
|
|
117767
117930
|
init_zod();
|
|
117768
|
-
import * as
|
|
117931
|
+
import * as path139 from "node:path";
|
|
117769
117932
|
init_path_security();
|
|
117770
117933
|
init_create_tool();
|
|
117771
117934
|
var VALID_ACTIONS = [
|
|
@@ -117790,7 +117953,7 @@ function validateFile(p) {
|
|
|
117790
117953
|
return "file contains control characters";
|
|
117791
117954
|
if (containsPathTraversal(p))
|
|
117792
117955
|
return "file contains path traversal";
|
|
117793
|
-
if (
|
|
117956
|
+
if (path139.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
|
|
117794
117957
|
return "file must be a workspace-relative path, not absolute";
|
|
117795
117958
|
}
|
|
117796
117959
|
return null;
|
|
@@ -117813,8 +117976,8 @@ function ok(action, payload) {
|
|
|
117813
117976
|
}
|
|
117814
117977
|
function toRelativeGraphPath(input, workspaceRoot) {
|
|
117815
117978
|
const normalized = input.replace(/\\/g, "/");
|
|
117816
|
-
if (
|
|
117817
|
-
const rel =
|
|
117979
|
+
if (path139.isAbsolute(normalized)) {
|
|
117980
|
+
const rel = path139.relative(workspaceRoot, normalized).replace(/\\/g, "/");
|
|
117818
117981
|
return normalizeGraphPath2(rel);
|
|
117819
117982
|
}
|
|
117820
117983
|
return normalizeGraphPath2(normalized);
|
|
@@ -117958,8 +118121,8 @@ var repo_map = createSwarmTool({
|
|
|
117958
118121
|
// src/tools/req-coverage.ts
|
|
117959
118122
|
init_zod();
|
|
117960
118123
|
init_create_tool();
|
|
117961
|
-
import * as
|
|
117962
|
-
import * as
|
|
118124
|
+
import * as fs102 from "node:fs";
|
|
118125
|
+
import * as path140 from "node:path";
|
|
117963
118126
|
var SPEC_FILE = ".swarm/spec.md";
|
|
117964
118127
|
var EVIDENCE_DIR4 = ".swarm/evidence";
|
|
117965
118128
|
var OBLIGATION_KEYWORDS = ["MUST", "SHOULD", "SHALL"];
|
|
@@ -118018,19 +118181,19 @@ function extractObligationAndText(id, lineText) {
|
|
|
118018
118181
|
var PHASE_TASK_ID_REGEX = /^\d+\.\d+(\.\d+)*$/;
|
|
118019
118182
|
function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
118020
118183
|
const touchedFiles = new Set;
|
|
118021
|
-
if (!
|
|
118184
|
+
if (!fs102.existsSync(evidenceDir) || !fs102.statSync(evidenceDir).isDirectory()) {
|
|
118022
118185
|
return [];
|
|
118023
118186
|
}
|
|
118024
118187
|
let entries;
|
|
118025
118188
|
try {
|
|
118026
|
-
entries =
|
|
118189
|
+
entries = fs102.readdirSync(evidenceDir);
|
|
118027
118190
|
} catch {
|
|
118028
118191
|
return [];
|
|
118029
118192
|
}
|
|
118030
118193
|
for (const entry of entries) {
|
|
118031
|
-
const entryPath =
|
|
118194
|
+
const entryPath = path140.join(evidenceDir, entry);
|
|
118032
118195
|
try {
|
|
118033
|
-
const stat9 =
|
|
118196
|
+
const stat9 = fs102.statSync(entryPath);
|
|
118034
118197
|
if (!stat9.isDirectory()) {
|
|
118035
118198
|
continue;
|
|
118036
118199
|
}
|
|
@@ -118044,14 +118207,14 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
118044
118207
|
if (entryPhase !== String(phase)) {
|
|
118045
118208
|
continue;
|
|
118046
118209
|
}
|
|
118047
|
-
const evidenceFilePath =
|
|
118210
|
+
const evidenceFilePath = path140.join(entryPath, "evidence.json");
|
|
118048
118211
|
try {
|
|
118049
|
-
const resolvedPath =
|
|
118050
|
-
const evidenceDirResolved =
|
|
118051
|
-
if (!resolvedPath.startsWith(evidenceDirResolved +
|
|
118212
|
+
const resolvedPath = path140.resolve(evidenceFilePath);
|
|
118213
|
+
const evidenceDirResolved = path140.resolve(evidenceDir);
|
|
118214
|
+
if (!resolvedPath.startsWith(evidenceDirResolved + path140.sep)) {
|
|
118052
118215
|
continue;
|
|
118053
118216
|
}
|
|
118054
|
-
const stat9 =
|
|
118217
|
+
const stat9 = fs102.lstatSync(evidenceFilePath);
|
|
118055
118218
|
if (!stat9.isFile()) {
|
|
118056
118219
|
continue;
|
|
118057
118220
|
}
|
|
@@ -118063,7 +118226,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
118063
118226
|
}
|
|
118064
118227
|
let content;
|
|
118065
118228
|
try {
|
|
118066
|
-
content =
|
|
118229
|
+
content = fs102.readFileSync(evidenceFilePath, "utf-8");
|
|
118067
118230
|
} catch {
|
|
118068
118231
|
continue;
|
|
118069
118232
|
}
|
|
@@ -118082,7 +118245,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
118082
118245
|
if (Array.isArray(diffEntry.files_changed)) {
|
|
118083
118246
|
for (const file3 of diffEntry.files_changed) {
|
|
118084
118247
|
if (typeof file3 === "string") {
|
|
118085
|
-
touchedFiles.add(
|
|
118248
|
+
touchedFiles.add(path140.resolve(cwd, file3));
|
|
118086
118249
|
}
|
|
118087
118250
|
}
|
|
118088
118251
|
}
|
|
@@ -118095,12 +118258,12 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
118095
118258
|
}
|
|
118096
118259
|
function searchFileForKeywords(filePath, keywords, cwd) {
|
|
118097
118260
|
try {
|
|
118098
|
-
const resolvedPath =
|
|
118099
|
-
const cwdResolved =
|
|
118261
|
+
const resolvedPath = path140.resolve(filePath);
|
|
118262
|
+
const cwdResolved = path140.resolve(cwd);
|
|
118100
118263
|
if (!resolvedPath.startsWith(cwdResolved)) {
|
|
118101
118264
|
return false;
|
|
118102
118265
|
}
|
|
118103
|
-
const content =
|
|
118266
|
+
const content = fs102.readFileSync(resolvedPath, "utf-8");
|
|
118104
118267
|
for (const keyword of keywords) {
|
|
118105
118268
|
const regex = new RegExp(`\\b${keyword}\\b`, "i");
|
|
118106
118269
|
if (regex.test(content)) {
|
|
@@ -118230,10 +118393,10 @@ var req_coverage = createSwarmTool({
|
|
|
118230
118393
|
}, null, 2);
|
|
118231
118394
|
}
|
|
118232
118395
|
const cwd = inputDirectory || directory;
|
|
118233
|
-
const specPath =
|
|
118396
|
+
const specPath = path140.join(cwd, SPEC_FILE);
|
|
118234
118397
|
let specContent;
|
|
118235
118398
|
try {
|
|
118236
|
-
specContent =
|
|
118399
|
+
specContent = fs102.readFileSync(specPath, "utf-8");
|
|
118237
118400
|
} catch (readError) {
|
|
118238
118401
|
return JSON.stringify({
|
|
118239
118402
|
success: false,
|
|
@@ -118257,7 +118420,7 @@ var req_coverage = createSwarmTool({
|
|
|
118257
118420
|
message: "No FR requirements found in spec.md"
|
|
118258
118421
|
}, null, 2);
|
|
118259
118422
|
}
|
|
118260
|
-
const evidenceDir =
|
|
118423
|
+
const evidenceDir = path140.join(cwd, EVIDENCE_DIR4);
|
|
118261
118424
|
const touchedFiles = readTouchedFiles(evidenceDir, phase, cwd);
|
|
118262
118425
|
const analyzedRequirements = [];
|
|
118263
118426
|
let coveredCount = 0;
|
|
@@ -118283,12 +118446,12 @@ var req_coverage = createSwarmTool({
|
|
|
118283
118446
|
requirements: analyzedRequirements
|
|
118284
118447
|
};
|
|
118285
118448
|
const reportFilename = `req-coverage-phase-${phase}.json`;
|
|
118286
|
-
const reportPath =
|
|
118449
|
+
const reportPath = path140.join(evidenceDir, reportFilename);
|
|
118287
118450
|
try {
|
|
118288
|
-
if (!
|
|
118289
|
-
|
|
118451
|
+
if (!fs102.existsSync(evidenceDir)) {
|
|
118452
|
+
fs102.mkdirSync(evidenceDir, { recursive: true });
|
|
118290
118453
|
}
|
|
118291
|
-
|
|
118454
|
+
fs102.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8");
|
|
118292
118455
|
} catch (writeError) {
|
|
118293
118456
|
console.warn(`Failed to write coverage report: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
118294
118457
|
}
|
|
@@ -118370,8 +118533,8 @@ init_plan_schema();
|
|
|
118370
118533
|
init_qa_gate_profile();
|
|
118371
118534
|
init_file_locks();
|
|
118372
118535
|
import * as crypto12 from "node:crypto";
|
|
118373
|
-
import * as
|
|
118374
|
-
import * as
|
|
118536
|
+
import * as fs103 from "node:fs";
|
|
118537
|
+
import * as path141 from "node:path";
|
|
118375
118538
|
init_ledger();
|
|
118376
118539
|
init_manager();
|
|
118377
118540
|
init_state();
|
|
@@ -118452,17 +118615,17 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
118452
118615
|
};
|
|
118453
118616
|
}
|
|
118454
118617
|
if (args2.working_directory && fallbackDir) {
|
|
118455
|
-
const resolvedTarget =
|
|
118456
|
-
const resolvedRoot =
|
|
118618
|
+
const resolvedTarget = path141.resolve(args2.working_directory);
|
|
118619
|
+
const resolvedRoot = path141.resolve(fallbackDir);
|
|
118457
118620
|
let fallbackExists = false;
|
|
118458
118621
|
try {
|
|
118459
|
-
|
|
118622
|
+
fs103.accessSync(resolvedRoot, fs103.constants.F_OK);
|
|
118460
118623
|
fallbackExists = true;
|
|
118461
118624
|
} catch {
|
|
118462
118625
|
fallbackExists = false;
|
|
118463
118626
|
}
|
|
118464
118627
|
if (fallbackExists) {
|
|
118465
|
-
const isSubdirectory = resolvedTarget.startsWith(resolvedRoot +
|
|
118628
|
+
const isSubdirectory = resolvedTarget.startsWith(resolvedRoot + path141.sep);
|
|
118466
118629
|
if (isSubdirectory) {
|
|
118467
118630
|
return {
|
|
118468
118631
|
success: false,
|
|
@@ -118478,11 +118641,11 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
118478
118641
|
let specMtime;
|
|
118479
118642
|
let specHash;
|
|
118480
118643
|
if (process.env.SWARM_SKIP_SPEC_GATE !== "1") {
|
|
118481
|
-
const specPath =
|
|
118644
|
+
const specPath = path141.join(targetWorkspace, ".swarm", "spec.md");
|
|
118482
118645
|
try {
|
|
118483
|
-
const stat9 = await
|
|
118646
|
+
const stat9 = await fs103.promises.stat(specPath);
|
|
118484
118647
|
specMtime = stat9.mtime.toISOString();
|
|
118485
|
-
const content = await
|
|
118648
|
+
const content = await fs103.promises.readFile(specPath, "utf8");
|
|
118486
118649
|
specHash = crypto12.createHash("sha256").update(content).digest("hex");
|
|
118487
118650
|
} catch {
|
|
118488
118651
|
return {
|
|
@@ -118494,10 +118657,10 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
118494
118657
|
}
|
|
118495
118658
|
}
|
|
118496
118659
|
if (process.env.SWARM_SKIP_GATE_SELECTION !== "1") {
|
|
118497
|
-
const contextPath =
|
|
118660
|
+
const contextPath = path141.join(targetWorkspace, ".swarm", "context.md");
|
|
118498
118661
|
let contextContent = "";
|
|
118499
118662
|
try {
|
|
118500
|
-
contextContent = await
|
|
118663
|
+
contextContent = await fs103.promises.readFile(contextPath, "utf8");
|
|
118501
118664
|
} catch {}
|
|
118502
118665
|
const hasPendingSection = contextContent.includes("## Pending QA Gate Selection");
|
|
118503
118666
|
if (!hasPendingSection) {
|
|
@@ -118784,14 +118947,14 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
118784
118947
|
}
|
|
118785
118948
|
await writeCheckpoint(dir).catch(() => {});
|
|
118786
118949
|
try {
|
|
118787
|
-
const markerPath =
|
|
118950
|
+
const markerPath = path141.join(dir, ".swarm", ".plan-write-marker");
|
|
118788
118951
|
const marker = JSON.stringify({
|
|
118789
118952
|
source: "save_plan",
|
|
118790
118953
|
timestamp: new Date().toISOString(),
|
|
118791
118954
|
phases_count: plan.phases.length,
|
|
118792
118955
|
tasks_count: tasksCount
|
|
118793
118956
|
});
|
|
118794
|
-
await
|
|
118957
|
+
await fs103.promises.writeFile(markerPath, marker, "utf8");
|
|
118795
118958
|
} catch {}
|
|
118796
118959
|
const warnings = [];
|
|
118797
118960
|
let criticReviewFound = false;
|
|
@@ -118807,7 +118970,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
118807
118970
|
return {
|
|
118808
118971
|
success: true,
|
|
118809
118972
|
message: "Plan saved successfully",
|
|
118810
|
-
plan_path:
|
|
118973
|
+
plan_path: path141.join(dir, ".swarm", "plan.json"),
|
|
118811
118974
|
phases_count: plan.phases.length,
|
|
118812
118975
|
tasks_count: tasksCount,
|
|
118813
118976
|
...resolvedProfile !== undefined ? { execution_profile: resolvedProfile } : {},
|
|
@@ -118872,8 +119035,8 @@ var save_plan = createSwarmTool({
|
|
|
118872
119035
|
// src/tools/sbom-generate.ts
|
|
118873
119036
|
init_zod();
|
|
118874
119037
|
init_manager2();
|
|
118875
|
-
import * as
|
|
118876
|
-
import * as
|
|
119038
|
+
import * as fs104 from "node:fs";
|
|
119039
|
+
import * as path142 from "node:path";
|
|
118877
119040
|
|
|
118878
119041
|
// src/sbom/detectors/index.ts
|
|
118879
119042
|
init_utils();
|
|
@@ -119721,9 +119884,9 @@ function findManifestFiles(rootDir) {
|
|
|
119721
119884
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
119722
119885
|
function searchDir(dir) {
|
|
119723
119886
|
try {
|
|
119724
|
-
const entries =
|
|
119887
|
+
const entries = fs104.readdirSync(dir, { withFileTypes: true });
|
|
119725
119888
|
for (const entry of entries) {
|
|
119726
|
-
const fullPath =
|
|
119889
|
+
const fullPath = path142.join(dir, entry.name);
|
|
119727
119890
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
119728
119891
|
continue;
|
|
119729
119892
|
}
|
|
@@ -119732,7 +119895,7 @@ function findManifestFiles(rootDir) {
|
|
|
119732
119895
|
} else if (entry.isFile()) {
|
|
119733
119896
|
for (const pattern of patterns) {
|
|
119734
119897
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
119735
|
-
manifestFiles.push(
|
|
119898
|
+
manifestFiles.push(path142.relative(rootDir, fullPath));
|
|
119736
119899
|
break;
|
|
119737
119900
|
}
|
|
119738
119901
|
}
|
|
@@ -119748,13 +119911,13 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
119748
119911
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
119749
119912
|
for (const dir of directories) {
|
|
119750
119913
|
try {
|
|
119751
|
-
const entries =
|
|
119914
|
+
const entries = fs104.readdirSync(dir, { withFileTypes: true });
|
|
119752
119915
|
for (const entry of entries) {
|
|
119753
|
-
const fullPath =
|
|
119916
|
+
const fullPath = path142.join(dir, entry.name);
|
|
119754
119917
|
if (entry.isFile()) {
|
|
119755
119918
|
for (const pattern of patterns) {
|
|
119756
119919
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
119757
|
-
found.push(
|
|
119920
|
+
found.push(path142.relative(workingDir, fullPath));
|
|
119758
119921
|
break;
|
|
119759
119922
|
}
|
|
119760
119923
|
}
|
|
@@ -119767,11 +119930,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
119767
119930
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
119768
119931
|
const dirs = new Set;
|
|
119769
119932
|
for (const file3 of changedFiles) {
|
|
119770
|
-
let currentDir =
|
|
119933
|
+
let currentDir = path142.dirname(file3);
|
|
119771
119934
|
while (true) {
|
|
119772
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
119773
|
-
dirs.add(
|
|
119774
|
-
const parent =
|
|
119935
|
+
if (currentDir && currentDir !== "." && currentDir !== path142.sep) {
|
|
119936
|
+
dirs.add(path142.join(workingDir, currentDir));
|
|
119937
|
+
const parent = path142.dirname(currentDir);
|
|
119775
119938
|
if (parent === currentDir)
|
|
119776
119939
|
break;
|
|
119777
119940
|
currentDir = parent;
|
|
@@ -119785,7 +119948,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
119785
119948
|
}
|
|
119786
119949
|
function ensureOutputDir(outputDir) {
|
|
119787
119950
|
try {
|
|
119788
|
-
|
|
119951
|
+
fs104.mkdirSync(outputDir, { recursive: true });
|
|
119789
119952
|
} catch (error93) {
|
|
119790
119953
|
if (!error93 || error93.code !== "EEXIST") {
|
|
119791
119954
|
throw error93;
|
|
@@ -119855,7 +120018,7 @@ var sbom_generate = createSwarmTool({
|
|
|
119855
120018
|
const changedFiles = obj.changed_files;
|
|
119856
120019
|
const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
|
|
119857
120020
|
const workingDir = directory;
|
|
119858
|
-
const outputDir =
|
|
120021
|
+
const outputDir = path142.isAbsolute(relativeOutputDir) ? relativeOutputDir : path142.join(workingDir, relativeOutputDir);
|
|
119859
120022
|
let manifestFiles = [];
|
|
119860
120023
|
if (scope === "all") {
|
|
119861
120024
|
manifestFiles = findManifestFiles(workingDir);
|
|
@@ -119878,11 +120041,11 @@ var sbom_generate = createSwarmTool({
|
|
|
119878
120041
|
const processedFiles = [];
|
|
119879
120042
|
for (const manifestFile of manifestFiles) {
|
|
119880
120043
|
try {
|
|
119881
|
-
const fullPath =
|
|
119882
|
-
if (!
|
|
120044
|
+
const fullPath = path142.isAbsolute(manifestFile) ? manifestFile : path142.join(workingDir, manifestFile);
|
|
120045
|
+
if (!fs104.existsSync(fullPath)) {
|
|
119883
120046
|
continue;
|
|
119884
120047
|
}
|
|
119885
|
-
const content =
|
|
120048
|
+
const content = fs104.readFileSync(fullPath, "utf-8");
|
|
119886
120049
|
const components = detectComponents(manifestFile, content);
|
|
119887
120050
|
processedFiles.push(manifestFile);
|
|
119888
120051
|
if (components.length > 0) {
|
|
@@ -119895,8 +120058,8 @@ var sbom_generate = createSwarmTool({
|
|
|
119895
120058
|
const bom = generateCycloneDX(allComponents);
|
|
119896
120059
|
const bomJson = serializeCycloneDX(bom);
|
|
119897
120060
|
const filename = generateSbomFilename();
|
|
119898
|
-
const outputPath =
|
|
119899
|
-
|
|
120061
|
+
const outputPath = path142.join(outputDir, filename);
|
|
120062
|
+
fs104.writeFileSync(outputPath, bomJson, "utf-8");
|
|
119900
120063
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
119901
120064
|
try {
|
|
119902
120065
|
const timestamp = new Date().toISOString();
|
|
@@ -119938,8 +120101,8 @@ var sbom_generate = createSwarmTool({
|
|
|
119938
120101
|
// src/tools/schema-drift.ts
|
|
119939
120102
|
init_zod();
|
|
119940
120103
|
init_create_tool();
|
|
119941
|
-
import * as
|
|
119942
|
-
import * as
|
|
120104
|
+
import * as fs105 from "node:fs";
|
|
120105
|
+
import * as path143 from "node:path";
|
|
119943
120106
|
var SPEC_CANDIDATES = [
|
|
119944
120107
|
"openapi.json",
|
|
119945
120108
|
"openapi.yaml",
|
|
@@ -119971,28 +120134,28 @@ function normalizePath4(p) {
|
|
|
119971
120134
|
}
|
|
119972
120135
|
function discoverSpecFile(cwd, specFileArg) {
|
|
119973
120136
|
if (specFileArg) {
|
|
119974
|
-
const resolvedPath =
|
|
119975
|
-
const normalizedCwd = cwd.endsWith(
|
|
120137
|
+
const resolvedPath = path143.resolve(cwd, specFileArg);
|
|
120138
|
+
const normalizedCwd = cwd.endsWith(path143.sep) ? cwd : cwd + path143.sep;
|
|
119976
120139
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
119977
120140
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
119978
120141
|
}
|
|
119979
|
-
const ext =
|
|
120142
|
+
const ext = path143.extname(resolvedPath).toLowerCase();
|
|
119980
120143
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
119981
120144
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
119982
120145
|
}
|
|
119983
|
-
const stats =
|
|
120146
|
+
const stats = fs105.statSync(resolvedPath);
|
|
119984
120147
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
119985
120148
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
119986
120149
|
}
|
|
119987
|
-
if (!
|
|
120150
|
+
if (!fs105.existsSync(resolvedPath)) {
|
|
119988
120151
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
119989
120152
|
}
|
|
119990
120153
|
return resolvedPath;
|
|
119991
120154
|
}
|
|
119992
120155
|
for (const candidate of SPEC_CANDIDATES) {
|
|
119993
|
-
const candidatePath =
|
|
119994
|
-
if (
|
|
119995
|
-
const stats =
|
|
120156
|
+
const candidatePath = path143.resolve(cwd, candidate);
|
|
120157
|
+
if (fs105.existsSync(candidatePath)) {
|
|
120158
|
+
const stats = fs105.statSync(candidatePath);
|
|
119996
120159
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
119997
120160
|
return candidatePath;
|
|
119998
120161
|
}
|
|
@@ -120001,8 +120164,8 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
120001
120164
|
return null;
|
|
120002
120165
|
}
|
|
120003
120166
|
function parseSpec(specFile) {
|
|
120004
|
-
const content =
|
|
120005
|
-
const ext =
|
|
120167
|
+
const content = fs105.readFileSync(specFile, "utf-8");
|
|
120168
|
+
const ext = path143.extname(specFile).toLowerCase();
|
|
120006
120169
|
if (ext === ".json") {
|
|
120007
120170
|
return parseJsonSpec(content);
|
|
120008
120171
|
}
|
|
@@ -120073,12 +120236,12 @@ function extractRoutes(cwd) {
|
|
|
120073
120236
|
function walkDir(dir) {
|
|
120074
120237
|
let entries;
|
|
120075
120238
|
try {
|
|
120076
|
-
entries =
|
|
120239
|
+
entries = fs105.readdirSync(dir, { withFileTypes: true });
|
|
120077
120240
|
} catch {
|
|
120078
120241
|
return;
|
|
120079
120242
|
}
|
|
120080
120243
|
for (const entry of entries) {
|
|
120081
|
-
const fullPath =
|
|
120244
|
+
const fullPath = path143.join(dir, entry.name);
|
|
120082
120245
|
if (entry.isSymbolicLink()) {
|
|
120083
120246
|
continue;
|
|
120084
120247
|
}
|
|
@@ -120088,7 +120251,7 @@ function extractRoutes(cwd) {
|
|
|
120088
120251
|
}
|
|
120089
120252
|
walkDir(fullPath);
|
|
120090
120253
|
} else if (entry.isFile()) {
|
|
120091
|
-
const ext =
|
|
120254
|
+
const ext = path143.extname(entry.name).toLowerCase();
|
|
120092
120255
|
const baseName = entry.name.toLowerCase();
|
|
120093
120256
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
120094
120257
|
continue;
|
|
@@ -120106,7 +120269,7 @@ function extractRoutes(cwd) {
|
|
|
120106
120269
|
}
|
|
120107
120270
|
function extractRoutesFromFile(filePath) {
|
|
120108
120271
|
const routes = [];
|
|
120109
|
-
const content =
|
|
120272
|
+
const content = fs105.readFileSync(filePath, "utf-8");
|
|
120110
120273
|
const lines = content.split(/\r?\n/);
|
|
120111
120274
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
120112
120275
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -120255,8 +120418,8 @@ init_zod();
|
|
|
120255
120418
|
init_bun_compat();
|
|
120256
120419
|
init_path_security();
|
|
120257
120420
|
init_create_tool();
|
|
120258
|
-
import * as
|
|
120259
|
-
import * as
|
|
120421
|
+
import * as fs106 from "node:fs";
|
|
120422
|
+
import * as path144 from "node:path";
|
|
120260
120423
|
var DEFAULT_MAX_RESULTS = 100;
|
|
120261
120424
|
var DEFAULT_MAX_LINES = 200;
|
|
120262
120425
|
var REGEX_TIMEOUT_MS = 5000;
|
|
@@ -120292,11 +120455,11 @@ function containsWindowsAttacks3(str) {
|
|
|
120292
120455
|
}
|
|
120293
120456
|
function isPathInWorkspace3(filePath, workspace) {
|
|
120294
120457
|
try {
|
|
120295
|
-
const resolvedPath =
|
|
120296
|
-
const realWorkspace =
|
|
120297
|
-
const realResolvedPath =
|
|
120298
|
-
const relativePath =
|
|
120299
|
-
if (relativePath.startsWith("..") ||
|
|
120458
|
+
const resolvedPath = path144.resolve(workspace, filePath);
|
|
120459
|
+
const realWorkspace = fs106.realpathSync(workspace);
|
|
120460
|
+
const realResolvedPath = fs106.realpathSync(resolvedPath);
|
|
120461
|
+
const relativePath = path144.relative(realWorkspace, realResolvedPath);
|
|
120462
|
+
if (relativePath.startsWith("..") || path144.isAbsolute(relativePath)) {
|
|
120300
120463
|
return false;
|
|
120301
120464
|
}
|
|
120302
120465
|
return true;
|
|
@@ -120309,12 +120472,12 @@ function validatePathForRead2(filePath, workspace) {
|
|
|
120309
120472
|
}
|
|
120310
120473
|
function findRgInEnvPath() {
|
|
120311
120474
|
const searchPath = process.env.PATH ?? "";
|
|
120312
|
-
for (const dir of searchPath.split(
|
|
120475
|
+
for (const dir of searchPath.split(path144.delimiter)) {
|
|
120313
120476
|
if (!dir)
|
|
120314
120477
|
continue;
|
|
120315
120478
|
const isWindows = process.platform === "win32";
|
|
120316
|
-
const candidate =
|
|
120317
|
-
if (
|
|
120479
|
+
const candidate = path144.join(dir, isWindows ? "rg.exe" : "rg");
|
|
120480
|
+
if (fs106.existsSync(candidate))
|
|
120318
120481
|
return candidate;
|
|
120319
120482
|
}
|
|
120320
120483
|
return null;
|
|
@@ -120441,10 +120604,10 @@ function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
|
|
|
120441
120604
|
return files;
|
|
120442
120605
|
}
|
|
120443
120606
|
try {
|
|
120444
|
-
const entries =
|
|
120607
|
+
const entries = fs106.readdirSync(dir, { withFileTypes: true });
|
|
120445
120608
|
for (const entry of entries) {
|
|
120446
|
-
const fullPath =
|
|
120447
|
-
const relativePath =
|
|
120609
|
+
const fullPath = path144.join(dir, entry.name);
|
|
120610
|
+
const relativePath = path144.relative(workspace, fullPath);
|
|
120448
120611
|
if (!validatePathForRead2(fullPath, workspace)) {
|
|
120449
120612
|
continue;
|
|
120450
120613
|
}
|
|
@@ -120485,13 +120648,13 @@ async function fallbackSearch(opts) {
|
|
|
120485
120648
|
const matches = [];
|
|
120486
120649
|
let total = 0;
|
|
120487
120650
|
for (const file3 of files) {
|
|
120488
|
-
const fullPath =
|
|
120651
|
+
const fullPath = path144.join(opts.workspace, file3);
|
|
120489
120652
|
if (!validatePathForRead2(fullPath, opts.workspace)) {
|
|
120490
120653
|
continue;
|
|
120491
120654
|
}
|
|
120492
120655
|
let stats;
|
|
120493
120656
|
try {
|
|
120494
|
-
stats =
|
|
120657
|
+
stats = fs106.statSync(fullPath);
|
|
120495
120658
|
if (stats.size > MAX_FILE_SIZE_BYTES10) {
|
|
120496
120659
|
continue;
|
|
120497
120660
|
}
|
|
@@ -120500,7 +120663,7 @@ async function fallbackSearch(opts) {
|
|
|
120500
120663
|
}
|
|
120501
120664
|
let content;
|
|
120502
120665
|
try {
|
|
120503
|
-
content =
|
|
120666
|
+
content = fs106.readFileSync(fullPath, "utf-8");
|
|
120504
120667
|
} catch {
|
|
120505
120668
|
continue;
|
|
120506
120669
|
}
|
|
@@ -120612,7 +120775,7 @@ var search = createSwarmTool({
|
|
|
120612
120775
|
message: "Exclude pattern contains invalid Windows-specific sequence"
|
|
120613
120776
|
}, null, 2);
|
|
120614
120777
|
}
|
|
120615
|
-
if (!
|
|
120778
|
+
if (!fs106.existsSync(directory)) {
|
|
120616
120779
|
return JSON.stringify({
|
|
120617
120780
|
error: true,
|
|
120618
120781
|
type: "unknown",
|
|
@@ -120890,7 +121053,7 @@ init_config();
|
|
|
120890
121053
|
init_schema();
|
|
120891
121054
|
init_create_tool();
|
|
120892
121055
|
import { mkdir as mkdir23, rename as rename9, writeFile as writeFile18 } from "node:fs/promises";
|
|
120893
|
-
import * as
|
|
121056
|
+
import * as path145 from "node:path";
|
|
120894
121057
|
var MAX_SPEC_BYTES = 256 * 1024;
|
|
120895
121058
|
var spec_write = createSwarmTool({
|
|
120896
121059
|
description: "Write the canonical project spec to .swarm/spec.md. Atomic write, size-bounded (256 KiB), heading-required. Honors spec_writer.allow_spec_write.",
|
|
@@ -120931,14 +121094,14 @@ var spec_write = createSwarmTool({
|
|
|
120931
121094
|
reason: 'spec must contain at least one top-level "# Heading"'
|
|
120932
121095
|
}, null, 2);
|
|
120933
121096
|
}
|
|
120934
|
-
const target =
|
|
120935
|
-
await mkdir23(
|
|
121097
|
+
const target = path145.join(directory, ".swarm", "spec.md");
|
|
121098
|
+
await mkdir23(path145.dirname(target), { recursive: true });
|
|
120936
121099
|
const tmp = `${target}.tmp-${process.pid}-${Date.now()}`;
|
|
120937
121100
|
let finalContent = content;
|
|
120938
121101
|
if (mode === "append") {
|
|
120939
121102
|
try {
|
|
120940
|
-
const
|
|
120941
|
-
const prior = await
|
|
121103
|
+
const fs107 = await import("node:fs/promises");
|
|
121104
|
+
const prior = await fs107.readFile(target, "utf-8");
|
|
120942
121105
|
finalContent = `${prior.replace(/\s+$/, "")}
|
|
120943
121106
|
|
|
120944
121107
|
${content}
|
|
@@ -120962,12 +121125,12 @@ init_loader();
|
|
|
120962
121125
|
import {
|
|
120963
121126
|
existsSync as existsSync82,
|
|
120964
121127
|
mkdirSync as mkdirSync35,
|
|
120965
|
-
readFileSync as
|
|
121128
|
+
readFileSync as readFileSync68,
|
|
120966
121129
|
renameSync as renameSync21,
|
|
120967
121130
|
unlinkSync as unlinkSync18,
|
|
120968
121131
|
writeFileSync as writeFileSync28
|
|
120969
121132
|
} from "node:fs";
|
|
120970
|
-
import
|
|
121133
|
+
import path146 from "node:path";
|
|
120971
121134
|
init_create_tool();
|
|
120972
121135
|
init_resolve_working_directory();
|
|
120973
121136
|
var VerdictSchema2 = exports_external.object({
|
|
@@ -121097,9 +121260,9 @@ var submit_phase_council_verdicts = createSwarmTool({
|
|
|
121097
121260
|
}
|
|
121098
121261
|
});
|
|
121099
121262
|
function getPhaseMutationGapFinding(phaseNumber, workingDir) {
|
|
121100
|
-
const mutationGatePath =
|
|
121263
|
+
const mutationGatePath = path146.join(workingDir, ".swarm", "evidence", String(phaseNumber), "mutation-gate.json");
|
|
121101
121264
|
try {
|
|
121102
|
-
const raw =
|
|
121265
|
+
const raw = readFileSync68(mutationGatePath, "utf-8");
|
|
121103
121266
|
const parsed = JSON.parse(raw);
|
|
121104
121267
|
const gateEntry = (parsed.entries ?? []).find((entry) => entry?.type === "mutation-gate");
|
|
121105
121268
|
if (!gateEntry) {
|
|
@@ -121159,9 +121322,9 @@ function getPhaseMutationGapFinding(phaseNumber, workingDir) {
|
|
|
121159
121322
|
}
|
|
121160
121323
|
}
|
|
121161
121324
|
function writePhaseCouncilEvidence(workingDir, synthesis) {
|
|
121162
|
-
const evidenceDir =
|
|
121325
|
+
const evidenceDir = path146.join(workingDir, ".swarm", "evidence", String(synthesis.phaseNumber));
|
|
121163
121326
|
mkdirSync35(evidenceDir, { recursive: true });
|
|
121164
|
-
const evidenceFile =
|
|
121327
|
+
const evidenceFile = path146.join(evidenceDir, "phase-council.json");
|
|
121165
121328
|
const evidenceBundle = {
|
|
121166
121329
|
entries: [
|
|
121167
121330
|
{
|
|
@@ -121530,7 +121693,7 @@ init_schema3();
|
|
|
121530
121693
|
init_store();
|
|
121531
121694
|
init_create_tool();
|
|
121532
121695
|
init_resolve_working_directory();
|
|
121533
|
-
import * as
|
|
121696
|
+
import * as path147 from "node:path";
|
|
121534
121697
|
var FindingSchema2 = exports_external.object({
|
|
121535
121698
|
severity: exports_external.enum(["low", "medium", "high", "critical"]),
|
|
121536
121699
|
category: exports_external.string().min(1),
|
|
@@ -121594,7 +121757,7 @@ var write_architecture_supervisor_evidence = createSwarmTool({
|
|
|
121594
121757
|
if (config3.architectural_supervision?.persist_knowledge_recommendations && args2.knowledge_recommendations.length > 0) {
|
|
121595
121758
|
const knowledgeConfig = KnowledgeConfigSchema.parse(config3.knowledge ?? {});
|
|
121596
121759
|
const lessons = args2.knowledge_recommendations.map((r) => r.lesson);
|
|
121597
|
-
const result = await curateAndStoreSwarm(lessons,
|
|
121760
|
+
const result = await curateAndStoreSwarm(lessons, path147.basename(dirResult.directory), { phase_number: args2.phase }, dirResult.directory, knowledgeConfig, { skipAutoPromotion: true });
|
|
121598
121761
|
knowledgeProposed = result.stored;
|
|
121599
121762
|
}
|
|
121600
121763
|
} catch {}
|
|
@@ -121625,8 +121788,8 @@ var write_architecture_supervisor_evidence = createSwarmTool({
|
|
|
121625
121788
|
init_zod();
|
|
121626
121789
|
init_path_security();
|
|
121627
121790
|
init_create_tool();
|
|
121628
|
-
import * as
|
|
121629
|
-
import * as
|
|
121791
|
+
import * as fs107 from "node:fs";
|
|
121792
|
+
import * as path148 from "node:path";
|
|
121630
121793
|
var WINDOWS_RESERVED_NAMES4 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
121631
121794
|
function containsWindowsAttacks4(str) {
|
|
121632
121795
|
if (/:[^\\/]/.test(str))
|
|
@@ -121640,14 +121803,14 @@ function containsWindowsAttacks4(str) {
|
|
|
121640
121803
|
}
|
|
121641
121804
|
function isPathInWorkspace4(filePath, workspace) {
|
|
121642
121805
|
try {
|
|
121643
|
-
const resolvedPath =
|
|
121644
|
-
if (!
|
|
121806
|
+
const resolvedPath = path148.resolve(workspace, filePath);
|
|
121807
|
+
if (!fs107.existsSync(resolvedPath)) {
|
|
121645
121808
|
return true;
|
|
121646
121809
|
}
|
|
121647
|
-
const realWorkspace =
|
|
121648
|
-
const realResolvedPath =
|
|
121649
|
-
const relativePath =
|
|
121650
|
-
if (relativePath.startsWith("..") ||
|
|
121810
|
+
const realWorkspace = fs107.realpathSync(workspace);
|
|
121811
|
+
const realResolvedPath = fs107.realpathSync(resolvedPath);
|
|
121812
|
+
const relativePath = path148.relative(realWorkspace, realResolvedPath);
|
|
121813
|
+
if (relativePath.startsWith("..") || path148.isAbsolute(relativePath)) {
|
|
121651
121814
|
return false;
|
|
121652
121815
|
}
|
|
121653
121816
|
return true;
|
|
@@ -121819,7 +121982,7 @@ var suggestPatch = createSwarmTool({
|
|
|
121819
121982
|
message: "changes cannot be empty"
|
|
121820
121983
|
}, null, 2);
|
|
121821
121984
|
}
|
|
121822
|
-
if (!
|
|
121985
|
+
if (!fs107.existsSync(directory)) {
|
|
121823
121986
|
return JSON.stringify({
|
|
121824
121987
|
success: false,
|
|
121825
121988
|
error: true,
|
|
@@ -121855,8 +122018,8 @@ var suggestPatch = createSwarmTool({
|
|
|
121855
122018
|
});
|
|
121856
122019
|
continue;
|
|
121857
122020
|
}
|
|
121858
|
-
const fullPath =
|
|
121859
|
-
if (!
|
|
122021
|
+
const fullPath = path148.resolve(directory, change.file);
|
|
122022
|
+
if (!fs107.existsSync(fullPath)) {
|
|
121860
122023
|
errors5.push({
|
|
121861
122024
|
success: false,
|
|
121862
122025
|
error: true,
|
|
@@ -121870,7 +122033,7 @@ var suggestPatch = createSwarmTool({
|
|
|
121870
122033
|
}
|
|
121871
122034
|
let content;
|
|
121872
122035
|
try {
|
|
121873
|
-
content =
|
|
122036
|
+
content = fs107.readFileSync(fullPath, "utf-8");
|
|
121874
122037
|
} catch (err3) {
|
|
121875
122038
|
errors5.push({
|
|
121876
122039
|
success: false,
|
|
@@ -122158,12 +122321,12 @@ var lean_turbo_acquire_locks = createSwarmTool({
|
|
|
122158
122321
|
// src/tools/lean-turbo-plan-lanes.ts
|
|
122159
122322
|
init_zod();
|
|
122160
122323
|
init_constants();
|
|
122161
|
-
import * as
|
|
122162
|
-
import * as
|
|
122324
|
+
import * as fs109 from "node:fs";
|
|
122325
|
+
import * as path150 from "node:path";
|
|
122163
122326
|
|
|
122164
122327
|
// src/turbo/lean/conflicts.ts
|
|
122165
|
-
import * as
|
|
122166
|
-
import * as
|
|
122328
|
+
import * as fs108 from "node:fs";
|
|
122329
|
+
import * as path149 from "node:path";
|
|
122167
122330
|
var DEFAULT_GLOBAL_FILES = [
|
|
122168
122331
|
"package.json",
|
|
122169
122332
|
"package-lock.json",
|
|
@@ -122290,12 +122453,12 @@ function isProtectedPath2(normalizedPath) {
|
|
|
122290
122453
|
return false;
|
|
122291
122454
|
}
|
|
122292
122455
|
function readTaskScopes(directory, taskId) {
|
|
122293
|
-
const scopePath =
|
|
122456
|
+
const scopePath = path149.join(directory, ".swarm", "scopes", `scope-${taskId}.json`);
|
|
122294
122457
|
try {
|
|
122295
|
-
if (!
|
|
122458
|
+
if (!fs108.existsSync(scopePath)) {
|
|
122296
122459
|
return null;
|
|
122297
122460
|
}
|
|
122298
|
-
const raw =
|
|
122461
|
+
const raw = fs108.readFileSync(scopePath, "utf-8");
|
|
122299
122462
|
const parsed = JSON.parse(raw);
|
|
122300
122463
|
if (!parsed || !Array.isArray(parsed.files)) {
|
|
122301
122464
|
return null;
|
|
@@ -122678,12 +122841,12 @@ function createEmptyPlan(phaseNumber, planId) {
|
|
|
122678
122841
|
// src/tools/lean-turbo-plan-lanes.ts
|
|
122679
122842
|
init_create_tool();
|
|
122680
122843
|
function readPlanJson(directory) {
|
|
122681
|
-
const planPath =
|
|
122682
|
-
if (!
|
|
122844
|
+
const planPath = path150.join(directory, ".swarm", "plan.json");
|
|
122845
|
+
if (!fs109.existsSync(planPath)) {
|
|
122683
122846
|
return null;
|
|
122684
122847
|
}
|
|
122685
122848
|
try {
|
|
122686
|
-
return JSON.parse(
|
|
122849
|
+
return JSON.parse(fs109.readFileSync(planPath, "utf-8"));
|
|
122687
122850
|
} catch {
|
|
122688
122851
|
return null;
|
|
122689
122852
|
}
|
|
@@ -122732,8 +122895,8 @@ init_config();
|
|
|
122732
122895
|
|
|
122733
122896
|
// src/turbo/lean/reviewer.ts
|
|
122734
122897
|
init_state();
|
|
122735
|
-
import * as
|
|
122736
|
-
import * as
|
|
122898
|
+
import * as fs110 from "node:fs/promises";
|
|
122899
|
+
import * as path151 from "node:path";
|
|
122737
122900
|
init_state3();
|
|
122738
122901
|
var DEFAULT_CONFIG3 = {
|
|
122739
122902
|
reviewerAgent: "",
|
|
@@ -122849,9 +123012,9 @@ function parseReviewerVerdict(responseText) {
|
|
|
122849
123012
|
return { verdict, reason };
|
|
122850
123013
|
}
|
|
122851
123014
|
async function writeReviewerEvidence(directory, phase, verdict, reason) {
|
|
122852
|
-
const evidenceDir =
|
|
122853
|
-
await
|
|
122854
|
-
const evidencePath =
|
|
123015
|
+
const evidenceDir = path151.join(directory, ".swarm", "evidence", String(phase));
|
|
123016
|
+
await fs110.mkdir(evidenceDir, { recursive: true });
|
|
123017
|
+
const evidencePath = path151.join(evidenceDir, "lean-turbo-reviewer.json");
|
|
122855
123018
|
const content = JSON.stringify({
|
|
122856
123019
|
phase,
|
|
122857
123020
|
verdict,
|
|
@@ -122860,11 +123023,11 @@ async function writeReviewerEvidence(directory, phase, verdict, reason) {
|
|
|
122860
123023
|
}, null, 2);
|
|
122861
123024
|
const tempPath = `${evidencePath}.tmp.${process.pid}.${Date.now()}`;
|
|
122862
123025
|
try {
|
|
122863
|
-
await
|
|
122864
|
-
await
|
|
123026
|
+
await fs110.writeFile(tempPath, content, "utf-8");
|
|
123027
|
+
await fs110.rename(tempPath, evidencePath);
|
|
122865
123028
|
} catch (error93) {
|
|
122866
123029
|
try {
|
|
122867
|
-
await
|
|
123030
|
+
await fs110.unlink(tempPath);
|
|
122868
123031
|
} catch {}
|
|
122869
123032
|
throw error93;
|
|
122870
123033
|
}
|
|
@@ -123655,8 +123818,8 @@ var lean_turbo_status = createSwarmTool({
|
|
|
123655
123818
|
// src/tools/lint-spec.ts
|
|
123656
123819
|
init_spec_schema();
|
|
123657
123820
|
init_create_tool();
|
|
123658
|
-
import * as
|
|
123659
|
-
import * as
|
|
123821
|
+
import * as fs111 from "node:fs";
|
|
123822
|
+
import * as path152 from "node:path";
|
|
123660
123823
|
var SPEC_FILE_NAME = "spec.md";
|
|
123661
123824
|
var SWARM_DIR2 = ".swarm";
|
|
123662
123825
|
var OBLIGATION_KEYWORDS2 = ["MUST", "SHALL", "SHOULD", "MAY"];
|
|
@@ -123709,8 +123872,8 @@ var lint_spec = createSwarmTool({
|
|
|
123709
123872
|
async execute(_args, directory) {
|
|
123710
123873
|
const errors5 = [];
|
|
123711
123874
|
const warnings = [];
|
|
123712
|
-
const specPath =
|
|
123713
|
-
if (!
|
|
123875
|
+
const specPath = path152.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
|
|
123876
|
+
if (!fs111.existsSync(specPath)) {
|
|
123714
123877
|
const result2 = {
|
|
123715
123878
|
valid: false,
|
|
123716
123879
|
specMtime: null,
|
|
@@ -123729,12 +123892,12 @@ var lint_spec = createSwarmTool({
|
|
|
123729
123892
|
}
|
|
123730
123893
|
let specMtime = null;
|
|
123731
123894
|
try {
|
|
123732
|
-
const stats =
|
|
123895
|
+
const stats = fs111.statSync(specPath);
|
|
123733
123896
|
specMtime = stats.mtime.toISOString();
|
|
123734
123897
|
} catch {}
|
|
123735
123898
|
let content;
|
|
123736
123899
|
try {
|
|
123737
|
-
content =
|
|
123900
|
+
content = fs111.readFileSync(specPath, "utf-8");
|
|
123738
123901
|
} catch (e) {
|
|
123739
123902
|
const result2 = {
|
|
123740
123903
|
valid: false,
|
|
@@ -123779,13 +123942,13 @@ var lint_spec = createSwarmTool({
|
|
|
123779
123942
|
});
|
|
123780
123943
|
// src/tools/mutation-test.ts
|
|
123781
123944
|
init_zod();
|
|
123782
|
-
import * as
|
|
123783
|
-
import * as
|
|
123945
|
+
import * as fs112 from "node:fs";
|
|
123946
|
+
import * as path154 from "node:path";
|
|
123784
123947
|
|
|
123785
123948
|
// src/mutation/engine.ts
|
|
123786
123949
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
123787
123950
|
import { unlinkSync as unlinkSync19, writeFileSync as writeFileSync29 } from "node:fs";
|
|
123788
|
-
import * as
|
|
123951
|
+
import * as path153 from "node:path";
|
|
123789
123952
|
|
|
123790
123953
|
// src/mutation/equivalence.ts
|
|
123791
123954
|
function isStaticallyEquivalent(originalCode, mutatedCode) {
|
|
@@ -123931,7 +124094,7 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
|
|
|
123931
124094
|
let patchFile;
|
|
123932
124095
|
try {
|
|
123933
124096
|
const safeId2 = patch.id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
123934
|
-
patchFile =
|
|
124097
|
+
patchFile = path153.join(workingDir, `.mutation_patch_${safeId2}.diff`);
|
|
123935
124098
|
try {
|
|
123936
124099
|
writeFileSync29(patchFile, patch.patch);
|
|
123937
124100
|
} catch (writeErr) {
|
|
@@ -124335,8 +124498,8 @@ var mutation_test = createSwarmTool({
|
|
|
124335
124498
|
];
|
|
124336
124499
|
for (const filePath of uniquePaths) {
|
|
124337
124500
|
try {
|
|
124338
|
-
const resolvedPath =
|
|
124339
|
-
sourceFiles.set(filePath,
|
|
124501
|
+
const resolvedPath = path154.resolve(cwd, filePath);
|
|
124502
|
+
sourceFiles.set(filePath, fs112.readFileSync(resolvedPath, "utf-8"));
|
|
124340
124503
|
} catch {}
|
|
124341
124504
|
}
|
|
124342
124505
|
const report = await executeMutationSuite(typedArgs.patches, typedArgs.test_command, typedArgs.files, cwd, undefined, undefined, sourceFiles.size > 0 ? sourceFiles : undefined);
|
|
@@ -124354,8 +124517,8 @@ var mutation_test = createSwarmTool({
|
|
|
124354
124517
|
init_zod();
|
|
124355
124518
|
init_manager2();
|
|
124356
124519
|
init_detector();
|
|
124357
|
-
import * as
|
|
124358
|
-
import * as
|
|
124520
|
+
import * as fs113 from "node:fs";
|
|
124521
|
+
import * as path155 from "node:path";
|
|
124359
124522
|
init_create_tool();
|
|
124360
124523
|
var MAX_FILE_SIZE2 = 2 * 1024 * 1024;
|
|
124361
124524
|
var BINARY_CHECK_BYTES = 8192;
|
|
@@ -124421,7 +124584,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
124421
124584
|
if (languages?.length) {
|
|
124422
124585
|
const lowerLangs = languages.map((l) => l.toLowerCase());
|
|
124423
124586
|
filesToCheck = filesToCheck.filter((file3) => {
|
|
124424
|
-
const ext =
|
|
124587
|
+
const ext = path155.extname(file3.path).toLowerCase();
|
|
124425
124588
|
const langDef = getLanguageForExtension(ext);
|
|
124426
124589
|
const fileProfile = getProfileForFile(file3.path);
|
|
124427
124590
|
const langId = fileProfile?.id || langDef?.id;
|
|
@@ -124434,7 +124597,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
124434
124597
|
let skippedCount = 0;
|
|
124435
124598
|
for (const fileInfo of filesToCheck) {
|
|
124436
124599
|
const { path: filePath } = fileInfo;
|
|
124437
|
-
const fullPath =
|
|
124600
|
+
const fullPath = path155.isAbsolute(filePath) ? filePath : path155.join(directory, filePath);
|
|
124438
124601
|
const result = {
|
|
124439
124602
|
path: filePath,
|
|
124440
124603
|
language: "",
|
|
@@ -124464,7 +124627,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
124464
124627
|
}
|
|
124465
124628
|
let content;
|
|
124466
124629
|
try {
|
|
124467
|
-
content =
|
|
124630
|
+
content = fs113.readFileSync(fullPath, "utf8");
|
|
124468
124631
|
} catch {
|
|
124469
124632
|
result.skipped_reason = "file_read_error";
|
|
124470
124633
|
skippedCount++;
|
|
@@ -124483,7 +124646,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
124483
124646
|
results.push(result);
|
|
124484
124647
|
continue;
|
|
124485
124648
|
}
|
|
124486
|
-
const ext =
|
|
124649
|
+
const ext = path155.extname(filePath).toLowerCase();
|
|
124487
124650
|
const langDef = getLanguageForExtension(ext);
|
|
124488
124651
|
result.language = profile?.id || langDef?.id || "unknown";
|
|
124489
124652
|
const errors5 = extractSyntaxErrors(parser, content);
|
|
@@ -124580,8 +124743,8 @@ init_zod();
|
|
|
124580
124743
|
init_utils();
|
|
124581
124744
|
init_create_tool();
|
|
124582
124745
|
init_path_security();
|
|
124583
|
-
import * as
|
|
124584
|
-
import * as
|
|
124746
|
+
import * as fs114 from "node:fs";
|
|
124747
|
+
import * as path156 from "node:path";
|
|
124585
124748
|
var MAX_TEXT_LENGTH = 200;
|
|
124586
124749
|
var MAX_FILE_SIZE_BYTES11 = 1024 * 1024;
|
|
124587
124750
|
var SUPPORTED_EXTENSIONS4 = new Set([
|
|
@@ -124647,9 +124810,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
124647
124810
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
124648
124811
|
}
|
|
124649
124812
|
try {
|
|
124650
|
-
const resolvedPath =
|
|
124651
|
-
const normalizedCwd =
|
|
124652
|
-
const normalizedResolved =
|
|
124813
|
+
const resolvedPath = path156.resolve(paths);
|
|
124814
|
+
const normalizedCwd = path156.resolve(cwd);
|
|
124815
|
+
const normalizedResolved = path156.resolve(resolvedPath);
|
|
124653
124816
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
124654
124817
|
return {
|
|
124655
124818
|
error: "paths must be within the current working directory",
|
|
@@ -124665,13 +124828,13 @@ function validatePathsInput(paths, cwd) {
|
|
|
124665
124828
|
}
|
|
124666
124829
|
}
|
|
124667
124830
|
function isSupportedExtension(filePath) {
|
|
124668
|
-
const ext =
|
|
124831
|
+
const ext = path156.extname(filePath).toLowerCase();
|
|
124669
124832
|
return SUPPORTED_EXTENSIONS4.has(ext);
|
|
124670
124833
|
}
|
|
124671
124834
|
function findSourceFiles3(dir, files = []) {
|
|
124672
124835
|
let entries;
|
|
124673
124836
|
try {
|
|
124674
|
-
entries =
|
|
124837
|
+
entries = fs114.readdirSync(dir);
|
|
124675
124838
|
} catch {
|
|
124676
124839
|
return files;
|
|
124677
124840
|
}
|
|
@@ -124680,10 +124843,10 @@ function findSourceFiles3(dir, files = []) {
|
|
|
124680
124843
|
if (SKIP_DIRECTORIES5.has(entry)) {
|
|
124681
124844
|
continue;
|
|
124682
124845
|
}
|
|
124683
|
-
const fullPath =
|
|
124846
|
+
const fullPath = path156.join(dir, entry);
|
|
124684
124847
|
let stat9;
|
|
124685
124848
|
try {
|
|
124686
|
-
stat9 =
|
|
124849
|
+
stat9 = fs114.statSync(fullPath);
|
|
124687
124850
|
} catch {
|
|
124688
124851
|
continue;
|
|
124689
124852
|
}
|
|
@@ -124776,7 +124939,7 @@ var todo_extract = createSwarmTool({
|
|
|
124776
124939
|
return JSON.stringify(errorResult, null, 2);
|
|
124777
124940
|
}
|
|
124778
124941
|
const scanPath = resolvedPath;
|
|
124779
|
-
if (!
|
|
124942
|
+
if (!fs114.existsSync(scanPath)) {
|
|
124780
124943
|
const errorResult = {
|
|
124781
124944
|
error: `path not found: ${pathsInput}`,
|
|
124782
124945
|
total: 0,
|
|
@@ -124786,13 +124949,13 @@ var todo_extract = createSwarmTool({
|
|
|
124786
124949
|
return JSON.stringify(errorResult, null, 2);
|
|
124787
124950
|
}
|
|
124788
124951
|
const filesToScan = [];
|
|
124789
|
-
const stat9 =
|
|
124952
|
+
const stat9 = fs114.statSync(scanPath);
|
|
124790
124953
|
if (stat9.isFile()) {
|
|
124791
124954
|
if (isSupportedExtension(scanPath)) {
|
|
124792
124955
|
filesToScan.push(scanPath);
|
|
124793
124956
|
} else {
|
|
124794
124957
|
const errorResult = {
|
|
124795
|
-
error: `unsupported file extension: ${
|
|
124958
|
+
error: `unsupported file extension: ${path156.extname(scanPath)}`,
|
|
124796
124959
|
total: 0,
|
|
124797
124960
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
124798
124961
|
entries: []
|
|
@@ -124805,11 +124968,11 @@ var todo_extract = createSwarmTool({
|
|
|
124805
124968
|
const allEntries = [];
|
|
124806
124969
|
for (const filePath of filesToScan) {
|
|
124807
124970
|
try {
|
|
124808
|
-
const fileStat =
|
|
124971
|
+
const fileStat = fs114.statSync(filePath);
|
|
124809
124972
|
if (fileStat.size > MAX_FILE_SIZE_BYTES11) {
|
|
124810
124973
|
continue;
|
|
124811
124974
|
}
|
|
124812
|
-
const content =
|
|
124975
|
+
const content = fs114.readFileSync(filePath, "utf-8");
|
|
124813
124976
|
const entries = parseTodoComments(content, filePath, tagsSet);
|
|
124814
124977
|
allEntries.push(...entries);
|
|
124815
124978
|
} catch {}
|
|
@@ -124840,18 +125003,18 @@ init_loader();
|
|
|
124840
125003
|
init_schema();
|
|
124841
125004
|
init_qa_gate_profile();
|
|
124842
125005
|
init_gate_evidence();
|
|
124843
|
-
import * as
|
|
124844
|
-
import * as
|
|
125006
|
+
import * as fs118 from "node:fs";
|
|
125007
|
+
import * as path160 from "node:path";
|
|
124845
125008
|
|
|
124846
125009
|
// src/hooks/diff-scope.ts
|
|
124847
125010
|
init_bun_compat();
|
|
124848
|
-
import * as
|
|
124849
|
-
import * as
|
|
125011
|
+
import * as fs116 from "node:fs";
|
|
125012
|
+
import * as path158 from "node:path";
|
|
124850
125013
|
|
|
124851
125014
|
// src/utils/gitignore-warning.ts
|
|
124852
125015
|
init_bun_compat();
|
|
124853
|
-
import * as
|
|
124854
|
-
import * as
|
|
125016
|
+
import * as fs115 from "node:fs";
|
|
125017
|
+
import * as path157 from "node:path";
|
|
124855
125018
|
var _internals67 = { bunSpawn };
|
|
124856
125019
|
var _swarmGitExcludedChecked = false;
|
|
124857
125020
|
function fileCoversSwarm(content) {
|
|
@@ -124925,16 +125088,16 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
124925
125088
|
const excludeRelPath = excludePathRaw.trim();
|
|
124926
125089
|
if (!excludeRelPath)
|
|
124927
125090
|
return;
|
|
124928
|
-
const excludePath =
|
|
125091
|
+
const excludePath = path157.isAbsolute(excludeRelPath) ? excludeRelPath : path157.join(directory, excludeRelPath);
|
|
124929
125092
|
if (checkIgnoreExitCode !== 0) {
|
|
124930
125093
|
try {
|
|
124931
|
-
|
|
125094
|
+
fs115.mkdirSync(path157.dirname(excludePath), { recursive: true });
|
|
124932
125095
|
let existing = "";
|
|
124933
125096
|
try {
|
|
124934
|
-
existing =
|
|
125097
|
+
existing = fs115.readFileSync(excludePath, "utf8");
|
|
124935
125098
|
} catch {}
|
|
124936
125099
|
if (!fileCoversSwarm(existing)) {
|
|
124937
|
-
|
|
125100
|
+
fs115.appendFileSync(excludePath, `
|
|
124938
125101
|
# opencode-swarm local runtime state
|
|
124939
125102
|
.swarm/
|
|
124940
125103
|
`, "utf8");
|
|
@@ -124972,10 +125135,10 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
124972
125135
|
var _internals68 = { bunSpawn };
|
|
124973
125136
|
function getDeclaredScope(taskId, directory) {
|
|
124974
125137
|
try {
|
|
124975
|
-
const planPath =
|
|
124976
|
-
if (!
|
|
125138
|
+
const planPath = path158.join(directory, ".swarm", "plan.json");
|
|
125139
|
+
if (!fs116.existsSync(planPath))
|
|
124977
125140
|
return null;
|
|
124978
|
-
const raw =
|
|
125141
|
+
const raw = fs116.readFileSync(planPath, "utf-8");
|
|
124979
125142
|
const plan = JSON.parse(raw);
|
|
124980
125143
|
for (const phase of plan.phases ?? []) {
|
|
124981
125144
|
for (const task of phase.tasks ?? []) {
|
|
@@ -125077,8 +125240,8 @@ init_telemetry();
|
|
|
125077
125240
|
|
|
125078
125241
|
// src/turbo/lean/task-completion.ts
|
|
125079
125242
|
init_file_locks();
|
|
125080
|
-
import * as
|
|
125081
|
-
import * as
|
|
125243
|
+
import * as fs117 from "node:fs";
|
|
125244
|
+
import * as path159 from "node:path";
|
|
125082
125245
|
var _internals69 = {
|
|
125083
125246
|
listActiveLocks,
|
|
125084
125247
|
verifyLeanTurboTaskCompletion
|
|
@@ -125097,7 +125260,7 @@ var TIER_3_PATTERNS = [
|
|
|
125097
125260
|
];
|
|
125098
125261
|
function matchesTier3Pattern(files) {
|
|
125099
125262
|
for (const file3 of files) {
|
|
125100
|
-
const fileName =
|
|
125263
|
+
const fileName = path159.basename(file3);
|
|
125101
125264
|
for (const pattern of TIER_3_PATTERNS) {
|
|
125102
125265
|
if (pattern.test(fileName)) {
|
|
125103
125266
|
return true;
|
|
@@ -125109,14 +125272,14 @@ function matchesTier3Pattern(files) {
|
|
|
125109
125272
|
function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
|
|
125110
125273
|
let persisted = null;
|
|
125111
125274
|
try {
|
|
125112
|
-
const statePath =
|
|
125113
|
-
if (!
|
|
125275
|
+
const statePath = path159.join(directory, ".swarm", "turbo-state.json");
|
|
125276
|
+
if (!fs117.existsSync(statePath)) {
|
|
125114
125277
|
return {
|
|
125115
125278
|
ok: false,
|
|
125116
125279
|
reason: "Lean Turbo state file not found"
|
|
125117
125280
|
};
|
|
125118
125281
|
}
|
|
125119
|
-
const raw =
|
|
125282
|
+
const raw = fs117.readFileSync(statePath, "utf-8");
|
|
125120
125283
|
persisted = JSON.parse(raw);
|
|
125121
125284
|
} catch {
|
|
125122
125285
|
return {
|
|
@@ -125193,11 +125356,11 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
|
|
|
125193
125356
|
};
|
|
125194
125357
|
}
|
|
125195
125358
|
const phase = runState.phase ?? 0;
|
|
125196
|
-
const evidencePath =
|
|
125197
|
-
const expectedDir =
|
|
125198
|
-
const resolvedPath =
|
|
125199
|
-
const resolvedDir =
|
|
125200
|
-
if (!resolvedPath.startsWith(resolvedDir +
|
|
125359
|
+
const evidencePath = path159.join(directory, ".swarm", "evidence", String(phase), "lean-turbo", `${lane.laneId}.json`);
|
|
125360
|
+
const expectedDir = path159.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
|
|
125361
|
+
const resolvedPath = path159.resolve(evidencePath);
|
|
125362
|
+
const resolvedDir = path159.resolve(expectedDir);
|
|
125363
|
+
if (!resolvedPath.startsWith(resolvedDir + path159.sep) && resolvedPath !== resolvedDir) {
|
|
125201
125364
|
return {
|
|
125202
125365
|
ok: false,
|
|
125203
125366
|
reason: `Lane ID causes path traversal: ${lane.laneId}`,
|
|
@@ -125209,7 +125372,7 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
|
|
|
125209
125372
|
}
|
|
125210
125373
|
};
|
|
125211
125374
|
}
|
|
125212
|
-
if (!
|
|
125375
|
+
if (!fs117.existsSync(evidencePath)) {
|
|
125213
125376
|
return {
|
|
125214
125377
|
ok: false,
|
|
125215
125378
|
reason: `Lane ${lane.laneId} evidence file not found: ${evidencePath}`,
|
|
@@ -125237,8 +125400,8 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
|
|
|
125237
125400
|
}
|
|
125238
125401
|
let filesTouched = [];
|
|
125239
125402
|
try {
|
|
125240
|
-
const planPath =
|
|
125241
|
-
const planRaw =
|
|
125403
|
+
const planPath = path159.join(directory, ".swarm", "plan.json");
|
|
125404
|
+
const planRaw = fs117.readFileSync(planPath, "utf-8");
|
|
125242
125405
|
const plan = JSON.parse(planRaw);
|
|
125243
125406
|
for (const planPhase of plan.phases ?? []) {
|
|
125244
125407
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -125321,7 +125484,7 @@ var TIER_3_PATTERNS2 = [
|
|
|
125321
125484
|
];
|
|
125322
125485
|
function matchesTier3Pattern2(files) {
|
|
125323
125486
|
for (const file3 of files) {
|
|
125324
|
-
const fileName =
|
|
125487
|
+
const fileName = path160.basename(file3);
|
|
125325
125488
|
for (const pattern of TIER_3_PATTERNS2) {
|
|
125326
125489
|
if (pattern.test(fileName)) {
|
|
125327
125490
|
return true;
|
|
@@ -125360,8 +125523,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
125360
125523
|
if (!skipStandardTurboBypass && hasActiveTurboMode()) {
|
|
125361
125524
|
const resolvedDir2 = workingDirectory;
|
|
125362
125525
|
try {
|
|
125363
|
-
const planPath =
|
|
125364
|
-
const planRaw =
|
|
125526
|
+
const planPath = path160.join(resolvedDir2, ".swarm", "plan.json");
|
|
125527
|
+
const planRaw = fs118.readFileSync(planPath, "utf-8");
|
|
125365
125528
|
const plan = JSON.parse(planRaw);
|
|
125366
125529
|
for (const planPhase of plan.phases ?? []) {
|
|
125367
125530
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -125438,8 +125601,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
125438
125601
|
}
|
|
125439
125602
|
if (resolvedDir) {
|
|
125440
125603
|
try {
|
|
125441
|
-
const planPath =
|
|
125442
|
-
const planRaw =
|
|
125604
|
+
const planPath = path160.join(resolvedDir, ".swarm", "plan.json");
|
|
125605
|
+
const planRaw = fs118.readFileSync(planPath, "utf-8");
|
|
125443
125606
|
const plan = JSON.parse(planRaw);
|
|
125444
125607
|
for (const planPhase of plan.phases ?? []) {
|
|
125445
125608
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -125657,72 +125820,35 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
|
|
|
125657
125820
|
session.currentTaskId = args2.task_id;
|
|
125658
125821
|
}
|
|
125659
125822
|
}
|
|
125660
|
-
let normalizedDir;
|
|
125661
125823
|
let directory;
|
|
125662
|
-
if (args2.working_directory
|
|
125663
|
-
|
|
125664
|
-
|
|
125665
|
-
|
|
125666
|
-
|
|
125667
|
-
|
|
125668
|
-
|
|
125669
|
-
|
|
125670
|
-
|
|
125671
|
-
|
|
125672
|
-
|
|
125673
|
-
|
|
125674
|
-
|
|
125675
|
-
|
|
125676
|
-
|
|
125677
|
-
|
|
125678
|
-
|
|
125679
|
-
|
|
125680
|
-
|
|
125681
|
-
|
|
125682
|
-
|
|
125683
|
-
|
|
125684
|
-
|
|
125685
|
-
"Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
125686
|
-
]
|
|
125687
|
-
};
|
|
125688
|
-
}
|
|
125689
|
-
const resolvedDir = path155.resolve(normalizedDir);
|
|
125690
|
-
try {
|
|
125691
|
-
const realPath = fs113.realpathSync(resolvedDir);
|
|
125692
|
-
const planPath = path155.join(realPath, ".swarm", "plan.json");
|
|
125693
|
-
if (!fs113.existsSync(planPath)) {
|
|
125694
|
-
return {
|
|
125695
|
-
success: false,
|
|
125696
|
-
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
125697
|
-
errors: [
|
|
125698
|
-
`Invalid working_directory: plan not found in "${realPath}"`
|
|
125699
|
-
]
|
|
125700
|
-
};
|
|
125701
|
-
}
|
|
125702
|
-
directory = realPath;
|
|
125703
|
-
} catch {
|
|
125704
|
-
return {
|
|
125705
|
-
success: false,
|
|
125706
|
-
message: `Invalid working_directory: path "${resolvedDir}" does not exist or is inaccessible`,
|
|
125707
|
-
errors: [
|
|
125708
|
-
`Invalid working_directory: path "${resolvedDir}" does not exist or is inaccessible`
|
|
125709
|
-
]
|
|
125710
|
-
};
|
|
125711
|
-
}
|
|
125712
|
-
} else {
|
|
125713
|
-
if (!fallbackDir) {
|
|
125714
|
-
return {
|
|
125715
|
-
success: false,
|
|
125716
|
-
message: "No working_directory provided and fallbackDir is undefined",
|
|
125717
|
-
errors: ["Cannot resolve directory for task status update"]
|
|
125718
|
-
};
|
|
125719
|
-
}
|
|
125720
|
-
directory = fallbackDir;
|
|
125824
|
+
if (!args2.working_directory && !fallbackDir) {
|
|
125825
|
+
return {
|
|
125826
|
+
success: false,
|
|
125827
|
+
message: "No working_directory provided and fallbackDir is undefined",
|
|
125828
|
+
errors: ["Cannot resolve directory for task status update"]
|
|
125829
|
+
};
|
|
125830
|
+
}
|
|
125831
|
+
const resolveResult = resolveWorkingDirectory(args2.working_directory ?? fallbackDir, fallbackDir);
|
|
125832
|
+
if (!resolveResult.success) {
|
|
125833
|
+
return {
|
|
125834
|
+
success: false,
|
|
125835
|
+
message: resolveResult.message,
|
|
125836
|
+
errors: [resolveResult.message]
|
|
125837
|
+
};
|
|
125838
|
+
}
|
|
125839
|
+
directory = resolveResult.directory;
|
|
125840
|
+
const planPath = path160.join(directory, ".swarm", "plan.json");
|
|
125841
|
+
if (!fs118.existsSync(planPath)) {
|
|
125842
|
+
return {
|
|
125843
|
+
success: false,
|
|
125844
|
+
message: `Invalid working_directory: plan not found in "${directory}"`,
|
|
125845
|
+
errors: [`Invalid working_directory: plan not found in "${directory}"`]
|
|
125846
|
+
};
|
|
125721
125847
|
}
|
|
125722
125848
|
if (fallbackDir && directory !== fallbackDir) {
|
|
125723
|
-
const canonicalDir =
|
|
125724
|
-
const canonicalRoot =
|
|
125725
|
-
if (canonicalDir.startsWith(canonicalRoot +
|
|
125849
|
+
const canonicalDir = fs118.realpathSync(path160.resolve(directory));
|
|
125850
|
+
const canonicalRoot = fs118.realpathSync(path160.resolve(fallbackDir));
|
|
125851
|
+
if (canonicalDir.startsWith(canonicalRoot + path160.sep)) {
|
|
125726
125852
|
return {
|
|
125727
125853
|
success: false,
|
|
125728
125854
|
message: `Invalid working_directory: "${directory}" is a subdirectory of ` + `the project root "${fallbackDir}". Pass the project root path or ` + `omit working_directory entirely.`,
|
|
@@ -125734,22 +125860,22 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
|
|
|
125734
125860
|
}
|
|
125735
125861
|
if (args2.status === "in_progress") {
|
|
125736
125862
|
try {
|
|
125737
|
-
const evidencePath =
|
|
125738
|
-
|
|
125739
|
-
const fd =
|
|
125863
|
+
const evidencePath = path160.join(directory, ".swarm", "evidence", `${args2.task_id}.json`);
|
|
125864
|
+
fs118.mkdirSync(path160.dirname(evidencePath), { recursive: true });
|
|
125865
|
+
const fd = fs118.openSync(evidencePath, "wx");
|
|
125740
125866
|
let writeOk = false;
|
|
125741
125867
|
try {
|
|
125742
|
-
|
|
125868
|
+
fs118.writeSync(fd, JSON.stringify({
|
|
125743
125869
|
taskId: args2.task_id,
|
|
125744
125870
|
required_gates: [],
|
|
125745
125871
|
gates: {}
|
|
125746
125872
|
}, null, 2));
|
|
125747
125873
|
writeOk = true;
|
|
125748
125874
|
} finally {
|
|
125749
|
-
|
|
125875
|
+
fs118.closeSync(fd);
|
|
125750
125876
|
if (!writeOk) {
|
|
125751
125877
|
try {
|
|
125752
|
-
|
|
125878
|
+
fs118.unlinkSync(evidencePath);
|
|
125753
125879
|
} catch {}
|
|
125754
125880
|
}
|
|
125755
125881
|
}
|
|
@@ -125759,8 +125885,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
|
|
|
125759
125885
|
recoverTaskStateFromDelegations(args2.task_id, directory);
|
|
125760
125886
|
let phaseRequiresReviewer = true;
|
|
125761
125887
|
try {
|
|
125762
|
-
const
|
|
125763
|
-
const planRaw =
|
|
125888
|
+
const planPath2 = path160.join(directory, ".swarm", "plan.json");
|
|
125889
|
+
const planRaw = fs118.readFileSync(planPath2, "utf-8");
|
|
125764
125890
|
const plan = JSON.parse(planRaw);
|
|
125765
125891
|
const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
|
|
125766
125892
|
if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
|
|
@@ -125987,7 +126113,7 @@ init_utils2();
|
|
|
125987
126113
|
init_redaction();
|
|
125988
126114
|
import { createHash as createHash12 } from "node:crypto";
|
|
125989
126115
|
import { appendFile as appendFile14, mkdir as mkdir25 } from "node:fs/promises";
|
|
125990
|
-
import * as
|
|
126116
|
+
import * as path161 from "node:path";
|
|
125991
126117
|
var EVIDENCE_CACHE_FILE = "evidence-cache/documents.jsonl";
|
|
125992
126118
|
var MAX_EVIDENCE_TEXT_LENGTH = 4000;
|
|
125993
126119
|
async function writeEvidenceDocuments(directory, inputs, now = () => new Date) {
|
|
@@ -125995,7 +126121,7 @@ async function writeEvidenceDocuments(directory, inputs, now = () => new Date) {
|
|
|
125995
126121
|
const capturedAt = now().toISOString();
|
|
125996
126122
|
const records = inputs.map((input) => createEvidenceDocumentRecord(input, capturedAt)).filter((record3) => record3 !== null);
|
|
125997
126123
|
if (records.length > 0) {
|
|
125998
|
-
await mkdir25(
|
|
126124
|
+
await mkdir25(path161.dirname(filePath), { recursive: true });
|
|
125999
126125
|
await appendFile14(filePath, `${records.map((record3) => JSON.stringify(record3)).join(`
|
|
126000
126126
|
`)}
|
|
126001
126127
|
`, "utf-8");
|
|
@@ -126188,8 +126314,8 @@ init_utils2();
|
|
|
126188
126314
|
init_ledger();
|
|
126189
126315
|
init_manager();
|
|
126190
126316
|
init_create_tool();
|
|
126191
|
-
import
|
|
126192
|
-
import
|
|
126317
|
+
import fs119 from "node:fs";
|
|
126318
|
+
import path162 from "node:path";
|
|
126193
126319
|
function normalizeVerdict(verdict) {
|
|
126194
126320
|
switch (verdict) {
|
|
126195
126321
|
case "APPROVED":
|
|
@@ -126237,7 +126363,7 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
126237
126363
|
entries: [evidenceEntry]
|
|
126238
126364
|
};
|
|
126239
126365
|
const filename = "drift-verifier.json";
|
|
126240
|
-
const relativePath =
|
|
126366
|
+
const relativePath = path162.join("evidence", String(phase), filename);
|
|
126241
126367
|
let validatedPath;
|
|
126242
126368
|
try {
|
|
126243
126369
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -126248,12 +126374,12 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
126248
126374
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
126249
126375
|
}, null, 2);
|
|
126250
126376
|
}
|
|
126251
|
-
const evidenceDir =
|
|
126377
|
+
const evidenceDir = path162.dirname(validatedPath);
|
|
126252
126378
|
try {
|
|
126253
|
-
await
|
|
126254
|
-
const tempPath =
|
|
126255
|
-
await
|
|
126256
|
-
await
|
|
126379
|
+
await fs119.promises.mkdir(evidenceDir, { recursive: true });
|
|
126380
|
+
const tempPath = path162.join(evidenceDir, `.${filename}.tmp`);
|
|
126381
|
+
await fs119.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
126382
|
+
await fs119.promises.rename(tempPath, validatedPath);
|
|
126257
126383
|
let snapshotInfo;
|
|
126258
126384
|
let snapshotError;
|
|
126259
126385
|
let qaProfileLocked;
|
|
@@ -126346,8 +126472,8 @@ var write_drift_evidence = createSwarmTool({
|
|
|
126346
126472
|
// src/tools/write-final-council-evidence.ts
|
|
126347
126473
|
init_zod();
|
|
126348
126474
|
init_loader();
|
|
126349
|
-
import
|
|
126350
|
-
import
|
|
126475
|
+
import fs120 from "node:fs";
|
|
126476
|
+
import path163 from "node:path";
|
|
126351
126477
|
init_utils2();
|
|
126352
126478
|
init_manager();
|
|
126353
126479
|
init_create_tool();
|
|
@@ -126435,7 +126561,7 @@ async function executeWriteFinalCouncilEvidence(args2, directory) {
|
|
|
126435
126561
|
timestamp: synthesis.timestamp
|
|
126436
126562
|
};
|
|
126437
126563
|
const filename = "final-council.json";
|
|
126438
|
-
const relativePath =
|
|
126564
|
+
const relativePath = path163.join("evidence", filename);
|
|
126439
126565
|
let validatedPath;
|
|
126440
126566
|
try {
|
|
126441
126567
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -126449,12 +126575,12 @@ async function executeWriteFinalCouncilEvidence(args2, directory) {
|
|
|
126449
126575
|
const evidenceContent = {
|
|
126450
126576
|
entries: [evidenceEntry]
|
|
126451
126577
|
};
|
|
126452
|
-
const evidenceDir =
|
|
126578
|
+
const evidenceDir = path163.dirname(validatedPath);
|
|
126453
126579
|
try {
|
|
126454
|
-
await
|
|
126455
|
-
const tempPath =
|
|
126456
|
-
await
|
|
126457
|
-
await
|
|
126580
|
+
await fs120.promises.mkdir(evidenceDir, { recursive: true });
|
|
126581
|
+
const tempPath = path163.join(evidenceDir, `.${filename}.tmp`);
|
|
126582
|
+
await fs120.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
126583
|
+
await fs120.promises.rename(tempPath, validatedPath);
|
|
126458
126584
|
return JSON.stringify({
|
|
126459
126585
|
success: true,
|
|
126460
126586
|
phase: input.phase,
|
|
@@ -126510,8 +126636,8 @@ var write_final_council_evidence = createSwarmTool({
|
|
|
126510
126636
|
init_zod();
|
|
126511
126637
|
init_utils2();
|
|
126512
126638
|
init_create_tool();
|
|
126513
|
-
import
|
|
126514
|
-
import
|
|
126639
|
+
import fs121 from "node:fs";
|
|
126640
|
+
import path164 from "node:path";
|
|
126515
126641
|
function normalizeVerdict2(verdict) {
|
|
126516
126642
|
switch (verdict) {
|
|
126517
126643
|
case "APPROVED":
|
|
@@ -126559,7 +126685,7 @@ async function executeWriteHallucinationEvidence(args2, directory) {
|
|
|
126559
126685
|
entries: [evidenceEntry]
|
|
126560
126686
|
};
|
|
126561
126687
|
const filename = "hallucination-guard.json";
|
|
126562
|
-
const relativePath =
|
|
126688
|
+
const relativePath = path164.join("evidence", String(phase), filename);
|
|
126563
126689
|
let validatedPath;
|
|
126564
126690
|
try {
|
|
126565
126691
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -126570,12 +126696,12 @@ async function executeWriteHallucinationEvidence(args2, directory) {
|
|
|
126570
126696
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
126571
126697
|
}, null, 2);
|
|
126572
126698
|
}
|
|
126573
|
-
const evidenceDir =
|
|
126699
|
+
const evidenceDir = path164.dirname(validatedPath);
|
|
126574
126700
|
try {
|
|
126575
|
-
await
|
|
126576
|
-
const tempPath =
|
|
126577
|
-
await
|
|
126578
|
-
await
|
|
126701
|
+
await fs121.promises.mkdir(evidenceDir, { recursive: true });
|
|
126702
|
+
const tempPath = path164.join(evidenceDir, `.${filename}.tmp`);
|
|
126703
|
+
await fs121.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
126704
|
+
await fs121.promises.rename(tempPath, validatedPath);
|
|
126579
126705
|
return JSON.stringify({
|
|
126580
126706
|
success: true,
|
|
126581
126707
|
phase,
|
|
@@ -126621,8 +126747,8 @@ var write_hallucination_evidence = createSwarmTool({
|
|
|
126621
126747
|
init_zod();
|
|
126622
126748
|
init_utils2();
|
|
126623
126749
|
init_create_tool();
|
|
126624
|
-
import
|
|
126625
|
-
import
|
|
126750
|
+
import fs122 from "node:fs";
|
|
126751
|
+
import path165 from "node:path";
|
|
126626
126752
|
function normalizeVerdict3(verdict) {
|
|
126627
126753
|
switch (verdict) {
|
|
126628
126754
|
case "PASS":
|
|
@@ -126696,7 +126822,7 @@ async function executeWriteMutationEvidence(args2, directory) {
|
|
|
126696
126822
|
entries: [evidenceEntry]
|
|
126697
126823
|
};
|
|
126698
126824
|
const filename = "mutation-gate.json";
|
|
126699
|
-
const relativePath =
|
|
126825
|
+
const relativePath = path165.join("evidence", String(phase), filename);
|
|
126700
126826
|
let validatedPath;
|
|
126701
126827
|
try {
|
|
126702
126828
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -126707,12 +126833,12 @@ async function executeWriteMutationEvidence(args2, directory) {
|
|
|
126707
126833
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
126708
126834
|
}, null, 2);
|
|
126709
126835
|
}
|
|
126710
|
-
const evidenceDir =
|
|
126836
|
+
const evidenceDir = path165.dirname(validatedPath);
|
|
126711
126837
|
try {
|
|
126712
|
-
await
|
|
126713
|
-
const tempPath =
|
|
126714
|
-
await
|
|
126715
|
-
await
|
|
126838
|
+
await fs122.promises.mkdir(evidenceDir, { recursive: true });
|
|
126839
|
+
const tempPath = path165.join(evidenceDir, `.${filename}.tmp`);
|
|
126840
|
+
await fs122.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
126841
|
+
await fs122.promises.rename(tempPath, validatedPath);
|
|
126716
126842
|
return JSON.stringify({
|
|
126717
126843
|
success: true,
|
|
126718
126844
|
phase,
|
|
@@ -127060,7 +127186,7 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
127060
127186
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
127061
127187
|
preflightTriggerManager = new PTM(automationConfig);
|
|
127062
127188
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
127063
|
-
const swarmDir =
|
|
127189
|
+
const swarmDir = path167.resolve(ctx.directory, ".swarm");
|
|
127064
127190
|
statusArtifact = new ASA(swarmDir);
|
|
127065
127191
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
127066
127192
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|
|
@@ -127657,7 +127783,7 @@ ${promptRaw}`;
|
|
|
127657
127783
|
const meta3 = readSkillMetadata(s.skillPath, ctx.directory);
|
|
127658
127784
|
let desc = meta3.description || "";
|
|
127659
127785
|
if (!desc || desc === "No description provided") {
|
|
127660
|
-
desc =
|
|
127786
|
+
desc = path167.basename(path167.dirname(s.skillPath));
|
|
127661
127787
|
}
|
|
127662
127788
|
desc = desc.replace(/,/g, ";");
|
|
127663
127789
|
return `file:${s.skillPath} (-- ${desc})`;
|
|
@@ -127667,7 +127793,7 @@ ${promptRaw}`;
|
|
|
127667
127793
|
|
|
127668
127794
|
${promptRaw}`;
|
|
127669
127795
|
argsRecord.prompt = newPrompt;
|
|
127670
|
-
const skillNames = topSkills.map((s) => `${
|
|
127796
|
+
const skillNames = topSkills.map((s) => `${path167.basename(s.skillPath)} (score: ${s.score.toFixed(2)})`).join(", ");
|
|
127671
127797
|
console.warn(`[skill-propagation-gate] Injected skills: ${skillNames}`);
|
|
127672
127798
|
for (const skill of topSkills) {
|
|
127673
127799
|
try {
|