opencode-swarm 7.20.2 → 7.21.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 +1 -1
- package/dist/hooks/skill-propagation-gate.d.ts +113 -0
- package/dist/hooks/skill-scoring.d.ts +127 -0
- package/dist/hooks/skill-usage-log.d.ts +109 -0
- package/dist/index.js +1476 -759
- package/dist/tools/update-task-status.d.ts +4 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -33,7 +33,7 @@ var package_default;
|
|
|
33
33
|
var init_package = __esm(() => {
|
|
34
34
|
package_default = {
|
|
35
35
|
name: "opencode-swarm",
|
|
36
|
-
version: "7.
|
|
36
|
+
version: "7.21.1",
|
|
37
37
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
38
38
|
main: "dist/index.js",
|
|
39
39
|
types: "dist/index.d.ts",
|
|
@@ -62852,9 +62852,14 @@ At session start, before your first delegation:
|
|
|
62852
62852
|
1. Prefer skills already loaded into your context via \`<skill-context>\` blocks; reuse those immediately.
|
|
62853
62853
|
2. When you need to inspect on-disk skills, use the \`search\` tool with \`include\` patterns like \`.opencode/skills/*/SKILL.md,.claude/skills/*/SKILL.md\` and frontmatter queries such as \`^name:\` / \`^description:\` so you only read the YAML lines you need.
|
|
62854
62854
|
3. Write a brief skill index to \`.swarm/context.md\` under \`## Available Skills\`:
|
|
62855
|
-
- writing-tests: Guidelines for writing tests (
|
|
62856
|
-
- engineering-conventions: Engineering invariants
|
|
62857
|
-
- [name]: [description] → [applicable agents]
|
|
62855
|
+
- writing-tests: Guidelines for writing tests (used: 12, compliance: 95%) → test_engineer, coder
|
|
62856
|
+
- engineering-conventions: Engineering invariants (used: 8, compliance: 100%) → coder, reviewer, test_engineer
|
|
62857
|
+
- [name]: [description] (used: N, compliance: N%) → [applicable agents]
|
|
62858
|
+
|
|
62859
|
+
If \`.swarm/skill-usage.jsonl\` exists, read it at session start to inform skill prioritization. Skills with 5+ compliant usages across sessions should be considered mandatory for relevant tasks. Read \`.swarm/skill-usage.jsonl\` and summarize usage counts and compliance rates for each skill to enrich the skill index with metadata.
|
|
62860
|
+
|
|
62861
|
+
If skill-usage.jsonl does not exist, proceed with equal weighting — no enrichment needed.
|
|
62862
|
+
|
|
62858
62863
|
4. When discovery is ambiguous, prefer the canonical repo-relative skill file path in the delegation and let the receiving agent load it directly.
|
|
62859
62864
|
|
|
62860
62865
|
### Step 2 — Route skills to agents
|
|
@@ -62892,6 +62897,12 @@ Default to repo-relative \`file:\` references for coder, reviewer, test_engineer
|
|
|
62892
62897
|
|
|
62893
62898
|
**Mandatory for coding tasks:** Always provide \`writing-tests\` to test_engineer and \`engineering-conventions\` to coder + reviewer when those skills are present in the project. Prefer \`file:\` references when the files exist.
|
|
62894
62899
|
|
|
62900
|
+
### Step 4 — Forward skills to reviewer
|
|
62901
|
+
|
|
62902
|
+
When delegating to the reviewer after a coder task, include a \`SKILLS_USED_BY_CODER: [comma-separated list of skill paths from the coder delegation]\` field. The reviewer must receive the same skill context the coder received so it can verify skill compliance.
|
|
62903
|
+
|
|
62904
|
+
Example: If the coder received \`SKILLS: file:.claude/skills/writing-tests/SKILL.md\`, the reviewer delegation must include \`SKILLS_USED_BY_CODER: file:.claude/skills/writing-tests/SKILL.md\` in addition to the reviewer's own \`SKILLS:\` field.
|
|
62905
|
+
|
|
62895
62906
|
## SWARM KNOWLEDGE DIRECTIVES (v2 acknowledgment contract)
|
|
62896
62907
|
|
|
62897
62908
|
If a \`<swarm_knowledge_directives>\` block is present in your context, treat each
|
|
@@ -62942,6 +62953,7 @@ Continue handling small touch-ups (typos, cross-references) inline.
|
|
|
62942
62953
|
- ✗ "I don't know which skill is relevant" → When uncertain, pass ALL discovered skills. Subagents discard inapplicable content.
|
|
62943
62954
|
- ✗ "The skill was loaded earlier so the agent knows it" → Each subagent Task call is a fresh context. Skills do NOT persist across Task boundaries.
|
|
62944
62955
|
- ✗ "I'll paste the whole skill body every time just to be safe" → Inline bodies are fallback only. Prefer \`file:\` references to avoid unnecessary context bloat.
|
|
62956
|
+
- ✗ "The reviewer doesn't need the coder's skills" → WRONG. The reviewer cannot verify skill compliance without knowing what skills the coder received. Always forward via SKILLS_USED_BY_CODER.
|
|
62945
62957
|
|
|
62946
62958
|
## SLASH COMMANDS
|
|
62947
62959
|
{{SLASH_COMMANDS}}
|
|
@@ -63002,6 +63014,7 @@ TASK: Review login validation
|
|
|
63002
63014
|
FILE: src/auth/login.ts
|
|
63003
63015
|
CHECK: [security, correctness, edge-cases]
|
|
63004
63016
|
GATES: lint=PASS, sast_scan=PASS, secretscan=PASS
|
|
63017
|
+
SKILLS_USED_BY_CODER: file:.claude/skills/engineering-conventions/SKILL.md
|
|
63005
63018
|
OUTPUT: VERDICT + RISK + ISSUES
|
|
63006
63019
|
SKILLS: file:.claude/skills/engineering-conventions/SKILL.md
|
|
63007
63020
|
|
|
@@ -65696,6 +65709,7 @@ AFFECTS: [callers/consumers/dependents to inspect, or "infer from diff"]
|
|
|
65696
65709
|
CHECK: [list of dimensions to evaluate]
|
|
65697
65710
|
GATES: [pre-completed gate results (lint, SAST, secretscan, etc.), or "none" if unavailable]
|
|
65698
65711
|
SKILLS: [optional — either "none", repo-relative file: references (preferred), or inline skill content pasted by architect]
|
|
65712
|
+
SKILLS_USED_BY_CODER: [list of skill paths that were passed to the coder for this task, or "none" if no skills were used]
|
|
65699
65713
|
|
|
65700
65714
|
SKILLS HANDLING: If SKILLS is present and not "none", load EVERY referenced skill before beginning your review.
|
|
65701
65715
|
- For \`file:\` entries, use the search tool to read the referenced \`SKILL.md\` file with \`include\` set to that exact repo-relative path, \`mode: regex\`, \`query: .*\`, \`max_results: 1000\`, and \`max_lines: 1000\`.
|
|
@@ -65704,6 +65718,13 @@ SKILLS HANDLING: If SKILLS is present and not "none", load EVERY referenced skil
|
|
|
65704
65718
|
- If inline \`--- skill-name ---\` sections are present, read them directly.
|
|
65705
65719
|
- Skills contain project-specific constraints (coding standards, architectural invariants, security requirements) that supplement and may extend your normal review dimensions. Flag any violation of a skill rule at the same severity as a logic error.
|
|
65706
65720
|
|
|
65721
|
+
SKILL COMPLIANCE REVIEW: When SKILLS_USED_BY_CODER is provided and not "none":
|
|
65722
|
+
- Load each skill the coder received using the same SKILLS HANDLING procedure above
|
|
65723
|
+
- For each skill rule, verify the coder's changes comply
|
|
65724
|
+
- Flag violations at the same severity as logic errors
|
|
65725
|
+
- Report the overall compliance verdict in SKILL_COMPLIANCE field of your output
|
|
65726
|
+
- If you cannot load a skill (SKILL_LOAD_FAILED), report SKILL_COMPLIANCE: PARTIAL — [skill path] could not be loaded
|
|
65727
|
+
|
|
65707
65728
|
PROCESSING: If GATES is provided and includes passing results for lint, SAST, placeholder-scan, or secret-scan: skip the corresponding Tier 2 checks that those gates already cover. Focus Tier 2 time on checks NOT covered by automated gates.
|
|
65708
65729
|
|
|
65709
65730
|
## OUTPUT FORMAT (MANDATORY — deviations will be rejected)
|
|
@@ -65713,6 +65734,7 @@ VERDICT: APPROVED | REJECTED
|
|
|
65713
65734
|
REUSE_RE_VERIFICATION: [VERIFIED | DUPLICATION_DETECTED | SKIPPED] — DUPLICATION_DETECTED is only valid when VERDICT is REJECTED
|
|
65714
65735
|
RISK: LOW | MEDIUM | HIGH | CRITICAL
|
|
65715
65736
|
ISSUES: list with line numbers, grouped by CHECK dimension
|
|
65737
|
+
SKILL_COMPLIANCE: COMPLIANT | PARTIAL | VIOLATED — [list of violations or "all rules followed"]
|
|
65716
65738
|
FIXES: required changes if rejected
|
|
65717
65739
|
Use INFO only inside ISSUES for non-blocking suggestions. RISK reflects the highest blocking severity, so it never uses INFO.
|
|
65718
65740
|
|
|
@@ -71634,15 +71656,15 @@ var init_curator_drift = __esm(() => {
|
|
|
71634
71656
|
var exports_project_context = {};
|
|
71635
71657
|
__export(exports_project_context, {
|
|
71636
71658
|
buildProjectContext: () => buildProjectContext,
|
|
71637
|
-
_internals: () =>
|
|
71659
|
+
_internals: () => _internals55,
|
|
71638
71660
|
LANG_BACKEND_DETECTION_TIMEOUT_MS: () => LANG_BACKEND_DETECTION_TIMEOUT_MS
|
|
71639
71661
|
});
|
|
71640
|
-
import * as
|
|
71641
|
-
import * as
|
|
71662
|
+
import * as fs112 from "node:fs";
|
|
71663
|
+
import * as path142 from "node:path";
|
|
71642
71664
|
function detectFileExists2(directory, pattern) {
|
|
71643
71665
|
if (pattern.includes("*") || pattern.includes("?")) {
|
|
71644
71666
|
try {
|
|
71645
|
-
const files =
|
|
71667
|
+
const files = fs112.readdirSync(directory);
|
|
71646
71668
|
const regex = new RegExp(`^${pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".")}$`);
|
|
71647
71669
|
return files.some((f) => regex.test(f));
|
|
71648
71670
|
} catch {
|
|
@@ -71650,7 +71672,7 @@ function detectFileExists2(directory, pattern) {
|
|
|
71650
71672
|
}
|
|
71651
71673
|
}
|
|
71652
71674
|
try {
|
|
71653
|
-
|
|
71675
|
+
fs112.accessSync(path142.join(directory, pattern));
|
|
71654
71676
|
return true;
|
|
71655
71677
|
} catch {
|
|
71656
71678
|
return false;
|
|
@@ -71659,7 +71681,7 @@ function detectFileExists2(directory, pattern) {
|
|
|
71659
71681
|
function selectTestCommandFromScriptsTest(backend, directory) {
|
|
71660
71682
|
let pkgRaw;
|
|
71661
71683
|
try {
|
|
71662
|
-
pkgRaw =
|
|
71684
|
+
pkgRaw = fs112.readFileSync(path142.join(directory, "package.json"), "utf-8");
|
|
71663
71685
|
} catch {
|
|
71664
71686
|
return null;
|
|
71665
71687
|
}
|
|
@@ -71718,7 +71740,7 @@ function selectLintCommand(backend, directory) {
|
|
|
71718
71740
|
return null;
|
|
71719
71741
|
}
|
|
71720
71742
|
async function buildProjectContext(directory) {
|
|
71721
|
-
const backend = await
|
|
71743
|
+
const backend = await _internals55.pickBackend(directory);
|
|
71722
71744
|
if (!backend)
|
|
71723
71745
|
return null;
|
|
71724
71746
|
const ctx = emptyProjectContext();
|
|
@@ -71749,16 +71771,16 @@ async function buildProjectContext(directory) {
|
|
|
71749
71771
|
if (backend.prompts.reviewerChecklist.length > 0) {
|
|
71750
71772
|
ctx.REVIEWER_CHECKLIST = bulletList(backend.prompts.reviewerChecklist);
|
|
71751
71773
|
}
|
|
71752
|
-
const profiles =
|
|
71774
|
+
const profiles = _internals55.pickedProfiles(directory);
|
|
71753
71775
|
if (profiles.length > 1) {
|
|
71754
71776
|
ctx.PROJECT_CONTEXT_SECONDARY_LANGUAGES = profiles.slice(1).map((p) => p.id).join(", ");
|
|
71755
71777
|
}
|
|
71756
71778
|
return ctx;
|
|
71757
71779
|
}
|
|
71758
|
-
var LANG_BACKEND_DETECTION_TIMEOUT_MS = 300,
|
|
71780
|
+
var LANG_BACKEND_DETECTION_TIMEOUT_MS = 300, _internals55;
|
|
71759
71781
|
var init_project_context = __esm(() => {
|
|
71760
71782
|
init_dispatch();
|
|
71761
|
-
|
|
71783
|
+
_internals55 = {
|
|
71762
71784
|
pickBackend,
|
|
71763
71785
|
pickedProfiles
|
|
71764
71786
|
};
|
|
@@ -71768,7 +71790,7 @@ var init_project_context = __esm(() => {
|
|
|
71768
71790
|
init_package();
|
|
71769
71791
|
init_agents2();
|
|
71770
71792
|
init_critic();
|
|
71771
|
-
import * as
|
|
71793
|
+
import * as path143 from "node:path";
|
|
71772
71794
|
|
|
71773
71795
|
// src/background/index.ts
|
|
71774
71796
|
init_event_bus();
|
|
@@ -82651,9 +82673,702 @@ function createSelfReviewHook(config3, injectAdvisory) {
|
|
|
82651
82673
|
};
|
|
82652
82674
|
}
|
|
82653
82675
|
|
|
82654
|
-
// src/hooks/
|
|
82676
|
+
// src/hooks/skill-propagation-gate.ts
|
|
82677
|
+
init_schema();
|
|
82678
|
+
init_logger();
|
|
82679
|
+
import * as fs62 from "node:fs";
|
|
82680
|
+
import * as path89 from "node:path";
|
|
82681
|
+
|
|
82682
|
+
// src/hooks/skill-scoring.ts
|
|
82683
|
+
import * as path88 from "node:path";
|
|
82684
|
+
|
|
82685
|
+
// src/hooks/skill-usage-log.ts
|
|
82686
|
+
init_utils2();
|
|
82687
|
+
import * as crypto9 from "node:crypto";
|
|
82655
82688
|
import * as fs61 from "node:fs";
|
|
82656
82689
|
import * as path87 from "node:path";
|
|
82690
|
+
function resolveLogPath(directory) {
|
|
82691
|
+
return validateSwarmPath(directory, "skill-usage.jsonl");
|
|
82692
|
+
}
|
|
82693
|
+
var _internals40 = {
|
|
82694
|
+
generateId: () => crypto9.randomUUID(),
|
|
82695
|
+
appendFileSync: fs61.appendFileSync.bind(fs61),
|
|
82696
|
+
readFileSync: fs61.readFileSync.bind(fs61),
|
|
82697
|
+
writeFileSync: fs61.writeFileSync.bind(fs61),
|
|
82698
|
+
renameSync: fs61.renameSync.bind(fs61),
|
|
82699
|
+
mkdirSync: fs61.mkdirSync.bind(fs61),
|
|
82700
|
+
existsSync: fs61.existsSync.bind(fs61),
|
|
82701
|
+
statSync: fs61.statSync.bind(fs61),
|
|
82702
|
+
openSync: fs61.openSync.bind(fs61),
|
|
82703
|
+
readSync: fs61.readSync.bind(fs61),
|
|
82704
|
+
closeSync: fs61.closeSync.bind(fs61)
|
|
82705
|
+
};
|
|
82706
|
+
function appendSkillUsageEntry(directory, entry) {
|
|
82707
|
+
const {
|
|
82708
|
+
skillPath,
|
|
82709
|
+
agentName,
|
|
82710
|
+
taskID,
|
|
82711
|
+
timestamp,
|
|
82712
|
+
complianceVerdict,
|
|
82713
|
+
sessionID,
|
|
82714
|
+
reviewerNotes
|
|
82715
|
+
} = entry;
|
|
82716
|
+
if (!skillPath || typeof skillPath !== "string") {
|
|
82717
|
+
throw new Error("skillPath is required and must be a non-empty string");
|
|
82718
|
+
}
|
|
82719
|
+
if (/\.\.[/\\]/.test(skillPath)) {
|
|
82720
|
+
throw new Error("skillPath contains path traversal sequence");
|
|
82721
|
+
}
|
|
82722
|
+
if (!agentName || typeof agentName !== "string") {
|
|
82723
|
+
throw new Error("agentName is required and must be a non-empty string");
|
|
82724
|
+
}
|
|
82725
|
+
if (!taskID || typeof taskID !== "string") {
|
|
82726
|
+
throw new Error("taskID is required and must be a non-empty string");
|
|
82727
|
+
}
|
|
82728
|
+
if (!timestamp || typeof timestamp !== "string") {
|
|
82729
|
+
throw new Error("timestamp is required and must be a non-empty string");
|
|
82730
|
+
}
|
|
82731
|
+
if (!complianceVerdict || typeof complianceVerdict !== "string") {
|
|
82732
|
+
throw new Error("complianceVerdict is required and must be a non-empty string");
|
|
82733
|
+
}
|
|
82734
|
+
if (!sessionID || typeof sessionID !== "string") {
|
|
82735
|
+
throw new Error("sessionID is required and must be a non-empty string");
|
|
82736
|
+
}
|
|
82737
|
+
const resolved = validateSwarmPath(directory, "skill-usage.jsonl");
|
|
82738
|
+
const dir = path87.dirname(resolved);
|
|
82739
|
+
if (!_internals40.existsSync(dir)) {
|
|
82740
|
+
_internals40.mkdirSync(dir, { recursive: true });
|
|
82741
|
+
}
|
|
82742
|
+
const fullEntry = {
|
|
82743
|
+
id: _internals40.generateId(),
|
|
82744
|
+
skillPath,
|
|
82745
|
+
agentName,
|
|
82746
|
+
taskID,
|
|
82747
|
+
timestamp,
|
|
82748
|
+
complianceVerdict,
|
|
82749
|
+
sessionID,
|
|
82750
|
+
...reviewerNotes !== undefined && { reviewerNotes }
|
|
82751
|
+
};
|
|
82752
|
+
_internals40.appendFileSync(resolved, `${JSON.stringify(fullEntry)}
|
|
82753
|
+
`, "utf-8");
|
|
82754
|
+
}
|
|
82755
|
+
function readSkillUsageEntries(directory, options) {
|
|
82756
|
+
const resolved = resolveLogPath(directory);
|
|
82757
|
+
if (!_internals40.existsSync(resolved)) {
|
|
82758
|
+
return [];
|
|
82759
|
+
}
|
|
82760
|
+
const raw = _internals40.readFileSync(resolved, "utf-8");
|
|
82761
|
+
const entries = [];
|
|
82762
|
+
for (const line of raw.split(`
|
|
82763
|
+
`)) {
|
|
82764
|
+
const trimmed = line.trim();
|
|
82765
|
+
if (!trimmed)
|
|
82766
|
+
continue;
|
|
82767
|
+
try {
|
|
82768
|
+
entries.push(JSON.parse(trimmed));
|
|
82769
|
+
} catch {}
|
|
82770
|
+
}
|
|
82771
|
+
if (!options)
|
|
82772
|
+
return entries;
|
|
82773
|
+
return entries.filter((e) => {
|
|
82774
|
+
if (options.sessionID !== undefined && e.sessionID !== options.sessionID) {
|
|
82775
|
+
return false;
|
|
82776
|
+
}
|
|
82777
|
+
if (options.skillPath !== undefined && e.skillPath !== options.skillPath) {
|
|
82778
|
+
return false;
|
|
82779
|
+
}
|
|
82780
|
+
if (options.agentName !== undefined && e.agentName !== options.agentName) {
|
|
82781
|
+
return false;
|
|
82782
|
+
}
|
|
82783
|
+
if (options.taskID !== undefined && e.taskID !== options.taskID) {
|
|
82784
|
+
return false;
|
|
82785
|
+
}
|
|
82786
|
+
if (options.dateRange !== undefined) {
|
|
82787
|
+
if (e.timestamp < options.dateRange.start)
|
|
82788
|
+
return false;
|
|
82789
|
+
if (e.timestamp > options.dateRange.end)
|
|
82790
|
+
return false;
|
|
82791
|
+
}
|
|
82792
|
+
return true;
|
|
82793
|
+
});
|
|
82794
|
+
}
|
|
82795
|
+
var TAIL_BYTES_DEFAULT = 64 * 1024;
|
|
82796
|
+
function readSkillUsageEntriesTail(directory, filters, maxBytes = TAIL_BYTES_DEFAULT) {
|
|
82797
|
+
const logPath = resolveLogPath(directory);
|
|
82798
|
+
if (!_internals40.existsSync(logPath))
|
|
82799
|
+
return [];
|
|
82800
|
+
try {
|
|
82801
|
+
const stat7 = _internals40.statSync(logPath);
|
|
82802
|
+
const start2 = Math.max(0, stat7.size - maxBytes);
|
|
82803
|
+
const fd = _internals40.openSync(logPath, "r");
|
|
82804
|
+
try {
|
|
82805
|
+
const readLen = stat7.size - start2;
|
|
82806
|
+
if (readLen === 0)
|
|
82807
|
+
return [];
|
|
82808
|
+
const buf = Buffer.alloc(readLen);
|
|
82809
|
+
_internals40.readSync(fd, buf, 0, buf.length, start2);
|
|
82810
|
+
const content = buf.toString("utf-8");
|
|
82811
|
+
let usable;
|
|
82812
|
+
if (start2 > 0) {
|
|
82813
|
+
const firstNewline = content.indexOf(`
|
|
82814
|
+
`);
|
|
82815
|
+
usable = firstNewline >= 0 ? content.slice(firstNewline + 1) : "";
|
|
82816
|
+
} else {
|
|
82817
|
+
usable = content;
|
|
82818
|
+
}
|
|
82819
|
+
const entries = [];
|
|
82820
|
+
for (const line of usable.split(`
|
|
82821
|
+
`)) {
|
|
82822
|
+
if (!line.trim())
|
|
82823
|
+
continue;
|
|
82824
|
+
try {
|
|
82825
|
+
const entry = JSON.parse(line);
|
|
82826
|
+
if (filters.sessionID !== undefined && entry.sessionID !== filters.sessionID) {
|
|
82827
|
+
continue;
|
|
82828
|
+
}
|
|
82829
|
+
entries.push(entry);
|
|
82830
|
+
} catch {}
|
|
82831
|
+
}
|
|
82832
|
+
return entries;
|
|
82833
|
+
} finally {
|
|
82834
|
+
_internals40.closeSync(fd);
|
|
82835
|
+
}
|
|
82836
|
+
} catch {
|
|
82837
|
+
return [];
|
|
82838
|
+
}
|
|
82839
|
+
}
|
|
82840
|
+
|
|
82841
|
+
// src/hooks/skill-scoring.ts
|
|
82842
|
+
var FREQUENCY_CAP = 10;
|
|
82843
|
+
var FREQUENCY_WEIGHT = 0.3;
|
|
82844
|
+
var COMPLIANCE_WEIGHT = 0.3;
|
|
82845
|
+
var RECENCY_WEIGHT = 0.15;
|
|
82846
|
+
var TASK_DIVERSITY_WEIGHT = 0.05;
|
|
82847
|
+
var CONTEXT_WEIGHT = 0.2;
|
|
82848
|
+
var RECENCY_DECAY_MS = 30 * 24 * 60 * 60 * 1000;
|
|
82849
|
+
var _internals41 = {
|
|
82850
|
+
computeSkillRelevanceScore: null,
|
|
82851
|
+
rankSkillsForContext: null,
|
|
82852
|
+
getSkillStats: null,
|
|
82853
|
+
formatSkillIndexWithContext: null,
|
|
82854
|
+
extractSkillName: null,
|
|
82855
|
+
computeRecencyScore: null,
|
|
82856
|
+
computeContextMatchScore: null
|
|
82857
|
+
};
|
|
82858
|
+
function extractSkillName(skillPath) {
|
|
82859
|
+
const base = path88.basename(skillPath, path88.extname(skillPath));
|
|
82860
|
+
if (base !== "SKILL")
|
|
82861
|
+
return base;
|
|
82862
|
+
const parent = path88.basename(path88.dirname(skillPath));
|
|
82863
|
+
return parent;
|
|
82864
|
+
}
|
|
82865
|
+
function computeRecencyScore(lastUsedTimestamp) {
|
|
82866
|
+
if (!lastUsedTimestamp)
|
|
82867
|
+
return 0;
|
|
82868
|
+
const lastUsed = new Date(lastUsedTimestamp).getTime();
|
|
82869
|
+
if (Number.isNaN(lastUsed))
|
|
82870
|
+
return 0;
|
|
82871
|
+
const ageMs = Date.now() - lastUsed;
|
|
82872
|
+
if (ageMs <= 0)
|
|
82873
|
+
return 1;
|
|
82874
|
+
if (ageMs >= RECENCY_DECAY_MS)
|
|
82875
|
+
return 0;
|
|
82876
|
+
return 1 - ageMs / RECENCY_DECAY_MS;
|
|
82877
|
+
}
|
|
82878
|
+
var MIN_KEYWORD_LENGTH = 3;
|
|
82879
|
+
function extractKeywords(text) {
|
|
82880
|
+
const words = text.toLowerCase().split(/[^a-z0-9]+/).filter((w) => w.length >= MIN_KEYWORD_LENGTH);
|
|
82881
|
+
return new Set(words);
|
|
82882
|
+
}
|
|
82883
|
+
function computeContextMatchScore(taskDescription, skillPath) {
|
|
82884
|
+
const taskKeywords = extractKeywords(taskDescription);
|
|
82885
|
+
if (taskKeywords.size === 0)
|
|
82886
|
+
return 0;
|
|
82887
|
+
const skillName = extractSkillName(skillPath);
|
|
82888
|
+
const skillText = `${skillPath} ${skillName}`;
|
|
82889
|
+
const skillKeywords = extractKeywords(skillText);
|
|
82890
|
+
let matchCount = 0;
|
|
82891
|
+
for (const kw of taskKeywords) {
|
|
82892
|
+
if (skillKeywords.has(kw)) {
|
|
82893
|
+
matchCount++;
|
|
82894
|
+
}
|
|
82895
|
+
}
|
|
82896
|
+
return matchCount / taskKeywords.size;
|
|
82897
|
+
}
|
|
82898
|
+
function computeSkillRelevanceScore(skillPath, taskDescription, usageHistory) {
|
|
82899
|
+
const contextScore = computeContextMatchScore(taskDescription, skillPath) * CONTEXT_WEIGHT;
|
|
82900
|
+
if (usageHistory.length === 0)
|
|
82901
|
+
return contextScore;
|
|
82902
|
+
const usageCount = usageHistory.length;
|
|
82903
|
+
const frequencyScore = Math.min(1, usageCount / FREQUENCY_CAP) * FREQUENCY_WEIGHT;
|
|
82904
|
+
const entriesWithVerdict = usageHistory.filter((e) => e.complianceVerdict !== undefined && e.complianceVerdict !== "not_checked");
|
|
82905
|
+
const compliantCount = entriesWithVerdict.filter((e) => e.complianceVerdict === "compliant").length;
|
|
82906
|
+
const denominator = Math.max(1, entriesWithVerdict.length);
|
|
82907
|
+
const complianceScore = compliantCount / denominator * COMPLIANCE_WEIGHT;
|
|
82908
|
+
const sortedByTime = [...usageHistory].sort((a, b) => b.timestamp > a.timestamp ? 1 : b.timestamp < a.timestamp ? -1 : 0);
|
|
82909
|
+
const lastUsedTimestamp = sortedByTime[0]?.timestamp ?? "";
|
|
82910
|
+
const recencyScore = computeRecencyScore(lastUsedTimestamp) * RECENCY_WEIGHT;
|
|
82911
|
+
const distinctTaskIDs = new Set(usageHistory.map((e) => e.taskID).filter(Boolean)).size;
|
|
82912
|
+
const taskDiversityScore = distinctTaskIDs / Math.max(1, usageHistory.length) * TASK_DIVERSITY_WEIGHT;
|
|
82913
|
+
return frequencyScore + complianceScore + recencyScore + taskDiversityScore + contextScore;
|
|
82914
|
+
}
|
|
82915
|
+
function rankSkillsForContext(skills, taskContext, directory) {
|
|
82916
|
+
const allEntries = readSkillUsageEntries(directory);
|
|
82917
|
+
const results = [];
|
|
82918
|
+
for (const skillPath of skills) {
|
|
82919
|
+
const skillEntries = allEntries.filter((e) => e.skillPath === skillPath);
|
|
82920
|
+
const score = computeSkillRelevanceScore(skillPath, taskContext, skillEntries);
|
|
82921
|
+
const entriesWithVerdict = skillEntries.filter((e) => e.complianceVerdict !== undefined && e.complianceVerdict !== "not_checked");
|
|
82922
|
+
const compliantCount = entriesWithVerdict.filter((e) => e.complianceVerdict === "compliant").length;
|
|
82923
|
+
const complianceRate = entriesWithVerdict.length > 0 ? compliantCount / entriesWithVerdict.length : 0;
|
|
82924
|
+
results.push({
|
|
82925
|
+
skillPath,
|
|
82926
|
+
score,
|
|
82927
|
+
usageCount: skillEntries.length,
|
|
82928
|
+
complianceRate
|
|
82929
|
+
});
|
|
82930
|
+
}
|
|
82931
|
+
results.sort((a, b) => {
|
|
82932
|
+
if (b.score !== a.score)
|
|
82933
|
+
return b.score - a.score;
|
|
82934
|
+
return b.usageCount - a.usageCount;
|
|
82935
|
+
});
|
|
82936
|
+
return results;
|
|
82937
|
+
}
|
|
82938
|
+
function getSkillStats(skillPath, directory) {
|
|
82939
|
+
const entries = readSkillUsageEntries(directory, { skillPath });
|
|
82940
|
+
if (entries.length === 0) {
|
|
82941
|
+
return {
|
|
82942
|
+
totalUsage: 0,
|
|
82943
|
+
complianceRate: 0,
|
|
82944
|
+
lastUsed: "",
|
|
82945
|
+
topAgents: []
|
|
82946
|
+
};
|
|
82947
|
+
}
|
|
82948
|
+
const entriesWithVerdict = entries.filter((e) => e.complianceVerdict !== undefined && e.complianceVerdict !== "not_checked");
|
|
82949
|
+
const compliantCount = entriesWithVerdict.filter((e) => e.complianceVerdict === "compliant").length;
|
|
82950
|
+
const complianceRate = entriesWithVerdict.length > 0 ? compliantCount / entriesWithVerdict.length : 0;
|
|
82951
|
+
const sortedByTime = [...entries].sort((a, b) => b.timestamp > a.timestamp ? 1 : b.timestamp < a.timestamp ? -1 : 0);
|
|
82952
|
+
const lastUsed = sortedByTime[0]?.timestamp ?? "";
|
|
82953
|
+
const agentCounts = new Map;
|
|
82954
|
+
for (const entry of entries) {
|
|
82955
|
+
agentCounts.set(entry.agentName, (agentCounts.get(entry.agentName) ?? 0) + 1);
|
|
82956
|
+
}
|
|
82957
|
+
const topAgents = Array.from(agentCounts.entries()).sort((a, b) => b[1] - a[1]).map(([agent, count]) => ({ agent, count }));
|
|
82958
|
+
return {
|
|
82959
|
+
totalUsage: entries.length,
|
|
82960
|
+
complianceRate,
|
|
82961
|
+
lastUsed,
|
|
82962
|
+
topAgents
|
|
82963
|
+
};
|
|
82964
|
+
}
|
|
82965
|
+
function formatSkillIndexWithContext(skills, directory) {
|
|
82966
|
+
const allEntries = readSkillUsageEntries(directory);
|
|
82967
|
+
const hasHistory = allEntries.length > 0;
|
|
82968
|
+
if (!hasHistory) {
|
|
82969
|
+
return skills.map((sp) => ` - ${extractSkillName(sp)}`).join(`
|
|
82970
|
+
`);
|
|
82971
|
+
}
|
|
82972
|
+
const lines = [];
|
|
82973
|
+
for (const skillPath of skills) {
|
|
82974
|
+
const stats = getSkillStats(skillPath, directory);
|
|
82975
|
+
const name2 = extractSkillName(skillPath);
|
|
82976
|
+
const compliancePct = Math.round(stats.complianceRate * 100);
|
|
82977
|
+
const topAgentNames = stats.topAgents.slice(0, 3).map((a) => a.agent).join(", ");
|
|
82978
|
+
lines.push(` ${name2}: ${skillPath} (used: ${stats.totalUsage}, compliance: ${compliancePct}%)` + (stats.topAgents.length > 0 ? ` → ${topAgentNames}` : ""));
|
|
82979
|
+
}
|
|
82980
|
+
return lines.join(`
|
|
82981
|
+
`);
|
|
82982
|
+
}
|
|
82983
|
+
_internals41.computeSkillRelevanceScore = computeSkillRelevanceScore;
|
|
82984
|
+
_internals41.rankSkillsForContext = rankSkillsForContext;
|
|
82985
|
+
_internals41.getSkillStats = getSkillStats;
|
|
82986
|
+
_internals41.formatSkillIndexWithContext = formatSkillIndexWithContext;
|
|
82987
|
+
_internals41.extractSkillName = extractSkillName;
|
|
82988
|
+
_internals41.computeRecencyScore = computeRecencyScore;
|
|
82989
|
+
_internals41.computeContextMatchScore = computeContextMatchScore;
|
|
82990
|
+
|
|
82991
|
+
// src/hooks/skill-propagation-gate.ts
|
|
82992
|
+
var SKILL_CAPABLE_AGENTS = new Set([
|
|
82993
|
+
"coder",
|
|
82994
|
+
"reviewer",
|
|
82995
|
+
"test_engineer",
|
|
82996
|
+
"sme",
|
|
82997
|
+
"docs",
|
|
82998
|
+
"designer"
|
|
82999
|
+
]);
|
|
83000
|
+
var SKILL_SEARCH_ROOTS = [
|
|
83001
|
+
".opencode/skills",
|
|
83002
|
+
".opencode/skills/generated",
|
|
83003
|
+
".claude/skills"
|
|
83004
|
+
];
|
|
83005
|
+
var MAX_SCORING_SESSION_ENTRIES = 500;
|
|
83006
|
+
var _internals42 = {
|
|
83007
|
+
readdirSync: fs62.readdirSync.bind(fs62),
|
|
83008
|
+
existsSync: fs62.existsSync.bind(fs62),
|
|
83009
|
+
statSync: fs62.statSync.bind(fs62),
|
|
83010
|
+
mkdirSync: fs62.mkdirSync.bind(fs62),
|
|
83011
|
+
appendFileSync: fs62.appendFileSync.bind(fs62),
|
|
83012
|
+
skillPropagationGateBefore: null,
|
|
83013
|
+
skillPropagationTransformScan: null,
|
|
83014
|
+
SKILL_CAPABLE_AGENTS,
|
|
83015
|
+
MAX_SCORING_SESSION_ENTRIES,
|
|
83016
|
+
writeWarnEvent: null,
|
|
83017
|
+
discoverAvailableSkills: null,
|
|
83018
|
+
parseDelegationArgs: null,
|
|
83019
|
+
appendSkillUsageEntry,
|
|
83020
|
+
readSkillUsageEntries,
|
|
83021
|
+
readSkillUsageEntriesTail,
|
|
83022
|
+
parseSkillPaths: null,
|
|
83023
|
+
extractTaskIdFromPrompt: null,
|
|
83024
|
+
computeSkillRelevanceScore
|
|
83025
|
+
};
|
|
83026
|
+
function discoverAvailableSkills(directory) {
|
|
83027
|
+
const results = [];
|
|
83028
|
+
for (const root of SKILL_SEARCH_ROOTS) {
|
|
83029
|
+
const rootPath = path89.join(directory, root);
|
|
83030
|
+
if (!_internals42.existsSync(rootPath))
|
|
83031
|
+
continue;
|
|
83032
|
+
let entries;
|
|
83033
|
+
try {
|
|
83034
|
+
entries = _internals42.readdirSync(rootPath);
|
|
83035
|
+
} catch {
|
|
83036
|
+
continue;
|
|
83037
|
+
}
|
|
83038
|
+
for (const entry of entries) {
|
|
83039
|
+
if (entry.startsWith("."))
|
|
83040
|
+
continue;
|
|
83041
|
+
const skillDir = path89.join(rootPath, entry);
|
|
83042
|
+
const skillFile = path89.join(skillDir, "SKILL.md");
|
|
83043
|
+
try {
|
|
83044
|
+
if (_internals42.statSync(skillDir).isDirectory() && _internals42.existsSync(skillFile)) {
|
|
83045
|
+
results.push(path89.join(root, entry, "SKILL.md"));
|
|
83046
|
+
}
|
|
83047
|
+
} catch (err2) {
|
|
83048
|
+
warn(`[skill-propagation-gate] failed to stat skill directory ${entry}: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
83049
|
+
}
|
|
83050
|
+
}
|
|
83051
|
+
}
|
|
83052
|
+
return [...new Set(results)];
|
|
83053
|
+
}
|
|
83054
|
+
function parseDelegationArgs(args2) {
|
|
83055
|
+
if (!args2 || typeof args2 !== "object")
|
|
83056
|
+
return null;
|
|
83057
|
+
const record3 = args2;
|
|
83058
|
+
const subagentType = typeof record3.subagent_type === "string" ? record3.subagent_type : "";
|
|
83059
|
+
const prompt = typeof record3.prompt === "string" ? record3.prompt : "";
|
|
83060
|
+
if (!subagentType && !prompt)
|
|
83061
|
+
return null;
|
|
83062
|
+
let targetAgent = subagentType;
|
|
83063
|
+
if (!targetAgent && prompt) {
|
|
83064
|
+
const lines = prompt.split(`
|
|
83065
|
+
`);
|
|
83066
|
+
for (const line of lines) {
|
|
83067
|
+
const trimmed = line.trim();
|
|
83068
|
+
if (trimmed) {
|
|
83069
|
+
targetAgent = trimmed;
|
|
83070
|
+
break;
|
|
83071
|
+
}
|
|
83072
|
+
}
|
|
83073
|
+
}
|
|
83074
|
+
if (!targetAgent)
|
|
83075
|
+
return null;
|
|
83076
|
+
let skillsField = "";
|
|
83077
|
+
if (prompt) {
|
|
83078
|
+
const lines = prompt.split(`
|
|
83079
|
+
`);
|
|
83080
|
+
for (const line of lines) {
|
|
83081
|
+
const trimmed = line.trim();
|
|
83082
|
+
if (trimmed.startsWith("SKILLS:")) {
|
|
83083
|
+
skillsField = trimmed.slice("SKILLS:".length).trim();
|
|
83084
|
+
break;
|
|
83085
|
+
}
|
|
83086
|
+
}
|
|
83087
|
+
}
|
|
83088
|
+
return { targetAgent, skillsField };
|
|
83089
|
+
}
|
|
83090
|
+
function writeWarnEvent2(directory, record3) {
|
|
83091
|
+
const filePath = path89.join(directory, ".swarm", "events.jsonl");
|
|
83092
|
+
try {
|
|
83093
|
+
const dir = path89.dirname(filePath);
|
|
83094
|
+
if (!_internals42.existsSync(dir)) {
|
|
83095
|
+
_internals42.mkdirSync(dir, { recursive: true });
|
|
83096
|
+
}
|
|
83097
|
+
_internals42.appendFileSync(filePath, `${JSON.stringify(record3)}
|
|
83098
|
+
`, "utf-8");
|
|
83099
|
+
} catch (err2) {
|
|
83100
|
+
warn(`[skill-propagation-gate] failed to write warning event: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
83101
|
+
}
|
|
83102
|
+
}
|
|
83103
|
+
function parseSkillPaths(fieldValue) {
|
|
83104
|
+
if (!fieldValue || typeof fieldValue !== "string")
|
|
83105
|
+
return [];
|
|
83106
|
+
const trimmed = fieldValue.trim();
|
|
83107
|
+
if (trimmed.toLowerCase() === "none" || trimmed === "")
|
|
83108
|
+
return [];
|
|
83109
|
+
return trimmed.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
83110
|
+
}
|
|
83111
|
+
function extractTaskIdFromPrompt(prompt) {
|
|
83112
|
+
if (!prompt || typeof prompt !== "string")
|
|
83113
|
+
return "unknown";
|
|
83114
|
+
const taskIdMatch = prompt.match(/\btaskId\s*[:=]\s*(\S+)/i);
|
|
83115
|
+
if (taskIdMatch)
|
|
83116
|
+
return taskIdMatch[1];
|
|
83117
|
+
const taskMatch = prompt.match(/\bTASK\s*[:=]\s*(\S+)/i);
|
|
83118
|
+
if (taskMatch)
|
|
83119
|
+
return taskMatch[1];
|
|
83120
|
+
return "unknown";
|
|
83121
|
+
}
|
|
83122
|
+
async function skillPropagationGateBefore(directory, input, config3) {
|
|
83123
|
+
if (!config3.enabled)
|
|
83124
|
+
return;
|
|
83125
|
+
const toolName = typeof input.tool === "string" ? input.tool : "";
|
|
83126
|
+
if (toolName !== "task" && toolName !== "Task")
|
|
83127
|
+
return;
|
|
83128
|
+
const agentRaw = typeof input.agent === "string" ? input.agent : "";
|
|
83129
|
+
if (!agentRaw)
|
|
83130
|
+
return;
|
|
83131
|
+
const baseAgent = stripKnownSwarmPrefix(agentRaw);
|
|
83132
|
+
if (baseAgent !== "architect")
|
|
83133
|
+
return;
|
|
83134
|
+
const parsed = _internals42.parseDelegationArgs(input.args);
|
|
83135
|
+
if (!parsed)
|
|
83136
|
+
return;
|
|
83137
|
+
const targetBase = stripKnownSwarmPrefix(parsed.targetAgent);
|
|
83138
|
+
if (!_internals42.SKILL_CAPABLE_AGENTS.has(targetBase))
|
|
83139
|
+
return;
|
|
83140
|
+
const sessionID = typeof input.sessionID === "string" ? input.sessionID : "unknown";
|
|
83141
|
+
const availableSkills = _internals42.discoverAvailableSkills(directory);
|
|
83142
|
+
const skillsValue = parsed.skillsField.trim();
|
|
83143
|
+
if (skillsValue && skillsValue.toLowerCase() !== "none") {
|
|
83144
|
+
const prompt = typeof input.args?.prompt === "string" ? String(input.args.prompt) : "";
|
|
83145
|
+
const taskId = _internals42.extractTaskIdFromPrompt(prompt);
|
|
83146
|
+
const skillPaths = _internals42.parseSkillPaths(skillsValue);
|
|
83147
|
+
let coderSkillPaths = [];
|
|
83148
|
+
if (prompt) {
|
|
83149
|
+
for (const line of prompt.split(`
|
|
83150
|
+
`)) {
|
|
83151
|
+
const trimmed = line.trim();
|
|
83152
|
+
if (trimmed.startsWith("SKILLS_USED_BY_CODER:")) {
|
|
83153
|
+
const fieldVal = trimmed.slice("SKILLS_USED_BY_CODER:".length).trim();
|
|
83154
|
+
coderSkillPaths = _internals42.parseSkillPaths(fieldVal);
|
|
83155
|
+
break;
|
|
83156
|
+
}
|
|
83157
|
+
}
|
|
83158
|
+
}
|
|
83159
|
+
const allPaths = [...new Set([...skillPaths, ...coderSkillPaths])];
|
|
83160
|
+
for (const skillPath of allPaths) {
|
|
83161
|
+
try {
|
|
83162
|
+
_internals42.appendSkillUsageEntry(directory, {
|
|
83163
|
+
skillPath,
|
|
83164
|
+
agentName: targetBase,
|
|
83165
|
+
taskID: taskId,
|
|
83166
|
+
complianceVerdict: "not_checked",
|
|
83167
|
+
sessionID,
|
|
83168
|
+
timestamp: new Date().toISOString()
|
|
83169
|
+
});
|
|
83170
|
+
} catch (err2) {
|
|
83171
|
+
warn(`[skill-propagation-gate] failed to record skill usage entry: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
83172
|
+
}
|
|
83173
|
+
}
|
|
83174
|
+
}
|
|
83175
|
+
if (skillsValue && skillsValue.toLowerCase() !== "none" && availableSkills.length > 0) {
|
|
83176
|
+
try {
|
|
83177
|
+
const sessionEntries = _internals42.readSkillUsageEntriesTail(directory, {
|
|
83178
|
+
sessionID
|
|
83179
|
+
});
|
|
83180
|
+
if (sessionEntries.length > _internals42.MAX_SCORING_SESSION_ENTRIES) {
|
|
83181
|
+
warn(`[skill-propagation-gate] skipping scoring — session has ${sessionEntries.length} entries (limit: ${_internals42.MAX_SCORING_SESSION_ENTRIES})`);
|
|
83182
|
+
} else {
|
|
83183
|
+
const prompt = typeof input.args?.prompt === "string" ? String(input.args.prompt) : "";
|
|
83184
|
+
const scored = availableSkills.map((skillPath) => {
|
|
83185
|
+
const skillEntries = sessionEntries.filter((e) => e.skillPath === skillPath);
|
|
83186
|
+
const score = _internals42.computeSkillRelevanceScore(skillPath, prompt, skillEntries);
|
|
83187
|
+
return { skillPath, score, usageCount: skillEntries.length };
|
|
83188
|
+
}).sort((a, b) => b.score - a.score || b.usageCount - a.usageCount);
|
|
83189
|
+
if (scored.length > 0) {
|
|
83190
|
+
const topSkills = scored.slice(0, 5).map((r) => ` ${r.skillPath} (score: ${r.score.toFixed(3)}, used: ${r.usageCount})`).join(`
|
|
83191
|
+
`);
|
|
83192
|
+
warn(`[skill-propagation-gate] Skill recommendations for task: ${topSkills}`);
|
|
83193
|
+
}
|
|
83194
|
+
}
|
|
83195
|
+
} catch (err2) {
|
|
83196
|
+
warn(`[skill-propagation-gate] skill scoring failed (non-blocking): ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
83197
|
+
}
|
|
83198
|
+
}
|
|
83199
|
+
if (availableSkills.length === 0)
|
|
83200
|
+
return;
|
|
83201
|
+
const skillsLower = skillsValue.toLowerCase();
|
|
83202
|
+
if (skillsValue && skillsLower !== "none")
|
|
83203
|
+
return;
|
|
83204
|
+
try {
|
|
83205
|
+
_internals42.writeWarnEvent(directory, {
|
|
83206
|
+
type: "skill_propagation_warn",
|
|
83207
|
+
timestamp: new Date().toISOString(),
|
|
83208
|
+
tool: toolName,
|
|
83209
|
+
agent: agentRaw,
|
|
83210
|
+
target_agent: parsed.targetAgent,
|
|
83211
|
+
sessionID,
|
|
83212
|
+
skills_missing: true,
|
|
83213
|
+
available_skills: availableSkills
|
|
83214
|
+
});
|
|
83215
|
+
} catch {}
|
|
83216
|
+
}
|
|
83217
|
+
var COMPLIANCE_PATTERN = /SKILL_COMPLIANCE\s*:\s*(COMPLIANT|PARTIAL|VIOLATED)(?:\s*(?:—|-)\s*(.*))?\s*$/i;
|
|
83218
|
+
var CODER_SKILLS_PATTERN = /SKILLS_USED_BY_CODER\s*:\s*(.+)/i;
|
|
83219
|
+
async function skillPropagationTransformScan(directory, output, sessionID) {
|
|
83220
|
+
if (!output?.messages)
|
|
83221
|
+
return;
|
|
83222
|
+
if (!sessionID)
|
|
83223
|
+
return;
|
|
83224
|
+
const messages = output.messages;
|
|
83225
|
+
let hadRecordingError = false;
|
|
83226
|
+
let dedupKeys = new Set;
|
|
83227
|
+
let existingEntries = [];
|
|
83228
|
+
try {
|
|
83229
|
+
existingEntries = _internals42.readSkillUsageEntries(directory, {
|
|
83230
|
+
sessionID
|
|
83231
|
+
});
|
|
83232
|
+
dedupKeys = new Set(existingEntries.map((e) => `${e.skillPath}|${e.agentName}|${e.taskID}`));
|
|
83233
|
+
} catch (err2) {
|
|
83234
|
+
warn(`[skill-propagation-gate] dedup preload failed, continuing without dedup: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
83235
|
+
}
|
|
83236
|
+
function isDuplicate(skillPath, agentName, taskID) {
|
|
83237
|
+
const key = `${skillPath}|${agentName}|${taskID}`;
|
|
83238
|
+
if (dedupKeys.has(key))
|
|
83239
|
+
return true;
|
|
83240
|
+
dedupKeys.add(key);
|
|
83241
|
+
return false;
|
|
83242
|
+
}
|
|
83243
|
+
for (let i2 = messages.length - 1;i2 >= 0; i2--) {
|
|
83244
|
+
const m = messages[i2];
|
|
83245
|
+
const agent = m.info?.agent;
|
|
83246
|
+
if (typeof agent !== "string" || stripKnownSwarmPrefix(agent) !== "reviewer") {
|
|
83247
|
+
continue;
|
|
83248
|
+
}
|
|
83249
|
+
const text = (m.parts ?? []).map((p) => typeof p.text === "string" ? p.text : "").join(`
|
|
83250
|
+
`);
|
|
83251
|
+
if (!text)
|
|
83252
|
+
continue;
|
|
83253
|
+
const skillPaths = [];
|
|
83254
|
+
for (const line of text.split(`
|
|
83255
|
+
`)) {
|
|
83256
|
+
const coderMatch = line.trim().match(CODER_SKILLS_PATTERN);
|
|
83257
|
+
if (coderMatch) {
|
|
83258
|
+
const parsed = _internals42.parseSkillPaths(coderMatch[1]);
|
|
83259
|
+
skillPaths.push(...parsed);
|
|
83260
|
+
}
|
|
83261
|
+
}
|
|
83262
|
+
let resolvedTaskID = "unknown";
|
|
83263
|
+
if (existingEntries.length > 0) {
|
|
83264
|
+
const latestDelegation = [...existingEntries].reverse().find((e) => e.agentName !== "reviewer" && e.skillPath !== "__overall__");
|
|
83265
|
+
if (latestDelegation) {
|
|
83266
|
+
resolvedTaskID = latestDelegation.taskID;
|
|
83267
|
+
if (skillPaths.length === 0) {
|
|
83268
|
+
const delegatedPaths = existingEntries.filter((e) => e.agentName !== "reviewer" && e.skillPath !== "__overall__" && e.taskID === resolvedTaskID).map((e) => e.skillPath);
|
|
83269
|
+
if (delegatedPaths.length > 0) {
|
|
83270
|
+
skillPaths.push(...new Set(delegatedPaths));
|
|
83271
|
+
}
|
|
83272
|
+
}
|
|
83273
|
+
}
|
|
83274
|
+
}
|
|
83275
|
+
for (const line of text.split(`
|
|
83276
|
+
`)) {
|
|
83277
|
+
const complianceMatch = line.trim().match(COMPLIANCE_PATTERN);
|
|
83278
|
+
if (!complianceMatch)
|
|
83279
|
+
continue;
|
|
83280
|
+
const verdict = complianceMatch[1].toLowerCase();
|
|
83281
|
+
const notes = (complianceMatch[2] ?? "").trim();
|
|
83282
|
+
const paths = skillPaths.length > 0 ? skillPaths : ["__overall__"];
|
|
83283
|
+
for (const skillPath of paths) {
|
|
83284
|
+
if (hadRecordingError)
|
|
83285
|
+
break;
|
|
83286
|
+
if (isDuplicate(skillPath, "reviewer", resolvedTaskID))
|
|
83287
|
+
continue;
|
|
83288
|
+
try {
|
|
83289
|
+
_internals42.appendSkillUsageEntry(directory, {
|
|
83290
|
+
skillPath,
|
|
83291
|
+
agentName: "reviewer",
|
|
83292
|
+
taskID: resolvedTaskID,
|
|
83293
|
+
complianceVerdict: verdict,
|
|
83294
|
+
reviewerNotes: notes || undefined,
|
|
83295
|
+
sessionID,
|
|
83296
|
+
timestamp: new Date().toISOString()
|
|
83297
|
+
});
|
|
83298
|
+
} catch (err2) {
|
|
83299
|
+
hadRecordingError = true;
|
|
83300
|
+
warn(`[skill-propagation-gate] transform-scan compliance recording failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
83301
|
+
}
|
|
83302
|
+
}
|
|
83303
|
+
break;
|
|
83304
|
+
}
|
|
83305
|
+
break;
|
|
83306
|
+
}
|
|
83307
|
+
if (hadRecordingError)
|
|
83308
|
+
return;
|
|
83309
|
+
for (let i2 = messages.length - 1;i2 >= 0; i2--) {
|
|
83310
|
+
const m = messages[i2];
|
|
83311
|
+
const agent = m.info?.agent;
|
|
83312
|
+
if (typeof agent !== "string" || stripKnownSwarmPrefix(agent) !== "architect") {
|
|
83313
|
+
continue;
|
|
83314
|
+
}
|
|
83315
|
+
const text = (m.parts ?? []).map((p) => typeof p.text === "string" ? p.text : "").join(`
|
|
83316
|
+
`);
|
|
83317
|
+
if (!text)
|
|
83318
|
+
continue;
|
|
83319
|
+
let currentTargetAgent = "";
|
|
83320
|
+
let skillsField = "";
|
|
83321
|
+
for (const line of text.split(`
|
|
83322
|
+
`)) {
|
|
83323
|
+
const trimmed = line.trim();
|
|
83324
|
+
if (trimmed.match(/TO\s+(coder|reviewer|test_engineer|sme|docs|designer)/i)) {
|
|
83325
|
+
const agentMatch = trimmed.match(/TO\s+(coder|reviewer|test_engineer|sme|docs|designer)/i);
|
|
83326
|
+
if (agentMatch)
|
|
83327
|
+
currentTargetAgent = agentMatch[1].toLowerCase();
|
|
83328
|
+
}
|
|
83329
|
+
if (trimmed.startsWith("SKILLS:")) {
|
|
83330
|
+
skillsField = trimmed.slice("SKILLS:".length).trim();
|
|
83331
|
+
}
|
|
83332
|
+
if (currentTargetAgent && skillsField && skillsField.toLowerCase() !== "none") {
|
|
83333
|
+
const skillPaths = _internals42.parseSkillPaths(skillsField);
|
|
83334
|
+
const taskId = _internals42.extractTaskIdFromPrompt(text);
|
|
83335
|
+
for (const skillPath of skillPaths) {
|
|
83336
|
+
if (hadRecordingError)
|
|
83337
|
+
break;
|
|
83338
|
+
if (isDuplicate(skillPath, currentTargetAgent, taskId))
|
|
83339
|
+
continue;
|
|
83340
|
+
try {
|
|
83341
|
+
_internals42.appendSkillUsageEntry(directory, {
|
|
83342
|
+
skillPath,
|
|
83343
|
+
agentName: currentTargetAgent,
|
|
83344
|
+
taskID: taskId,
|
|
83345
|
+
complianceVerdict: "not_checked",
|
|
83346
|
+
sessionID,
|
|
83347
|
+
timestamp: new Date().toISOString()
|
|
83348
|
+
});
|
|
83349
|
+
} catch (err2) {
|
|
83350
|
+
hadRecordingError = true;
|
|
83351
|
+
warn(`[skill-propagation-gate] transform-scan delegation recording failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
83352
|
+
}
|
|
83353
|
+
}
|
|
83354
|
+
currentTargetAgent = "";
|
|
83355
|
+
skillsField = "";
|
|
83356
|
+
}
|
|
83357
|
+
}
|
|
83358
|
+
break;
|
|
83359
|
+
}
|
|
83360
|
+
}
|
|
83361
|
+
_internals42.skillPropagationGateBefore = skillPropagationGateBefore;
|
|
83362
|
+
_internals42.skillPropagationTransformScan = skillPropagationTransformScan;
|
|
83363
|
+
_internals42.writeWarnEvent = writeWarnEvent2;
|
|
83364
|
+
_internals42.discoverAvailableSkills = discoverAvailableSkills;
|
|
83365
|
+
_internals42.parseDelegationArgs = parseDelegationArgs;
|
|
83366
|
+
_internals42.parseSkillPaths = parseSkillPaths;
|
|
83367
|
+
_internals42.extractTaskIdFromPrompt = extractTaskIdFromPrompt;
|
|
83368
|
+
|
|
83369
|
+
// src/hooks/slop-detector.ts
|
|
83370
|
+
import * as fs63 from "node:fs";
|
|
83371
|
+
import * as path90 from "node:path";
|
|
82657
83372
|
var WRITE_EDIT_TOOLS = new Set([
|
|
82658
83373
|
"write",
|
|
82659
83374
|
"edit",
|
|
@@ -82698,12 +83413,12 @@ function checkBoilerplateExplosion(content, taskDescription, threshold) {
|
|
|
82698
83413
|
function walkFiles(dir, exts, deadline) {
|
|
82699
83414
|
const results = [];
|
|
82700
83415
|
try {
|
|
82701
|
-
for (const entry of
|
|
83416
|
+
for (const entry of fs63.readdirSync(dir, { withFileTypes: true })) {
|
|
82702
83417
|
if (deadline !== undefined && Date.now() > deadline)
|
|
82703
83418
|
break;
|
|
82704
83419
|
if (entry.isSymbolicLink())
|
|
82705
83420
|
continue;
|
|
82706
|
-
const full =
|
|
83421
|
+
const full = path90.join(dir, entry.name);
|
|
82707
83422
|
if (entry.isDirectory()) {
|
|
82708
83423
|
if (entry.name === "node_modules" || entry.name === ".git")
|
|
82709
83424
|
continue;
|
|
@@ -82718,7 +83433,7 @@ function walkFiles(dir, exts, deadline) {
|
|
|
82718
83433
|
return results;
|
|
82719
83434
|
}
|
|
82720
83435
|
function checkDeadExports(content, projectDir, startTime) {
|
|
82721
|
-
const hasPackageJson =
|
|
83436
|
+
const hasPackageJson = fs63.existsSync(path90.join(projectDir, "package.json"));
|
|
82722
83437
|
if (!hasPackageJson)
|
|
82723
83438
|
return null;
|
|
82724
83439
|
const exportMatches = content.matchAll(/^\+(?:export)\s+(?:function|class|const|type|interface)\s+(\w{3,})/gm);
|
|
@@ -82741,7 +83456,7 @@ function checkDeadExports(content, projectDir, startTime) {
|
|
|
82741
83456
|
if (found || Date.now() - startTime > 480)
|
|
82742
83457
|
break;
|
|
82743
83458
|
try {
|
|
82744
|
-
const text =
|
|
83459
|
+
const text = fs63.readFileSync(file3, "utf-8");
|
|
82745
83460
|
if (importPattern.test(text))
|
|
82746
83461
|
found = true;
|
|
82747
83462
|
importPattern.lastIndex = 0;
|
|
@@ -82832,17 +83547,17 @@ function checkDuplicateUtility(content, projectDir, startTime, targetFile) {
|
|
|
82832
83547
|
for (const utilDir of utilityDirs) {
|
|
82833
83548
|
if (Date.now() > deadline)
|
|
82834
83549
|
break;
|
|
82835
|
-
const utilPath =
|
|
82836
|
-
if (!
|
|
83550
|
+
const utilPath = path90.join(projectDir, utilDir);
|
|
83551
|
+
if (!fs63.existsSync(utilPath))
|
|
82837
83552
|
continue;
|
|
82838
83553
|
const files = walkFiles(utilPath, [".ts", ".tsx", ".js", ".jsx"], deadline);
|
|
82839
83554
|
for (const file3 of files) {
|
|
82840
83555
|
if (Date.now() > deadline)
|
|
82841
83556
|
break;
|
|
82842
|
-
if (targetFile &&
|
|
83557
|
+
if (targetFile && path90.resolve(file3) === path90.resolve(targetFile))
|
|
82843
83558
|
continue;
|
|
82844
83559
|
try {
|
|
82845
|
-
const text =
|
|
83560
|
+
const text = fs63.readFileSync(file3, "utf-8");
|
|
82846
83561
|
for (const name2 of newExports) {
|
|
82847
83562
|
const exportPattern = new RegExp(`\\bexport\\s+(?:function|class|const|type|interface)\\s+${name2}\\b`);
|
|
82848
83563
|
if (exportPattern.test(text)) {
|
|
@@ -82925,7 +83640,7 @@ Review before proceeding.`;
|
|
|
82925
83640
|
// src/hooks/steering-consumed.ts
|
|
82926
83641
|
init_bun_compat();
|
|
82927
83642
|
init_utils2();
|
|
82928
|
-
import * as
|
|
83643
|
+
import * as fs64 from "node:fs";
|
|
82929
83644
|
function recordSteeringConsumed(directory, directiveId) {
|
|
82930
83645
|
try {
|
|
82931
83646
|
const eventsPath = validateSwarmPath(directory, "events.jsonl");
|
|
@@ -82934,7 +83649,7 @@ function recordSteeringConsumed(directory, directiveId) {
|
|
|
82934
83649
|
directiveId,
|
|
82935
83650
|
timestamp: new Date().toISOString()
|
|
82936
83651
|
};
|
|
82937
|
-
|
|
83652
|
+
fs64.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
82938
83653
|
`, "utf-8");
|
|
82939
83654
|
} catch {}
|
|
82940
83655
|
}
|
|
@@ -82976,15 +83691,15 @@ function createSteeringConsumedHook(directory) {
|
|
|
82976
83691
|
|
|
82977
83692
|
// src/hooks/trajectory-logger.ts
|
|
82978
83693
|
init_manager2();
|
|
82979
|
-
import * as
|
|
82980
|
-
import * as
|
|
83694
|
+
import * as fs66 from "node:fs/promises";
|
|
83695
|
+
import * as path92 from "node:path";
|
|
82981
83696
|
|
|
82982
83697
|
// src/prm/trajectory-store.ts
|
|
82983
83698
|
init_utils2();
|
|
82984
|
-
import * as
|
|
82985
|
-
import * as
|
|
83699
|
+
import * as fs65 from "node:fs/promises";
|
|
83700
|
+
import * as path91 from "node:path";
|
|
82986
83701
|
function getTrajectoryPath(sessionId, directory) {
|
|
82987
|
-
const relativePath =
|
|
83702
|
+
const relativePath = path91.join("trajectories", `${sessionId}.jsonl`);
|
|
82988
83703
|
return validateSwarmPath(directory, relativePath);
|
|
82989
83704
|
}
|
|
82990
83705
|
var _inMemoryTrajectoryCache = new Map;
|
|
@@ -83003,10 +83718,10 @@ async function appendTrajectoryEntry(sessionId, entry, directory, maxLines = 100
|
|
|
83003
83718
|
_inMemoryTrajectoryCache.set(sessionId, cached3);
|
|
83004
83719
|
}
|
|
83005
83720
|
const trajectoryPath = getTrajectoryPath(sessionId, directory);
|
|
83006
|
-
await
|
|
83721
|
+
await fs65.mkdir(path91.dirname(trajectoryPath), { recursive: true });
|
|
83007
83722
|
const line = `${JSON.stringify(entry)}
|
|
83008
83723
|
`;
|
|
83009
|
-
await
|
|
83724
|
+
await fs65.appendFile(trajectoryPath, line, "utf-8");
|
|
83010
83725
|
} catch (err2) {
|
|
83011
83726
|
console.warn(`[trajectory-store] Failed to append trajectory entry: ${err2}`);
|
|
83012
83727
|
}
|
|
@@ -83014,7 +83729,7 @@ async function appendTrajectoryEntry(sessionId, entry, directory, maxLines = 100
|
|
|
83014
83729
|
async function readTrajectory(sessionId, directory) {
|
|
83015
83730
|
try {
|
|
83016
83731
|
const trajectoryPath = getTrajectoryPath(sessionId, directory);
|
|
83017
|
-
const content = await
|
|
83732
|
+
const content = await fs65.readFile(trajectoryPath, "utf-8");
|
|
83018
83733
|
const lines = content.split(`
|
|
83019
83734
|
`).filter((line) => line.trim().length > 0);
|
|
83020
83735
|
const entries = [];
|
|
@@ -83038,15 +83753,15 @@ async function cleanupOldTrajectoryFiles(directory, maxAgeDays = 7) {
|
|
|
83038
83753
|
for (const subdir of ["trajectories", "replays"]) {
|
|
83039
83754
|
try {
|
|
83040
83755
|
const dirPath = validateSwarmPath(directory, subdir);
|
|
83041
|
-
const entries = await
|
|
83756
|
+
const entries = await fs65.readdir(dirPath, { withFileTypes: true });
|
|
83042
83757
|
for (const entry of entries) {
|
|
83043
83758
|
if (!entry.isFile())
|
|
83044
83759
|
continue;
|
|
83045
|
-
const filePath =
|
|
83760
|
+
const filePath = path91.join(dirPath, entry.name);
|
|
83046
83761
|
try {
|
|
83047
|
-
const stat8 = await
|
|
83762
|
+
const stat8 = await fs65.stat(filePath);
|
|
83048
83763
|
if (now - stat8.mtimeMs > cutoffMs) {
|
|
83049
|
-
await
|
|
83764
|
+
await fs65.unlink(filePath);
|
|
83050
83765
|
}
|
|
83051
83766
|
} catch {}
|
|
83052
83767
|
}
|
|
@@ -83096,7 +83811,7 @@ function isSensitiveKey(key) {
|
|
|
83096
83811
|
}
|
|
83097
83812
|
async function truncateTrajectoryFile(filePath, maxLines) {
|
|
83098
83813
|
try {
|
|
83099
|
-
const content = await
|
|
83814
|
+
const content = await fs66.readFile(filePath, "utf-8");
|
|
83100
83815
|
const lines = content.split(`
|
|
83101
83816
|
`).filter((line) => line.trim().length > 0);
|
|
83102
83817
|
if (lines.length <= maxLines) {
|
|
@@ -83104,7 +83819,7 @@ async function truncateTrajectoryFile(filePath, maxLines) {
|
|
|
83104
83819
|
}
|
|
83105
83820
|
const keepCount = Math.floor(maxLines / 2);
|
|
83106
83821
|
const keptLines = lines.slice(-keepCount);
|
|
83107
|
-
await
|
|
83822
|
+
await fs66.writeFile(filePath, `${keptLines.join(`
|
|
83108
83823
|
`)}
|
|
83109
83824
|
`, "utf-8");
|
|
83110
83825
|
} catch {}
|
|
@@ -83234,13 +83949,13 @@ function createTrajectoryLoggerHook(config3, _directory) {
|
|
|
83234
83949
|
elapsed_ms
|
|
83235
83950
|
};
|
|
83236
83951
|
const sanitized = sanitizeTaskId2(taskId);
|
|
83237
|
-
const relativePath =
|
|
83952
|
+
const relativePath = path92.join("evidence", sanitized, "trajectory.jsonl");
|
|
83238
83953
|
const trajectoryPath = validateSwarmPath(_directory, relativePath);
|
|
83239
83954
|
try {
|
|
83240
|
-
await
|
|
83955
|
+
await fs66.mkdir(path92.dirname(trajectoryPath), { recursive: true });
|
|
83241
83956
|
const line = `${JSON.stringify(entry)}
|
|
83242
83957
|
`;
|
|
83243
|
-
await
|
|
83958
|
+
await fs66.appendFile(trajectoryPath, line, "utf-8");
|
|
83244
83959
|
await truncateTrajectoryFile(trajectoryPath, maxLines);
|
|
83245
83960
|
} catch {}
|
|
83246
83961
|
try {
|
|
@@ -83787,17 +84502,17 @@ init_state();
|
|
|
83787
84502
|
init_telemetry();
|
|
83788
84503
|
|
|
83789
84504
|
// src/prm/replay.ts
|
|
83790
|
-
import { promises as
|
|
83791
|
-
import
|
|
84505
|
+
import { promises as fs67 } from "node:fs";
|
|
84506
|
+
import path93 from "node:path";
|
|
83792
84507
|
function isPathSafe2(targetPath, basePath) {
|
|
83793
|
-
const resolvedTarget =
|
|
83794
|
-
const resolvedBase =
|
|
83795
|
-
const rel =
|
|
83796
|
-
return !rel.startsWith("..") && !
|
|
84508
|
+
const resolvedTarget = path93.resolve(targetPath);
|
|
84509
|
+
const resolvedBase = path93.resolve(basePath);
|
|
84510
|
+
const rel = path93.relative(resolvedBase, resolvedTarget);
|
|
84511
|
+
return !rel.startsWith("..") && !path93.isAbsolute(rel);
|
|
83797
84512
|
}
|
|
83798
84513
|
function isWithinReplaysDir(targetPath) {
|
|
83799
|
-
const resolved =
|
|
83800
|
-
const parts2 = resolved.split(
|
|
84514
|
+
const resolved = path93.resolve(targetPath);
|
|
84515
|
+
const parts2 = resolved.split(path93.sep);
|
|
83801
84516
|
for (let i2 = 0;i2 < parts2.length - 1; i2++) {
|
|
83802
84517
|
if (parts2[i2] === ".swarm" && parts2[i2 + 1] === "replays") {
|
|
83803
84518
|
return true;
|
|
@@ -83810,15 +84525,15 @@ function sanitizeFilename(input) {
|
|
|
83810
84525
|
}
|
|
83811
84526
|
async function startReplayRecording(sessionID, directory) {
|
|
83812
84527
|
try {
|
|
83813
|
-
const replayDir =
|
|
84528
|
+
const replayDir = path93.join(directory, ".swarm", "replays");
|
|
83814
84529
|
const safeSessionID = sanitizeFilename(sessionID);
|
|
83815
84530
|
const filename = `${safeSessionID}-${Date.now()}.jsonl`;
|
|
83816
|
-
const filepath =
|
|
84531
|
+
const filepath = path93.join(replayDir, filename);
|
|
83817
84532
|
if (!isPathSafe2(filepath, replayDir)) {
|
|
83818
84533
|
console.warn(`[replay] Invalid path detected - path traversal attempt blocked for session ${sessionID}`);
|
|
83819
84534
|
return null;
|
|
83820
84535
|
}
|
|
83821
|
-
await
|
|
84536
|
+
await fs67.mkdir(replayDir, { recursive: true });
|
|
83822
84537
|
return filepath;
|
|
83823
84538
|
} catch (err2) {
|
|
83824
84539
|
console.warn(`[replay] Failed to start recording for session ${sessionID}: ${err2}`);
|
|
@@ -83838,7 +84553,7 @@ async function recordReplayEntry(artifactPath, sessionID, entry) {
|
|
|
83838
84553
|
};
|
|
83839
84554
|
const line = `${JSON.stringify(fullEntry)}
|
|
83840
84555
|
`;
|
|
83841
|
-
await
|
|
84556
|
+
await fs67.appendFile(artifactPath, line, "utf-8");
|
|
83842
84557
|
} catch (err2) {
|
|
83843
84558
|
console.warn(`[replay] Failed to record entry: ${err2}`);
|
|
83844
84559
|
}
|
|
@@ -83973,7 +84688,7 @@ init_version_check();
|
|
|
83973
84688
|
init_utils2();
|
|
83974
84689
|
init_state();
|
|
83975
84690
|
init_bun_compat();
|
|
83976
|
-
import { renameSync as
|
|
84691
|
+
import { renameSync as renameSync18 } from "node:fs";
|
|
83977
84692
|
var TRANSIENT_SESSION_FIELDS = [
|
|
83978
84693
|
{ name: "revisionLimitHit", resetValue: false },
|
|
83979
84694
|
{ name: "coderRevisions", resetValue: 0 },
|
|
@@ -84100,7 +84815,7 @@ async function readSnapshot(directory) {
|
|
|
84100
84815
|
if (parsed.version !== 1 && parsed.version !== 2) {
|
|
84101
84816
|
try {
|
|
84102
84817
|
const quarantinePath = validateSwarmPath(directory, "session/state.json.quarantine");
|
|
84103
|
-
|
|
84818
|
+
renameSync18(resolvedPath, quarantinePath);
|
|
84104
84819
|
} catch {}
|
|
84105
84820
|
return null;
|
|
84106
84821
|
}
|
|
@@ -84186,8 +84901,8 @@ init_telemetry();
|
|
|
84186
84901
|
// src/tools/batch-symbols.ts
|
|
84187
84902
|
init_dist();
|
|
84188
84903
|
init_create_tool();
|
|
84189
|
-
import * as
|
|
84190
|
-
import * as
|
|
84904
|
+
import * as fs68 from "node:fs";
|
|
84905
|
+
import * as path94 from "node:path";
|
|
84191
84906
|
init_path_security();
|
|
84192
84907
|
var WINDOWS_RESERVED_NAMES2 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
84193
84908
|
function containsWindowsAttacks2(str) {
|
|
@@ -84204,14 +84919,14 @@ function containsWindowsAttacks2(str) {
|
|
|
84204
84919
|
}
|
|
84205
84920
|
function isPathInWorkspace2(filePath, workspace) {
|
|
84206
84921
|
try {
|
|
84207
|
-
const resolvedPath =
|
|
84208
|
-
if (!
|
|
84922
|
+
const resolvedPath = path94.resolve(workspace, filePath);
|
|
84923
|
+
if (!fs68.existsSync(resolvedPath)) {
|
|
84209
84924
|
return true;
|
|
84210
84925
|
}
|
|
84211
|
-
const realWorkspace =
|
|
84212
|
-
const realResolvedPath =
|
|
84213
|
-
const relativePath =
|
|
84214
|
-
if (relativePath.startsWith("..") ||
|
|
84926
|
+
const realWorkspace = fs68.realpathSync(workspace);
|
|
84927
|
+
const realResolvedPath = fs68.realpathSync(resolvedPath);
|
|
84928
|
+
const relativePath = path94.relative(realWorkspace, realResolvedPath);
|
|
84929
|
+
if (relativePath.startsWith("..") || path94.isAbsolute(relativePath)) {
|
|
84215
84930
|
return false;
|
|
84216
84931
|
}
|
|
84217
84932
|
return true;
|
|
@@ -84220,7 +84935,7 @@ function isPathInWorkspace2(filePath, workspace) {
|
|
|
84220
84935
|
}
|
|
84221
84936
|
}
|
|
84222
84937
|
function processFile2(file3, cwd, exportedOnly) {
|
|
84223
|
-
const ext =
|
|
84938
|
+
const ext = path94.extname(file3);
|
|
84224
84939
|
if (containsControlChars(file3)) {
|
|
84225
84940
|
return {
|
|
84226
84941
|
file: file3,
|
|
@@ -84253,8 +84968,8 @@ function processFile2(file3, cwd, exportedOnly) {
|
|
|
84253
84968
|
errorType: "path-outside-workspace"
|
|
84254
84969
|
};
|
|
84255
84970
|
}
|
|
84256
|
-
const fullPath =
|
|
84257
|
-
if (!
|
|
84971
|
+
const fullPath = path94.join(cwd, file3);
|
|
84972
|
+
if (!fs68.existsSync(fullPath)) {
|
|
84258
84973
|
return {
|
|
84259
84974
|
file: file3,
|
|
84260
84975
|
success: false,
|
|
@@ -84285,14 +85000,14 @@ function processFile2(file3, cwd, exportedOnly) {
|
|
|
84285
85000
|
}
|
|
84286
85001
|
let isEmptyFile = false;
|
|
84287
85002
|
try {
|
|
84288
|
-
const stats =
|
|
85003
|
+
const stats = fs68.statSync(fullPath);
|
|
84289
85004
|
if (stats.size === 0) {
|
|
84290
85005
|
isEmptyFile = true;
|
|
84291
85006
|
}
|
|
84292
85007
|
} catch {}
|
|
84293
85008
|
if (syms.length === 0) {
|
|
84294
85009
|
try {
|
|
84295
|
-
const content =
|
|
85010
|
+
const content = fs68.readFileSync(fullPath, "utf-8");
|
|
84296
85011
|
if (content.trim().length === 0) {
|
|
84297
85012
|
isEmptyFile = true;
|
|
84298
85013
|
}
|
|
@@ -84544,25 +85259,25 @@ init_manager2();
|
|
|
84544
85259
|
init_task_id();
|
|
84545
85260
|
init_create_tool();
|
|
84546
85261
|
init_resolve_working_directory();
|
|
84547
|
-
import * as
|
|
84548
|
-
import * as
|
|
85262
|
+
import * as fs69 from "node:fs";
|
|
85263
|
+
import * as path95 from "node:path";
|
|
84549
85264
|
var EVIDENCE_DIR = ".swarm/evidence";
|
|
84550
85265
|
function isValidTaskId3(taskId) {
|
|
84551
85266
|
return isStrictTaskId(taskId);
|
|
84552
85267
|
}
|
|
84553
85268
|
function isPathWithinSwarm(filePath, workspaceRoot) {
|
|
84554
|
-
const normalizedWorkspace =
|
|
84555
|
-
const swarmPath =
|
|
84556
|
-
const normalizedPath =
|
|
85269
|
+
const normalizedWorkspace = path95.resolve(workspaceRoot);
|
|
85270
|
+
const swarmPath = path95.join(normalizedWorkspace, ".swarm", "evidence");
|
|
85271
|
+
const normalizedPath = path95.resolve(filePath);
|
|
84557
85272
|
return normalizedPath.startsWith(swarmPath);
|
|
84558
85273
|
}
|
|
84559
85274
|
function readEvidenceFile(evidencePath) {
|
|
84560
|
-
if (!
|
|
85275
|
+
if (!fs69.existsSync(evidencePath)) {
|
|
84561
85276
|
return null;
|
|
84562
85277
|
}
|
|
84563
85278
|
let content;
|
|
84564
85279
|
try {
|
|
84565
|
-
content =
|
|
85280
|
+
content = fs69.readFileSync(evidencePath, "utf-8");
|
|
84566
85281
|
} catch {
|
|
84567
85282
|
return null;
|
|
84568
85283
|
}
|
|
@@ -84634,7 +85349,7 @@ var check_gate_status = createSwarmTool({
|
|
|
84634
85349
|
};
|
|
84635
85350
|
return JSON.stringify(errorResult, null, 2);
|
|
84636
85351
|
}
|
|
84637
|
-
const evidencePath =
|
|
85352
|
+
const evidencePath = path95.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
|
|
84638
85353
|
if (!isPathWithinSwarm(evidencePath, directory)) {
|
|
84639
85354
|
const errorResult = {
|
|
84640
85355
|
taskId: taskIdInput,
|
|
@@ -84730,8 +85445,8 @@ init_utils2();
|
|
|
84730
85445
|
init_state();
|
|
84731
85446
|
init_create_tool();
|
|
84732
85447
|
init_resolve_working_directory();
|
|
84733
|
-
import * as
|
|
84734
|
-
import * as
|
|
85448
|
+
import * as fs70 from "node:fs";
|
|
85449
|
+
import * as path96 from "node:path";
|
|
84735
85450
|
function extractMatches(regex, text) {
|
|
84736
85451
|
return Array.from(text.matchAll(regex));
|
|
84737
85452
|
}
|
|
@@ -84825,7 +85540,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
84825
85540
|
let plan;
|
|
84826
85541
|
try {
|
|
84827
85542
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
84828
|
-
const planRaw =
|
|
85543
|
+
const planRaw = fs70.readFileSync(planPath, "utf-8");
|
|
84829
85544
|
plan = JSON.parse(planRaw);
|
|
84830
85545
|
} catch {
|
|
84831
85546
|
const result2 = {
|
|
@@ -84883,10 +85598,10 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
84883
85598
|
let hasFileReadFailure = false;
|
|
84884
85599
|
for (const filePath of fileTargets) {
|
|
84885
85600
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
84886
|
-
const resolvedPath =
|
|
84887
|
-
const projectRoot =
|
|
84888
|
-
const relative20 =
|
|
84889
|
-
const withinProject = relative20 === "" || !relative20.startsWith("..") && !
|
|
85601
|
+
const resolvedPath = path96.resolve(directory, normalizedPath);
|
|
85602
|
+
const projectRoot = path96.resolve(directory);
|
|
85603
|
+
const relative20 = path96.relative(projectRoot, resolvedPath);
|
|
85604
|
+
const withinProject = relative20 === "" || !relative20.startsWith("..") && !path96.isAbsolute(relative20);
|
|
84890
85605
|
if (!withinProject) {
|
|
84891
85606
|
blockedTasks.push({
|
|
84892
85607
|
task_id: task.id,
|
|
@@ -84899,7 +85614,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
84899
85614
|
}
|
|
84900
85615
|
let fileContent;
|
|
84901
85616
|
try {
|
|
84902
|
-
fileContent =
|
|
85617
|
+
fileContent = fs70.readFileSync(resolvedPath, "utf-8");
|
|
84903
85618
|
} catch {
|
|
84904
85619
|
blockedTasks.push({
|
|
84905
85620
|
task_id: task.id,
|
|
@@ -84941,9 +85656,9 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
84941
85656
|
blockedTasks
|
|
84942
85657
|
};
|
|
84943
85658
|
try {
|
|
84944
|
-
const evidenceDir =
|
|
84945
|
-
const evidencePath =
|
|
84946
|
-
|
|
85659
|
+
const evidenceDir = path96.join(directory, ".swarm", "evidence", `${phase}`);
|
|
85660
|
+
const evidencePath = path96.join(evidenceDir, "completion-verify.json");
|
|
85661
|
+
fs70.mkdirSync(evidenceDir, { recursive: true });
|
|
84947
85662
|
const evidenceBundle = {
|
|
84948
85663
|
schema_version: "1.0.0",
|
|
84949
85664
|
task_id: "completion-verify",
|
|
@@ -84964,7 +85679,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
84964
85679
|
}
|
|
84965
85680
|
]
|
|
84966
85681
|
};
|
|
84967
|
-
|
|
85682
|
+
fs70.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
|
|
84968
85683
|
} catch {}
|
|
84969
85684
|
return JSON.stringify(result, null, 2);
|
|
84970
85685
|
}
|
|
@@ -85018,12 +85733,12 @@ var completion_verify = createSwarmTool({
|
|
|
85018
85733
|
});
|
|
85019
85734
|
// src/tools/complexity-hotspots.ts
|
|
85020
85735
|
init_zod();
|
|
85021
|
-
import * as
|
|
85022
|
-
import * as
|
|
85736
|
+
import * as fs72 from "node:fs";
|
|
85737
|
+
import * as path98 from "node:path";
|
|
85023
85738
|
|
|
85024
85739
|
// src/quality/metrics.ts
|
|
85025
|
-
import * as
|
|
85026
|
-
import * as
|
|
85740
|
+
import * as fs71 from "node:fs";
|
|
85741
|
+
import * as path97 from "node:path";
|
|
85027
85742
|
var MAX_FILE_SIZE_BYTES4 = 256 * 1024;
|
|
85028
85743
|
var MIN_DUPLICATION_LINES = 10;
|
|
85029
85744
|
function estimateCyclomaticComplexity(content) {
|
|
@@ -85061,11 +85776,11 @@ function estimateCyclomaticComplexity(content) {
|
|
|
85061
85776
|
}
|
|
85062
85777
|
function getComplexityForFile(filePath) {
|
|
85063
85778
|
try {
|
|
85064
|
-
const stat8 =
|
|
85779
|
+
const stat8 = fs71.statSync(filePath);
|
|
85065
85780
|
if (stat8.size > MAX_FILE_SIZE_BYTES4) {
|
|
85066
85781
|
return null;
|
|
85067
85782
|
}
|
|
85068
|
-
const content =
|
|
85783
|
+
const content = fs71.readFileSync(filePath, "utf-8");
|
|
85069
85784
|
return estimateCyclomaticComplexity(content);
|
|
85070
85785
|
} catch {
|
|
85071
85786
|
return null;
|
|
@@ -85075,8 +85790,8 @@ async function computeComplexityDelta(files, workingDir) {
|
|
|
85075
85790
|
let totalComplexity = 0;
|
|
85076
85791
|
const analyzedFiles = [];
|
|
85077
85792
|
for (const file3 of files) {
|
|
85078
|
-
const fullPath =
|
|
85079
|
-
if (!
|
|
85793
|
+
const fullPath = path97.isAbsolute(file3) ? file3 : path97.join(workingDir, file3);
|
|
85794
|
+
if (!fs71.existsSync(fullPath)) {
|
|
85080
85795
|
continue;
|
|
85081
85796
|
}
|
|
85082
85797
|
const complexity = getComplexityForFile(fullPath);
|
|
@@ -85197,8 +85912,8 @@ function countGoExports(content) {
|
|
|
85197
85912
|
}
|
|
85198
85913
|
function getExportCountForFile(filePath) {
|
|
85199
85914
|
try {
|
|
85200
|
-
const content =
|
|
85201
|
-
const ext =
|
|
85915
|
+
const content = fs71.readFileSync(filePath, "utf-8");
|
|
85916
|
+
const ext = path97.extname(filePath).toLowerCase();
|
|
85202
85917
|
switch (ext) {
|
|
85203
85918
|
case ".ts":
|
|
85204
85919
|
case ".tsx":
|
|
@@ -85224,8 +85939,8 @@ async function computePublicApiDelta(files, workingDir) {
|
|
|
85224
85939
|
let totalExports = 0;
|
|
85225
85940
|
const analyzedFiles = [];
|
|
85226
85941
|
for (const file3 of files) {
|
|
85227
|
-
const fullPath =
|
|
85228
|
-
if (!
|
|
85942
|
+
const fullPath = path97.isAbsolute(file3) ? file3 : path97.join(workingDir, file3);
|
|
85943
|
+
if (!fs71.existsSync(fullPath)) {
|
|
85229
85944
|
continue;
|
|
85230
85945
|
}
|
|
85231
85946
|
const exports = getExportCountForFile(fullPath);
|
|
@@ -85258,16 +85973,16 @@ async function computeDuplicationRatio(files, workingDir) {
|
|
|
85258
85973
|
let duplicateLines = 0;
|
|
85259
85974
|
const analyzedFiles = [];
|
|
85260
85975
|
for (const file3 of files) {
|
|
85261
|
-
const fullPath =
|
|
85262
|
-
if (!
|
|
85976
|
+
const fullPath = path97.isAbsolute(file3) ? file3 : path97.join(workingDir, file3);
|
|
85977
|
+
if (!fs71.existsSync(fullPath)) {
|
|
85263
85978
|
continue;
|
|
85264
85979
|
}
|
|
85265
85980
|
try {
|
|
85266
|
-
const stat8 =
|
|
85981
|
+
const stat8 = fs71.statSync(fullPath);
|
|
85267
85982
|
if (stat8.size > MAX_FILE_SIZE_BYTES4) {
|
|
85268
85983
|
continue;
|
|
85269
85984
|
}
|
|
85270
|
-
const content =
|
|
85985
|
+
const content = fs71.readFileSync(fullPath, "utf-8");
|
|
85271
85986
|
const lines = content.split(`
|
|
85272
85987
|
`).filter((line) => line.trim().length > 0);
|
|
85273
85988
|
if (lines.length < MIN_DUPLICATION_LINES) {
|
|
@@ -85291,8 +86006,8 @@ function countCodeLines(content) {
|
|
|
85291
86006
|
return lines.length;
|
|
85292
86007
|
}
|
|
85293
86008
|
function isTestFile(filePath) {
|
|
85294
|
-
const
|
|
85295
|
-
const _ext =
|
|
86009
|
+
const basename13 = path97.basename(filePath);
|
|
86010
|
+
const _ext = path97.extname(filePath).toLowerCase();
|
|
85296
86011
|
const testPatterns = [
|
|
85297
86012
|
".test.",
|
|
85298
86013
|
".spec.",
|
|
@@ -85307,7 +86022,7 @@ function isTestFile(filePath) {
|
|
|
85307
86022
|
".spec.jsx"
|
|
85308
86023
|
];
|
|
85309
86024
|
for (const pattern of testPatterns) {
|
|
85310
|
-
if (
|
|
86025
|
+
if (basename13.includes(pattern)) {
|
|
85311
86026
|
return true;
|
|
85312
86027
|
}
|
|
85313
86028
|
}
|
|
@@ -85373,8 +86088,8 @@ function matchGlobSegment(globSegments, pathSegments) {
|
|
|
85373
86088
|
}
|
|
85374
86089
|
return gIndex === globSegments.length && pIndex === pathSegments.length;
|
|
85375
86090
|
}
|
|
85376
|
-
function matchesGlobSegment(
|
|
85377
|
-
const normalizedPath =
|
|
86091
|
+
function matchesGlobSegment(path98, glob) {
|
|
86092
|
+
const normalizedPath = path98.replace(/\\/g, "/");
|
|
85378
86093
|
const normalizedGlob = glob.replace(/\\/g, "/");
|
|
85379
86094
|
if (normalizedPath.includes("//")) {
|
|
85380
86095
|
return false;
|
|
@@ -85405,8 +86120,8 @@ function simpleGlobToRegex2(glob) {
|
|
|
85405
86120
|
function hasGlobstar(glob) {
|
|
85406
86121
|
return glob.includes("**");
|
|
85407
86122
|
}
|
|
85408
|
-
function globMatches(
|
|
85409
|
-
const normalizedPath =
|
|
86123
|
+
function globMatches(path98, glob) {
|
|
86124
|
+
const normalizedPath = path98.replace(/\\/g, "/");
|
|
85410
86125
|
if (!glob || glob === "") {
|
|
85411
86126
|
if (normalizedPath.includes("//")) {
|
|
85412
86127
|
return false;
|
|
@@ -85442,31 +86157,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
|
|
|
85442
86157
|
async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
85443
86158
|
let testLines = 0;
|
|
85444
86159
|
let codeLines = 0;
|
|
85445
|
-
const srcDir =
|
|
85446
|
-
if (
|
|
86160
|
+
const srcDir = path97.join(workingDir, "src");
|
|
86161
|
+
if (fs71.existsSync(srcDir)) {
|
|
85447
86162
|
await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
85448
86163
|
codeLines += lines;
|
|
85449
86164
|
});
|
|
85450
86165
|
}
|
|
85451
86166
|
const possibleSrcDirs = ["lib", "app", "source", "core"];
|
|
85452
86167
|
for (const dir of possibleSrcDirs) {
|
|
85453
|
-
const dirPath =
|
|
85454
|
-
if (
|
|
86168
|
+
const dirPath = path97.join(workingDir, dir);
|
|
86169
|
+
if (fs71.existsSync(dirPath)) {
|
|
85455
86170
|
await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
85456
86171
|
codeLines += lines;
|
|
85457
86172
|
});
|
|
85458
86173
|
}
|
|
85459
86174
|
}
|
|
85460
|
-
const testsDir =
|
|
85461
|
-
if (
|
|
86175
|
+
const testsDir = path97.join(workingDir, "tests");
|
|
86176
|
+
if (fs71.existsSync(testsDir)) {
|
|
85462
86177
|
await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
85463
86178
|
testLines += lines;
|
|
85464
86179
|
});
|
|
85465
86180
|
}
|
|
85466
86181
|
const possibleTestDirs = ["test", "__tests__", "specs"];
|
|
85467
86182
|
for (const dir of possibleTestDirs) {
|
|
85468
|
-
const dirPath =
|
|
85469
|
-
if (
|
|
86183
|
+
const dirPath = path97.join(workingDir, dir);
|
|
86184
|
+
if (fs71.existsSync(dirPath) && dirPath !== testsDir) {
|
|
85470
86185
|
await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
85471
86186
|
testLines += lines;
|
|
85472
86187
|
});
|
|
@@ -85478,9 +86193,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
85478
86193
|
}
|
|
85479
86194
|
async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
|
|
85480
86195
|
try {
|
|
85481
|
-
const entries =
|
|
86196
|
+
const entries = fs71.readdirSync(dirPath, { withFileTypes: true });
|
|
85482
86197
|
for (const entry of entries) {
|
|
85483
|
-
const fullPath =
|
|
86198
|
+
const fullPath = path97.join(dirPath, entry.name);
|
|
85484
86199
|
if (entry.isDirectory()) {
|
|
85485
86200
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
|
|
85486
86201
|
continue;
|
|
@@ -85488,7 +86203,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
85488
86203
|
await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
|
|
85489
86204
|
} else if (entry.isFile()) {
|
|
85490
86205
|
const relativePath = fullPath.replace(`${dirPath}/`, "");
|
|
85491
|
-
const ext =
|
|
86206
|
+
const ext = path97.extname(entry.name).toLowerCase();
|
|
85492
86207
|
const validExts = [
|
|
85493
86208
|
".ts",
|
|
85494
86209
|
".tsx",
|
|
@@ -85524,7 +86239,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
85524
86239
|
continue;
|
|
85525
86240
|
}
|
|
85526
86241
|
try {
|
|
85527
|
-
const content =
|
|
86242
|
+
const content = fs71.readFileSync(fullPath, "utf-8");
|
|
85528
86243
|
const lines = countCodeLines(content);
|
|
85529
86244
|
callback(lines);
|
|
85530
86245
|
} catch {}
|
|
@@ -85724,11 +86439,11 @@ async function getGitChurn(days, directory) {
|
|
|
85724
86439
|
}
|
|
85725
86440
|
function getComplexityForFile2(filePath) {
|
|
85726
86441
|
try {
|
|
85727
|
-
const stat8 =
|
|
86442
|
+
const stat8 = fs72.statSync(filePath);
|
|
85728
86443
|
if (stat8.size > MAX_FILE_SIZE_BYTES5) {
|
|
85729
86444
|
return null;
|
|
85730
86445
|
}
|
|
85731
|
-
const content =
|
|
86446
|
+
const content = fs72.readFileSync(filePath, "utf-8");
|
|
85732
86447
|
return estimateCyclomaticComplexity(content);
|
|
85733
86448
|
} catch {
|
|
85734
86449
|
return null;
|
|
@@ -85739,7 +86454,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
85739
86454
|
const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
|
|
85740
86455
|
const filteredChurn = new Map;
|
|
85741
86456
|
for (const [file3, count] of churnMap) {
|
|
85742
|
-
const ext =
|
|
86457
|
+
const ext = path98.extname(file3).toLowerCase();
|
|
85743
86458
|
if (extSet.has(ext)) {
|
|
85744
86459
|
filteredChurn.set(file3, count);
|
|
85745
86460
|
}
|
|
@@ -85749,8 +86464,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
85749
86464
|
let analyzedFiles = 0;
|
|
85750
86465
|
for (const [file3, churnCount] of filteredChurn) {
|
|
85751
86466
|
let fullPath = file3;
|
|
85752
|
-
if (!
|
|
85753
|
-
fullPath =
|
|
86467
|
+
if (!fs72.existsSync(fullPath)) {
|
|
86468
|
+
fullPath = path98.join(cwd, file3);
|
|
85754
86469
|
}
|
|
85755
86470
|
const complexity = getComplexityForFile2(fullPath);
|
|
85756
86471
|
if (complexity !== null) {
|
|
@@ -85918,13 +86633,13 @@ ${body2}`);
|
|
|
85918
86633
|
|
|
85919
86634
|
// src/council/council-evidence-writer.ts
|
|
85920
86635
|
import {
|
|
85921
|
-
appendFileSync as
|
|
85922
|
-
existsSync as
|
|
85923
|
-
mkdirSync as
|
|
85924
|
-
readFileSync as
|
|
85925
|
-
writeFileSync as
|
|
86636
|
+
appendFileSync as appendFileSync11,
|
|
86637
|
+
existsSync as existsSync53,
|
|
86638
|
+
mkdirSync as mkdirSync24,
|
|
86639
|
+
readFileSync as readFileSync43,
|
|
86640
|
+
writeFileSync as writeFileSync16
|
|
85926
86641
|
} from "node:fs";
|
|
85927
|
-
import { join as
|
|
86642
|
+
import { join as join83 } from "node:path";
|
|
85928
86643
|
var EVIDENCE_DIR2 = ".swarm/evidence";
|
|
85929
86644
|
var VALID_TASK_ID = /^\d+\.\d+(\.\d+)*$/;
|
|
85930
86645
|
var COUNCIL_GATE_NAME = "council";
|
|
@@ -85958,13 +86673,13 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
85958
86673
|
if (!VALID_TASK_ID.test(synthesis.taskId)) {
|
|
85959
86674
|
throw new Error(`writeCouncilEvidence: invalid taskId "${synthesis.taskId}" — must match N.M or N.M.P format`);
|
|
85960
86675
|
}
|
|
85961
|
-
const dir =
|
|
85962
|
-
|
|
85963
|
-
const filePath =
|
|
86676
|
+
const dir = join83(workingDir, EVIDENCE_DIR2);
|
|
86677
|
+
mkdirSync24(dir, { recursive: true });
|
|
86678
|
+
const filePath = join83(dir, `${synthesis.taskId}.json`);
|
|
85964
86679
|
const existingRoot = Object.create(null);
|
|
85965
|
-
if (
|
|
86680
|
+
if (existsSync53(filePath)) {
|
|
85966
86681
|
try {
|
|
85967
|
-
const parsed = JSON.parse(
|
|
86682
|
+
const parsed = JSON.parse(readFileSync43(filePath, "utf-8"));
|
|
85968
86683
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
85969
86684
|
safeAssignOwnProps(existingRoot, parsed);
|
|
85970
86685
|
}
|
|
@@ -85992,17 +86707,17 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
85992
86707
|
updated.taskId = synthesis.taskId;
|
|
85993
86708
|
if (!Array.isArray(updated.required_gates))
|
|
85994
86709
|
updated.required_gates = [];
|
|
85995
|
-
|
|
86710
|
+
writeFileSync16(filePath, JSON.stringify(updated, null, 2));
|
|
85996
86711
|
try {
|
|
85997
|
-
const councilDir =
|
|
85998
|
-
|
|
86712
|
+
const councilDir = join83(workingDir, ".swarm", "council");
|
|
86713
|
+
mkdirSync24(councilDir, { recursive: true });
|
|
85999
86714
|
const auditLine = JSON.stringify({
|
|
86000
86715
|
round: synthesis.roundNumber,
|
|
86001
86716
|
verdict: synthesis.overallVerdict,
|
|
86002
86717
|
timestamp: synthesis.timestamp,
|
|
86003
86718
|
vetoedBy: synthesis.vetoedBy
|
|
86004
86719
|
});
|
|
86005
|
-
|
|
86720
|
+
appendFileSync11(join83(councilDir, `${synthesis.taskId}.rounds.jsonl`), `${auditLine}
|
|
86006
86721
|
`);
|
|
86007
86722
|
} catch (auditError) {
|
|
86008
86723
|
console.warn(`writeCouncilEvidence: failed to append round-history audit log: ${auditError instanceof Error ? auditError.message : String(auditError)}`);
|
|
@@ -86324,25 +87039,25 @@ function buildFinalCouncilFeedback(projectSummary, verdict, vetoedBy, requiredFi
|
|
|
86324
87039
|
}
|
|
86325
87040
|
|
|
86326
87041
|
// src/council/criteria-store.ts
|
|
86327
|
-
import { existsSync as
|
|
86328
|
-
import { join as
|
|
87042
|
+
import { existsSync as existsSync54, mkdirSync as mkdirSync25, readFileSync as readFileSync44, writeFileSync as writeFileSync17 } from "node:fs";
|
|
87043
|
+
import { join as join84 } from "node:path";
|
|
86329
87044
|
var COUNCIL_DIR = ".swarm/council";
|
|
86330
87045
|
function writeCriteria(workingDir, taskId, criteria) {
|
|
86331
|
-
const dir =
|
|
86332
|
-
|
|
87046
|
+
const dir = join84(workingDir, COUNCIL_DIR);
|
|
87047
|
+
mkdirSync25(dir, { recursive: true });
|
|
86333
87048
|
const payload = {
|
|
86334
87049
|
taskId,
|
|
86335
87050
|
criteria,
|
|
86336
87051
|
declaredAt: new Date().toISOString()
|
|
86337
87052
|
};
|
|
86338
|
-
|
|
87053
|
+
writeFileSync17(join84(dir, `${safeId(taskId)}.json`), JSON.stringify(payload, null, 2));
|
|
86339
87054
|
}
|
|
86340
87055
|
function readCriteria(workingDir, taskId) {
|
|
86341
|
-
const filePath =
|
|
86342
|
-
if (!
|
|
87056
|
+
const filePath = join84(workingDir, COUNCIL_DIR, `${safeId(taskId)}.json`);
|
|
87057
|
+
if (!existsSync54(filePath))
|
|
86343
87058
|
return null;
|
|
86344
87059
|
try {
|
|
86345
|
-
const parsed = JSON.parse(
|
|
87060
|
+
const parsed = JSON.parse(readFileSync44(filePath, "utf-8"));
|
|
86346
87061
|
if (parsed && typeof parsed === "object" && typeof parsed.taskId === "string" && Array.isArray(parsed.criteria)) {
|
|
86347
87062
|
return parsed;
|
|
86348
87063
|
}
|
|
@@ -86490,8 +87205,8 @@ var submit_council_verdicts = createSwarmTool({
|
|
|
86490
87205
|
// src/tools/convene-general-council.ts
|
|
86491
87206
|
init_zod();
|
|
86492
87207
|
init_loader();
|
|
86493
|
-
import * as
|
|
86494
|
-
import * as
|
|
87208
|
+
import * as fs73 from "node:fs";
|
|
87209
|
+
import * as path99 from "node:path";
|
|
86495
87210
|
|
|
86496
87211
|
// src/council/general-council-advisory.ts
|
|
86497
87212
|
var ADVISORY_HEADER = "[general_council] (advisory; not blocking)";
|
|
@@ -86919,13 +87634,13 @@ var convene_general_council = createSwarmTool({
|
|
|
86919
87634
|
const round1 = input.round1Responses;
|
|
86920
87635
|
const round2 = input.round2Responses ?? [];
|
|
86921
87636
|
const result = synthesizeGeneralCouncil(input.question, input.mode, round1, round2);
|
|
86922
|
-
const evidenceDir =
|
|
87637
|
+
const evidenceDir = path99.join(workingDir, ".swarm", "council", "general");
|
|
86923
87638
|
const safeTimestamp = result.timestamp.replace(/[:.]/g, "-");
|
|
86924
87639
|
const evidenceFile = `${safeTimestamp}-${input.mode}.json`;
|
|
86925
|
-
const evidencePath =
|
|
87640
|
+
const evidencePath = path99.join(evidenceDir, evidenceFile);
|
|
86926
87641
|
try {
|
|
86927
|
-
await
|
|
86928
|
-
await
|
|
87642
|
+
await fs73.promises.mkdir(evidenceDir, { recursive: true });
|
|
87643
|
+
await fs73.promises.writeFile(evidencePath, JSON.stringify(result, null, 2));
|
|
86929
87644
|
} catch (err2) {
|
|
86930
87645
|
const message = err2 instanceof Error ? err2.message : String(err2);
|
|
86931
87646
|
console.warn(`[convene_general_council] Failed to write evidence to ${evidencePath}: ${message}`);
|
|
@@ -87166,8 +87881,8 @@ init_scope_persistence();
|
|
|
87166
87881
|
init_state();
|
|
87167
87882
|
init_task_id();
|
|
87168
87883
|
init_create_tool();
|
|
87169
|
-
import * as
|
|
87170
|
-
import * as
|
|
87884
|
+
import * as fs74 from "node:fs";
|
|
87885
|
+
import * as path100 from "node:path";
|
|
87171
87886
|
function validateTaskIdFormat2(taskId) {
|
|
87172
87887
|
return validateTaskIdFormat(taskId);
|
|
87173
87888
|
}
|
|
@@ -87241,8 +87956,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
87241
87956
|
};
|
|
87242
87957
|
}
|
|
87243
87958
|
}
|
|
87244
|
-
normalizedDir =
|
|
87245
|
-
const pathParts = normalizedDir.split(
|
|
87959
|
+
normalizedDir = path100.normalize(args2.working_directory);
|
|
87960
|
+
const pathParts = normalizedDir.split(path100.sep);
|
|
87246
87961
|
if (pathParts.includes("..")) {
|
|
87247
87962
|
return {
|
|
87248
87963
|
success: false,
|
|
@@ -87252,11 +87967,11 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
87252
87967
|
]
|
|
87253
87968
|
};
|
|
87254
87969
|
}
|
|
87255
|
-
const resolvedDir =
|
|
87970
|
+
const resolvedDir = path100.resolve(normalizedDir);
|
|
87256
87971
|
try {
|
|
87257
|
-
const realPath =
|
|
87258
|
-
const planPath2 =
|
|
87259
|
-
if (!
|
|
87972
|
+
const realPath = fs74.realpathSync(resolvedDir);
|
|
87973
|
+
const planPath2 = path100.join(realPath, ".swarm", "plan.json");
|
|
87974
|
+
if (!fs74.existsSync(planPath2)) {
|
|
87260
87975
|
return {
|
|
87261
87976
|
success: false,
|
|
87262
87977
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -87279,8 +87994,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
87279
87994
|
console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
|
|
87280
87995
|
}
|
|
87281
87996
|
const directory = normalizedDir || fallbackDir;
|
|
87282
|
-
const planPath =
|
|
87283
|
-
if (!
|
|
87997
|
+
const planPath = path100.resolve(directory, ".swarm", "plan.json");
|
|
87998
|
+
if (!fs74.existsSync(planPath)) {
|
|
87284
87999
|
return {
|
|
87285
88000
|
success: false,
|
|
87286
88001
|
message: "No plan found",
|
|
@@ -87289,7 +88004,7 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
87289
88004
|
}
|
|
87290
88005
|
let planContent;
|
|
87291
88006
|
try {
|
|
87292
|
-
planContent = JSON.parse(
|
|
88007
|
+
planContent = JSON.parse(fs74.readFileSync(planPath, "utf-8"));
|
|
87293
88008
|
} catch {
|
|
87294
88009
|
return {
|
|
87295
88010
|
success: false,
|
|
@@ -87319,8 +88034,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
87319
88034
|
const normalizeErrors = [];
|
|
87320
88035
|
const dir = normalizedDir || fallbackDir || process.cwd();
|
|
87321
88036
|
const mergedFiles = rawMergedFiles.map((file3) => {
|
|
87322
|
-
if (
|
|
87323
|
-
const relativePath =
|
|
88037
|
+
if (path100.isAbsolute(file3)) {
|
|
88038
|
+
const relativePath = path100.relative(dir, file3).replace(/\\/g, "/");
|
|
87324
88039
|
if (relativePath.startsWith("..")) {
|
|
87325
88040
|
normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
|
|
87326
88041
|
return file3;
|
|
@@ -87380,8 +88095,8 @@ var declare_scope = createSwarmTool({
|
|
|
87380
88095
|
// src/tools/diff.ts
|
|
87381
88096
|
init_zod();
|
|
87382
88097
|
import * as child_process7 from "node:child_process";
|
|
87383
|
-
import * as
|
|
87384
|
-
import * as
|
|
88098
|
+
import * as fs75 from "node:fs";
|
|
88099
|
+
import * as path101 from "node:path";
|
|
87385
88100
|
init_create_tool();
|
|
87386
88101
|
var MAX_DIFF_LINES = 500;
|
|
87387
88102
|
var DIFF_TIMEOUT_MS = 30000;
|
|
@@ -87410,20 +88125,20 @@ function validateBase(base) {
|
|
|
87410
88125
|
function validatePaths(paths) {
|
|
87411
88126
|
if (!paths)
|
|
87412
88127
|
return null;
|
|
87413
|
-
for (const
|
|
87414
|
-
if (!
|
|
88128
|
+
for (const path102 of paths) {
|
|
88129
|
+
if (!path102 || path102.length === 0) {
|
|
87415
88130
|
return "empty path not allowed";
|
|
87416
88131
|
}
|
|
87417
|
-
if (
|
|
88132
|
+
if (path102.length > MAX_PATH_LENGTH) {
|
|
87418
88133
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
87419
88134
|
}
|
|
87420
|
-
if (SHELL_METACHARACTERS2.test(
|
|
88135
|
+
if (SHELL_METACHARACTERS2.test(path102)) {
|
|
87421
88136
|
return "path contains shell metacharacters";
|
|
87422
88137
|
}
|
|
87423
|
-
if (
|
|
88138
|
+
if (path102.startsWith("-")) {
|
|
87424
88139
|
return 'path cannot start with "-" (option-like arguments not allowed)';
|
|
87425
88140
|
}
|
|
87426
|
-
if (CONTROL_CHAR_PATTERN2.test(
|
|
88141
|
+
if (CONTROL_CHAR_PATTERN2.test(path102)) {
|
|
87427
88142
|
return "path contains control characters";
|
|
87428
88143
|
}
|
|
87429
88144
|
}
|
|
@@ -87531,8 +88246,8 @@ var diff = createSwarmTool({
|
|
|
87531
88246
|
if (parts2.length >= 3) {
|
|
87532
88247
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
87533
88248
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
87534
|
-
const
|
|
87535
|
-
files.push({ path:
|
|
88249
|
+
const path102 = parts2[2];
|
|
88250
|
+
files.push({ path: path102, additions, deletions });
|
|
87536
88251
|
}
|
|
87537
88252
|
}
|
|
87538
88253
|
const contractChanges = [];
|
|
@@ -87572,7 +88287,7 @@ var diff = createSwarmTool({
|
|
|
87572
88287
|
} else if (base === "unstaged") {
|
|
87573
88288
|
const oldRef = `:${file3.path}`;
|
|
87574
88289
|
oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
|
|
87575
|
-
newContent =
|
|
88290
|
+
newContent = fs75.readFileSync(path101.join(directory, file3.path), "utf-8");
|
|
87576
88291
|
} else {
|
|
87577
88292
|
const oldRef = `${base}:${file3.path}`;
|
|
87578
88293
|
oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
|
|
@@ -87646,8 +88361,8 @@ var diff = createSwarmTool({
|
|
|
87646
88361
|
// src/tools/diff-summary.ts
|
|
87647
88362
|
init_zod();
|
|
87648
88363
|
import * as child_process8 from "node:child_process";
|
|
87649
|
-
import * as
|
|
87650
|
-
import * as
|
|
88364
|
+
import * as fs76 from "node:fs";
|
|
88365
|
+
import * as path102 from "node:path";
|
|
87651
88366
|
init_create_tool();
|
|
87652
88367
|
var diff_summary = createSwarmTool({
|
|
87653
88368
|
description: "Generate a filtered semantic diff summary from AST analysis. Returns SemanticDiffSummary with optional filtering by classification or riskLevel.",
|
|
@@ -87695,7 +88410,7 @@ var diff_summary = createSwarmTool({
|
|
|
87695
88410
|
}
|
|
87696
88411
|
try {
|
|
87697
88412
|
let oldContent;
|
|
87698
|
-
const newContent =
|
|
88413
|
+
const newContent = fs76.readFileSync(path102.join(workingDir, filePath), "utf-8");
|
|
87699
88414
|
if (fileExistsInHead) {
|
|
87700
88415
|
oldContent = child_process8.execFileSync("git", ["show", `HEAD:${filePath}`], {
|
|
87701
88416
|
encoding: "utf-8",
|
|
@@ -87923,8 +88638,8 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
87923
88638
|
init_zod();
|
|
87924
88639
|
init_create_tool();
|
|
87925
88640
|
init_path_security();
|
|
87926
|
-
import * as
|
|
87927
|
-
import * as
|
|
88641
|
+
import * as fs77 from "node:fs";
|
|
88642
|
+
import * as path103 from "node:path";
|
|
87928
88643
|
var MAX_FILE_SIZE_BYTES6 = 1024 * 1024;
|
|
87929
88644
|
var MAX_EVIDENCE_FILES = 1000;
|
|
87930
88645
|
var EVIDENCE_DIR3 = ".swarm/evidence";
|
|
@@ -87951,9 +88666,9 @@ function validateRequiredTypes(input) {
|
|
|
87951
88666
|
return null;
|
|
87952
88667
|
}
|
|
87953
88668
|
function isPathWithinSwarm2(filePath, cwd) {
|
|
87954
|
-
const normalizedCwd =
|
|
87955
|
-
const swarmPath =
|
|
87956
|
-
const normalizedPath =
|
|
88669
|
+
const normalizedCwd = path103.resolve(cwd);
|
|
88670
|
+
const swarmPath = path103.join(normalizedCwd, ".swarm");
|
|
88671
|
+
const normalizedPath = path103.resolve(filePath);
|
|
87957
88672
|
return normalizedPath.startsWith(swarmPath);
|
|
87958
88673
|
}
|
|
87959
88674
|
function parseCompletedTasks(planContent) {
|
|
@@ -87969,12 +88684,12 @@ function parseCompletedTasks(planContent) {
|
|
|
87969
88684
|
}
|
|
87970
88685
|
function readEvidenceFiles(evidenceDir, _cwd) {
|
|
87971
88686
|
const evidence = [];
|
|
87972
|
-
if (!
|
|
88687
|
+
if (!fs77.existsSync(evidenceDir) || !fs77.statSync(evidenceDir).isDirectory()) {
|
|
87973
88688
|
return evidence;
|
|
87974
88689
|
}
|
|
87975
88690
|
let files;
|
|
87976
88691
|
try {
|
|
87977
|
-
files =
|
|
88692
|
+
files = fs77.readdirSync(evidenceDir);
|
|
87978
88693
|
} catch {
|
|
87979
88694
|
return evidence;
|
|
87980
88695
|
}
|
|
@@ -87983,14 +88698,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
87983
88698
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
87984
88699
|
continue;
|
|
87985
88700
|
}
|
|
87986
|
-
const filePath =
|
|
88701
|
+
const filePath = path103.join(evidenceDir, filename);
|
|
87987
88702
|
try {
|
|
87988
|
-
const resolvedPath =
|
|
87989
|
-
const evidenceDirResolved =
|
|
88703
|
+
const resolvedPath = path103.resolve(filePath);
|
|
88704
|
+
const evidenceDirResolved = path103.resolve(evidenceDir);
|
|
87990
88705
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
87991
88706
|
continue;
|
|
87992
88707
|
}
|
|
87993
|
-
const stat8 =
|
|
88708
|
+
const stat8 = fs77.lstatSync(filePath);
|
|
87994
88709
|
if (!stat8.isFile()) {
|
|
87995
88710
|
continue;
|
|
87996
88711
|
}
|
|
@@ -87999,7 +88714,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
87999
88714
|
}
|
|
88000
88715
|
let fileStat;
|
|
88001
88716
|
try {
|
|
88002
|
-
fileStat =
|
|
88717
|
+
fileStat = fs77.statSync(filePath);
|
|
88003
88718
|
if (fileStat.size > MAX_FILE_SIZE_BYTES6) {
|
|
88004
88719
|
continue;
|
|
88005
88720
|
}
|
|
@@ -88008,7 +88723,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
88008
88723
|
}
|
|
88009
88724
|
let content;
|
|
88010
88725
|
try {
|
|
88011
|
-
content =
|
|
88726
|
+
content = fs77.readFileSync(filePath, "utf-8");
|
|
88012
88727
|
} catch {
|
|
88013
88728
|
continue;
|
|
88014
88729
|
}
|
|
@@ -88104,7 +88819,7 @@ var evidence_check = createSwarmTool({
|
|
|
88104
88819
|
return JSON.stringify(errorResult, null, 2);
|
|
88105
88820
|
}
|
|
88106
88821
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
|
|
88107
|
-
const planPath =
|
|
88822
|
+
const planPath = path103.join(cwd, PLAN_FILE);
|
|
88108
88823
|
if (!isPathWithinSwarm2(planPath, cwd)) {
|
|
88109
88824
|
const errorResult = {
|
|
88110
88825
|
error: "plan file path validation failed",
|
|
@@ -88118,7 +88833,7 @@ var evidence_check = createSwarmTool({
|
|
|
88118
88833
|
}
|
|
88119
88834
|
let planContent;
|
|
88120
88835
|
try {
|
|
88121
|
-
planContent =
|
|
88836
|
+
planContent = fs77.readFileSync(planPath, "utf-8");
|
|
88122
88837
|
} catch {
|
|
88123
88838
|
const result2 = {
|
|
88124
88839
|
message: "No completed tasks found in plan.",
|
|
@@ -88136,7 +88851,7 @@ var evidence_check = createSwarmTool({
|
|
|
88136
88851
|
};
|
|
88137
88852
|
return JSON.stringify(result2, null, 2);
|
|
88138
88853
|
}
|
|
88139
|
-
const evidenceDir =
|
|
88854
|
+
const evidenceDir = path103.join(cwd, EVIDENCE_DIR3);
|
|
88140
88855
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
88141
88856
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
88142
88857
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -88153,8 +88868,8 @@ var evidence_check = createSwarmTool({
|
|
|
88153
88868
|
// src/tools/file-extractor.ts
|
|
88154
88869
|
init_zod();
|
|
88155
88870
|
init_create_tool();
|
|
88156
|
-
import * as
|
|
88157
|
-
import * as
|
|
88871
|
+
import * as fs78 from "node:fs";
|
|
88872
|
+
import * as path104 from "node:path";
|
|
88158
88873
|
var EXT_MAP = {
|
|
88159
88874
|
python: ".py",
|
|
88160
88875
|
py: ".py",
|
|
@@ -88216,8 +88931,8 @@ var extract_code_blocks = createSwarmTool({
|
|
|
88216
88931
|
execute: async (args2, directory) => {
|
|
88217
88932
|
const { content, output_dir, prefix } = args2;
|
|
88218
88933
|
const targetDir = output_dir || directory;
|
|
88219
|
-
if (!
|
|
88220
|
-
|
|
88934
|
+
if (!fs78.existsSync(targetDir)) {
|
|
88935
|
+
fs78.mkdirSync(targetDir, { recursive: true });
|
|
88221
88936
|
}
|
|
88222
88937
|
if (!content) {
|
|
88223
88938
|
return "Error: content is required";
|
|
@@ -88235,16 +88950,16 @@ var extract_code_blocks = createSwarmTool({
|
|
|
88235
88950
|
if (prefix) {
|
|
88236
88951
|
filename = `${prefix}_${filename}`;
|
|
88237
88952
|
}
|
|
88238
|
-
let filepath =
|
|
88239
|
-
const base =
|
|
88240
|
-
const ext =
|
|
88953
|
+
let filepath = path104.join(targetDir, filename);
|
|
88954
|
+
const base = path104.basename(filepath, path104.extname(filepath));
|
|
88955
|
+
const ext = path104.extname(filepath);
|
|
88241
88956
|
let counter = 1;
|
|
88242
|
-
while (
|
|
88243
|
-
filepath =
|
|
88957
|
+
while (fs78.existsSync(filepath)) {
|
|
88958
|
+
filepath = path104.join(targetDir, `${base}_${counter}${ext}`);
|
|
88244
88959
|
counter++;
|
|
88245
88960
|
}
|
|
88246
88961
|
try {
|
|
88247
|
-
|
|
88962
|
+
fs78.writeFileSync(filepath, code.trim(), "utf-8");
|
|
88248
88963
|
savedFiles.push(filepath);
|
|
88249
88964
|
} catch (error93) {
|
|
88250
88965
|
errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
@@ -88497,8 +89212,8 @@ var gitingest = createSwarmTool({
|
|
|
88497
89212
|
init_zod();
|
|
88498
89213
|
init_create_tool();
|
|
88499
89214
|
init_path_security();
|
|
88500
|
-
import * as
|
|
88501
|
-
import * as
|
|
89215
|
+
import * as fs79 from "node:fs";
|
|
89216
|
+
import * as path105 from "node:path";
|
|
88502
89217
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
88503
89218
|
var MAX_SYMBOL_LENGTH = 256;
|
|
88504
89219
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
@@ -88546,7 +89261,7 @@ function validateSymbolInput(symbol3) {
|
|
|
88546
89261
|
return null;
|
|
88547
89262
|
}
|
|
88548
89263
|
function isBinaryFile2(filePath, buffer) {
|
|
88549
|
-
const ext =
|
|
89264
|
+
const ext = path105.extname(filePath).toLowerCase();
|
|
88550
89265
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
88551
89266
|
return false;
|
|
88552
89267
|
}
|
|
@@ -88570,15 +89285,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
88570
89285
|
const imports = [];
|
|
88571
89286
|
let _resolvedTarget;
|
|
88572
89287
|
try {
|
|
88573
|
-
_resolvedTarget =
|
|
89288
|
+
_resolvedTarget = path105.resolve(targetFile);
|
|
88574
89289
|
} catch {
|
|
88575
89290
|
_resolvedTarget = targetFile;
|
|
88576
89291
|
}
|
|
88577
|
-
const targetBasename =
|
|
89292
|
+
const targetBasename = path105.basename(targetFile, path105.extname(targetFile));
|
|
88578
89293
|
const targetWithExt = targetFile;
|
|
88579
89294
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
88580
|
-
const normalizedTargetWithExt =
|
|
88581
|
-
const normalizedTargetWithoutExt =
|
|
89295
|
+
const normalizedTargetWithExt = path105.normalize(targetWithExt).replace(/\\/g, "/");
|
|
89296
|
+
const normalizedTargetWithoutExt = path105.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
88582
89297
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
88583
89298
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
88584
89299
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -88601,9 +89316,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
88601
89316
|
}
|
|
88602
89317
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
88603
89318
|
let isMatch = false;
|
|
88604
|
-
const _targetDir =
|
|
88605
|
-
const targetExt =
|
|
88606
|
-
const targetBasenameNoExt =
|
|
89319
|
+
const _targetDir = path105.dirname(targetFile);
|
|
89320
|
+
const targetExt = path105.extname(targetFile);
|
|
89321
|
+
const targetBasenameNoExt = path105.basename(targetFile, targetExt);
|
|
88607
89322
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
88608
89323
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
88609
89324
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -88660,7 +89375,7 @@ var SKIP_DIRECTORIES4 = new Set([
|
|
|
88660
89375
|
function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
|
|
88661
89376
|
let entries;
|
|
88662
89377
|
try {
|
|
88663
|
-
entries =
|
|
89378
|
+
entries = fs79.readdirSync(dir);
|
|
88664
89379
|
} catch (e) {
|
|
88665
89380
|
stats.fileErrors.push({
|
|
88666
89381
|
path: dir,
|
|
@@ -88671,13 +89386,13 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
88671
89386
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
88672
89387
|
for (const entry of entries) {
|
|
88673
89388
|
if (SKIP_DIRECTORIES4.has(entry)) {
|
|
88674
|
-
stats.skippedDirs.push(
|
|
89389
|
+
stats.skippedDirs.push(path105.join(dir, entry));
|
|
88675
89390
|
continue;
|
|
88676
89391
|
}
|
|
88677
|
-
const fullPath =
|
|
89392
|
+
const fullPath = path105.join(dir, entry);
|
|
88678
89393
|
let stat8;
|
|
88679
89394
|
try {
|
|
88680
|
-
stat8 =
|
|
89395
|
+
stat8 = fs79.statSync(fullPath);
|
|
88681
89396
|
} catch (e) {
|
|
88682
89397
|
stats.fileErrors.push({
|
|
88683
89398
|
path: fullPath,
|
|
@@ -88688,7 +89403,7 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
88688
89403
|
if (stat8.isDirectory()) {
|
|
88689
89404
|
findSourceFiles2(fullPath, files, stats);
|
|
88690
89405
|
} else if (stat8.isFile()) {
|
|
88691
|
-
const ext =
|
|
89406
|
+
const ext = path105.extname(fullPath).toLowerCase();
|
|
88692
89407
|
if (SUPPORTED_EXTENSIONS3.includes(ext)) {
|
|
88693
89408
|
files.push(fullPath);
|
|
88694
89409
|
}
|
|
@@ -88745,8 +89460,8 @@ var imports = createSwarmTool({
|
|
|
88745
89460
|
return JSON.stringify(errorResult, null, 2);
|
|
88746
89461
|
}
|
|
88747
89462
|
try {
|
|
88748
|
-
const targetFile =
|
|
88749
|
-
if (!
|
|
89463
|
+
const targetFile = path105.resolve(file3);
|
|
89464
|
+
if (!fs79.existsSync(targetFile)) {
|
|
88750
89465
|
const errorResult = {
|
|
88751
89466
|
error: `target file not found: ${file3}`,
|
|
88752
89467
|
target: file3,
|
|
@@ -88756,7 +89471,7 @@ var imports = createSwarmTool({
|
|
|
88756
89471
|
};
|
|
88757
89472
|
return JSON.stringify(errorResult, null, 2);
|
|
88758
89473
|
}
|
|
88759
|
-
const targetStat =
|
|
89474
|
+
const targetStat = fs79.statSync(targetFile);
|
|
88760
89475
|
if (!targetStat.isFile()) {
|
|
88761
89476
|
const errorResult = {
|
|
88762
89477
|
error: "target must be a file, not a directory",
|
|
@@ -88767,7 +89482,7 @@ var imports = createSwarmTool({
|
|
|
88767
89482
|
};
|
|
88768
89483
|
return JSON.stringify(errorResult, null, 2);
|
|
88769
89484
|
}
|
|
88770
|
-
const baseDir =
|
|
89485
|
+
const baseDir = path105.dirname(targetFile);
|
|
88771
89486
|
const scanStats = {
|
|
88772
89487
|
skippedDirs: [],
|
|
88773
89488
|
skippedFiles: 0,
|
|
@@ -88782,12 +89497,12 @@ var imports = createSwarmTool({
|
|
|
88782
89497
|
if (consumers.length >= MAX_CONSUMERS)
|
|
88783
89498
|
break;
|
|
88784
89499
|
try {
|
|
88785
|
-
const stat8 =
|
|
89500
|
+
const stat8 = fs79.statSync(filePath);
|
|
88786
89501
|
if (stat8.size > MAX_FILE_SIZE_BYTES7) {
|
|
88787
89502
|
skippedFileCount++;
|
|
88788
89503
|
continue;
|
|
88789
89504
|
}
|
|
88790
|
-
const buffer =
|
|
89505
|
+
const buffer = fs79.readFileSync(filePath);
|
|
88791
89506
|
if (isBinaryFile2(filePath, buffer)) {
|
|
88792
89507
|
skippedFileCount++;
|
|
88793
89508
|
continue;
|
|
@@ -88852,7 +89567,7 @@ var imports = createSwarmTool({
|
|
|
88852
89567
|
});
|
|
88853
89568
|
// src/tools/knowledge-ack.ts
|
|
88854
89569
|
init_zod();
|
|
88855
|
-
import { randomUUID as
|
|
89570
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
88856
89571
|
init_state();
|
|
88857
89572
|
init_logger();
|
|
88858
89573
|
init_create_tool();
|
|
@@ -88885,7 +89600,7 @@ var knowledge_ack = createSwarmTool({
|
|
|
88885
89600
|
let sessionId = ctx?.sessionID;
|
|
88886
89601
|
if (!sessionId) {
|
|
88887
89602
|
warn("[knowledge-ack] No sessionID in tool context — dedup disabled for this acknowledgment");
|
|
88888
|
-
sessionId =
|
|
89603
|
+
sessionId = randomUUID8();
|
|
88889
89604
|
}
|
|
88890
89605
|
const dedupKey = buildAckDedupKey(sessionId, a.id, a.result);
|
|
88891
89606
|
if (swarmState.knowledgeAckDedup.has(dedupKey)) {
|
|
@@ -88915,7 +89630,7 @@ init_knowledge_store();
|
|
|
88915
89630
|
init_knowledge_validator();
|
|
88916
89631
|
init_manager();
|
|
88917
89632
|
init_create_tool();
|
|
88918
|
-
import { randomUUID as
|
|
89633
|
+
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
88919
89634
|
var VALID_CATEGORIES2 = [
|
|
88920
89635
|
"process",
|
|
88921
89636
|
"architecture",
|
|
@@ -88989,7 +89704,7 @@ var knowledge_add = createSwarmTool({
|
|
|
88989
89704
|
project_name = plan?.title ?? "";
|
|
88990
89705
|
} catch {}
|
|
88991
89706
|
const entry = {
|
|
88992
|
-
id:
|
|
89707
|
+
id: randomUUID9(),
|
|
88993
89708
|
tier: "swarm",
|
|
88994
89709
|
lesson,
|
|
88995
89710
|
category,
|
|
@@ -89058,7 +89773,7 @@ init_zod();
|
|
|
89058
89773
|
init_config();
|
|
89059
89774
|
init_knowledge_store();
|
|
89060
89775
|
init_create_tool();
|
|
89061
|
-
import { existsSync as
|
|
89776
|
+
import { existsSync as existsSync59 } from "node:fs";
|
|
89062
89777
|
var DEFAULT_LIMIT = 10;
|
|
89063
89778
|
var MAX_LESSON_LENGTH = 200;
|
|
89064
89779
|
var VALID_CATEGORIES3 = [
|
|
@@ -89128,14 +89843,14 @@ function validateLimit(limit) {
|
|
|
89128
89843
|
}
|
|
89129
89844
|
async function readSwarmKnowledge(directory) {
|
|
89130
89845
|
const swarmPath = resolveSwarmKnowledgePath(directory);
|
|
89131
|
-
if (!
|
|
89846
|
+
if (!existsSync59(swarmPath)) {
|
|
89132
89847
|
return [];
|
|
89133
89848
|
}
|
|
89134
89849
|
return readKnowledge(swarmPath);
|
|
89135
89850
|
}
|
|
89136
89851
|
async function readHiveKnowledge() {
|
|
89137
89852
|
const hivePath = resolveHiveKnowledgePath();
|
|
89138
|
-
if (!
|
|
89853
|
+
if (!existsSync59(hivePath)) {
|
|
89139
89854
|
return [];
|
|
89140
89855
|
}
|
|
89141
89856
|
return readKnowledge(hivePath);
|
|
@@ -89369,30 +90084,30 @@ init_config();
|
|
|
89369
90084
|
init_schema();
|
|
89370
90085
|
init_qa_gate_profile();
|
|
89371
90086
|
init_manager2();
|
|
89372
|
-
import * as
|
|
89373
|
-
import * as
|
|
90087
|
+
import * as fs84 from "node:fs";
|
|
90088
|
+
import * as path110 from "node:path";
|
|
89374
90089
|
|
|
89375
90090
|
// src/full-auto/phase-approval.ts
|
|
89376
90091
|
init_utils2();
|
|
89377
90092
|
init_logger();
|
|
89378
90093
|
init_state2();
|
|
89379
|
-
import * as
|
|
89380
|
-
import * as
|
|
90094
|
+
import * as fs80 from "node:fs";
|
|
90095
|
+
import * as path106 from "node:path";
|
|
89381
90096
|
var APPROVAL_TTL_MS = 24 * 60 * 60 * 1000;
|
|
89382
90097
|
function readEvidenceDir(directory, phase) {
|
|
89383
90098
|
try {
|
|
89384
|
-
const dirPath = validateSwarmPath(directory,
|
|
89385
|
-
if (!
|
|
90099
|
+
const dirPath = validateSwarmPath(directory, path106.posix.join("evidence", String(phase)));
|
|
90100
|
+
if (!fs80.existsSync(dirPath))
|
|
89386
90101
|
return [];
|
|
89387
|
-
const entries =
|
|
89388
|
-
return entries.filter((e) => e.startsWith("full-auto-") && e.endsWith(".json")).map((e) =>
|
|
90102
|
+
const entries = fs80.readdirSync(dirPath);
|
|
90103
|
+
return entries.filter((e) => e.startsWith("full-auto-") && e.endsWith(".json")).map((e) => path106.join(dirPath, e));
|
|
89389
90104
|
} catch {
|
|
89390
90105
|
return [];
|
|
89391
90106
|
}
|
|
89392
90107
|
}
|
|
89393
90108
|
function parseEvidence(filePath) {
|
|
89394
90109
|
try {
|
|
89395
|
-
const raw =
|
|
90110
|
+
const raw = fs80.readFileSync(filePath, "utf-8");
|
|
89396
90111
|
const parsed = JSON.parse(raw);
|
|
89397
90112
|
return parsed;
|
|
89398
90113
|
} catch (error93) {
|
|
@@ -89481,9 +90196,9 @@ function verifyFullAutoPhaseApproval(directory, sessionID, phase, config3) {
|
|
|
89481
90196
|
function phaseIsExplicitlyNonCode(directory, phase) {
|
|
89482
90197
|
try {
|
|
89483
90198
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
89484
|
-
if (!
|
|
90199
|
+
if (!fs80.existsSync(planPath))
|
|
89485
90200
|
return false;
|
|
89486
|
-
const raw =
|
|
90201
|
+
const raw = fs80.readFileSync(planPath, "utf-8");
|
|
89487
90202
|
const plan = JSON.parse(raw);
|
|
89488
90203
|
const phases = Array.isArray(plan.phases) ? plan.phases : [];
|
|
89489
90204
|
const entry = phases.find((p) => p.id === phase || p.phase === phase);
|
|
@@ -89511,6 +90226,7 @@ function phaseIsExplicitlyNonCode(directory, phase) {
|
|
|
89511
90226
|
}
|
|
89512
90227
|
|
|
89513
90228
|
// src/tools/phase-complete.ts
|
|
90229
|
+
init_gate_evidence();
|
|
89514
90230
|
init_curator();
|
|
89515
90231
|
init_knowledge_curator();
|
|
89516
90232
|
init_knowledge_reader();
|
|
@@ -89523,20 +90239,20 @@ init_file_locks();
|
|
|
89523
90239
|
init_plan_schema();
|
|
89524
90240
|
init_ledger();
|
|
89525
90241
|
init_manager();
|
|
89526
|
-
import * as
|
|
89527
|
-
import * as
|
|
90242
|
+
import * as fs81 from "node:fs";
|
|
90243
|
+
import * as path107 from "node:path";
|
|
89528
90244
|
async function writeCheckpoint(directory) {
|
|
89529
90245
|
try {
|
|
89530
90246
|
const plan = await loadPlan(directory);
|
|
89531
90247
|
if (!plan)
|
|
89532
90248
|
return;
|
|
89533
|
-
const swarmDir =
|
|
89534
|
-
|
|
89535
|
-
const jsonPath =
|
|
89536
|
-
const mdPath =
|
|
89537
|
-
|
|
90249
|
+
const swarmDir = path107.join(directory, ".swarm");
|
|
90250
|
+
fs81.mkdirSync(swarmDir, { recursive: true });
|
|
90251
|
+
const jsonPath = path107.join(swarmDir, "SWARM_PLAN.json");
|
|
90252
|
+
const mdPath = path107.join(swarmDir, "SWARM_PLAN.md");
|
|
90253
|
+
fs81.writeFileSync(jsonPath, JSON.stringify(plan, null, 2), "utf8");
|
|
89538
90254
|
const md = derivePlanMarkdown(plan);
|
|
89539
|
-
|
|
90255
|
+
fs81.writeFileSync(mdPath, md, "utf8");
|
|
89540
90256
|
} catch (error93) {
|
|
89541
90257
|
console.warn(`[checkpoint] Failed to write SWARM_PLAN checkpoint: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
89542
90258
|
}
|
|
@@ -89551,16 +90267,16 @@ init_telemetry();
|
|
|
89551
90267
|
|
|
89552
90268
|
// src/turbo/lean/phase-ready.ts
|
|
89553
90269
|
init_file_locks();
|
|
89554
|
-
import * as
|
|
89555
|
-
import * as
|
|
90270
|
+
import * as fs83 from "node:fs";
|
|
90271
|
+
import * as path109 from "node:path";
|
|
89556
90272
|
|
|
89557
90273
|
// src/turbo/lean/evidence.ts
|
|
89558
90274
|
init_bun_compat();
|
|
89559
90275
|
import { rmSync as rmSync5 } from "node:fs";
|
|
89560
|
-
import * as
|
|
89561
|
-
import * as
|
|
90276
|
+
import * as fs82 from "node:fs/promises";
|
|
90277
|
+
import * as path108 from "node:path";
|
|
89562
90278
|
function leanTurboEvidenceDir(directory, phase) {
|
|
89563
|
-
return
|
|
90279
|
+
return path108.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
|
|
89564
90280
|
}
|
|
89565
90281
|
function validateLaneId(laneId) {
|
|
89566
90282
|
if (laneId.length === 0) {
|
|
@@ -89582,21 +90298,21 @@ function validateLaneId(laneId) {
|
|
|
89582
90298
|
function laneEvidencePath(directory, phase, laneId) {
|
|
89583
90299
|
validateLaneId(laneId);
|
|
89584
90300
|
const expectedDir = leanTurboEvidenceDir(directory, phase);
|
|
89585
|
-
const resolvedPath =
|
|
89586
|
-
const resolvedDir =
|
|
89587
|
-
if (!resolvedPath.startsWith(resolvedDir +
|
|
90301
|
+
const resolvedPath = path108.resolve(path108.join(expectedDir, `${laneId}.json`));
|
|
90302
|
+
const resolvedDir = path108.resolve(expectedDir);
|
|
90303
|
+
if (!resolvedPath.startsWith(resolvedDir + path108.sep) && resolvedPath !== resolvedDir) {
|
|
89588
90304
|
throw new Error(`Invalid laneId: path traversal detected (got "${laneId}")`);
|
|
89589
90305
|
}
|
|
89590
90306
|
return resolvedPath;
|
|
89591
90307
|
}
|
|
89592
90308
|
async function atomicWriteJson(filePath, data) {
|
|
89593
90309
|
const content = JSON.stringify(data, null, 2);
|
|
89594
|
-
const dir =
|
|
89595
|
-
await
|
|
90310
|
+
const dir = path108.dirname(filePath);
|
|
90311
|
+
await fs82.mkdir(dir, { recursive: true });
|
|
89596
90312
|
const tempPath = `${filePath}.tmp.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
89597
90313
|
try {
|
|
89598
90314
|
await bunWrite(tempPath, content);
|
|
89599
|
-
await
|
|
90315
|
+
await fs82.rename(tempPath, filePath);
|
|
89600
90316
|
} catch (error93) {
|
|
89601
90317
|
try {
|
|
89602
90318
|
rmSync5(tempPath, { force: true });
|
|
@@ -89605,7 +90321,7 @@ async function atomicWriteJson(filePath, data) {
|
|
|
89605
90321
|
}
|
|
89606
90322
|
}
|
|
89607
90323
|
function phaseEvidencePath(directory, phase) {
|
|
89608
|
-
return
|
|
90324
|
+
return path108.join(leanTurboEvidenceDir(directory, phase), "lean-turbo-phase.json");
|
|
89609
90325
|
}
|
|
89610
90326
|
async function writeLaneEvidence(directory, phase, evidence) {
|
|
89611
90327
|
const targetPath = laneEvidencePath(directory, phase, evidence.laneId);
|
|
@@ -89615,7 +90331,7 @@ async function readPhaseEvidence(directory, phase) {
|
|
|
89615
90331
|
const targetPath = phaseEvidencePath(directory, phase);
|
|
89616
90332
|
let content;
|
|
89617
90333
|
try {
|
|
89618
|
-
content = await
|
|
90334
|
+
content = await fs82.readFile(targetPath, "utf-8");
|
|
89619
90335
|
} catch (error93) {
|
|
89620
90336
|
const code = error93.code;
|
|
89621
90337
|
if (code === "ENOENT" || code === "ENOTDIR") {
|
|
@@ -89633,7 +90349,7 @@ async function listLaneEvidence(directory, phase) {
|
|
|
89633
90349
|
const evidenceDir = leanTurboEvidenceDir(directory, phase);
|
|
89634
90350
|
let entries;
|
|
89635
90351
|
try {
|
|
89636
|
-
entries = await
|
|
90352
|
+
entries = await fs82.readdir(evidenceDir);
|
|
89637
90353
|
} catch (error93) {
|
|
89638
90354
|
const code = error93.code;
|
|
89639
90355
|
if (code === "ENOENT" || code === "ENOTDIR") {
|
|
@@ -89649,10 +90365,10 @@ async function listLaneEvidence(directory, phase) {
|
|
|
89649
90365
|
if (entry === "lean-turbo-phase.json") {
|
|
89650
90366
|
continue;
|
|
89651
90367
|
}
|
|
89652
|
-
const filePath =
|
|
90368
|
+
const filePath = path108.join(evidenceDir, entry);
|
|
89653
90369
|
let content;
|
|
89654
90370
|
try {
|
|
89655
|
-
content = await
|
|
90371
|
+
content = await fs82.readFile(filePath, "utf-8");
|
|
89656
90372
|
} catch {
|
|
89657
90373
|
continue;
|
|
89658
90374
|
}
|
|
@@ -89673,10 +90389,10 @@ var DEFAULT_CONFIG2 = {
|
|
|
89673
90389
|
};
|
|
89674
90390
|
function defaultReadPlanJson(dir) {
|
|
89675
90391
|
try {
|
|
89676
|
-
const planPath =
|
|
89677
|
-
if (!
|
|
90392
|
+
const planPath = path109.join(dir, ".swarm", "plan.json");
|
|
90393
|
+
if (!fs83.existsSync(planPath))
|
|
89678
90394
|
return null;
|
|
89679
|
-
const raw =
|
|
90395
|
+
const raw = fs83.readFileSync(planPath, "utf-8");
|
|
89680
90396
|
const plan = JSON.parse(raw);
|
|
89681
90397
|
if (typeof plan !== "object" || plan === null || !Array.isArray(plan.phases)) {
|
|
89682
90398
|
return null;
|
|
@@ -89688,11 +90404,11 @@ function defaultReadPlanJson(dir) {
|
|
|
89688
90404
|
}
|
|
89689
90405
|
function readReviewerEvidenceFromFile(directory, phase) {
|
|
89690
90406
|
try {
|
|
89691
|
-
const evidencePath =
|
|
89692
|
-
if (!
|
|
90407
|
+
const evidencePath = path109.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-reviewer.json");
|
|
90408
|
+
if (!fs83.existsSync(evidencePath)) {
|
|
89693
90409
|
return null;
|
|
89694
90410
|
}
|
|
89695
|
-
const raw =
|
|
90411
|
+
const raw = fs83.readFileSync(evidencePath, "utf-8");
|
|
89696
90412
|
const parsed = JSON.parse(raw);
|
|
89697
90413
|
if (typeof parsed !== "object" || parsed === null || typeof parsed.verdict !== "string") {
|
|
89698
90414
|
return null;
|
|
@@ -89708,11 +90424,11 @@ function readReviewerEvidenceFromFile(directory, phase) {
|
|
|
89708
90424
|
}
|
|
89709
90425
|
function readCriticEvidenceFromFile(directory, phase) {
|
|
89710
90426
|
try {
|
|
89711
|
-
const evidencePath =
|
|
89712
|
-
if (!
|
|
90427
|
+
const evidencePath = path109.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-critic.json");
|
|
90428
|
+
if (!fs83.existsSync(evidencePath)) {
|
|
89713
90429
|
return null;
|
|
89714
90430
|
}
|
|
89715
|
-
const raw =
|
|
90431
|
+
const raw = fs83.readFileSync(evidencePath, "utf-8");
|
|
89716
90432
|
const parsed = JSON.parse(raw);
|
|
89717
90433
|
if (typeof parsed !== "object" || parsed === null || typeof parsed.verdict !== "string") {
|
|
89718
90434
|
return null;
|
|
@@ -89727,10 +90443,10 @@ function readCriticEvidenceFromFile(directory, phase) {
|
|
|
89727
90443
|
}
|
|
89728
90444
|
}
|
|
89729
90445
|
function listLaneEvidenceSync(directory, phase) {
|
|
89730
|
-
const evidenceDir =
|
|
90446
|
+
const evidenceDir = path109.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
|
|
89731
90447
|
let entries;
|
|
89732
90448
|
try {
|
|
89733
|
-
entries =
|
|
90449
|
+
entries = fs83.readdirSync(evidenceDir);
|
|
89734
90450
|
} catch {
|
|
89735
90451
|
return [];
|
|
89736
90452
|
}
|
|
@@ -89743,7 +90459,7 @@ function listLaneEvidenceSync(directory, phase) {
|
|
|
89743
90459
|
}
|
|
89744
90460
|
return laneIds;
|
|
89745
90461
|
}
|
|
89746
|
-
var
|
|
90462
|
+
var _internals43 = {
|
|
89747
90463
|
listActiveLocks,
|
|
89748
90464
|
readPersisted: readPersisted2,
|
|
89749
90465
|
readPlanJson: defaultReadPlanJson,
|
|
@@ -89797,14 +90513,14 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
89797
90513
|
...DEFAULT_CONFIG2,
|
|
89798
90514
|
...actualConfig
|
|
89799
90515
|
};
|
|
89800
|
-
const statePath =
|
|
89801
|
-
if (!
|
|
90516
|
+
const statePath = path109.join(directory, ".swarm", "turbo-state.json");
|
|
90517
|
+
if (!fs83.existsSync(statePath)) {
|
|
89802
90518
|
return {
|
|
89803
90519
|
ok: false,
|
|
89804
90520
|
reason: "Lean Turbo state unreadable or missing"
|
|
89805
90521
|
};
|
|
89806
90522
|
}
|
|
89807
|
-
const persisted =
|
|
90523
|
+
const persisted = _internals43.readPersisted(directory);
|
|
89808
90524
|
if (!persisted) {
|
|
89809
90525
|
return {
|
|
89810
90526
|
ok: false,
|
|
@@ -89868,7 +90584,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
89868
90584
|
}
|
|
89869
90585
|
}
|
|
89870
90586
|
if (runState.lanes.length > 0) {
|
|
89871
|
-
const evidenceLaneIds = new Set(
|
|
90587
|
+
const evidenceLaneIds = new Set(_internals43.listLaneEvidenceSync(directory, phase));
|
|
89872
90588
|
for (const lane of runState.lanes) {
|
|
89873
90589
|
if ((lane.status === "completed" || lane.status === "failed") && !evidenceLaneIds.has(lane.laneId)) {
|
|
89874
90590
|
return {
|
|
@@ -89878,7 +90594,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
89878
90594
|
}
|
|
89879
90595
|
}
|
|
89880
90596
|
}
|
|
89881
|
-
const activeLocks =
|
|
90597
|
+
const activeLocks = _internals43.listActiveLocks(directory);
|
|
89882
90598
|
const phaseLaneIds = new Set(laneIds);
|
|
89883
90599
|
for (const lock of activeLocks) {
|
|
89884
90600
|
if (lock.laneId && phaseLaneIds.has(lock.laneId)) {
|
|
@@ -89898,7 +90614,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
89898
90614
|
}
|
|
89899
90615
|
const serialDegradedTasks = runState.degradedTasks.filter((dt) => !laneTaskIds.has(dt.taskId));
|
|
89900
90616
|
if (serialDegradedTasks.length > 0) {
|
|
89901
|
-
const plan =
|
|
90617
|
+
const plan = _internals43.readPlanJson(directory);
|
|
89902
90618
|
if (!plan) {
|
|
89903
90619
|
return {
|
|
89904
90620
|
ok: false,
|
|
@@ -89942,7 +90658,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
89942
90658
|
}
|
|
89943
90659
|
const serializedTasks = runState.serializedTasks;
|
|
89944
90660
|
if (Array.isArray(serializedTasks) && serializedTasks.length > 0) {
|
|
89945
|
-
const plan =
|
|
90661
|
+
const plan = _internals43.readPlanJson(directory);
|
|
89946
90662
|
if (!plan) {
|
|
89947
90663
|
return {
|
|
89948
90664
|
ok: false,
|
|
@@ -89985,10 +90701,10 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
89985
90701
|
}
|
|
89986
90702
|
}
|
|
89987
90703
|
if (mergedConfig.integrated_diff_required) {
|
|
89988
|
-
const evidencePath =
|
|
90704
|
+
const evidencePath = path109.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-phase.json");
|
|
89989
90705
|
let hasDiff = false;
|
|
89990
90706
|
try {
|
|
89991
|
-
const content =
|
|
90707
|
+
const content = fs83.readFileSync(evidencePath, "utf-8");
|
|
89992
90708
|
const evidence = JSON.parse(content);
|
|
89993
90709
|
hasDiff = !!evidence.integratedDiffSummary;
|
|
89994
90710
|
} catch {}
|
|
@@ -90001,7 +90717,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
90001
90717
|
}
|
|
90002
90718
|
let reviewerVerdict = runState.lastReviewerVerdict;
|
|
90003
90719
|
if (!reviewerVerdict) {
|
|
90004
|
-
const evidence =
|
|
90720
|
+
const evidence = _internals43.readReviewerEvidence(directory, phase);
|
|
90005
90721
|
reviewerVerdict = evidence?.verdict ?? undefined;
|
|
90006
90722
|
}
|
|
90007
90723
|
if (mergedConfig.phase_reviewer) {
|
|
@@ -90014,7 +90730,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
90014
90730
|
}
|
|
90015
90731
|
let criticVerdict = runState.lastCriticVerdict;
|
|
90016
90732
|
if (!criticVerdict) {
|
|
90017
|
-
const evidence =
|
|
90733
|
+
const evidence = _internals43.readCriticEvidence(directory, phase);
|
|
90018
90734
|
criticVerdict = evidence?.verdict ?? undefined;
|
|
90019
90735
|
}
|
|
90020
90736
|
if (mergedConfig.phase_critic) {
|
|
@@ -90046,6 +90762,23 @@ function safeWarn(message, error93) {
|
|
|
90046
90762
|
warn(message, error93 instanceof Error ? error93.message : String(error93));
|
|
90047
90763
|
} catch {}
|
|
90048
90764
|
}
|
|
90765
|
+
var TASK_GATE_INFERABLE_AGENTS = new Set([
|
|
90766
|
+
"coder",
|
|
90767
|
+
"reviewer",
|
|
90768
|
+
"test_engineer"
|
|
90769
|
+
]);
|
|
90770
|
+
function canInferMissingAgentsFromTaskGates(agentsMissing) {
|
|
90771
|
+
return agentsMissing.every((agent) => TASK_GATE_INFERABLE_AGENTS.has(agent));
|
|
90772
|
+
}
|
|
90773
|
+
async function allCompletedTasksHavePassedGateEvidence(directory, tasks) {
|
|
90774
|
+
for (const task of tasks) {
|
|
90775
|
+
if (task.status !== "completed")
|
|
90776
|
+
return false;
|
|
90777
|
+
if (!await hasPassedAllGates(directory, task.id))
|
|
90778
|
+
return false;
|
|
90779
|
+
}
|
|
90780
|
+
return tasks.length > 0;
|
|
90781
|
+
}
|
|
90049
90782
|
function collectCrossSessionDispatchedAgents(phaseReferenceTimestamp, callerSessionId) {
|
|
90050
90783
|
const agents = new Set;
|
|
90051
90784
|
const contributorSessionIds = [];
|
|
@@ -90057,12 +90790,9 @@ function collectCrossSessionDispatchedAgents(phaseReferenceTimestamp, callerSess
|
|
|
90057
90790
|
agents.add(agent);
|
|
90058
90791
|
}
|
|
90059
90792
|
}
|
|
90060
|
-
const
|
|
90061
|
-
|
|
90062
|
-
|
|
90063
|
-
agents.add(stripKnownSwarmPrefix(delegation.from));
|
|
90064
|
-
agents.add(stripKnownSwarmPrefix(delegation.to));
|
|
90065
|
-
}
|
|
90793
|
+
for (const delegation of _getDelegationsSince(callerSessionId, phaseReferenceTimestamp)) {
|
|
90794
|
+
agents.add(stripKnownSwarmPrefix(delegation.from));
|
|
90795
|
+
agents.add(stripKnownSwarmPrefix(delegation.to));
|
|
90066
90796
|
}
|
|
90067
90797
|
}
|
|
90068
90798
|
for (const [sessionId, session] of swarmState.agentSessions) {
|
|
@@ -90081,17 +90811,24 @@ function collectCrossSessionDispatchedAgents(phaseReferenceTimestamp, callerSess
|
|
|
90081
90811
|
agents.add(agent);
|
|
90082
90812
|
}
|
|
90083
90813
|
}
|
|
90084
|
-
const
|
|
90085
|
-
|
|
90086
|
-
|
|
90087
|
-
agents.add(stripKnownSwarmPrefix(delegation.from));
|
|
90088
|
-
agents.add(stripKnownSwarmPrefix(delegation.to));
|
|
90089
|
-
}
|
|
90814
|
+
for (const delegation of _getDelegationsSince(sessionId, phaseReferenceTimestamp)) {
|
|
90815
|
+
agents.add(stripKnownSwarmPrefix(delegation.from));
|
|
90816
|
+
agents.add(stripKnownSwarmPrefix(delegation.to));
|
|
90090
90817
|
}
|
|
90091
90818
|
}
|
|
90092
90819
|
}
|
|
90093
90820
|
return { agents, contributorSessionIds };
|
|
90094
90821
|
}
|
|
90822
|
+
function _getDelegationsSince(sessionID, sinceTimestamp) {
|
|
90823
|
+
const chain = swarmState.delegationChains.get(sessionID);
|
|
90824
|
+
if (!chain) {
|
|
90825
|
+
return [];
|
|
90826
|
+
}
|
|
90827
|
+
if (sinceTimestamp === 0) {
|
|
90828
|
+
return chain;
|
|
90829
|
+
}
|
|
90830
|
+
return chain.filter((entry) => entry.timestamp > sinceTimestamp);
|
|
90831
|
+
}
|
|
90095
90832
|
function isValidRetroEntry(entry, phase) {
|
|
90096
90833
|
return entry.type === "retrospective" && "phase_number" in entry && entry.phase_number === phase && "verdict" in entry && entry.verdict === "pass";
|
|
90097
90834
|
}
|
|
@@ -90259,8 +90996,8 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
90259
90996
|
let driftCheckEnabled = true;
|
|
90260
90997
|
let driftHasSpecMd = false;
|
|
90261
90998
|
try {
|
|
90262
|
-
const specMdPath =
|
|
90263
|
-
driftHasSpecMd =
|
|
90999
|
+
const specMdPath = path110.join(dir, ".swarm", "spec.md");
|
|
91000
|
+
driftHasSpecMd = fs84.existsSync(specMdPath);
|
|
90264
91001
|
const gatePlan = await loadPlan(dir);
|
|
90265
91002
|
if (gatePlan) {
|
|
90266
91003
|
const gatePlanId = derivePlanId(gatePlan);
|
|
@@ -90280,9 +91017,9 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
90280
91017
|
} else {
|
|
90281
91018
|
let phaseType;
|
|
90282
91019
|
try {
|
|
90283
|
-
const planPath =
|
|
90284
|
-
if (
|
|
90285
|
-
const planRaw =
|
|
91020
|
+
const planPath = path110.join(dir, ".swarm", "plan.json");
|
|
91021
|
+
if (fs84.existsSync(planPath)) {
|
|
91022
|
+
const planRaw = fs84.readFileSync(planPath, "utf-8");
|
|
90286
91023
|
const plan = JSON.parse(planRaw);
|
|
90287
91024
|
const targetPhase = plan.phases?.find((p) => p.id === phase);
|
|
90288
91025
|
phaseType = targetPhase?.type;
|
|
@@ -90292,11 +91029,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
90292
91029
|
warnings.push(`Phase ${phase} is annotated as 'non-code'. Drift verification was skipped per phase type annotation.`);
|
|
90293
91030
|
} else {
|
|
90294
91031
|
try {
|
|
90295
|
-
const driftEvidencePath =
|
|
91032
|
+
const driftEvidencePath = path110.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
|
|
90296
91033
|
let driftVerdictFound = false;
|
|
90297
91034
|
let driftVerdictApproved = false;
|
|
90298
91035
|
try {
|
|
90299
|
-
const driftEvidenceContent =
|
|
91036
|
+
const driftEvidenceContent = fs84.readFileSync(driftEvidencePath, "utf-8");
|
|
90300
91037
|
const driftEvidence = JSON.parse(driftEvidenceContent);
|
|
90301
91038
|
const entries = driftEvidence.entries ?? [];
|
|
90302
91039
|
for (const entry of entries) {
|
|
@@ -90330,9 +91067,9 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
90330
91067
|
let incompleteTaskCount = 0;
|
|
90331
91068
|
let planParseable = false;
|
|
90332
91069
|
try {
|
|
90333
|
-
const planPath =
|
|
90334
|
-
if (
|
|
90335
|
-
const planRaw =
|
|
91070
|
+
const planPath = path110.join(dir, ".swarm", "plan.json");
|
|
91071
|
+
if (fs84.existsSync(planPath)) {
|
|
91072
|
+
const planRaw = fs84.readFileSync(planPath, "utf-8");
|
|
90336
91073
|
const plan = JSON.parse(planRaw);
|
|
90337
91074
|
planParseable = true;
|
|
90338
91075
|
const planPhase = plan.phases?.find((p) => p.id === phase);
|
|
@@ -90397,11 +91134,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
90397
91134
|
const overrides = session2?.qaGateSessionOverrides ?? {};
|
|
90398
91135
|
const effective = getEffectiveGates(profile, overrides);
|
|
90399
91136
|
if (effective.hallucination_guard === true) {
|
|
90400
|
-
const hgPath =
|
|
91137
|
+
const hgPath = path110.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
|
|
90401
91138
|
let hgVerdictFound = false;
|
|
90402
91139
|
let hgVerdictApproved = false;
|
|
90403
91140
|
try {
|
|
90404
|
-
const hgContent =
|
|
91141
|
+
const hgContent = fs84.readFileSync(hgPath, "utf-8");
|
|
90405
91142
|
const hgBundle = JSON.parse(hgContent);
|
|
90406
91143
|
for (const entry of hgBundle.entries ?? []) {
|
|
90407
91144
|
if (typeof entry.type === "string" && entry.type.includes("hallucination") && typeof entry.verdict === "string") {
|
|
@@ -90469,11 +91206,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
90469
91206
|
const overrides = session2?.qaGateSessionOverrides ?? {};
|
|
90470
91207
|
const effective = getEffectiveGates(profile, overrides);
|
|
90471
91208
|
if (effective.mutation_test === true) {
|
|
90472
|
-
const mgPath =
|
|
91209
|
+
const mgPath = path110.join(dir, ".swarm", "evidence", String(phase), "mutation-gate.json");
|
|
90473
91210
|
let mgVerdictFound = false;
|
|
90474
91211
|
let mgVerdict;
|
|
90475
91212
|
try {
|
|
90476
|
-
const mgContent =
|
|
91213
|
+
const mgContent = fs84.readFileSync(mgPath, "utf-8");
|
|
90477
91214
|
const mgBundle = JSON.parse(mgContent);
|
|
90478
91215
|
for (const entry of mgBundle.entries ?? []) {
|
|
90479
91216
|
if (typeof entry.type === "string" && entry.type === "mutation-gate" && typeof entry.verdict === "string") {
|
|
@@ -90543,14 +91280,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
90543
91280
|
const effective = getEffectiveGates(profile, overrides);
|
|
90544
91281
|
if (effective.council_mode === true) {
|
|
90545
91282
|
councilModeEnabled = true;
|
|
90546
|
-
const pcPath =
|
|
91283
|
+
const pcPath = path110.join(dir, ".swarm", "evidence", String(phase), "phase-council.json");
|
|
90547
91284
|
let pcVerdictFound = false;
|
|
90548
91285
|
let _pcVerdict;
|
|
90549
91286
|
let pcQuorumSize;
|
|
90550
91287
|
let pcTimestamp;
|
|
90551
91288
|
let pcPhaseNumber;
|
|
90552
91289
|
try {
|
|
90553
|
-
const pcContent =
|
|
91290
|
+
const pcContent = fs84.readFileSync(pcPath, "utf-8");
|
|
90554
91291
|
const pcBundle = JSON.parse(pcContent);
|
|
90555
91292
|
for (const entry of pcBundle.entries ?? []) {
|
|
90556
91293
|
if (typeof entry.type === "string" && entry.type === "phase-council" && typeof entry.verdict === "string") {
|
|
@@ -90751,11 +91488,11 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
90751
91488
|
const effective = getEffectiveGates(profile, overrides);
|
|
90752
91489
|
if (effective.final_council === true) {
|
|
90753
91490
|
finalCouncilEnabled = true;
|
|
90754
|
-
const fcPath =
|
|
91491
|
+
const fcPath = path110.join(dir, ".swarm", "evidence", "final-council.json");
|
|
90755
91492
|
let fcVerdictFound = false;
|
|
90756
91493
|
let _fcVerdict;
|
|
90757
91494
|
try {
|
|
90758
|
-
const fcContent =
|
|
91495
|
+
const fcContent = fs84.readFileSync(fcPath, "utf-8");
|
|
90759
91496
|
const fcBundle = JSON.parse(fcContent);
|
|
90760
91497
|
for (const entry of fcBundle.entries ?? []) {
|
|
90761
91498
|
if (typeof entry.type === "string" && entry.type === "final-council" && typeof entry.verdict === "string") {
|
|
@@ -90916,7 +91653,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
90916
91653
|
phase_critic: leanConfig.phase_critic,
|
|
90917
91654
|
integrated_diff_required: leanConfig.integrated_diff_required
|
|
90918
91655
|
} : undefined;
|
|
90919
|
-
const leanCheck =
|
|
91656
|
+
const leanCheck = _internals43.verifyLeanTurboPhaseReady(dir, phase, sessionID, leanPhaseReadyConfig);
|
|
90920
91657
|
if (!leanCheck.ok) {
|
|
90921
91658
|
return JSON.stringify({
|
|
90922
91659
|
success: false,
|
|
@@ -90939,7 +91676,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
90939
91676
|
}
|
|
90940
91677
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
90941
91678
|
try {
|
|
90942
|
-
const projectName =
|
|
91679
|
+
const projectName = path110.basename(dir);
|
|
90943
91680
|
const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
|
|
90944
91681
|
if (curationResult) {
|
|
90945
91682
|
const sessionState = swarmState.agentSessions.get(sessionID);
|
|
@@ -91019,7 +91756,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
91019
91756
|
let phaseRequiredAgents;
|
|
91020
91757
|
try {
|
|
91021
91758
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
91022
|
-
const planRaw =
|
|
91759
|
+
const planRaw = fs84.readFileSync(planPath, "utf-8");
|
|
91023
91760
|
const plan = JSON.parse(planRaw);
|
|
91024
91761
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
91025
91762
|
phaseRequiredAgents = phaseObj?.required_agents;
|
|
@@ -91034,11 +91771,11 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
91034
91771
|
if (agentsMissing.length > 0) {
|
|
91035
91772
|
try {
|
|
91036
91773
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
91037
|
-
const planRaw =
|
|
91774
|
+
const planRaw = fs84.readFileSync(planPath, "utf-8");
|
|
91038
91775
|
const plan = JSON.parse(planRaw);
|
|
91039
91776
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
91040
|
-
if (targetPhase && targetPhase.tasks.length > 0 &&
|
|
91041
|
-
warnings.push(`Agent dispatch fallback: all ${targetPhase.tasks.length} tasks in phase ${phase} are completed in plan.json. Clearing missing agents: ${agentsMissing.join(", ")}.`);
|
|
91777
|
+
if (targetPhase && targetPhase.tasks.length > 0 && canInferMissingAgentsFromTaskGates(agentsMissing) && await allCompletedTasksHavePassedGateEvidence(dir, targetPhase.tasks)) {
|
|
91778
|
+
warnings.push(`Agent dispatch fallback: all ${targetPhase.tasks.length} tasks in phase ${phase} are completed in plan.json and durable gate evidence passed. Clearing missing agents: ${agentsMissing.join(", ")}.`);
|
|
91042
91779
|
agentsMissing = [];
|
|
91043
91780
|
}
|
|
91044
91781
|
} catch {}
|
|
@@ -91074,7 +91811,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
91074
91811
|
if (phaseCompleteConfig.regression_sweep?.enforce) {
|
|
91075
91812
|
try {
|
|
91076
91813
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
91077
|
-
const planRaw =
|
|
91814
|
+
const planRaw = fs84.readFileSync(planPath, "utf-8");
|
|
91078
91815
|
const plan = JSON.parse(planRaw);
|
|
91079
91816
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
91080
91817
|
if (targetPhase) {
|
|
@@ -91128,7 +91865,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
91128
91865
|
}
|
|
91129
91866
|
try {
|
|
91130
91867
|
const eventsPath = validateSwarmPath(dir, "events.jsonl");
|
|
91131
|
-
|
|
91868
|
+
fs84.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
91132
91869
|
`, "utf-8");
|
|
91133
91870
|
} catch (writeError) {
|
|
91134
91871
|
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -91203,12 +91940,12 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
91203
91940
|
warnings.push(`Warning: failed to update plan.json phase status`);
|
|
91204
91941
|
try {
|
|
91205
91942
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
91206
|
-
const planRaw =
|
|
91943
|
+
const planRaw = fs84.readFileSync(planPath, "utf-8");
|
|
91207
91944
|
const plan2 = JSON.parse(planRaw);
|
|
91208
91945
|
const phaseObj = plan2.phases.find((p) => p.id === phase);
|
|
91209
91946
|
if (phaseObj) {
|
|
91210
91947
|
phaseObj.status = "complete";
|
|
91211
|
-
|
|
91948
|
+
fs84.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
|
|
91212
91949
|
}
|
|
91213
91950
|
} catch {}
|
|
91214
91951
|
} else if (plan) {
|
|
@@ -91245,12 +91982,12 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
91245
91982
|
warnings.push(`Warning: failed to update plan.json phase status`);
|
|
91246
91983
|
try {
|
|
91247
91984
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
91248
|
-
const planRaw =
|
|
91985
|
+
const planRaw = fs84.readFileSync(planPath, "utf-8");
|
|
91249
91986
|
const plan = JSON.parse(planRaw);
|
|
91250
91987
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
91251
91988
|
if (phaseObj) {
|
|
91252
91989
|
phaseObj.status = "complete";
|
|
91253
|
-
|
|
91990
|
+
fs84.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
|
|
91254
91991
|
}
|
|
91255
91992
|
} catch {}
|
|
91256
91993
|
}
|
|
@@ -91308,8 +92045,8 @@ init_discovery();
|
|
|
91308
92045
|
init_utils();
|
|
91309
92046
|
init_bun_compat();
|
|
91310
92047
|
init_create_tool();
|
|
91311
|
-
import * as
|
|
91312
|
-
import * as
|
|
92048
|
+
import * as fs85 from "node:fs";
|
|
92049
|
+
import * as path111 from "node:path";
|
|
91313
92050
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
91314
92051
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
91315
92052
|
function isValidEcosystem(value) {
|
|
@@ -91337,31 +92074,31 @@ function validateArgs3(args2) {
|
|
|
91337
92074
|
function detectEcosystems(directory) {
|
|
91338
92075
|
const ecosystems = [];
|
|
91339
92076
|
const cwd = directory;
|
|
91340
|
-
if (
|
|
92077
|
+
if (fs85.existsSync(path111.join(cwd, "package.json"))) {
|
|
91341
92078
|
ecosystems.push("npm");
|
|
91342
92079
|
}
|
|
91343
|
-
if (
|
|
92080
|
+
if (fs85.existsSync(path111.join(cwd, "pyproject.toml")) || fs85.existsSync(path111.join(cwd, "requirements.txt"))) {
|
|
91344
92081
|
ecosystems.push("pip");
|
|
91345
92082
|
}
|
|
91346
|
-
if (
|
|
92083
|
+
if (fs85.existsSync(path111.join(cwd, "Cargo.toml"))) {
|
|
91347
92084
|
ecosystems.push("cargo");
|
|
91348
92085
|
}
|
|
91349
|
-
if (
|
|
92086
|
+
if (fs85.existsSync(path111.join(cwd, "go.mod"))) {
|
|
91350
92087
|
ecosystems.push("go");
|
|
91351
92088
|
}
|
|
91352
92089
|
try {
|
|
91353
|
-
const files =
|
|
92090
|
+
const files = fs85.readdirSync(cwd);
|
|
91354
92091
|
if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
91355
92092
|
ecosystems.push("dotnet");
|
|
91356
92093
|
}
|
|
91357
92094
|
} catch {}
|
|
91358
|
-
if (
|
|
92095
|
+
if (fs85.existsSync(path111.join(cwd, "Gemfile")) || fs85.existsSync(path111.join(cwd, "Gemfile.lock"))) {
|
|
91359
92096
|
ecosystems.push("ruby");
|
|
91360
92097
|
}
|
|
91361
|
-
if (
|
|
92098
|
+
if (fs85.existsSync(path111.join(cwd, "pubspec.yaml"))) {
|
|
91362
92099
|
ecosystems.push("dart");
|
|
91363
92100
|
}
|
|
91364
|
-
if (
|
|
92101
|
+
if (fs85.existsSync(path111.join(cwd, "composer.lock"))) {
|
|
91365
92102
|
ecosystems.push("composer");
|
|
91366
92103
|
}
|
|
91367
92104
|
return ecosystems;
|
|
@@ -92496,8 +93233,8 @@ var pkg_audit = createSwarmTool({
|
|
|
92496
93233
|
// src/tools/placeholder-scan.ts
|
|
92497
93234
|
init_zod();
|
|
92498
93235
|
init_manager2();
|
|
92499
|
-
import * as
|
|
92500
|
-
import * as
|
|
93236
|
+
import * as fs86 from "node:fs";
|
|
93237
|
+
import * as path112 from "node:path";
|
|
92501
93238
|
init_utils();
|
|
92502
93239
|
init_create_tool();
|
|
92503
93240
|
var MAX_FILE_SIZE = 1024 * 1024;
|
|
@@ -92620,7 +93357,7 @@ function isScaffoldFile(filePath) {
|
|
|
92620
93357
|
if (SCAFFOLD_PATH_PATTERNS.some((pattern) => pattern.test(normalizedPath))) {
|
|
92621
93358
|
return true;
|
|
92622
93359
|
}
|
|
92623
|
-
const filename =
|
|
93360
|
+
const filename = path112.basename(filePath);
|
|
92624
93361
|
if (SCAFFOLD_FILENAME_PATTERNS.some((pattern) => pattern.test(filename))) {
|
|
92625
93362
|
return true;
|
|
92626
93363
|
}
|
|
@@ -92637,7 +93374,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
|
|
|
92637
93374
|
if (regex.test(normalizedPath)) {
|
|
92638
93375
|
return true;
|
|
92639
93376
|
}
|
|
92640
|
-
const filename =
|
|
93377
|
+
const filename = path112.basename(filePath);
|
|
92641
93378
|
const filenameRegex = new RegExp(`^${regexPattern}$`, "i");
|
|
92642
93379
|
if (filenameRegex.test(filename)) {
|
|
92643
93380
|
return true;
|
|
@@ -92646,7 +93383,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
|
|
|
92646
93383
|
return false;
|
|
92647
93384
|
}
|
|
92648
93385
|
function isParserSupported(filePath) {
|
|
92649
|
-
const ext =
|
|
93386
|
+
const ext = path112.extname(filePath).toLowerCase();
|
|
92650
93387
|
return SUPPORTED_PARSER_EXTENSIONS.has(ext);
|
|
92651
93388
|
}
|
|
92652
93389
|
function isPlanFile(filePath) {
|
|
@@ -92893,28 +93630,28 @@ async function placeholderScan(input, directory) {
|
|
|
92893
93630
|
let filesScanned = 0;
|
|
92894
93631
|
const filesWithFindings = new Set;
|
|
92895
93632
|
for (const filePath of changed_files) {
|
|
92896
|
-
const fullPath =
|
|
92897
|
-
const resolvedDirectory =
|
|
92898
|
-
if (!fullPath.startsWith(resolvedDirectory +
|
|
93633
|
+
const fullPath = path112.isAbsolute(filePath) ? filePath : path112.resolve(directory, filePath);
|
|
93634
|
+
const resolvedDirectory = path112.resolve(directory);
|
|
93635
|
+
if (!fullPath.startsWith(resolvedDirectory + path112.sep) && fullPath !== resolvedDirectory) {
|
|
92899
93636
|
continue;
|
|
92900
93637
|
}
|
|
92901
|
-
if (!
|
|
93638
|
+
if (!fs86.existsSync(fullPath)) {
|
|
92902
93639
|
continue;
|
|
92903
93640
|
}
|
|
92904
93641
|
if (isAllowedByGlobs(filePath, allow_globs)) {
|
|
92905
93642
|
continue;
|
|
92906
93643
|
}
|
|
92907
|
-
const relativeFilePath =
|
|
93644
|
+
const relativeFilePath = path112.relative(directory, fullPath).replace(/\\/g, "/");
|
|
92908
93645
|
if (FILE_ALLOWLIST.some((allowed) => relativeFilePath.endsWith(allowed))) {
|
|
92909
93646
|
continue;
|
|
92910
93647
|
}
|
|
92911
93648
|
let content;
|
|
92912
93649
|
try {
|
|
92913
|
-
const stat8 =
|
|
93650
|
+
const stat8 = fs86.statSync(fullPath);
|
|
92914
93651
|
if (stat8.size > MAX_FILE_SIZE) {
|
|
92915
93652
|
continue;
|
|
92916
93653
|
}
|
|
92917
|
-
content =
|
|
93654
|
+
content = fs86.readFileSync(fullPath, "utf-8");
|
|
92918
93655
|
} catch {
|
|
92919
93656
|
continue;
|
|
92920
93657
|
}
|
|
@@ -92975,8 +93712,8 @@ var placeholder_scan = createSwarmTool({
|
|
|
92975
93712
|
}
|
|
92976
93713
|
});
|
|
92977
93714
|
// src/tools/pre-check-batch.ts
|
|
92978
|
-
import * as
|
|
92979
|
-
import * as
|
|
93715
|
+
import * as fs90 from "node:fs";
|
|
93716
|
+
import * as path116 from "node:path";
|
|
92980
93717
|
init_zod();
|
|
92981
93718
|
init_manager2();
|
|
92982
93719
|
init_utils();
|
|
@@ -93104,11 +93841,11 @@ var quality_budget = createSwarmTool({
|
|
|
93104
93841
|
}).optional().describe("Quality budget thresholds")
|
|
93105
93842
|
},
|
|
93106
93843
|
async execute(args2, directory) {
|
|
93107
|
-
const result = await
|
|
93844
|
+
const result = await _internals44.qualityBudget(args2, directory);
|
|
93108
93845
|
return JSON.stringify(result);
|
|
93109
93846
|
}
|
|
93110
93847
|
});
|
|
93111
|
-
var
|
|
93848
|
+
var _internals44 = {
|
|
93112
93849
|
qualityBudget
|
|
93113
93850
|
};
|
|
93114
93851
|
|
|
@@ -93116,9 +93853,9 @@ var _internals41 = {
|
|
|
93116
93853
|
init_zod();
|
|
93117
93854
|
init_manager2();
|
|
93118
93855
|
init_detector();
|
|
93119
|
-
import * as
|
|
93120
|
-
import * as
|
|
93121
|
-
import { extname as
|
|
93856
|
+
import * as fs89 from "node:fs";
|
|
93857
|
+
import * as path115 from "node:path";
|
|
93858
|
+
import { extname as extname20 } from "node:path";
|
|
93122
93859
|
|
|
93123
93860
|
// src/sast/rules/c.ts
|
|
93124
93861
|
var cRules = [
|
|
@@ -93832,12 +94569,12 @@ function executeRulesSync(filePath, content, language) {
|
|
|
93832
94569
|
|
|
93833
94570
|
// src/sast/semgrep.ts
|
|
93834
94571
|
import * as child_process9 from "node:child_process";
|
|
93835
|
-
import * as
|
|
93836
|
-
import * as
|
|
94572
|
+
import * as fs87 from "node:fs";
|
|
94573
|
+
import * as path113 from "node:path";
|
|
93837
94574
|
var semgrepAvailableCache = null;
|
|
93838
94575
|
var DEFAULT_RULES_DIR = ".swarm/semgrep-rules";
|
|
93839
94576
|
var DEFAULT_TIMEOUT_MS3 = 30000;
|
|
93840
|
-
var
|
|
94577
|
+
var _internals45 = {
|
|
93841
94578
|
isSemgrepAvailable,
|
|
93842
94579
|
checkSemgrepAvailable,
|
|
93843
94580
|
resetSemgrepCache,
|
|
@@ -93862,7 +94599,7 @@ function isSemgrepAvailable() {
|
|
|
93862
94599
|
}
|
|
93863
94600
|
}
|
|
93864
94601
|
async function checkSemgrepAvailable() {
|
|
93865
|
-
return
|
|
94602
|
+
return _internals45.isSemgrepAvailable();
|
|
93866
94603
|
}
|
|
93867
94604
|
function resetSemgrepCache() {
|
|
93868
94605
|
semgrepAvailableCache = null;
|
|
@@ -93959,12 +94696,12 @@ async function runSemgrep(options) {
|
|
|
93959
94696
|
const timeoutMs = options.timeoutMs || DEFAULT_TIMEOUT_MS3;
|
|
93960
94697
|
if (files.length === 0) {
|
|
93961
94698
|
return {
|
|
93962
|
-
available:
|
|
94699
|
+
available: _internals45.isSemgrepAvailable(),
|
|
93963
94700
|
findings: [],
|
|
93964
94701
|
engine: "tier_a"
|
|
93965
94702
|
};
|
|
93966
94703
|
}
|
|
93967
|
-
if (!
|
|
94704
|
+
if (!_internals45.isSemgrepAvailable()) {
|
|
93968
94705
|
return {
|
|
93969
94706
|
available: false,
|
|
93970
94707
|
findings: [],
|
|
@@ -94020,14 +94757,14 @@ async function runSemgrep(options) {
|
|
|
94020
94757
|
}
|
|
94021
94758
|
function getRulesDirectory(projectRoot) {
|
|
94022
94759
|
if (projectRoot) {
|
|
94023
|
-
return
|
|
94760
|
+
return path113.resolve(projectRoot, DEFAULT_RULES_DIR);
|
|
94024
94761
|
}
|
|
94025
94762
|
return DEFAULT_RULES_DIR;
|
|
94026
94763
|
}
|
|
94027
94764
|
function hasBundledRules(projectRoot) {
|
|
94028
94765
|
const rulesDir = getRulesDirectory(projectRoot);
|
|
94029
94766
|
try {
|
|
94030
|
-
return
|
|
94767
|
+
return fs87.existsSync(rulesDir);
|
|
94031
94768
|
} catch {
|
|
94032
94769
|
return false;
|
|
94033
94770
|
}
|
|
@@ -94039,26 +94776,26 @@ init_create_tool();
|
|
|
94039
94776
|
|
|
94040
94777
|
// src/tools/sast-baseline.ts
|
|
94041
94778
|
init_utils2();
|
|
94042
|
-
import * as
|
|
94043
|
-
import * as
|
|
94044
|
-
import * as
|
|
94779
|
+
import * as crypto10 from "node:crypto";
|
|
94780
|
+
import * as fs88 from "node:fs";
|
|
94781
|
+
import * as path114 from "node:path";
|
|
94045
94782
|
var BASELINE_SCHEMA_VERSION = "1.0.0";
|
|
94046
94783
|
var MAX_BASELINE_FINDINGS = 2000;
|
|
94047
94784
|
var MAX_BASELINE_BYTES = 2 * 1048576;
|
|
94048
94785
|
var LOCK_RETRY_DELAYS_MS = [50, 100, 200, 400, 800];
|
|
94049
94786
|
function normalizeFindingPath(directory, file3) {
|
|
94050
|
-
const resolved =
|
|
94051
|
-
const rel =
|
|
94787
|
+
const resolved = path114.isAbsolute(file3) ? file3 : path114.resolve(directory, file3);
|
|
94788
|
+
const rel = path114.relative(path114.resolve(directory), resolved);
|
|
94052
94789
|
return rel.replace(/\\/g, "/");
|
|
94053
94790
|
}
|
|
94054
94791
|
function baselineRelPath(phase) {
|
|
94055
|
-
return
|
|
94792
|
+
return path114.join("evidence", String(phase), "sast-baseline.json");
|
|
94056
94793
|
}
|
|
94057
94794
|
function tempRelPath(phase) {
|
|
94058
|
-
return
|
|
94795
|
+
return path114.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
|
|
94059
94796
|
}
|
|
94060
94797
|
function lockRelPath(phase) {
|
|
94061
|
-
return
|
|
94798
|
+
return path114.join("evidence", String(phase), "sast-baseline.json.lock");
|
|
94062
94799
|
}
|
|
94063
94800
|
function getLine(lines, idx) {
|
|
94064
94801
|
if (idx < 0 || idx >= lines.length)
|
|
@@ -94075,7 +94812,7 @@ function fingerprintFinding(finding, directory, occurrenceIndex) {
|
|
|
94075
94812
|
}
|
|
94076
94813
|
const lineNum = finding.location.line;
|
|
94077
94814
|
try {
|
|
94078
|
-
const content =
|
|
94815
|
+
const content = fs88.readFileSync(finding.location.file, "utf-8");
|
|
94079
94816
|
const lines = content.split(`
|
|
94080
94817
|
`);
|
|
94081
94818
|
const idx = lineNum - 1;
|
|
@@ -94085,7 +94822,7 @@ function fingerprintFinding(finding, directory, occurrenceIndex) {
|
|
|
94085
94822
|
getLine(lines, idx + 1)
|
|
94086
94823
|
].join(`
|
|
94087
94824
|
`);
|
|
94088
|
-
const hash3 =
|
|
94825
|
+
const hash3 = crypto10.createHash("sha256").update(window2).digest("hex").slice(0, 16);
|
|
94089
94826
|
return {
|
|
94090
94827
|
fingerprint: `${relFile}|${finding.rule_id}|${hash3}|#${occurrenceIndex}`,
|
|
94091
94828
|
stable: true
|
|
@@ -94106,7 +94843,7 @@ function assignOccurrenceIndices(findings, directory) {
|
|
|
94106
94843
|
try {
|
|
94107
94844
|
if (relFile.startsWith(".."))
|
|
94108
94845
|
throw new Error("escapes workspace");
|
|
94109
|
-
const content =
|
|
94846
|
+
const content = fs88.readFileSync(finding.location.file, "utf-8");
|
|
94110
94847
|
const lines = content.split(`
|
|
94111
94848
|
`);
|
|
94112
94849
|
const idx = lineNum - 1;
|
|
@@ -94116,14 +94853,14 @@ function assignOccurrenceIndices(findings, directory) {
|
|
|
94116
94853
|
getLine(lines, idx + 1)
|
|
94117
94854
|
].join(`
|
|
94118
94855
|
`);
|
|
94119
|
-
const hash3 =
|
|
94856
|
+
const hash3 = crypto10.createHash("sha256").update(window2).digest("hex").slice(0, 16);
|
|
94120
94857
|
baseKey = `${relFile}|${finding.rule_id}|${hash3}`;
|
|
94121
94858
|
} catch {
|
|
94122
94859
|
baseKey = `${relFile}|${finding.rule_id}|L${lineNum}|UNSTABLE`;
|
|
94123
94860
|
}
|
|
94124
94861
|
const occIdx = countMap.get(baseKey) ?? 0;
|
|
94125
94862
|
countMap.set(baseKey, occIdx + 1);
|
|
94126
|
-
const fp =
|
|
94863
|
+
const fp = _internals46.fingerprintFinding(finding, directory, occIdx);
|
|
94127
94864
|
return {
|
|
94128
94865
|
finding,
|
|
94129
94866
|
index: occIdx,
|
|
@@ -94135,11 +94872,11 @@ function assignOccurrenceIndices(findings, directory) {
|
|
|
94135
94872
|
async function acquireLock2(lockPath) {
|
|
94136
94873
|
for (let attempt = 0;attempt <= LOCK_RETRY_DELAYS_MS.length; attempt++) {
|
|
94137
94874
|
try {
|
|
94138
|
-
const fd =
|
|
94139
|
-
|
|
94875
|
+
const fd = fs88.openSync(lockPath, "wx");
|
|
94876
|
+
fs88.closeSync(fd);
|
|
94140
94877
|
return () => {
|
|
94141
94878
|
try {
|
|
94142
|
-
|
|
94879
|
+
fs88.unlinkSync(lockPath);
|
|
94143
94880
|
} catch {}
|
|
94144
94881
|
};
|
|
94145
94882
|
} catch {
|
|
@@ -94179,20 +94916,20 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
94179
94916
|
message: e instanceof Error ? e.message : "Path validation failed"
|
|
94180
94917
|
};
|
|
94181
94918
|
}
|
|
94182
|
-
|
|
94183
|
-
|
|
94919
|
+
fs88.mkdirSync(path114.dirname(baselinePath), { recursive: true });
|
|
94920
|
+
fs88.mkdirSync(path114.dirname(tempPath), { recursive: true });
|
|
94184
94921
|
const releaseLock = await acquireLock2(lockPath);
|
|
94185
94922
|
try {
|
|
94186
94923
|
let existing = null;
|
|
94187
94924
|
try {
|
|
94188
|
-
const raw =
|
|
94925
|
+
const raw = fs88.readFileSync(baselinePath, "utf-8");
|
|
94189
94926
|
const parsed = JSON.parse(raw);
|
|
94190
94927
|
if (parsed.schema_version === BASELINE_SCHEMA_VERSION) {
|
|
94191
94928
|
existing = parsed;
|
|
94192
94929
|
}
|
|
94193
94930
|
} catch {}
|
|
94194
94931
|
const scannedRelFiles = new Set(scannedFiles.map((f) => normalizeFindingPath(directory, f)));
|
|
94195
|
-
const indexed =
|
|
94932
|
+
const indexed = _internals46.assignOccurrenceIndices(findings, directory);
|
|
94196
94933
|
if (existing && !opts?.force) {
|
|
94197
94934
|
const prunedFingerprints = existing.fingerprints.filter((fp) => {
|
|
94198
94935
|
const relFile = fp.slice(0, fp.indexOf("|"));
|
|
@@ -94245,8 +94982,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
94245
94982
|
message: `Baseline would exceed size cap (${json4.length} bytes > ${MAX_BASELINE_BYTES})`
|
|
94246
94983
|
};
|
|
94247
94984
|
}
|
|
94248
|
-
|
|
94249
|
-
|
|
94985
|
+
fs88.writeFileSync(tempPath, json4, "utf-8");
|
|
94986
|
+
fs88.renameSync(tempPath, baselinePath);
|
|
94250
94987
|
return {
|
|
94251
94988
|
status: "merged",
|
|
94252
94989
|
path: baselinePath,
|
|
@@ -94277,8 +95014,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
94277
95014
|
message: `Baseline would exceed size cap (${json3.length} bytes > ${MAX_BASELINE_BYTES})`
|
|
94278
95015
|
};
|
|
94279
95016
|
}
|
|
94280
|
-
|
|
94281
|
-
|
|
95017
|
+
fs88.writeFileSync(tempPath, json3, "utf-8");
|
|
95018
|
+
fs88.renameSync(tempPath, baselinePath);
|
|
94282
95019
|
return {
|
|
94283
95020
|
status: "written",
|
|
94284
95021
|
path: baselinePath,
|
|
@@ -94303,7 +95040,7 @@ function loadBaseline(directory, phase) {
|
|
|
94303
95040
|
};
|
|
94304
95041
|
}
|
|
94305
95042
|
try {
|
|
94306
|
-
const raw =
|
|
95043
|
+
const raw = fs88.readFileSync(baselinePath, "utf-8");
|
|
94307
95044
|
const parsed = JSON.parse(raw);
|
|
94308
95045
|
if (parsed.schema_version !== BASELINE_SCHEMA_VERSION) {
|
|
94309
95046
|
return {
|
|
@@ -94332,7 +95069,7 @@ function loadBaseline(directory, phase) {
|
|
|
94332
95069
|
};
|
|
94333
95070
|
}
|
|
94334
95071
|
}
|
|
94335
|
-
var
|
|
95072
|
+
var _internals46 = {
|
|
94336
95073
|
fingerprintFinding,
|
|
94337
95074
|
assignOccurrenceIndices,
|
|
94338
95075
|
captureOrMergeBaseline,
|
|
@@ -94351,17 +95088,17 @@ var SEVERITY_ORDER = {
|
|
|
94351
95088
|
};
|
|
94352
95089
|
function shouldSkipFile(filePath) {
|
|
94353
95090
|
try {
|
|
94354
|
-
const stats =
|
|
95091
|
+
const stats = fs89.statSync(filePath);
|
|
94355
95092
|
if (stats.size > MAX_FILE_SIZE_BYTES8) {
|
|
94356
95093
|
return { skip: true, reason: "file too large" };
|
|
94357
95094
|
}
|
|
94358
95095
|
if (stats.size === 0) {
|
|
94359
95096
|
return { skip: true, reason: "empty file" };
|
|
94360
95097
|
}
|
|
94361
|
-
const fd =
|
|
95098
|
+
const fd = fs89.openSync(filePath, "r");
|
|
94362
95099
|
const buffer = Buffer.alloc(8192);
|
|
94363
|
-
const bytesRead =
|
|
94364
|
-
|
|
95100
|
+
const bytesRead = fs89.readSync(fd, buffer, 0, 8192, 0);
|
|
95101
|
+
fs89.closeSync(fd);
|
|
94365
95102
|
if (bytesRead > 0) {
|
|
94366
95103
|
let nullCount = 0;
|
|
94367
95104
|
for (let i2 = 0;i2 < bytesRead; i2++) {
|
|
@@ -94400,7 +95137,7 @@ function countBySeverity(findings) {
|
|
|
94400
95137
|
}
|
|
94401
95138
|
function scanFileWithTierA(filePath, language) {
|
|
94402
95139
|
try {
|
|
94403
|
-
const content =
|
|
95140
|
+
const content = fs89.readFileSync(filePath, "utf-8");
|
|
94404
95141
|
const findings = executeRulesSync(filePath, content, language);
|
|
94405
95142
|
return findings.map((f) => ({
|
|
94406
95143
|
rule_id: f.rule_id,
|
|
@@ -94453,13 +95190,13 @@ async function sastScan(input, directory, config3) {
|
|
|
94453
95190
|
_filesSkipped++;
|
|
94454
95191
|
continue;
|
|
94455
95192
|
}
|
|
94456
|
-
const resolvedPath =
|
|
94457
|
-
const resolvedDirectory =
|
|
94458
|
-
if (!resolvedPath.startsWith(resolvedDirectory +
|
|
95193
|
+
const resolvedPath = path115.isAbsolute(filePath) ? filePath : path115.resolve(directory, filePath);
|
|
95194
|
+
const resolvedDirectory = path115.resolve(directory);
|
|
95195
|
+
if (!resolvedPath.startsWith(resolvedDirectory + path115.sep) && resolvedPath !== resolvedDirectory) {
|
|
94459
95196
|
_filesSkipped++;
|
|
94460
95197
|
continue;
|
|
94461
95198
|
}
|
|
94462
|
-
if (!
|
|
95199
|
+
if (!fs89.existsSync(resolvedPath)) {
|
|
94463
95200
|
_filesSkipped++;
|
|
94464
95201
|
continue;
|
|
94465
95202
|
}
|
|
@@ -94468,7 +95205,7 @@ async function sastScan(input, directory, config3) {
|
|
|
94468
95205
|
_filesSkipped++;
|
|
94469
95206
|
continue;
|
|
94470
95207
|
}
|
|
94471
|
-
const ext =
|
|
95208
|
+
const ext = extname20(resolvedPath).toLowerCase();
|
|
94472
95209
|
const profile = getProfileForFile(resolvedPath);
|
|
94473
95210
|
const langDef = getLanguageForExtension(ext);
|
|
94474
95211
|
if (!profile && !langDef) {
|
|
@@ -94742,11 +95479,11 @@ var sast_scan = createSwarmTool({
|
|
|
94742
95479
|
capture_baseline: safeArgs.capture_baseline,
|
|
94743
95480
|
phase: safeArgs.phase
|
|
94744
95481
|
};
|
|
94745
|
-
const result = await
|
|
95482
|
+
const result = await _internals47.sastScan(input, directory);
|
|
94746
95483
|
return JSON.stringify(result, null, 2);
|
|
94747
95484
|
}
|
|
94748
95485
|
});
|
|
94749
|
-
var
|
|
95486
|
+
var _internals47 = {
|
|
94750
95487
|
sastScan,
|
|
94751
95488
|
sast_scan
|
|
94752
95489
|
};
|
|
@@ -94770,18 +95507,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
94770
95507
|
let resolved;
|
|
94771
95508
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
94772
95509
|
if (isWinAbs) {
|
|
94773
|
-
resolved =
|
|
94774
|
-
} else if (
|
|
94775
|
-
resolved =
|
|
95510
|
+
resolved = path116.win32.resolve(inputPath);
|
|
95511
|
+
} else if (path116.isAbsolute(inputPath)) {
|
|
95512
|
+
resolved = path116.resolve(inputPath);
|
|
94776
95513
|
} else {
|
|
94777
|
-
resolved =
|
|
95514
|
+
resolved = path116.resolve(baseDir, inputPath);
|
|
94778
95515
|
}
|
|
94779
|
-
const workspaceResolved =
|
|
95516
|
+
const workspaceResolved = path116.resolve(workspaceDir);
|
|
94780
95517
|
let relative24;
|
|
94781
95518
|
if (isWinAbs) {
|
|
94782
|
-
relative24 =
|
|
95519
|
+
relative24 = path116.win32.relative(workspaceResolved, resolved);
|
|
94783
95520
|
} else {
|
|
94784
|
-
relative24 =
|
|
95521
|
+
relative24 = path116.relative(workspaceResolved, resolved);
|
|
94785
95522
|
}
|
|
94786
95523
|
if (relative24.startsWith("..")) {
|
|
94787
95524
|
return "path traversal detected";
|
|
@@ -94846,7 +95583,7 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
94846
95583
|
if (typeof file3 !== "string") {
|
|
94847
95584
|
continue;
|
|
94848
95585
|
}
|
|
94849
|
-
const resolvedPath =
|
|
95586
|
+
const resolvedPath = path116.resolve(file3);
|
|
94850
95587
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
94851
95588
|
if (validationError) {
|
|
94852
95589
|
continue;
|
|
@@ -95003,7 +95740,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
95003
95740
|
skippedFiles++;
|
|
95004
95741
|
continue;
|
|
95005
95742
|
}
|
|
95006
|
-
const resolvedPath =
|
|
95743
|
+
const resolvedPath = path116.resolve(file3);
|
|
95007
95744
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
95008
95745
|
if (validationError) {
|
|
95009
95746
|
skippedFiles++;
|
|
@@ -95021,14 +95758,14 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
95021
95758
|
};
|
|
95022
95759
|
}
|
|
95023
95760
|
for (const file3 of validatedFiles) {
|
|
95024
|
-
const ext =
|
|
95761
|
+
const ext = path116.extname(file3).toLowerCase();
|
|
95025
95762
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
95026
95763
|
skippedFiles++;
|
|
95027
95764
|
continue;
|
|
95028
95765
|
}
|
|
95029
95766
|
let stat8;
|
|
95030
95767
|
try {
|
|
95031
|
-
stat8 =
|
|
95768
|
+
stat8 = fs90.statSync(file3);
|
|
95032
95769
|
} catch {
|
|
95033
95770
|
skippedFiles++;
|
|
95034
95771
|
continue;
|
|
@@ -95039,7 +95776,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
95039
95776
|
}
|
|
95040
95777
|
let content;
|
|
95041
95778
|
try {
|
|
95042
|
-
const buffer =
|
|
95779
|
+
const buffer = fs90.readFileSync(file3);
|
|
95043
95780
|
if (buffer.includes(0)) {
|
|
95044
95781
|
skippedFiles++;
|
|
95045
95782
|
continue;
|
|
@@ -95240,7 +95977,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
|
|
|
95240
95977
|
const preexistingFindings = [];
|
|
95241
95978
|
for (const finding of findings) {
|
|
95242
95979
|
const filePath = finding.location.file;
|
|
95243
|
-
const normalised =
|
|
95980
|
+
const normalised = path116.relative(directory, filePath).replace(/\\/g, "/");
|
|
95244
95981
|
const changedLines = changedLineRanges.get(normalised);
|
|
95245
95982
|
if (changedLines?.has(finding.location.line)) {
|
|
95246
95983
|
newFindings.push(finding);
|
|
@@ -95291,7 +96028,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
|
|
|
95291
96028
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
95292
96029
|
continue;
|
|
95293
96030
|
}
|
|
95294
|
-
changedFiles.push(
|
|
96031
|
+
changedFiles.push(path116.resolve(directory, file3));
|
|
95295
96032
|
}
|
|
95296
96033
|
if (changedFiles.length === 0) {
|
|
95297
96034
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -95492,7 +96229,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
95492
96229
|
};
|
|
95493
96230
|
return JSON.stringify(errorResult, null, 2);
|
|
95494
96231
|
}
|
|
95495
|
-
const resolvedDirectory =
|
|
96232
|
+
const resolvedDirectory = path116.resolve(typedArgs.directory);
|
|
95496
96233
|
const workspaceAnchor = resolvedDirectory;
|
|
95497
96234
|
const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
|
|
95498
96235
|
if (dirError) {
|
|
@@ -95533,7 +96270,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
95533
96270
|
});
|
|
95534
96271
|
// src/tools/repo-map.ts
|
|
95535
96272
|
init_zod();
|
|
95536
|
-
import * as
|
|
96273
|
+
import * as path117 from "node:path";
|
|
95537
96274
|
init_path_security();
|
|
95538
96275
|
init_create_tool();
|
|
95539
96276
|
var VALID_ACTIONS = [
|
|
@@ -95558,7 +96295,7 @@ function validateFile(p) {
|
|
|
95558
96295
|
return "file contains control characters";
|
|
95559
96296
|
if (containsPathTraversal(p))
|
|
95560
96297
|
return "file contains path traversal";
|
|
95561
|
-
if (
|
|
96298
|
+
if (path117.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
|
|
95562
96299
|
return "file must be a workspace-relative path, not absolute";
|
|
95563
96300
|
}
|
|
95564
96301
|
return null;
|
|
@@ -95581,8 +96318,8 @@ function ok(action, payload) {
|
|
|
95581
96318
|
}
|
|
95582
96319
|
function toRelativeGraphPath(input, workspaceRoot) {
|
|
95583
96320
|
const normalized = input.replace(/\\/g, "/");
|
|
95584
|
-
if (
|
|
95585
|
-
const rel =
|
|
96321
|
+
if (path117.isAbsolute(normalized)) {
|
|
96322
|
+
const rel = path117.relative(workspaceRoot, normalized).replace(/\\/g, "/");
|
|
95586
96323
|
return normalizeGraphPath2(rel);
|
|
95587
96324
|
}
|
|
95588
96325
|
return normalizeGraphPath2(normalized);
|
|
@@ -95726,8 +96463,8 @@ var repo_map = createSwarmTool({
|
|
|
95726
96463
|
// src/tools/req-coverage.ts
|
|
95727
96464
|
init_zod();
|
|
95728
96465
|
init_create_tool();
|
|
95729
|
-
import * as
|
|
95730
|
-
import * as
|
|
96466
|
+
import * as fs91 from "node:fs";
|
|
96467
|
+
import * as path118 from "node:path";
|
|
95731
96468
|
var SPEC_FILE = ".swarm/spec.md";
|
|
95732
96469
|
var EVIDENCE_DIR4 = ".swarm/evidence";
|
|
95733
96470
|
var OBLIGATION_KEYWORDS = ["MUST", "SHOULD", "SHALL"];
|
|
@@ -95786,19 +96523,19 @@ function extractObligationAndText(id, lineText) {
|
|
|
95786
96523
|
var PHASE_TASK_ID_REGEX = /^\d+\.\d+(\.\d+)*$/;
|
|
95787
96524
|
function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
95788
96525
|
const touchedFiles = new Set;
|
|
95789
|
-
if (!
|
|
96526
|
+
if (!fs91.existsSync(evidenceDir) || !fs91.statSync(evidenceDir).isDirectory()) {
|
|
95790
96527
|
return [];
|
|
95791
96528
|
}
|
|
95792
96529
|
let entries;
|
|
95793
96530
|
try {
|
|
95794
|
-
entries =
|
|
96531
|
+
entries = fs91.readdirSync(evidenceDir);
|
|
95795
96532
|
} catch {
|
|
95796
96533
|
return [];
|
|
95797
96534
|
}
|
|
95798
96535
|
for (const entry of entries) {
|
|
95799
|
-
const entryPath =
|
|
96536
|
+
const entryPath = path118.join(evidenceDir, entry);
|
|
95800
96537
|
try {
|
|
95801
|
-
const stat8 =
|
|
96538
|
+
const stat8 = fs91.statSync(entryPath);
|
|
95802
96539
|
if (!stat8.isDirectory()) {
|
|
95803
96540
|
continue;
|
|
95804
96541
|
}
|
|
@@ -95812,14 +96549,14 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
95812
96549
|
if (entryPhase !== String(phase)) {
|
|
95813
96550
|
continue;
|
|
95814
96551
|
}
|
|
95815
|
-
const evidenceFilePath =
|
|
96552
|
+
const evidenceFilePath = path118.join(entryPath, "evidence.json");
|
|
95816
96553
|
try {
|
|
95817
|
-
const resolvedPath =
|
|
95818
|
-
const evidenceDirResolved =
|
|
95819
|
-
if (!resolvedPath.startsWith(evidenceDirResolved +
|
|
96554
|
+
const resolvedPath = path118.resolve(evidenceFilePath);
|
|
96555
|
+
const evidenceDirResolved = path118.resolve(evidenceDir);
|
|
96556
|
+
if (!resolvedPath.startsWith(evidenceDirResolved + path118.sep)) {
|
|
95820
96557
|
continue;
|
|
95821
96558
|
}
|
|
95822
|
-
const stat8 =
|
|
96559
|
+
const stat8 = fs91.lstatSync(evidenceFilePath);
|
|
95823
96560
|
if (!stat8.isFile()) {
|
|
95824
96561
|
continue;
|
|
95825
96562
|
}
|
|
@@ -95831,7 +96568,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
95831
96568
|
}
|
|
95832
96569
|
let content;
|
|
95833
96570
|
try {
|
|
95834
|
-
content =
|
|
96571
|
+
content = fs91.readFileSync(evidenceFilePath, "utf-8");
|
|
95835
96572
|
} catch {
|
|
95836
96573
|
continue;
|
|
95837
96574
|
}
|
|
@@ -95850,7 +96587,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
95850
96587
|
if (Array.isArray(diffEntry.files_changed)) {
|
|
95851
96588
|
for (const file3 of diffEntry.files_changed) {
|
|
95852
96589
|
if (typeof file3 === "string") {
|
|
95853
|
-
touchedFiles.add(
|
|
96590
|
+
touchedFiles.add(path118.resolve(cwd, file3));
|
|
95854
96591
|
}
|
|
95855
96592
|
}
|
|
95856
96593
|
}
|
|
@@ -95863,12 +96600,12 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
95863
96600
|
}
|
|
95864
96601
|
function searchFileForKeywords(filePath, keywords, cwd) {
|
|
95865
96602
|
try {
|
|
95866
|
-
const resolvedPath =
|
|
95867
|
-
const cwdResolved =
|
|
96603
|
+
const resolvedPath = path118.resolve(filePath);
|
|
96604
|
+
const cwdResolved = path118.resolve(cwd);
|
|
95868
96605
|
if (!resolvedPath.startsWith(cwdResolved)) {
|
|
95869
96606
|
return false;
|
|
95870
96607
|
}
|
|
95871
|
-
const content =
|
|
96608
|
+
const content = fs91.readFileSync(resolvedPath, "utf-8");
|
|
95872
96609
|
for (const keyword of keywords) {
|
|
95873
96610
|
const regex = new RegExp(`\\b${keyword}\\b`, "i");
|
|
95874
96611
|
if (regex.test(content)) {
|
|
@@ -95998,10 +96735,10 @@ var req_coverage = createSwarmTool({
|
|
|
95998
96735
|
}, null, 2);
|
|
95999
96736
|
}
|
|
96000
96737
|
const cwd = inputDirectory || directory;
|
|
96001
|
-
const specPath =
|
|
96738
|
+
const specPath = path118.join(cwd, SPEC_FILE);
|
|
96002
96739
|
let specContent;
|
|
96003
96740
|
try {
|
|
96004
|
-
specContent =
|
|
96741
|
+
specContent = fs91.readFileSync(specPath, "utf-8");
|
|
96005
96742
|
} catch (readError) {
|
|
96006
96743
|
return JSON.stringify({
|
|
96007
96744
|
success: false,
|
|
@@ -96025,7 +96762,7 @@ var req_coverage = createSwarmTool({
|
|
|
96025
96762
|
message: "No FR requirements found in spec.md"
|
|
96026
96763
|
}, null, 2);
|
|
96027
96764
|
}
|
|
96028
|
-
const evidenceDir =
|
|
96765
|
+
const evidenceDir = path118.join(cwd, EVIDENCE_DIR4);
|
|
96029
96766
|
const touchedFiles = readTouchedFiles(evidenceDir, phase, cwd);
|
|
96030
96767
|
const analyzedRequirements = [];
|
|
96031
96768
|
let coveredCount = 0;
|
|
@@ -96051,12 +96788,12 @@ var req_coverage = createSwarmTool({
|
|
|
96051
96788
|
requirements: analyzedRequirements
|
|
96052
96789
|
};
|
|
96053
96790
|
const reportFilename = `req-coverage-phase-${phase}.json`;
|
|
96054
|
-
const reportPath =
|
|
96791
|
+
const reportPath = path118.join(evidenceDir, reportFilename);
|
|
96055
96792
|
try {
|
|
96056
|
-
if (!
|
|
96057
|
-
|
|
96793
|
+
if (!fs91.existsSync(evidenceDir)) {
|
|
96794
|
+
fs91.mkdirSync(evidenceDir, { recursive: true });
|
|
96058
96795
|
}
|
|
96059
|
-
|
|
96796
|
+
fs91.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8");
|
|
96060
96797
|
} catch (writeError) {
|
|
96061
96798
|
console.warn(`Failed to write coverage report: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
96062
96799
|
}
|
|
@@ -96137,9 +96874,9 @@ init_zod();
|
|
|
96137
96874
|
init_plan_schema();
|
|
96138
96875
|
init_qa_gate_profile();
|
|
96139
96876
|
init_file_locks();
|
|
96140
|
-
import * as
|
|
96141
|
-
import * as
|
|
96142
|
-
import * as
|
|
96877
|
+
import * as crypto11 from "node:crypto";
|
|
96878
|
+
import * as fs92 from "node:fs";
|
|
96879
|
+
import * as path119 from "node:path";
|
|
96143
96880
|
init_ledger();
|
|
96144
96881
|
init_manager();
|
|
96145
96882
|
init_state();
|
|
@@ -96217,17 +96954,17 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
96217
96954
|
};
|
|
96218
96955
|
}
|
|
96219
96956
|
if (args2.working_directory && fallbackDir) {
|
|
96220
|
-
const resolvedTarget =
|
|
96221
|
-
const resolvedRoot =
|
|
96957
|
+
const resolvedTarget = path119.resolve(args2.working_directory);
|
|
96958
|
+
const resolvedRoot = path119.resolve(fallbackDir);
|
|
96222
96959
|
let fallbackExists = false;
|
|
96223
96960
|
try {
|
|
96224
|
-
|
|
96961
|
+
fs92.accessSync(resolvedRoot, fs92.constants.F_OK);
|
|
96225
96962
|
fallbackExists = true;
|
|
96226
96963
|
} catch {
|
|
96227
96964
|
fallbackExists = false;
|
|
96228
96965
|
}
|
|
96229
96966
|
if (fallbackExists) {
|
|
96230
|
-
const isSubdirectory = resolvedTarget.startsWith(resolvedRoot +
|
|
96967
|
+
const isSubdirectory = resolvedTarget.startsWith(resolvedRoot + path119.sep);
|
|
96231
96968
|
if (isSubdirectory) {
|
|
96232
96969
|
return {
|
|
96233
96970
|
success: false,
|
|
@@ -96243,12 +96980,12 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
96243
96980
|
let specMtime;
|
|
96244
96981
|
let specHash;
|
|
96245
96982
|
if (process.env.SWARM_SKIP_SPEC_GATE !== "1") {
|
|
96246
|
-
const specPath =
|
|
96983
|
+
const specPath = path119.join(targetWorkspace, ".swarm", "spec.md");
|
|
96247
96984
|
try {
|
|
96248
|
-
const stat8 = await
|
|
96985
|
+
const stat8 = await fs92.promises.stat(specPath);
|
|
96249
96986
|
specMtime = stat8.mtime.toISOString();
|
|
96250
|
-
const content = await
|
|
96251
|
-
specHash =
|
|
96987
|
+
const content = await fs92.promises.readFile(specPath, "utf8");
|
|
96988
|
+
specHash = crypto11.createHash("sha256").update(content).digest("hex");
|
|
96252
96989
|
} catch {
|
|
96253
96990
|
return {
|
|
96254
96991
|
success: false,
|
|
@@ -96259,10 +96996,10 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
96259
96996
|
}
|
|
96260
96997
|
}
|
|
96261
96998
|
if (process.env.SWARM_SKIP_GATE_SELECTION !== "1") {
|
|
96262
|
-
const contextPath =
|
|
96999
|
+
const contextPath = path119.join(targetWorkspace, ".swarm", "context.md");
|
|
96263
97000
|
let contextContent = "";
|
|
96264
97001
|
try {
|
|
96265
|
-
contextContent = await
|
|
97002
|
+
contextContent = await fs92.promises.readFile(contextPath, "utf8");
|
|
96266
97003
|
} catch {}
|
|
96267
97004
|
const hasPendingSection = contextContent.includes("## Pending QA Gate Selection");
|
|
96268
97005
|
if (!hasPendingSection) {
|
|
@@ -96516,14 +97253,14 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
96516
97253
|
}
|
|
96517
97254
|
await writeCheckpoint(dir).catch(() => {});
|
|
96518
97255
|
try {
|
|
96519
|
-
const markerPath =
|
|
97256
|
+
const markerPath = path119.join(dir, ".swarm", ".plan-write-marker");
|
|
96520
97257
|
const marker = JSON.stringify({
|
|
96521
97258
|
source: "save_plan",
|
|
96522
97259
|
timestamp: new Date().toISOString(),
|
|
96523
97260
|
phases_count: plan.phases.length,
|
|
96524
97261
|
tasks_count: tasksCount
|
|
96525
97262
|
});
|
|
96526
|
-
await
|
|
97263
|
+
await fs92.promises.writeFile(markerPath, marker, "utf8");
|
|
96527
97264
|
} catch {}
|
|
96528
97265
|
const warnings = [];
|
|
96529
97266
|
let criticReviewFound = false;
|
|
@@ -96539,7 +97276,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
96539
97276
|
return {
|
|
96540
97277
|
success: true,
|
|
96541
97278
|
message: "Plan saved successfully",
|
|
96542
|
-
plan_path:
|
|
97279
|
+
plan_path: path119.join(dir, ".swarm", "plan.json"),
|
|
96543
97280
|
phases_count: plan.phases.length,
|
|
96544
97281
|
tasks_count: tasksCount,
|
|
96545
97282
|
...resolvedProfile !== undefined ? { execution_profile: resolvedProfile } : {},
|
|
@@ -96603,8 +97340,8 @@ var save_plan = createSwarmTool({
|
|
|
96603
97340
|
// src/tools/sbom-generate.ts
|
|
96604
97341
|
init_zod();
|
|
96605
97342
|
init_manager2();
|
|
96606
|
-
import * as
|
|
96607
|
-
import * as
|
|
97343
|
+
import * as fs93 from "node:fs";
|
|
97344
|
+
import * as path120 from "node:path";
|
|
96608
97345
|
|
|
96609
97346
|
// src/sbom/detectors/index.ts
|
|
96610
97347
|
init_utils();
|
|
@@ -97452,9 +98189,9 @@ function findManifestFiles(rootDir) {
|
|
|
97452
98189
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
97453
98190
|
function searchDir(dir) {
|
|
97454
98191
|
try {
|
|
97455
|
-
const entries =
|
|
98192
|
+
const entries = fs93.readdirSync(dir, { withFileTypes: true });
|
|
97456
98193
|
for (const entry of entries) {
|
|
97457
|
-
const fullPath =
|
|
98194
|
+
const fullPath = path120.join(dir, entry.name);
|
|
97458
98195
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
97459
98196
|
continue;
|
|
97460
98197
|
}
|
|
@@ -97463,7 +98200,7 @@ function findManifestFiles(rootDir) {
|
|
|
97463
98200
|
} else if (entry.isFile()) {
|
|
97464
98201
|
for (const pattern of patterns) {
|
|
97465
98202
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
97466
|
-
manifestFiles.push(
|
|
98203
|
+
manifestFiles.push(path120.relative(rootDir, fullPath));
|
|
97467
98204
|
break;
|
|
97468
98205
|
}
|
|
97469
98206
|
}
|
|
@@ -97479,13 +98216,13 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
97479
98216
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
97480
98217
|
for (const dir of directories) {
|
|
97481
98218
|
try {
|
|
97482
|
-
const entries =
|
|
98219
|
+
const entries = fs93.readdirSync(dir, { withFileTypes: true });
|
|
97483
98220
|
for (const entry of entries) {
|
|
97484
|
-
const fullPath =
|
|
98221
|
+
const fullPath = path120.join(dir, entry.name);
|
|
97485
98222
|
if (entry.isFile()) {
|
|
97486
98223
|
for (const pattern of patterns) {
|
|
97487
98224
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
97488
|
-
found.push(
|
|
98225
|
+
found.push(path120.relative(workingDir, fullPath));
|
|
97489
98226
|
break;
|
|
97490
98227
|
}
|
|
97491
98228
|
}
|
|
@@ -97498,11 +98235,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
97498
98235
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
97499
98236
|
const dirs = new Set;
|
|
97500
98237
|
for (const file3 of changedFiles) {
|
|
97501
|
-
let currentDir =
|
|
98238
|
+
let currentDir = path120.dirname(file3);
|
|
97502
98239
|
while (true) {
|
|
97503
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
97504
|
-
dirs.add(
|
|
97505
|
-
const parent =
|
|
98240
|
+
if (currentDir && currentDir !== "." && currentDir !== path120.sep) {
|
|
98241
|
+
dirs.add(path120.join(workingDir, currentDir));
|
|
98242
|
+
const parent = path120.dirname(currentDir);
|
|
97506
98243
|
if (parent === currentDir)
|
|
97507
98244
|
break;
|
|
97508
98245
|
currentDir = parent;
|
|
@@ -97516,7 +98253,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
97516
98253
|
}
|
|
97517
98254
|
function ensureOutputDir(outputDir) {
|
|
97518
98255
|
try {
|
|
97519
|
-
|
|
98256
|
+
fs93.mkdirSync(outputDir, { recursive: true });
|
|
97520
98257
|
} catch (error93) {
|
|
97521
98258
|
if (!error93 || error93.code !== "EEXIST") {
|
|
97522
98259
|
throw error93;
|
|
@@ -97586,7 +98323,7 @@ var sbom_generate = createSwarmTool({
|
|
|
97586
98323
|
const changedFiles = obj.changed_files;
|
|
97587
98324
|
const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
|
|
97588
98325
|
const workingDir = directory;
|
|
97589
|
-
const outputDir =
|
|
98326
|
+
const outputDir = path120.isAbsolute(relativeOutputDir) ? relativeOutputDir : path120.join(workingDir, relativeOutputDir);
|
|
97590
98327
|
let manifestFiles = [];
|
|
97591
98328
|
if (scope === "all") {
|
|
97592
98329
|
manifestFiles = findManifestFiles(workingDir);
|
|
@@ -97609,11 +98346,11 @@ var sbom_generate = createSwarmTool({
|
|
|
97609
98346
|
const processedFiles = [];
|
|
97610
98347
|
for (const manifestFile of manifestFiles) {
|
|
97611
98348
|
try {
|
|
97612
|
-
const fullPath =
|
|
97613
|
-
if (!
|
|
98349
|
+
const fullPath = path120.isAbsolute(manifestFile) ? manifestFile : path120.join(workingDir, manifestFile);
|
|
98350
|
+
if (!fs93.existsSync(fullPath)) {
|
|
97614
98351
|
continue;
|
|
97615
98352
|
}
|
|
97616
|
-
const content =
|
|
98353
|
+
const content = fs93.readFileSync(fullPath, "utf-8");
|
|
97617
98354
|
const components = detectComponents(manifestFile, content);
|
|
97618
98355
|
processedFiles.push(manifestFile);
|
|
97619
98356
|
if (components.length > 0) {
|
|
@@ -97626,8 +98363,8 @@ var sbom_generate = createSwarmTool({
|
|
|
97626
98363
|
const bom = generateCycloneDX(allComponents);
|
|
97627
98364
|
const bomJson = serializeCycloneDX(bom);
|
|
97628
98365
|
const filename = generateSbomFilename();
|
|
97629
|
-
const outputPath =
|
|
97630
|
-
|
|
98366
|
+
const outputPath = path120.join(outputDir, filename);
|
|
98367
|
+
fs93.writeFileSync(outputPath, bomJson, "utf-8");
|
|
97631
98368
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
97632
98369
|
try {
|
|
97633
98370
|
const timestamp = new Date().toISOString();
|
|
@@ -97669,8 +98406,8 @@ var sbom_generate = createSwarmTool({
|
|
|
97669
98406
|
// src/tools/schema-drift.ts
|
|
97670
98407
|
init_zod();
|
|
97671
98408
|
init_create_tool();
|
|
97672
|
-
import * as
|
|
97673
|
-
import * as
|
|
98409
|
+
import * as fs94 from "node:fs";
|
|
98410
|
+
import * as path121 from "node:path";
|
|
97674
98411
|
var SPEC_CANDIDATES = [
|
|
97675
98412
|
"openapi.json",
|
|
97676
98413
|
"openapi.yaml",
|
|
@@ -97702,28 +98439,28 @@ function normalizePath4(p) {
|
|
|
97702
98439
|
}
|
|
97703
98440
|
function discoverSpecFile(cwd, specFileArg) {
|
|
97704
98441
|
if (specFileArg) {
|
|
97705
|
-
const resolvedPath =
|
|
97706
|
-
const normalizedCwd = cwd.endsWith(
|
|
98442
|
+
const resolvedPath = path121.resolve(cwd, specFileArg);
|
|
98443
|
+
const normalizedCwd = cwd.endsWith(path121.sep) ? cwd : cwd + path121.sep;
|
|
97707
98444
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
97708
98445
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
97709
98446
|
}
|
|
97710
|
-
const ext =
|
|
98447
|
+
const ext = path121.extname(resolvedPath).toLowerCase();
|
|
97711
98448
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
97712
98449
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
97713
98450
|
}
|
|
97714
|
-
const stats =
|
|
98451
|
+
const stats = fs94.statSync(resolvedPath);
|
|
97715
98452
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
97716
98453
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
97717
98454
|
}
|
|
97718
|
-
if (!
|
|
98455
|
+
if (!fs94.existsSync(resolvedPath)) {
|
|
97719
98456
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
97720
98457
|
}
|
|
97721
98458
|
return resolvedPath;
|
|
97722
98459
|
}
|
|
97723
98460
|
for (const candidate of SPEC_CANDIDATES) {
|
|
97724
|
-
const candidatePath =
|
|
97725
|
-
if (
|
|
97726
|
-
const stats =
|
|
98461
|
+
const candidatePath = path121.resolve(cwd, candidate);
|
|
98462
|
+
if (fs94.existsSync(candidatePath)) {
|
|
98463
|
+
const stats = fs94.statSync(candidatePath);
|
|
97727
98464
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
97728
98465
|
return candidatePath;
|
|
97729
98466
|
}
|
|
@@ -97732,8 +98469,8 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
97732
98469
|
return null;
|
|
97733
98470
|
}
|
|
97734
98471
|
function parseSpec(specFile) {
|
|
97735
|
-
const content =
|
|
97736
|
-
const ext =
|
|
98472
|
+
const content = fs94.readFileSync(specFile, "utf-8");
|
|
98473
|
+
const ext = path121.extname(specFile).toLowerCase();
|
|
97737
98474
|
if (ext === ".json") {
|
|
97738
98475
|
return parseJsonSpec(content);
|
|
97739
98476
|
}
|
|
@@ -97804,12 +98541,12 @@ function extractRoutes(cwd) {
|
|
|
97804
98541
|
function walkDir(dir) {
|
|
97805
98542
|
let entries;
|
|
97806
98543
|
try {
|
|
97807
|
-
entries =
|
|
98544
|
+
entries = fs94.readdirSync(dir, { withFileTypes: true });
|
|
97808
98545
|
} catch {
|
|
97809
98546
|
return;
|
|
97810
98547
|
}
|
|
97811
98548
|
for (const entry of entries) {
|
|
97812
|
-
const fullPath =
|
|
98549
|
+
const fullPath = path121.join(dir, entry.name);
|
|
97813
98550
|
if (entry.isSymbolicLink()) {
|
|
97814
98551
|
continue;
|
|
97815
98552
|
}
|
|
@@ -97819,7 +98556,7 @@ function extractRoutes(cwd) {
|
|
|
97819
98556
|
}
|
|
97820
98557
|
walkDir(fullPath);
|
|
97821
98558
|
} else if (entry.isFile()) {
|
|
97822
|
-
const ext =
|
|
98559
|
+
const ext = path121.extname(entry.name).toLowerCase();
|
|
97823
98560
|
const baseName = entry.name.toLowerCase();
|
|
97824
98561
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
97825
98562
|
continue;
|
|
@@ -97837,7 +98574,7 @@ function extractRoutes(cwd) {
|
|
|
97837
98574
|
}
|
|
97838
98575
|
function extractRoutesFromFile(filePath) {
|
|
97839
98576
|
const routes = [];
|
|
97840
|
-
const content =
|
|
98577
|
+
const content = fs94.readFileSync(filePath, "utf-8");
|
|
97841
98578
|
const lines = content.split(/\r?\n/);
|
|
97842
98579
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
97843
98580
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -97986,8 +98723,8 @@ init_zod();
|
|
|
97986
98723
|
init_bun_compat();
|
|
97987
98724
|
init_path_security();
|
|
97988
98725
|
init_create_tool();
|
|
97989
|
-
import * as
|
|
97990
|
-
import * as
|
|
98726
|
+
import * as fs95 from "node:fs";
|
|
98727
|
+
import * as path122 from "node:path";
|
|
97991
98728
|
var DEFAULT_MAX_RESULTS = 100;
|
|
97992
98729
|
var DEFAULT_MAX_LINES = 200;
|
|
97993
98730
|
var REGEX_TIMEOUT_MS = 5000;
|
|
@@ -98023,11 +98760,11 @@ function containsWindowsAttacks3(str) {
|
|
|
98023
98760
|
}
|
|
98024
98761
|
function isPathInWorkspace3(filePath, workspace) {
|
|
98025
98762
|
try {
|
|
98026
|
-
const resolvedPath =
|
|
98027
|
-
const realWorkspace =
|
|
98028
|
-
const realResolvedPath =
|
|
98029
|
-
const relativePath =
|
|
98030
|
-
if (relativePath.startsWith("..") ||
|
|
98763
|
+
const resolvedPath = path122.resolve(workspace, filePath);
|
|
98764
|
+
const realWorkspace = fs95.realpathSync(workspace);
|
|
98765
|
+
const realResolvedPath = fs95.realpathSync(resolvedPath);
|
|
98766
|
+
const relativePath = path122.relative(realWorkspace, realResolvedPath);
|
|
98767
|
+
if (relativePath.startsWith("..") || path122.isAbsolute(relativePath)) {
|
|
98031
98768
|
return false;
|
|
98032
98769
|
}
|
|
98033
98770
|
return true;
|
|
@@ -98040,12 +98777,12 @@ function validatePathForRead2(filePath, workspace) {
|
|
|
98040
98777
|
}
|
|
98041
98778
|
function findRgInEnvPath() {
|
|
98042
98779
|
const searchPath = process.env.PATH ?? "";
|
|
98043
|
-
for (const dir of searchPath.split(
|
|
98780
|
+
for (const dir of searchPath.split(path122.delimiter)) {
|
|
98044
98781
|
if (!dir)
|
|
98045
98782
|
continue;
|
|
98046
98783
|
const isWindows = process.platform === "win32";
|
|
98047
|
-
const candidate =
|
|
98048
|
-
if (
|
|
98784
|
+
const candidate = path122.join(dir, isWindows ? "rg.exe" : "rg");
|
|
98785
|
+
if (fs95.existsSync(candidate))
|
|
98049
98786
|
return candidate;
|
|
98050
98787
|
}
|
|
98051
98788
|
return null;
|
|
@@ -98172,10 +98909,10 @@ function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
|
|
|
98172
98909
|
return files;
|
|
98173
98910
|
}
|
|
98174
98911
|
try {
|
|
98175
|
-
const entries =
|
|
98912
|
+
const entries = fs95.readdirSync(dir, { withFileTypes: true });
|
|
98176
98913
|
for (const entry of entries) {
|
|
98177
|
-
const fullPath =
|
|
98178
|
-
const relativePath =
|
|
98914
|
+
const fullPath = path122.join(dir, entry.name);
|
|
98915
|
+
const relativePath = path122.relative(workspace, fullPath);
|
|
98179
98916
|
if (!validatePathForRead2(fullPath, workspace)) {
|
|
98180
98917
|
continue;
|
|
98181
98918
|
}
|
|
@@ -98216,13 +98953,13 @@ async function fallbackSearch(opts) {
|
|
|
98216
98953
|
const matches = [];
|
|
98217
98954
|
let total = 0;
|
|
98218
98955
|
for (const file3 of files) {
|
|
98219
|
-
const fullPath =
|
|
98956
|
+
const fullPath = path122.join(opts.workspace, file3);
|
|
98220
98957
|
if (!validatePathForRead2(fullPath, opts.workspace)) {
|
|
98221
98958
|
continue;
|
|
98222
98959
|
}
|
|
98223
98960
|
let stats;
|
|
98224
98961
|
try {
|
|
98225
|
-
stats =
|
|
98962
|
+
stats = fs95.statSync(fullPath);
|
|
98226
98963
|
if (stats.size > MAX_FILE_SIZE_BYTES10) {
|
|
98227
98964
|
continue;
|
|
98228
98965
|
}
|
|
@@ -98231,7 +98968,7 @@ async function fallbackSearch(opts) {
|
|
|
98231
98968
|
}
|
|
98232
98969
|
let content;
|
|
98233
98970
|
try {
|
|
98234
|
-
content =
|
|
98971
|
+
content = fs95.readFileSync(fullPath, "utf-8");
|
|
98235
98972
|
} catch {
|
|
98236
98973
|
continue;
|
|
98237
98974
|
}
|
|
@@ -98343,7 +99080,7 @@ var search = createSwarmTool({
|
|
|
98343
99080
|
message: "Exclude pattern contains invalid Windows-specific sequence"
|
|
98344
99081
|
}, null, 2);
|
|
98345
99082
|
}
|
|
98346
|
-
if (!
|
|
99083
|
+
if (!fs95.existsSync(directory)) {
|
|
98347
99084
|
return JSON.stringify({
|
|
98348
99085
|
error: true,
|
|
98349
99086
|
type: "unknown",
|
|
@@ -98584,7 +99321,7 @@ init_config();
|
|
|
98584
99321
|
init_schema();
|
|
98585
99322
|
init_create_tool();
|
|
98586
99323
|
import { mkdir as mkdir19, rename as rename8, writeFile as writeFile15 } from "node:fs/promises";
|
|
98587
|
-
import * as
|
|
99324
|
+
import * as path123 from "node:path";
|
|
98588
99325
|
var MAX_SPEC_BYTES = 256 * 1024;
|
|
98589
99326
|
var spec_write = createSwarmTool({
|
|
98590
99327
|
description: "Write the canonical project spec to .swarm/spec.md. Atomic write, size-bounded (256 KiB), heading-required. Honors spec_writer.allow_spec_write.",
|
|
@@ -98625,14 +99362,14 @@ var spec_write = createSwarmTool({
|
|
|
98625
99362
|
reason: 'spec must contain at least one top-level "# Heading"'
|
|
98626
99363
|
}, null, 2);
|
|
98627
99364
|
}
|
|
98628
|
-
const target =
|
|
98629
|
-
await mkdir19(
|
|
99365
|
+
const target = path123.join(directory, ".swarm", "spec.md");
|
|
99366
|
+
await mkdir19(path123.dirname(target), { recursive: true });
|
|
98630
99367
|
const tmp = `${target}.tmp-${process.pid}-${Date.now()}`;
|
|
98631
99368
|
let finalContent = content;
|
|
98632
99369
|
if (mode === "append") {
|
|
98633
99370
|
try {
|
|
98634
|
-
const
|
|
98635
|
-
const prior = await
|
|
99371
|
+
const fs96 = await import("node:fs/promises");
|
|
99372
|
+
const prior = await fs96.readFile(target, "utf-8");
|
|
98636
99373
|
finalContent = `${prior.replace(/\s+$/, "")}
|
|
98637
99374
|
|
|
98638
99375
|
${content}
|
|
@@ -98654,14 +99391,14 @@ ${content}
|
|
|
98654
99391
|
init_zod();
|
|
98655
99392
|
init_loader();
|
|
98656
99393
|
import {
|
|
98657
|
-
existsSync as
|
|
98658
|
-
mkdirSync as
|
|
98659
|
-
readFileSync as
|
|
98660
|
-
renameSync as
|
|
99394
|
+
existsSync as existsSync72,
|
|
99395
|
+
mkdirSync as mkdirSync31,
|
|
99396
|
+
readFileSync as readFileSync62,
|
|
99397
|
+
renameSync as renameSync20,
|
|
98661
99398
|
unlinkSync as unlinkSync15,
|
|
98662
|
-
writeFileSync as
|
|
99399
|
+
writeFileSync as writeFileSync24
|
|
98663
99400
|
} from "node:fs";
|
|
98664
|
-
import
|
|
99401
|
+
import path124 from "node:path";
|
|
98665
99402
|
init_create_tool();
|
|
98666
99403
|
init_resolve_working_directory();
|
|
98667
99404
|
var VerdictSchema2 = exports_external.object({
|
|
@@ -98791,9 +99528,9 @@ var submit_phase_council_verdicts = createSwarmTool({
|
|
|
98791
99528
|
}
|
|
98792
99529
|
});
|
|
98793
99530
|
function getPhaseMutationGapFinding(phaseNumber, workingDir) {
|
|
98794
|
-
const mutationGatePath =
|
|
99531
|
+
const mutationGatePath = path124.join(workingDir, ".swarm", "evidence", String(phaseNumber), "mutation-gate.json");
|
|
98795
99532
|
try {
|
|
98796
|
-
const raw =
|
|
99533
|
+
const raw = readFileSync62(mutationGatePath, "utf-8");
|
|
98797
99534
|
const parsed = JSON.parse(raw);
|
|
98798
99535
|
const gateEntry = (parsed.entries ?? []).find((entry) => entry?.type === "mutation-gate");
|
|
98799
99536
|
if (!gateEntry) {
|
|
@@ -98853,9 +99590,9 @@ function getPhaseMutationGapFinding(phaseNumber, workingDir) {
|
|
|
98853
99590
|
}
|
|
98854
99591
|
}
|
|
98855
99592
|
function writePhaseCouncilEvidence(workingDir, synthesis) {
|
|
98856
|
-
const evidenceDir =
|
|
98857
|
-
|
|
98858
|
-
const evidenceFile =
|
|
99593
|
+
const evidenceDir = path124.join(workingDir, ".swarm", "evidence", String(synthesis.phaseNumber));
|
|
99594
|
+
mkdirSync31(evidenceDir, { recursive: true });
|
|
99595
|
+
const evidenceFile = path124.join(evidenceDir, "phase-council.json");
|
|
98859
99596
|
const evidenceBundle = {
|
|
98860
99597
|
entries: [
|
|
98861
99598
|
{
|
|
@@ -98888,10 +99625,10 @@ function writePhaseCouncilEvidence(workingDir, synthesis) {
|
|
|
98888
99625
|
};
|
|
98889
99626
|
const tempFile = `${evidenceFile}.tmp-${Date.now()}`;
|
|
98890
99627
|
try {
|
|
98891
|
-
|
|
98892
|
-
|
|
99628
|
+
writeFileSync24(tempFile, JSON.stringify(evidenceBundle, null, 2), "utf-8");
|
|
99629
|
+
renameSync20(tempFile, evidenceFile);
|
|
98893
99630
|
} finally {
|
|
98894
|
-
if (
|
|
99631
|
+
if (existsSync72(tempFile)) {
|
|
98895
99632
|
unlinkSync15(tempFile);
|
|
98896
99633
|
}
|
|
98897
99634
|
}
|
|
@@ -98940,8 +99677,8 @@ function createSwarmCommandTool(agents) {
|
|
|
98940
99677
|
init_zod();
|
|
98941
99678
|
init_path_security();
|
|
98942
99679
|
init_create_tool();
|
|
98943
|
-
import * as
|
|
98944
|
-
import * as
|
|
99680
|
+
import * as fs96 from "node:fs";
|
|
99681
|
+
import * as path125 from "node:path";
|
|
98945
99682
|
var WINDOWS_RESERVED_NAMES4 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
98946
99683
|
function containsWindowsAttacks4(str) {
|
|
98947
99684
|
if (/:[^\\/]/.test(str))
|
|
@@ -98955,14 +99692,14 @@ function containsWindowsAttacks4(str) {
|
|
|
98955
99692
|
}
|
|
98956
99693
|
function isPathInWorkspace4(filePath, workspace) {
|
|
98957
99694
|
try {
|
|
98958
|
-
const resolvedPath =
|
|
98959
|
-
if (!
|
|
99695
|
+
const resolvedPath = path125.resolve(workspace, filePath);
|
|
99696
|
+
if (!fs96.existsSync(resolvedPath)) {
|
|
98960
99697
|
return true;
|
|
98961
99698
|
}
|
|
98962
|
-
const realWorkspace =
|
|
98963
|
-
const realResolvedPath =
|
|
98964
|
-
const relativePath =
|
|
98965
|
-
if (relativePath.startsWith("..") ||
|
|
99699
|
+
const realWorkspace = fs96.realpathSync(workspace);
|
|
99700
|
+
const realResolvedPath = fs96.realpathSync(resolvedPath);
|
|
99701
|
+
const relativePath = path125.relative(realWorkspace, realResolvedPath);
|
|
99702
|
+
if (relativePath.startsWith("..") || path125.isAbsolute(relativePath)) {
|
|
98966
99703
|
return false;
|
|
98967
99704
|
}
|
|
98968
99705
|
return true;
|
|
@@ -99134,7 +99871,7 @@ var suggestPatch = createSwarmTool({
|
|
|
99134
99871
|
message: "changes cannot be empty"
|
|
99135
99872
|
}, null, 2);
|
|
99136
99873
|
}
|
|
99137
|
-
if (!
|
|
99874
|
+
if (!fs96.existsSync(directory)) {
|
|
99138
99875
|
return JSON.stringify({
|
|
99139
99876
|
success: false,
|
|
99140
99877
|
error: true,
|
|
@@ -99170,8 +99907,8 @@ var suggestPatch = createSwarmTool({
|
|
|
99170
99907
|
});
|
|
99171
99908
|
continue;
|
|
99172
99909
|
}
|
|
99173
|
-
const fullPath =
|
|
99174
|
-
if (!
|
|
99910
|
+
const fullPath = path125.resolve(directory, change.file);
|
|
99911
|
+
if (!fs96.existsSync(fullPath)) {
|
|
99175
99912
|
errors5.push({
|
|
99176
99913
|
success: false,
|
|
99177
99914
|
error: true,
|
|
@@ -99185,7 +99922,7 @@ var suggestPatch = createSwarmTool({
|
|
|
99185
99922
|
}
|
|
99186
99923
|
let content;
|
|
99187
99924
|
try {
|
|
99188
|
-
content =
|
|
99925
|
+
content = fs96.readFileSync(fullPath, "utf-8");
|
|
99189
99926
|
} catch (err3) {
|
|
99190
99927
|
errors5.push({
|
|
99191
99928
|
success: false,
|
|
@@ -99473,12 +100210,12 @@ var lean_turbo_acquire_locks = createSwarmTool({
|
|
|
99473
100210
|
// src/tools/lean-turbo-plan-lanes.ts
|
|
99474
100211
|
init_zod();
|
|
99475
100212
|
init_constants();
|
|
99476
|
-
import * as
|
|
99477
|
-
import * as
|
|
100213
|
+
import * as fs98 from "node:fs";
|
|
100214
|
+
import * as path127 from "node:path";
|
|
99478
100215
|
|
|
99479
100216
|
// src/turbo/lean/conflicts.ts
|
|
99480
|
-
import * as
|
|
99481
|
-
import * as
|
|
100217
|
+
import * as fs97 from "node:fs";
|
|
100218
|
+
import * as path126 from "node:path";
|
|
99482
100219
|
var DEFAULT_GLOBAL_FILES = [
|
|
99483
100220
|
"package.json",
|
|
99484
100221
|
"package-lock.json",
|
|
@@ -99605,12 +100342,12 @@ function isProtectedPath2(normalizedPath) {
|
|
|
99605
100342
|
return false;
|
|
99606
100343
|
}
|
|
99607
100344
|
function readTaskScopes(directory, taskId) {
|
|
99608
|
-
const scopePath =
|
|
100345
|
+
const scopePath = path126.join(directory, ".swarm", "scopes", `scope-${taskId}.json`);
|
|
99609
100346
|
try {
|
|
99610
|
-
if (!
|
|
100347
|
+
if (!fs97.existsSync(scopePath)) {
|
|
99611
100348
|
return null;
|
|
99612
100349
|
}
|
|
99613
|
-
const raw =
|
|
100350
|
+
const raw = fs97.readFileSync(scopePath, "utf-8");
|
|
99614
100351
|
const parsed = JSON.parse(raw);
|
|
99615
100352
|
if (!parsed || !Array.isArray(parsed.files)) {
|
|
99616
100353
|
return null;
|
|
@@ -99993,12 +100730,12 @@ function createEmptyPlan(phaseNumber, planId) {
|
|
|
99993
100730
|
// src/tools/lean-turbo-plan-lanes.ts
|
|
99994
100731
|
init_create_tool();
|
|
99995
100732
|
function readPlanJson(directory) {
|
|
99996
|
-
const planPath =
|
|
99997
|
-
if (!
|
|
100733
|
+
const planPath = path127.join(directory, ".swarm", "plan.json");
|
|
100734
|
+
if (!fs98.existsSync(planPath)) {
|
|
99998
100735
|
return null;
|
|
99999
100736
|
}
|
|
100000
100737
|
try {
|
|
100001
|
-
return JSON.parse(
|
|
100738
|
+
return JSON.parse(fs98.readFileSync(planPath, "utf-8"));
|
|
100002
100739
|
} catch {
|
|
100003
100740
|
return null;
|
|
100004
100741
|
}
|
|
@@ -100047,8 +100784,8 @@ init_config();
|
|
|
100047
100784
|
|
|
100048
100785
|
// src/turbo/lean/reviewer.ts
|
|
100049
100786
|
init_state();
|
|
100050
|
-
import * as
|
|
100051
|
-
import * as
|
|
100787
|
+
import * as fs99 from "node:fs/promises";
|
|
100788
|
+
import * as path128 from "node:path";
|
|
100052
100789
|
init_state3();
|
|
100053
100790
|
var DEFAULT_CONFIG3 = {
|
|
100054
100791
|
reviewerAgent: "",
|
|
@@ -100070,7 +100807,7 @@ function resolveDefaultReviewerAgent(generatedAgentNames) {
|
|
|
100070
100807
|
}
|
|
100071
100808
|
async function compileReviewPackage(directory, phase, sessionID, requireDiffSummary) {
|
|
100072
100809
|
const lanes = await listLaneEvidence(directory, phase);
|
|
100073
|
-
const persisted =
|
|
100810
|
+
const persisted = _internals48.readPersisted?.(directory) ?? null;
|
|
100074
100811
|
if (persisted) {
|
|
100075
100812
|
let matchingRunState = null;
|
|
100076
100813
|
for (const sessionState of Object.values(persisted.sessions)) {
|
|
@@ -100164,9 +100901,9 @@ function parseReviewerVerdict(responseText) {
|
|
|
100164
100901
|
return { verdict, reason };
|
|
100165
100902
|
}
|
|
100166
100903
|
async function writeReviewerEvidence(directory, phase, verdict, reason) {
|
|
100167
|
-
const evidenceDir =
|
|
100168
|
-
await
|
|
100169
|
-
const evidencePath =
|
|
100904
|
+
const evidenceDir = path128.join(directory, ".swarm", "evidence", String(phase));
|
|
100905
|
+
await fs99.mkdir(evidenceDir, { recursive: true });
|
|
100906
|
+
const evidencePath = path128.join(evidenceDir, "lean-turbo-reviewer.json");
|
|
100170
100907
|
const content = JSON.stringify({
|
|
100171
100908
|
phase,
|
|
100172
100909
|
verdict,
|
|
@@ -100175,11 +100912,11 @@ async function writeReviewerEvidence(directory, phase, verdict, reason) {
|
|
|
100175
100912
|
}, null, 2);
|
|
100176
100913
|
const tempPath = `${evidencePath}.tmp.${process.pid}.${Date.now()}`;
|
|
100177
100914
|
try {
|
|
100178
|
-
await
|
|
100179
|
-
await
|
|
100915
|
+
await fs99.writeFile(tempPath, content, "utf-8");
|
|
100916
|
+
await fs99.rename(tempPath, evidencePath);
|
|
100180
100917
|
} catch (error93) {
|
|
100181
100918
|
try {
|
|
100182
|
-
await
|
|
100919
|
+
await fs99.unlink(tempPath);
|
|
100183
100920
|
} catch {}
|
|
100184
100921
|
throw error93;
|
|
100185
100922
|
}
|
|
@@ -100262,7 +100999,7 @@ Be specific and evidence-based. Do not approve a phase with unresolved degraded
|
|
|
100262
100999
|
client.session.delete({ path: { id: sessionId } }).catch(() => {});
|
|
100263
101000
|
}
|
|
100264
101001
|
}
|
|
100265
|
-
var
|
|
101002
|
+
var _internals48 = {
|
|
100266
101003
|
compileReviewPackage,
|
|
100267
101004
|
parseReviewerVerdict,
|
|
100268
101005
|
writeReviewerEvidence,
|
|
@@ -100279,28 +101016,28 @@ async function dispatchPhaseReviewer(directory, phase, sessionID, config3) {
|
|
|
100279
101016
|
};
|
|
100280
101017
|
const generatedAgentNames = swarmState.generatedAgentNames;
|
|
100281
101018
|
const agentName = mergedConfig.reviewerAgent || resolveDefaultReviewerAgent(generatedAgentNames);
|
|
100282
|
-
const pkg = await
|
|
101019
|
+
const pkg = await _internals48.compileReviewPackage(directory, phase, sessionID, mergedConfig.requireDiffSummary);
|
|
100283
101020
|
let responseText;
|
|
100284
101021
|
try {
|
|
100285
|
-
responseText = await
|
|
101022
|
+
responseText = await _internals48.dispatchReviewerAgent(directory, pkg, agentName, mergedConfig.timeoutMs);
|
|
100286
101023
|
} catch (error93) {
|
|
100287
|
-
const evidencePath2 = await
|
|
101024
|
+
const evidencePath2 = await _internals48.writeReviewerEvidence(directory, phase, "REJECTED", error93 instanceof Error ? error93.message : String(error93));
|
|
100288
101025
|
return {
|
|
100289
101026
|
verdict: "REJECTED",
|
|
100290
101027
|
reason: `Reviewer dispatch failed: ${error93 instanceof Error ? error93.message : String(error93)}`,
|
|
100291
101028
|
evidencePath: evidencePath2
|
|
100292
101029
|
};
|
|
100293
101030
|
}
|
|
100294
|
-
const parsed =
|
|
101031
|
+
const parsed = _internals48.parseReviewerVerdict(responseText);
|
|
100295
101032
|
if (!parsed) {
|
|
100296
|
-
const evidencePath2 = await
|
|
101033
|
+
const evidencePath2 = await _internals48.writeReviewerEvidence(directory, phase, "REJECTED", "Reviewer response could not be parsed");
|
|
100297
101034
|
return {
|
|
100298
101035
|
verdict: "REJECTED",
|
|
100299
101036
|
reason: "Reviewer response could not be parsed",
|
|
100300
101037
|
evidencePath: evidencePath2
|
|
100301
101038
|
};
|
|
100302
101039
|
}
|
|
100303
|
-
const evidencePath = await
|
|
101040
|
+
const evidencePath = await _internals48.writeReviewerEvidence(directory, phase, parsed.verdict, parsed.reason);
|
|
100304
101041
|
return {
|
|
100305
101042
|
verdict: parsed.verdict,
|
|
100306
101043
|
reason: parsed.reason,
|
|
@@ -100806,7 +101543,7 @@ ${fileList}
|
|
|
100806
101543
|
|
|
100807
101544
|
// src/tools/lean-turbo-run-phase.ts
|
|
100808
101545
|
init_create_tool();
|
|
100809
|
-
var
|
|
101546
|
+
var _internals49 = {
|
|
100810
101547
|
LeanTurboRunner,
|
|
100811
101548
|
loadPluginConfigWithMeta
|
|
100812
101549
|
};
|
|
@@ -100816,9 +101553,9 @@ async function executeLeanTurboRunPhase(args2) {
|
|
|
100816
101553
|
let runError = null;
|
|
100817
101554
|
let runner = null;
|
|
100818
101555
|
try {
|
|
100819
|
-
const { config: config3 } =
|
|
101556
|
+
const { config: config3 } = _internals49.loadPluginConfigWithMeta(directory);
|
|
100820
101557
|
const leanConfig = config3.turbo?.strategy === "lean" ? config3.turbo.lean : undefined;
|
|
100821
|
-
runner = new
|
|
101558
|
+
runner = new _internals49.LeanTurboRunner({
|
|
100822
101559
|
directory,
|
|
100823
101560
|
sessionID,
|
|
100824
101561
|
opencodeClient: swarmState.opencodeClient ?? null,
|
|
@@ -100970,8 +101707,8 @@ var lean_turbo_status = createSwarmTool({
|
|
|
100970
101707
|
// src/tools/lint-spec.ts
|
|
100971
101708
|
init_spec_schema();
|
|
100972
101709
|
init_create_tool();
|
|
100973
|
-
import * as
|
|
100974
|
-
import * as
|
|
101710
|
+
import * as fs100 from "node:fs";
|
|
101711
|
+
import * as path129 from "node:path";
|
|
100975
101712
|
var SPEC_FILE_NAME = "spec.md";
|
|
100976
101713
|
var SWARM_DIR2 = ".swarm";
|
|
100977
101714
|
var OBLIGATION_KEYWORDS2 = ["MUST", "SHALL", "SHOULD", "MAY"];
|
|
@@ -101024,8 +101761,8 @@ var lint_spec = createSwarmTool({
|
|
|
101024
101761
|
async execute(_args, directory) {
|
|
101025
101762
|
const errors5 = [];
|
|
101026
101763
|
const warnings = [];
|
|
101027
|
-
const specPath =
|
|
101028
|
-
if (!
|
|
101764
|
+
const specPath = path129.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
|
|
101765
|
+
if (!fs100.existsSync(specPath)) {
|
|
101029
101766
|
const result2 = {
|
|
101030
101767
|
valid: false,
|
|
101031
101768
|
specMtime: null,
|
|
@@ -101044,12 +101781,12 @@ var lint_spec = createSwarmTool({
|
|
|
101044
101781
|
}
|
|
101045
101782
|
let specMtime = null;
|
|
101046
101783
|
try {
|
|
101047
|
-
const stats =
|
|
101784
|
+
const stats = fs100.statSync(specPath);
|
|
101048
101785
|
specMtime = stats.mtime.toISOString();
|
|
101049
101786
|
} catch {}
|
|
101050
101787
|
let content;
|
|
101051
101788
|
try {
|
|
101052
|
-
content =
|
|
101789
|
+
content = fs100.readFileSync(specPath, "utf-8");
|
|
101053
101790
|
} catch (e) {
|
|
101054
101791
|
const result2 = {
|
|
101055
101792
|
valid: false,
|
|
@@ -101094,13 +101831,13 @@ var lint_spec = createSwarmTool({
|
|
|
101094
101831
|
});
|
|
101095
101832
|
// src/tools/mutation-test.ts
|
|
101096
101833
|
init_zod();
|
|
101097
|
-
import * as
|
|
101098
|
-
import * as
|
|
101834
|
+
import * as fs101 from "node:fs";
|
|
101835
|
+
import * as path131 from "node:path";
|
|
101099
101836
|
|
|
101100
101837
|
// src/mutation/engine.ts
|
|
101101
101838
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
101102
|
-
import { unlinkSync as unlinkSync16, writeFileSync as
|
|
101103
|
-
import * as
|
|
101839
|
+
import { unlinkSync as unlinkSync16, writeFileSync as writeFileSync25 } from "node:fs";
|
|
101840
|
+
import * as path130 from "node:path";
|
|
101104
101841
|
|
|
101105
101842
|
// src/mutation/equivalence.ts
|
|
101106
101843
|
function isStaticallyEquivalent(originalCode, mutatedCode) {
|
|
@@ -101172,7 +101909,7 @@ function isStaticallyEquivalent(originalCode, mutatedCode) {
|
|
|
101172
101909
|
const strippedMutated = stripCode(mutatedCode);
|
|
101173
101910
|
return strippedOriginal === strippedMutated;
|
|
101174
101911
|
}
|
|
101175
|
-
var
|
|
101912
|
+
var _internals50 = {
|
|
101176
101913
|
isStaticallyEquivalent,
|
|
101177
101914
|
checkEquivalence,
|
|
101178
101915
|
batchCheckEquivalence
|
|
@@ -101212,7 +101949,7 @@ async function batchCheckEquivalence(patches, llmJudge) {
|
|
|
101212
101949
|
const results = [];
|
|
101213
101950
|
for (const { patch, originalCode, mutatedCode } of patches) {
|
|
101214
101951
|
try {
|
|
101215
|
-
const result = await
|
|
101952
|
+
const result = await _internals50.checkEquivalence(patch, originalCode, mutatedCode, llmJudge);
|
|
101216
101953
|
results.push(result);
|
|
101217
101954
|
} catch (err3) {
|
|
101218
101955
|
results.push({
|
|
@@ -101240,9 +101977,9 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
|
|
|
101240
101977
|
let patchFile;
|
|
101241
101978
|
try {
|
|
101242
101979
|
const safeId2 = patch.id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
101243
|
-
patchFile =
|
|
101980
|
+
patchFile = path130.join(workingDir, `.mutation_patch_${safeId2}.diff`);
|
|
101244
101981
|
try {
|
|
101245
|
-
|
|
101982
|
+
writeFileSync25(patchFile, patch.patch);
|
|
101246
101983
|
} catch (writeErr) {
|
|
101247
101984
|
error93 = `Failed to write patch file: ${writeErr}`;
|
|
101248
101985
|
outcome = "error";
|
|
@@ -101512,7 +102249,7 @@ async function executeMutationSuite(patches, testCommand, testFiles, workingDir,
|
|
|
101512
102249
|
}
|
|
101513
102250
|
|
|
101514
102251
|
// src/mutation/gate.ts
|
|
101515
|
-
var
|
|
102252
|
+
var _internals51 = {
|
|
101516
102253
|
evaluateMutationGate,
|
|
101517
102254
|
buildTestImprovementPrompt,
|
|
101518
102255
|
buildMessage
|
|
@@ -101533,8 +102270,8 @@ function evaluateMutationGate(report, passThreshold = PASS_THRESHOLD, warnThresh
|
|
|
101533
102270
|
} else {
|
|
101534
102271
|
verdict = "fail";
|
|
101535
102272
|
}
|
|
101536
|
-
const testImprovementPrompt =
|
|
101537
|
-
const message =
|
|
102273
|
+
const testImprovementPrompt = _internals51.buildTestImprovementPrompt(report, passThreshold, verdict);
|
|
102274
|
+
const message = _internals51.buildMessage(verdict, adjustedKillRate, report.killed, report.totalMutants, report.equivalent, warnThreshold);
|
|
101538
102275
|
return {
|
|
101539
102276
|
verdict,
|
|
101540
102277
|
killRate: report.killRate,
|
|
@@ -101639,8 +102376,8 @@ var mutation_test = createSwarmTool({
|
|
|
101639
102376
|
];
|
|
101640
102377
|
for (const filePath of uniquePaths) {
|
|
101641
102378
|
try {
|
|
101642
|
-
const resolvedPath =
|
|
101643
|
-
sourceFiles.set(filePath,
|
|
102379
|
+
const resolvedPath = path131.resolve(cwd, filePath);
|
|
102380
|
+
sourceFiles.set(filePath, fs101.readFileSync(resolvedPath, "utf-8"));
|
|
101644
102381
|
} catch {}
|
|
101645
102382
|
}
|
|
101646
102383
|
const report = await executeMutationSuite(typedArgs.patches, typedArgs.test_command, typedArgs.files, cwd, undefined, undefined, sourceFiles.size > 0 ? sourceFiles : undefined);
|
|
@@ -101658,8 +102395,8 @@ var mutation_test = createSwarmTool({
|
|
|
101658
102395
|
init_zod();
|
|
101659
102396
|
init_manager2();
|
|
101660
102397
|
init_detector();
|
|
101661
|
-
import * as
|
|
101662
|
-
import * as
|
|
102398
|
+
import * as fs102 from "node:fs";
|
|
102399
|
+
import * as path132 from "node:path";
|
|
101663
102400
|
init_create_tool();
|
|
101664
102401
|
var MAX_FILE_SIZE2 = 2 * 1024 * 1024;
|
|
101665
102402
|
var BINARY_CHECK_BYTES = 8192;
|
|
@@ -101725,7 +102462,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
101725
102462
|
if (languages?.length) {
|
|
101726
102463
|
const lowerLangs = languages.map((l) => l.toLowerCase());
|
|
101727
102464
|
filesToCheck = filesToCheck.filter((file3) => {
|
|
101728
|
-
const ext =
|
|
102465
|
+
const ext = path132.extname(file3.path).toLowerCase();
|
|
101729
102466
|
const langDef = getLanguageForExtension(ext);
|
|
101730
102467
|
const fileProfile = getProfileForFile(file3.path);
|
|
101731
102468
|
const langId = fileProfile?.id || langDef?.id;
|
|
@@ -101738,7 +102475,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
101738
102475
|
let skippedCount = 0;
|
|
101739
102476
|
for (const fileInfo of filesToCheck) {
|
|
101740
102477
|
const { path: filePath } = fileInfo;
|
|
101741
|
-
const fullPath =
|
|
102478
|
+
const fullPath = path132.isAbsolute(filePath) ? filePath : path132.join(directory, filePath);
|
|
101742
102479
|
const result = {
|
|
101743
102480
|
path: filePath,
|
|
101744
102481
|
language: "",
|
|
@@ -101768,7 +102505,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
101768
102505
|
}
|
|
101769
102506
|
let content;
|
|
101770
102507
|
try {
|
|
101771
|
-
content =
|
|
102508
|
+
content = fs102.readFileSync(fullPath, "utf8");
|
|
101772
102509
|
} catch {
|
|
101773
102510
|
result.skipped_reason = "file_read_error";
|
|
101774
102511
|
skippedCount++;
|
|
@@ -101787,7 +102524,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
101787
102524
|
results.push(result);
|
|
101788
102525
|
continue;
|
|
101789
102526
|
}
|
|
101790
|
-
const ext =
|
|
102527
|
+
const ext = path132.extname(filePath).toLowerCase();
|
|
101791
102528
|
const langDef = getLanguageForExtension(ext);
|
|
101792
102529
|
result.language = profile?.id || langDef?.id || "unknown";
|
|
101793
102530
|
const errors5 = extractSyntaxErrors(parser, content);
|
|
@@ -101879,8 +102616,8 @@ init_zod();
|
|
|
101879
102616
|
init_utils();
|
|
101880
102617
|
init_create_tool();
|
|
101881
102618
|
init_path_security();
|
|
101882
|
-
import * as
|
|
101883
|
-
import * as
|
|
102619
|
+
import * as fs103 from "node:fs";
|
|
102620
|
+
import * as path133 from "node:path";
|
|
101884
102621
|
var MAX_TEXT_LENGTH = 200;
|
|
101885
102622
|
var MAX_FILE_SIZE_BYTES11 = 1024 * 1024;
|
|
101886
102623
|
var SUPPORTED_EXTENSIONS4 = new Set([
|
|
@@ -101946,9 +102683,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
101946
102683
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
101947
102684
|
}
|
|
101948
102685
|
try {
|
|
101949
|
-
const resolvedPath =
|
|
101950
|
-
const normalizedCwd =
|
|
101951
|
-
const normalizedResolved =
|
|
102686
|
+
const resolvedPath = path133.resolve(paths);
|
|
102687
|
+
const normalizedCwd = path133.resolve(cwd);
|
|
102688
|
+
const normalizedResolved = path133.resolve(resolvedPath);
|
|
101952
102689
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
101953
102690
|
return {
|
|
101954
102691
|
error: "paths must be within the current working directory",
|
|
@@ -101964,13 +102701,13 @@ function validatePathsInput(paths, cwd) {
|
|
|
101964
102701
|
}
|
|
101965
102702
|
}
|
|
101966
102703
|
function isSupportedExtension(filePath) {
|
|
101967
|
-
const ext =
|
|
102704
|
+
const ext = path133.extname(filePath).toLowerCase();
|
|
101968
102705
|
return SUPPORTED_EXTENSIONS4.has(ext);
|
|
101969
102706
|
}
|
|
101970
102707
|
function findSourceFiles3(dir, files = []) {
|
|
101971
102708
|
let entries;
|
|
101972
102709
|
try {
|
|
101973
|
-
entries =
|
|
102710
|
+
entries = fs103.readdirSync(dir);
|
|
101974
102711
|
} catch {
|
|
101975
102712
|
return files;
|
|
101976
102713
|
}
|
|
@@ -101979,10 +102716,10 @@ function findSourceFiles3(dir, files = []) {
|
|
|
101979
102716
|
if (SKIP_DIRECTORIES5.has(entry)) {
|
|
101980
102717
|
continue;
|
|
101981
102718
|
}
|
|
101982
|
-
const fullPath =
|
|
102719
|
+
const fullPath = path133.join(dir, entry);
|
|
101983
102720
|
let stat8;
|
|
101984
102721
|
try {
|
|
101985
|
-
stat8 =
|
|
102722
|
+
stat8 = fs103.statSync(fullPath);
|
|
101986
102723
|
} catch {
|
|
101987
102724
|
continue;
|
|
101988
102725
|
}
|
|
@@ -102075,7 +102812,7 @@ var todo_extract = createSwarmTool({
|
|
|
102075
102812
|
return JSON.stringify(errorResult, null, 2);
|
|
102076
102813
|
}
|
|
102077
102814
|
const scanPath = resolvedPath;
|
|
102078
|
-
if (!
|
|
102815
|
+
if (!fs103.existsSync(scanPath)) {
|
|
102079
102816
|
const errorResult = {
|
|
102080
102817
|
error: `path not found: ${pathsInput}`,
|
|
102081
102818
|
total: 0,
|
|
@@ -102085,13 +102822,13 @@ var todo_extract = createSwarmTool({
|
|
|
102085
102822
|
return JSON.stringify(errorResult, null, 2);
|
|
102086
102823
|
}
|
|
102087
102824
|
const filesToScan = [];
|
|
102088
|
-
const stat8 =
|
|
102825
|
+
const stat8 = fs103.statSync(scanPath);
|
|
102089
102826
|
if (stat8.isFile()) {
|
|
102090
102827
|
if (isSupportedExtension(scanPath)) {
|
|
102091
102828
|
filesToScan.push(scanPath);
|
|
102092
102829
|
} else {
|
|
102093
102830
|
const errorResult = {
|
|
102094
|
-
error: `unsupported file extension: ${
|
|
102831
|
+
error: `unsupported file extension: ${path133.extname(scanPath)}`,
|
|
102095
102832
|
total: 0,
|
|
102096
102833
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
102097
102834
|
entries: []
|
|
@@ -102104,11 +102841,11 @@ var todo_extract = createSwarmTool({
|
|
|
102104
102841
|
const allEntries = [];
|
|
102105
102842
|
for (const filePath of filesToScan) {
|
|
102106
102843
|
try {
|
|
102107
|
-
const fileStat =
|
|
102844
|
+
const fileStat = fs103.statSync(filePath);
|
|
102108
102845
|
if (fileStat.size > MAX_FILE_SIZE_BYTES11) {
|
|
102109
102846
|
continue;
|
|
102110
102847
|
}
|
|
102111
|
-
const content =
|
|
102848
|
+
const content = fs103.readFileSync(filePath, "utf-8");
|
|
102112
102849
|
const entries = parseTodoComments(content, filePath, tagsSet);
|
|
102113
102850
|
allEntries.push(...entries);
|
|
102114
102851
|
} catch {}
|
|
@@ -102139,19 +102876,19 @@ init_loader();
|
|
|
102139
102876
|
init_schema();
|
|
102140
102877
|
init_qa_gate_profile();
|
|
102141
102878
|
init_gate_evidence();
|
|
102142
|
-
import * as
|
|
102143
|
-
import * as
|
|
102879
|
+
import * as fs107 from "node:fs";
|
|
102880
|
+
import * as path137 from "node:path";
|
|
102144
102881
|
|
|
102145
102882
|
// src/hooks/diff-scope.ts
|
|
102146
102883
|
init_bun_compat();
|
|
102147
|
-
import * as
|
|
102148
|
-
import * as
|
|
102884
|
+
import * as fs105 from "node:fs";
|
|
102885
|
+
import * as path135 from "node:path";
|
|
102149
102886
|
|
|
102150
102887
|
// src/utils/gitignore-warning.ts
|
|
102151
102888
|
init_bun_compat();
|
|
102152
|
-
import * as
|
|
102153
|
-
import * as
|
|
102154
|
-
var
|
|
102889
|
+
import * as fs104 from "node:fs";
|
|
102890
|
+
import * as path134 from "node:path";
|
|
102891
|
+
var _internals52 = { bunSpawn };
|
|
102155
102892
|
var _swarmGitExcludedChecked = false;
|
|
102156
102893
|
function fileCoversSwarm(content) {
|
|
102157
102894
|
for (const rawLine of content.split(`
|
|
@@ -102184,7 +102921,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
102184
102921
|
checkIgnoreExitCode
|
|
102185
102922
|
] = await Promise.all([
|
|
102186
102923
|
(async () => {
|
|
102187
|
-
const proc =
|
|
102924
|
+
const proc = _internals52.bunSpawn(["git", "-C", directory, "rev-parse", "--show-toplevel"], GIT_SPAWN_OPTIONS);
|
|
102188
102925
|
try {
|
|
102189
102926
|
return await Promise.all([proc.exited, proc.stdout.text()]);
|
|
102190
102927
|
} finally {
|
|
@@ -102194,7 +102931,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
102194
102931
|
}
|
|
102195
102932
|
})(),
|
|
102196
102933
|
(async () => {
|
|
102197
|
-
const proc =
|
|
102934
|
+
const proc = _internals52.bunSpawn(["git", "-C", directory, "rev-parse", "--git-path", "info/exclude"], GIT_SPAWN_OPTIONS);
|
|
102198
102935
|
try {
|
|
102199
102936
|
return await Promise.all([proc.exited, proc.stdout.text()]);
|
|
102200
102937
|
} finally {
|
|
@@ -102204,7 +102941,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
102204
102941
|
}
|
|
102205
102942
|
})(),
|
|
102206
102943
|
(async () => {
|
|
102207
|
-
const proc =
|
|
102944
|
+
const proc = _internals52.bunSpawn(["git", "-C", directory, "check-ignore", "-q", ".swarm/.gitkeep"], GIT_SPAWN_OPTIONS);
|
|
102208
102945
|
try {
|
|
102209
102946
|
return await proc.exited;
|
|
102210
102947
|
} finally {
|
|
@@ -102224,16 +102961,16 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
102224
102961
|
const excludeRelPath = excludePathRaw.trim();
|
|
102225
102962
|
if (!excludeRelPath)
|
|
102226
102963
|
return;
|
|
102227
|
-
const excludePath =
|
|
102964
|
+
const excludePath = path134.isAbsolute(excludeRelPath) ? excludeRelPath : path134.join(directory, excludeRelPath);
|
|
102228
102965
|
if (checkIgnoreExitCode !== 0) {
|
|
102229
102966
|
try {
|
|
102230
|
-
|
|
102967
|
+
fs104.mkdirSync(path134.dirname(excludePath), { recursive: true });
|
|
102231
102968
|
let existing = "";
|
|
102232
102969
|
try {
|
|
102233
|
-
existing =
|
|
102970
|
+
existing = fs104.readFileSync(excludePath, "utf8");
|
|
102234
102971
|
} catch {}
|
|
102235
102972
|
if (!fileCoversSwarm(existing)) {
|
|
102236
|
-
|
|
102973
|
+
fs104.appendFileSync(excludePath, `
|
|
102237
102974
|
# opencode-swarm local runtime state
|
|
102238
102975
|
.swarm/
|
|
102239
102976
|
`, "utf8");
|
|
@@ -102243,7 +102980,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
102243
102980
|
}
|
|
102244
102981
|
} catch {}
|
|
102245
102982
|
}
|
|
102246
|
-
const trackedProc =
|
|
102983
|
+
const trackedProc = _internals52.bunSpawn(["git", "-C", directory, "ls-files", "--", ".swarm"], GIT_SPAWN_OPTIONS);
|
|
102247
102984
|
let trackedExitCode;
|
|
102248
102985
|
let trackedOutput;
|
|
102249
102986
|
try {
|
|
@@ -102268,13 +103005,13 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
102268
103005
|
}
|
|
102269
103006
|
|
|
102270
103007
|
// src/hooks/diff-scope.ts
|
|
102271
|
-
var
|
|
103008
|
+
var _internals53 = { bunSpawn };
|
|
102272
103009
|
function getDeclaredScope(taskId, directory) {
|
|
102273
103010
|
try {
|
|
102274
|
-
const planPath =
|
|
102275
|
-
if (!
|
|
103011
|
+
const planPath = path135.join(directory, ".swarm", "plan.json");
|
|
103012
|
+
if (!fs105.existsSync(planPath))
|
|
102276
103013
|
return null;
|
|
102277
|
-
const raw =
|
|
103014
|
+
const raw = fs105.readFileSync(planPath, "utf-8");
|
|
102278
103015
|
const plan = JSON.parse(raw);
|
|
102279
103016
|
for (const phase of plan.phases ?? []) {
|
|
102280
103017
|
for (const task of phase.tasks ?? []) {
|
|
@@ -102303,7 +103040,7 @@ var GIT_DIFF_SPAWN_OPTIONS = {
|
|
|
102303
103040
|
};
|
|
102304
103041
|
async function getChangedFiles(directory) {
|
|
102305
103042
|
try {
|
|
102306
|
-
const proc =
|
|
103043
|
+
const proc = _internals53.bunSpawn(["git", "diff", "--name-only", "HEAD~1"], {
|
|
102307
103044
|
cwd: directory,
|
|
102308
103045
|
...GIT_DIFF_SPAWN_OPTIONS
|
|
102309
103046
|
});
|
|
@@ -102320,7 +103057,7 @@ async function getChangedFiles(directory) {
|
|
|
102320
103057
|
return stdout.trim().split(`
|
|
102321
103058
|
`).map((f) => f.trim()).filter((f) => f.length > 0);
|
|
102322
103059
|
}
|
|
102323
|
-
const proc2 =
|
|
103060
|
+
const proc2 = _internals53.bunSpawn(["git", "diff", "--name-only", "HEAD"], {
|
|
102324
103061
|
cwd: directory,
|
|
102325
103062
|
...GIT_DIFF_SPAWN_OPTIONS
|
|
102326
103063
|
});
|
|
@@ -102376,9 +103113,9 @@ init_telemetry();
|
|
|
102376
103113
|
|
|
102377
103114
|
// src/turbo/lean/task-completion.ts
|
|
102378
103115
|
init_file_locks();
|
|
102379
|
-
import * as
|
|
102380
|
-
import * as
|
|
102381
|
-
var
|
|
103116
|
+
import * as fs106 from "node:fs";
|
|
103117
|
+
import * as path136 from "node:path";
|
|
103118
|
+
var _internals54 = {
|
|
102382
103119
|
listActiveLocks,
|
|
102383
103120
|
verifyLeanTurboTaskCompletion
|
|
102384
103121
|
};
|
|
@@ -102396,7 +103133,7 @@ var TIER_3_PATTERNS = [
|
|
|
102396
103133
|
];
|
|
102397
103134
|
function matchesTier3Pattern(files) {
|
|
102398
103135
|
for (const file3 of files) {
|
|
102399
|
-
const fileName =
|
|
103136
|
+
const fileName = path136.basename(file3);
|
|
102400
103137
|
for (const pattern of TIER_3_PATTERNS) {
|
|
102401
103138
|
if (pattern.test(fileName)) {
|
|
102402
103139
|
return true;
|
|
@@ -102408,14 +103145,14 @@ function matchesTier3Pattern(files) {
|
|
|
102408
103145
|
function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
|
|
102409
103146
|
let persisted = null;
|
|
102410
103147
|
try {
|
|
102411
|
-
const statePath =
|
|
102412
|
-
if (!
|
|
103148
|
+
const statePath = path136.join(directory, ".swarm", "turbo-state.json");
|
|
103149
|
+
if (!fs106.existsSync(statePath)) {
|
|
102413
103150
|
return {
|
|
102414
103151
|
ok: false,
|
|
102415
103152
|
reason: "Lean Turbo state file not found"
|
|
102416
103153
|
};
|
|
102417
103154
|
}
|
|
102418
|
-
const raw =
|
|
103155
|
+
const raw = fs106.readFileSync(statePath, "utf-8");
|
|
102419
103156
|
persisted = JSON.parse(raw);
|
|
102420
103157
|
} catch {
|
|
102421
103158
|
return {
|
|
@@ -102492,11 +103229,11 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
|
|
|
102492
103229
|
};
|
|
102493
103230
|
}
|
|
102494
103231
|
const phase = runState.phase ?? 0;
|
|
102495
|
-
const evidencePath =
|
|
102496
|
-
const expectedDir =
|
|
102497
|
-
const resolvedPath =
|
|
102498
|
-
const resolvedDir =
|
|
102499
|
-
if (!resolvedPath.startsWith(resolvedDir +
|
|
103232
|
+
const evidencePath = path136.join(directory, ".swarm", "evidence", String(phase), "lean-turbo", `${lane.laneId}.json`);
|
|
103233
|
+
const expectedDir = path136.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
|
|
103234
|
+
const resolvedPath = path136.resolve(evidencePath);
|
|
103235
|
+
const resolvedDir = path136.resolve(expectedDir);
|
|
103236
|
+
if (!resolvedPath.startsWith(resolvedDir + path136.sep) && resolvedPath !== resolvedDir) {
|
|
102500
103237
|
return {
|
|
102501
103238
|
ok: false,
|
|
102502
103239
|
reason: `Lane ID causes path traversal: ${lane.laneId}`,
|
|
@@ -102508,7 +103245,7 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
|
|
|
102508
103245
|
}
|
|
102509
103246
|
};
|
|
102510
103247
|
}
|
|
102511
|
-
if (!
|
|
103248
|
+
if (!fs106.existsSync(evidencePath)) {
|
|
102512
103249
|
return {
|
|
102513
103250
|
ok: false,
|
|
102514
103251
|
reason: `Lane ${lane.laneId} evidence file not found: ${evidencePath}`,
|
|
@@ -102520,7 +103257,7 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
|
|
|
102520
103257
|
}
|
|
102521
103258
|
};
|
|
102522
103259
|
}
|
|
102523
|
-
const activeLocks =
|
|
103260
|
+
const activeLocks = _internals54.listActiveLocks(directory);
|
|
102524
103261
|
const laneLocks = activeLocks.filter((lock) => lock.laneId === lane.laneId);
|
|
102525
103262
|
if (laneLocks.length > 0) {
|
|
102526
103263
|
return {
|
|
@@ -102536,8 +103273,8 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
|
|
|
102536
103273
|
}
|
|
102537
103274
|
let filesTouched = [];
|
|
102538
103275
|
try {
|
|
102539
|
-
const planPath =
|
|
102540
|
-
const planRaw =
|
|
103276
|
+
const planPath = path136.join(directory, ".swarm", "plan.json");
|
|
103277
|
+
const planRaw = fs106.readFileSync(planPath, "utf-8");
|
|
102541
103278
|
const plan = JSON.parse(planRaw);
|
|
102542
103279
|
for (const planPhase of plan.phases ?? []) {
|
|
102543
103280
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -102619,7 +103356,7 @@ var TIER_3_PATTERNS2 = [
|
|
|
102619
103356
|
];
|
|
102620
103357
|
function matchesTier3Pattern2(files) {
|
|
102621
103358
|
for (const file3 of files) {
|
|
102622
|
-
const fileName =
|
|
103359
|
+
const fileName = path137.basename(file3);
|
|
102623
103360
|
for (const pattern of TIER_3_PATTERNS2) {
|
|
102624
103361
|
if (pattern.test(fileName)) {
|
|
102625
103362
|
return true;
|
|
@@ -102628,6 +103365,13 @@ function matchesTier3Pattern2(files) {
|
|
|
102628
103365
|
}
|
|
102629
103366
|
return false;
|
|
102630
103367
|
}
|
|
103368
|
+
function hasPassedDurableGateEvidence(workingDirectory, taskId) {
|
|
103369
|
+
const evidence = readTaskEvidenceRaw(workingDirectory, taskId);
|
|
103370
|
+
if (!evidence || !Array.isArray(evidence.required_gates) || evidence.required_gates.length === 0) {
|
|
103371
|
+
return false;
|
|
103372
|
+
}
|
|
103373
|
+
return evidence.required_gates.every((gate) => evidence.gates?.[gate] != null);
|
|
103374
|
+
}
|
|
102631
103375
|
function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = false, sessionID) {
|
|
102632
103376
|
try {
|
|
102633
103377
|
let skipStandardTurboBypass = false;
|
|
@@ -102651,8 +103395,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
102651
103395
|
if (!skipStandardTurboBypass && hasActiveTurboMode()) {
|
|
102652
103396
|
const resolvedDir2 = workingDirectory;
|
|
102653
103397
|
try {
|
|
102654
|
-
const planPath =
|
|
102655
|
-
const planRaw =
|
|
103398
|
+
const planPath = path137.join(resolvedDir2, ".swarm", "plan.json");
|
|
103399
|
+
const planRaw = fs107.readFileSync(planPath, "utf-8");
|
|
102656
103400
|
const plan = JSON.parse(planRaw);
|
|
102657
103401
|
for (const planPhase of plan.phases ?? []) {
|
|
102658
103402
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -102674,12 +103418,11 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
102674
103418
|
try {
|
|
102675
103419
|
const evidence = readTaskEvidenceRaw(resolvedDir, taskId);
|
|
102676
103420
|
if (evidence === null) {} else if (evidence.required_gates && Array.isArray(evidence.required_gates) && evidence.gates) {
|
|
102677
|
-
|
|
102678
|
-
if (allGatesMet) {
|
|
103421
|
+
if (evidence.required_gates.length > 0 && evidence.required_gates.every((gate) => evidence.gates[gate] != null)) {
|
|
102679
103422
|
return { blocked: false, reason: "" };
|
|
102680
103423
|
}
|
|
102681
103424
|
const missingGates = evidence.required_gates.filter((gate) => evidence.gates[gate] == null);
|
|
102682
|
-
evidenceIncompleteReason = `Task ${taskId} is missing required gates: [${missingGates.join(", ")}]. ` + `Required: [${evidence.required_gates.join(", ")}]. ` + `Completed: [${Object.keys(evidence.gates).join(", ")}]. ` + `Delegate the missing gate agents before marking task as completed.`;
|
|
103425
|
+
evidenceIncompleteReason = evidence.required_gates.length === 0 ? `Task ${taskId} has an evidence file with no required gates. Delegate reviewer and test_engineer before marking task as completed.` : `Task ${taskId} is missing required gates: [${missingGates.join(", ")}]. ` + `Required: [${evidence.required_gates.join(", ")}]. ` + `Completed: [${Object.keys(evidence.gates).join(", ")}]. ` + `Delegate the missing gate agents before marking task as completed.`;
|
|
102683
103426
|
}
|
|
102684
103427
|
} catch (error93) {
|
|
102685
103428
|
console.warn(`[gate-evidence] Evidence file for task ${taskId} is corrupt or unreadable:`, error93 instanceof Error ? error93.message : String(error93));
|
|
@@ -102689,7 +103432,7 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
102689
103432
|
reason: `Evidence file for task ${taskId} is corrupt or unreadable. ` + `Fix the file at .swarm/evidence/${taskId}.json or delete it to fall through to session state.`
|
|
102690
103433
|
};
|
|
102691
103434
|
}
|
|
102692
|
-
if (swarmState.agentSessions.size === 0) {
|
|
103435
|
+
if (swarmState.agentSessions.size === 0 && !evidenceIncompleteReason) {
|
|
102693
103436
|
return { blocked: false, reason: "" };
|
|
102694
103437
|
}
|
|
102695
103438
|
let validSessionCount = 0;
|
|
@@ -102706,7 +103449,7 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
102706
103449
|
return { blocked: false, reason: "" };
|
|
102707
103450
|
}
|
|
102708
103451
|
}
|
|
102709
|
-
if (validSessionCount === 0) {
|
|
103452
|
+
if (validSessionCount === 0 && !evidenceIncompleteReason) {
|
|
102710
103453
|
return { blocked: false, reason: "" };
|
|
102711
103454
|
}
|
|
102712
103455
|
const stateEntries = [];
|
|
@@ -102718,12 +103461,12 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
102718
103461
|
}
|
|
102719
103462
|
try {
|
|
102720
103463
|
const resolvedDir2 = workingDirectory;
|
|
102721
|
-
const planPath =
|
|
102722
|
-
const planRaw =
|
|
103464
|
+
const planPath = path137.join(resolvedDir2, ".swarm", "plan.json");
|
|
103465
|
+
const planRaw = fs107.readFileSync(planPath, "utf-8");
|
|
102723
103466
|
const plan = JSON.parse(planRaw);
|
|
102724
103467
|
for (const planPhase of plan.phases ?? []) {
|
|
102725
103468
|
for (const task of planPhase.tasks ?? []) {
|
|
102726
|
-
if (task.id === taskId && task.status === "completed") {
|
|
103469
|
+
if (task.id === taskId && task.status === "completed" && hasPassedDurableGateEvidence(resolvedDir2, taskId)) {
|
|
102727
103470
|
return { blocked: false, reason: "" };
|
|
102728
103471
|
}
|
|
102729
103472
|
}
|
|
@@ -102744,26 +103487,6 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
102744
103487
|
}
|
|
102745
103488
|
}
|
|
102746
103489
|
}
|
|
102747
|
-
if (!hasReviewer && !hasTestEngineer) {
|
|
102748
|
-
for (const [, chain] of swarmState.delegationChains) {
|
|
102749
|
-
let lastCoderIndex = -1;
|
|
102750
|
-
for (let i2 = chain.length - 1;i2 >= 0; i2--) {
|
|
102751
|
-
const target = stripKnownSwarmPrefix(chain[i2].to);
|
|
102752
|
-
if (target === "coder") {
|
|
102753
|
-
lastCoderIndex = i2;
|
|
102754
|
-
break;
|
|
102755
|
-
}
|
|
102756
|
-
}
|
|
102757
|
-
const searchStart = lastCoderIndex === -1 ? 0 : lastCoderIndex + 1;
|
|
102758
|
-
for (let i2 = searchStart;i2 < chain.length; i2++) {
|
|
102759
|
-
const target = stripKnownSwarmPrefix(chain[i2].to);
|
|
102760
|
-
if (target === "reviewer")
|
|
102761
|
-
hasReviewer = true;
|
|
102762
|
-
if (target === "test_engineer")
|
|
102763
|
-
hasTestEngineer = true;
|
|
102764
|
-
}
|
|
102765
|
-
}
|
|
102766
|
-
}
|
|
102767
103490
|
if (hasReviewer && hasTestEngineer) {
|
|
102768
103491
|
return { blocked: false, reason: "" };
|
|
102769
103492
|
}
|
|
@@ -102806,26 +103529,6 @@ function recoverTaskStateFromDelegations(taskId) {
|
|
|
102806
103529
|
}
|
|
102807
103530
|
}
|
|
102808
103531
|
}
|
|
102809
|
-
if (!hasReviewer && !hasTestEngineer) {
|
|
102810
|
-
for (const [, chain] of swarmState.delegationChains) {
|
|
102811
|
-
let lastCoderIndex = -1;
|
|
102812
|
-
for (let i2 = chain.length - 1;i2 >= 0; i2--) {
|
|
102813
|
-
const target = stripKnownSwarmPrefix(chain[i2].to);
|
|
102814
|
-
if (target === "coder") {
|
|
102815
|
-
lastCoderIndex = i2;
|
|
102816
|
-
break;
|
|
102817
|
-
}
|
|
102818
|
-
}
|
|
102819
|
-
const searchStart = lastCoderIndex === -1 ? 0 : lastCoderIndex + 1;
|
|
102820
|
-
for (let i2 = searchStart;i2 < chain.length; i2++) {
|
|
102821
|
-
const target = stripKnownSwarmPrefix(chain[i2].to);
|
|
102822
|
-
if (target === "reviewer")
|
|
102823
|
-
hasReviewer = true;
|
|
102824
|
-
if (target === "test_engineer")
|
|
102825
|
-
hasTestEngineer = true;
|
|
102826
|
-
}
|
|
102827
|
-
}
|
|
102828
|
-
}
|
|
102829
103532
|
if (!hasReviewer && !hasTestEngineer)
|
|
102830
103533
|
return;
|
|
102831
103534
|
for (const [, session] of swarmState.agentSessions) {
|
|
@@ -102903,8 +103606,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
|
|
|
102903
103606
|
};
|
|
102904
103607
|
}
|
|
102905
103608
|
}
|
|
102906
|
-
normalizedDir =
|
|
102907
|
-
const pathParts = normalizedDir.split(
|
|
103609
|
+
normalizedDir = path137.normalize(args2.working_directory);
|
|
103610
|
+
const pathParts = normalizedDir.split(path137.sep);
|
|
102908
103611
|
if (pathParts.includes("..")) {
|
|
102909
103612
|
return {
|
|
102910
103613
|
success: false,
|
|
@@ -102914,11 +103617,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
|
|
|
102914
103617
|
]
|
|
102915
103618
|
};
|
|
102916
103619
|
}
|
|
102917
|
-
const resolvedDir =
|
|
103620
|
+
const resolvedDir = path137.resolve(normalizedDir);
|
|
102918
103621
|
try {
|
|
102919
|
-
const realPath =
|
|
102920
|
-
const planPath =
|
|
102921
|
-
if (!
|
|
103622
|
+
const realPath = fs107.realpathSync(resolvedDir);
|
|
103623
|
+
const planPath = path137.join(realPath, ".swarm", "plan.json");
|
|
103624
|
+
if (!fs107.existsSync(planPath)) {
|
|
102922
103625
|
return {
|
|
102923
103626
|
success: false,
|
|
102924
103627
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -102949,22 +103652,22 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
|
|
|
102949
103652
|
}
|
|
102950
103653
|
if (args2.status === "in_progress") {
|
|
102951
103654
|
try {
|
|
102952
|
-
const evidencePath =
|
|
102953
|
-
|
|
102954
|
-
const fd =
|
|
103655
|
+
const evidencePath = path137.join(directory, ".swarm", "evidence", `${args2.task_id}.json`);
|
|
103656
|
+
fs107.mkdirSync(path137.dirname(evidencePath), { recursive: true });
|
|
103657
|
+
const fd = fs107.openSync(evidencePath, "wx");
|
|
102955
103658
|
let writeOk = false;
|
|
102956
103659
|
try {
|
|
102957
|
-
|
|
103660
|
+
fs107.writeSync(fd, JSON.stringify({
|
|
102958
103661
|
taskId: args2.task_id,
|
|
102959
103662
|
required_gates: ["reviewer", "test_engineer"],
|
|
102960
103663
|
gates: {}
|
|
102961
103664
|
}, null, 2));
|
|
102962
103665
|
writeOk = true;
|
|
102963
103666
|
} finally {
|
|
102964
|
-
|
|
103667
|
+
fs107.closeSync(fd);
|
|
102965
103668
|
if (!writeOk) {
|
|
102966
103669
|
try {
|
|
102967
|
-
|
|
103670
|
+
fs107.unlinkSync(evidencePath);
|
|
102968
103671
|
} catch {}
|
|
102969
103672
|
}
|
|
102970
103673
|
}
|
|
@@ -102974,8 +103677,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
|
|
|
102974
103677
|
recoverTaskStateFromDelegations(args2.task_id);
|
|
102975
103678
|
let phaseRequiresReviewer = true;
|
|
102976
103679
|
try {
|
|
102977
|
-
const planPath =
|
|
102978
|
-
const planRaw =
|
|
103680
|
+
const planPath = path137.join(directory, ".swarm", "plan.json");
|
|
103681
|
+
const planRaw = fs107.readFileSync(planPath, "utf-8");
|
|
102979
103682
|
const plan = JSON.parse(planRaw);
|
|
102980
103683
|
const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
|
|
102981
103684
|
if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
|
|
@@ -103285,8 +103988,8 @@ init_utils2();
|
|
|
103285
103988
|
init_ledger();
|
|
103286
103989
|
init_manager();
|
|
103287
103990
|
init_create_tool();
|
|
103288
|
-
import
|
|
103289
|
-
import
|
|
103991
|
+
import fs108 from "node:fs";
|
|
103992
|
+
import path138 from "node:path";
|
|
103290
103993
|
function normalizeVerdict(verdict) {
|
|
103291
103994
|
switch (verdict) {
|
|
103292
103995
|
case "APPROVED":
|
|
@@ -103334,7 +104037,7 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
103334
104037
|
entries: [evidenceEntry]
|
|
103335
104038
|
};
|
|
103336
104039
|
const filename = "drift-verifier.json";
|
|
103337
|
-
const relativePath =
|
|
104040
|
+
const relativePath = path138.join("evidence", String(phase), filename);
|
|
103338
104041
|
let validatedPath;
|
|
103339
104042
|
try {
|
|
103340
104043
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -103345,12 +104048,12 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
103345
104048
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
103346
104049
|
}, null, 2);
|
|
103347
104050
|
}
|
|
103348
|
-
const evidenceDir =
|
|
104051
|
+
const evidenceDir = path138.dirname(validatedPath);
|
|
103349
104052
|
try {
|
|
103350
|
-
await
|
|
103351
|
-
const tempPath =
|
|
103352
|
-
await
|
|
103353
|
-
await
|
|
104053
|
+
await fs108.promises.mkdir(evidenceDir, { recursive: true });
|
|
104054
|
+
const tempPath = path138.join(evidenceDir, `.${filename}.tmp`);
|
|
104055
|
+
await fs108.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
104056
|
+
await fs108.promises.rename(tempPath, validatedPath);
|
|
103354
104057
|
let snapshotInfo;
|
|
103355
104058
|
let snapshotError;
|
|
103356
104059
|
let qaProfileLocked;
|
|
@@ -103443,8 +104146,8 @@ var write_drift_evidence = createSwarmTool({
|
|
|
103443
104146
|
// src/tools/write-final-council-evidence.ts
|
|
103444
104147
|
init_zod();
|
|
103445
104148
|
init_loader();
|
|
103446
|
-
import
|
|
103447
|
-
import
|
|
104149
|
+
import fs109 from "node:fs";
|
|
104150
|
+
import path139 from "node:path";
|
|
103448
104151
|
init_utils2();
|
|
103449
104152
|
init_manager();
|
|
103450
104153
|
init_create_tool();
|
|
@@ -103532,7 +104235,7 @@ async function executeWriteFinalCouncilEvidence(args2, directory) {
|
|
|
103532
104235
|
timestamp: synthesis.timestamp
|
|
103533
104236
|
};
|
|
103534
104237
|
const filename = "final-council.json";
|
|
103535
|
-
const relativePath =
|
|
104238
|
+
const relativePath = path139.join("evidence", filename);
|
|
103536
104239
|
let validatedPath;
|
|
103537
104240
|
try {
|
|
103538
104241
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -103546,12 +104249,12 @@ async function executeWriteFinalCouncilEvidence(args2, directory) {
|
|
|
103546
104249
|
const evidenceContent = {
|
|
103547
104250
|
entries: [evidenceEntry]
|
|
103548
104251
|
};
|
|
103549
|
-
const evidenceDir =
|
|
104252
|
+
const evidenceDir = path139.dirname(validatedPath);
|
|
103550
104253
|
try {
|
|
103551
|
-
await
|
|
103552
|
-
const tempPath =
|
|
103553
|
-
await
|
|
103554
|
-
await
|
|
104254
|
+
await fs109.promises.mkdir(evidenceDir, { recursive: true });
|
|
104255
|
+
const tempPath = path139.join(evidenceDir, `.${filename}.tmp`);
|
|
104256
|
+
await fs109.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
104257
|
+
await fs109.promises.rename(tempPath, validatedPath);
|
|
103555
104258
|
return JSON.stringify({
|
|
103556
104259
|
success: true,
|
|
103557
104260
|
phase: input.phase,
|
|
@@ -103607,8 +104310,8 @@ var write_final_council_evidence = createSwarmTool({
|
|
|
103607
104310
|
init_zod();
|
|
103608
104311
|
init_utils2();
|
|
103609
104312
|
init_create_tool();
|
|
103610
|
-
import
|
|
103611
|
-
import
|
|
104313
|
+
import fs110 from "node:fs";
|
|
104314
|
+
import path140 from "node:path";
|
|
103612
104315
|
function normalizeVerdict2(verdict) {
|
|
103613
104316
|
switch (verdict) {
|
|
103614
104317
|
case "APPROVED":
|
|
@@ -103656,7 +104359,7 @@ async function executeWriteHallucinationEvidence(args2, directory) {
|
|
|
103656
104359
|
entries: [evidenceEntry]
|
|
103657
104360
|
};
|
|
103658
104361
|
const filename = "hallucination-guard.json";
|
|
103659
|
-
const relativePath =
|
|
104362
|
+
const relativePath = path140.join("evidence", String(phase), filename);
|
|
103660
104363
|
let validatedPath;
|
|
103661
104364
|
try {
|
|
103662
104365
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -103667,12 +104370,12 @@ async function executeWriteHallucinationEvidence(args2, directory) {
|
|
|
103667
104370
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
103668
104371
|
}, null, 2);
|
|
103669
104372
|
}
|
|
103670
|
-
const evidenceDir =
|
|
104373
|
+
const evidenceDir = path140.dirname(validatedPath);
|
|
103671
104374
|
try {
|
|
103672
|
-
await
|
|
103673
|
-
const tempPath =
|
|
103674
|
-
await
|
|
103675
|
-
await
|
|
104375
|
+
await fs110.promises.mkdir(evidenceDir, { recursive: true });
|
|
104376
|
+
const tempPath = path140.join(evidenceDir, `.${filename}.tmp`);
|
|
104377
|
+
await fs110.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
104378
|
+
await fs110.promises.rename(tempPath, validatedPath);
|
|
103676
104379
|
return JSON.stringify({
|
|
103677
104380
|
success: true,
|
|
103678
104381
|
phase,
|
|
@@ -103718,8 +104421,8 @@ var write_hallucination_evidence = createSwarmTool({
|
|
|
103718
104421
|
init_zod();
|
|
103719
104422
|
init_utils2();
|
|
103720
104423
|
init_create_tool();
|
|
103721
|
-
import
|
|
103722
|
-
import
|
|
104424
|
+
import fs111 from "node:fs";
|
|
104425
|
+
import path141 from "node:path";
|
|
103723
104426
|
function normalizeVerdict3(verdict) {
|
|
103724
104427
|
switch (verdict) {
|
|
103725
104428
|
case "PASS":
|
|
@@ -103793,7 +104496,7 @@ async function executeWriteMutationEvidence(args2, directory) {
|
|
|
103793
104496
|
entries: [evidenceEntry]
|
|
103794
104497
|
};
|
|
103795
104498
|
const filename = "mutation-gate.json";
|
|
103796
|
-
const relativePath =
|
|
104499
|
+
const relativePath = path141.join("evidence", String(phase), filename);
|
|
103797
104500
|
let validatedPath;
|
|
103798
104501
|
try {
|
|
103799
104502
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -103804,12 +104507,12 @@ async function executeWriteMutationEvidence(args2, directory) {
|
|
|
103804
104507
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
103805
104508
|
}, null, 2);
|
|
103806
104509
|
}
|
|
103807
|
-
const evidenceDir =
|
|
104510
|
+
const evidenceDir = path141.dirname(validatedPath);
|
|
103808
104511
|
try {
|
|
103809
|
-
await
|
|
103810
|
-
const tempPath =
|
|
103811
|
-
await
|
|
103812
|
-
await
|
|
104512
|
+
await fs111.promises.mkdir(evidenceDir, { recursive: true });
|
|
104513
|
+
const tempPath = path141.join(evidenceDir, `.${filename}.tmp`);
|
|
104514
|
+
await fs111.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
104515
|
+
await fs111.promises.rename(tempPath, validatedPath);
|
|
103813
104516
|
return JSON.stringify({
|
|
103814
104517
|
success: true,
|
|
103815
104518
|
phase,
|
|
@@ -104152,7 +104855,7 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
104152
104855
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
104153
104856
|
preflightTriggerManager = new PTM(automationConfig);
|
|
104154
104857
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
104155
|
-
const swarmDir =
|
|
104858
|
+
const swarmDir = path143.resolve(ctx.directory, ".swarm");
|
|
104156
104859
|
statusArtifact = new ASA(swarmDir);
|
|
104157
104860
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
104158
104861
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|
|
@@ -104551,6 +105254,14 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
104551
105254
|
return Promise.resolve();
|
|
104552
105255
|
}
|
|
104553
105256
|
},
|
|
105257
|
+
(input, output) => {
|
|
105258
|
+
try {
|
|
105259
|
+
const p = input;
|
|
105260
|
+
return skillPropagationTransformScan(ctx.directory, output, p.sessionID);
|
|
105261
|
+
} catch {
|
|
105262
|
+
return Promise.resolve();
|
|
105263
|
+
}
|
|
105264
|
+
},
|
|
104554
105265
|
(_input, output) => {
|
|
104555
105266
|
if (output.messages) {
|
|
104556
105267
|
output.messages = consolidateSystemMessages(output.messages);
|
|
@@ -104624,6 +105335,12 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
104624
105335
|
agent: input.agent,
|
|
104625
105336
|
sessionID: input.sessionID
|
|
104626
105337
|
}, KnowledgeApplicationConfigSchema.parse(config3.knowledge_application ?? {}));
|
|
105338
|
+
await skillPropagationGateBefore(ctx.directory, {
|
|
105339
|
+
tool: input.tool,
|
|
105340
|
+
agent: input.agent,
|
|
105341
|
+
sessionID: input.sessionID,
|
|
105342
|
+
args: input.args
|
|
105343
|
+
}, { enabled: true });
|
|
104627
105344
|
if (swarmState.lastBudgetPct >= 50) {
|
|
104628
105345
|
const pressureSession = ensureAgentSession(input.sessionID, swarmState.activeAgent.get(input.sessionID) ?? ORCHESTRATOR_NAME);
|
|
104629
105346
|
if (!pressureSession.contextPressureWarningSent) {
|