opencode-swarm 7.20.1 → 7.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +1432 -704
- 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.0",
|
|
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);
|
|
@@ -89523,20 +90238,20 @@ init_file_locks();
|
|
|
89523
90238
|
init_plan_schema();
|
|
89524
90239
|
init_ledger();
|
|
89525
90240
|
init_manager();
|
|
89526
|
-
import * as
|
|
89527
|
-
import * as
|
|
90241
|
+
import * as fs81 from "node:fs";
|
|
90242
|
+
import * as path107 from "node:path";
|
|
89528
90243
|
async function writeCheckpoint(directory) {
|
|
89529
90244
|
try {
|
|
89530
90245
|
const plan = await loadPlan(directory);
|
|
89531
90246
|
if (!plan)
|
|
89532
90247
|
return;
|
|
89533
|
-
const swarmDir =
|
|
89534
|
-
|
|
89535
|
-
const jsonPath =
|
|
89536
|
-
const mdPath =
|
|
89537
|
-
|
|
90248
|
+
const swarmDir = path107.join(directory, ".swarm");
|
|
90249
|
+
fs81.mkdirSync(swarmDir, { recursive: true });
|
|
90250
|
+
const jsonPath = path107.join(swarmDir, "SWARM_PLAN.json");
|
|
90251
|
+
const mdPath = path107.join(swarmDir, "SWARM_PLAN.md");
|
|
90252
|
+
fs81.writeFileSync(jsonPath, JSON.stringify(plan, null, 2), "utf8");
|
|
89538
90253
|
const md = derivePlanMarkdown(plan);
|
|
89539
|
-
|
|
90254
|
+
fs81.writeFileSync(mdPath, md, "utf8");
|
|
89540
90255
|
} catch (error93) {
|
|
89541
90256
|
console.warn(`[checkpoint] Failed to write SWARM_PLAN checkpoint: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
89542
90257
|
}
|
|
@@ -89551,16 +90266,16 @@ init_telemetry();
|
|
|
89551
90266
|
|
|
89552
90267
|
// src/turbo/lean/phase-ready.ts
|
|
89553
90268
|
init_file_locks();
|
|
89554
|
-
import * as
|
|
89555
|
-
import * as
|
|
90269
|
+
import * as fs83 from "node:fs";
|
|
90270
|
+
import * as path109 from "node:path";
|
|
89556
90271
|
|
|
89557
90272
|
// src/turbo/lean/evidence.ts
|
|
89558
90273
|
init_bun_compat();
|
|
89559
90274
|
import { rmSync as rmSync5 } from "node:fs";
|
|
89560
|
-
import * as
|
|
89561
|
-
import * as
|
|
90275
|
+
import * as fs82 from "node:fs/promises";
|
|
90276
|
+
import * as path108 from "node:path";
|
|
89562
90277
|
function leanTurboEvidenceDir(directory, phase) {
|
|
89563
|
-
return
|
|
90278
|
+
return path108.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
|
|
89564
90279
|
}
|
|
89565
90280
|
function validateLaneId(laneId) {
|
|
89566
90281
|
if (laneId.length === 0) {
|
|
@@ -89582,21 +90297,21 @@ function validateLaneId(laneId) {
|
|
|
89582
90297
|
function laneEvidencePath(directory, phase, laneId) {
|
|
89583
90298
|
validateLaneId(laneId);
|
|
89584
90299
|
const expectedDir = leanTurboEvidenceDir(directory, phase);
|
|
89585
|
-
const resolvedPath =
|
|
89586
|
-
const resolvedDir =
|
|
89587
|
-
if (!resolvedPath.startsWith(resolvedDir +
|
|
90300
|
+
const resolvedPath = path108.resolve(path108.join(expectedDir, `${laneId}.json`));
|
|
90301
|
+
const resolvedDir = path108.resolve(expectedDir);
|
|
90302
|
+
if (!resolvedPath.startsWith(resolvedDir + path108.sep) && resolvedPath !== resolvedDir) {
|
|
89588
90303
|
throw new Error(`Invalid laneId: path traversal detected (got "${laneId}")`);
|
|
89589
90304
|
}
|
|
89590
90305
|
return resolvedPath;
|
|
89591
90306
|
}
|
|
89592
90307
|
async function atomicWriteJson(filePath, data) {
|
|
89593
90308
|
const content = JSON.stringify(data, null, 2);
|
|
89594
|
-
const dir =
|
|
89595
|
-
await
|
|
90309
|
+
const dir = path108.dirname(filePath);
|
|
90310
|
+
await fs82.mkdir(dir, { recursive: true });
|
|
89596
90311
|
const tempPath = `${filePath}.tmp.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
89597
90312
|
try {
|
|
89598
90313
|
await bunWrite(tempPath, content);
|
|
89599
|
-
await
|
|
90314
|
+
await fs82.rename(tempPath, filePath);
|
|
89600
90315
|
} catch (error93) {
|
|
89601
90316
|
try {
|
|
89602
90317
|
rmSync5(tempPath, { force: true });
|
|
@@ -89605,7 +90320,7 @@ async function atomicWriteJson(filePath, data) {
|
|
|
89605
90320
|
}
|
|
89606
90321
|
}
|
|
89607
90322
|
function phaseEvidencePath(directory, phase) {
|
|
89608
|
-
return
|
|
90323
|
+
return path108.join(leanTurboEvidenceDir(directory, phase), "lean-turbo-phase.json");
|
|
89609
90324
|
}
|
|
89610
90325
|
async function writeLaneEvidence(directory, phase, evidence) {
|
|
89611
90326
|
const targetPath = laneEvidencePath(directory, phase, evidence.laneId);
|
|
@@ -89615,7 +90330,7 @@ async function readPhaseEvidence(directory, phase) {
|
|
|
89615
90330
|
const targetPath = phaseEvidencePath(directory, phase);
|
|
89616
90331
|
let content;
|
|
89617
90332
|
try {
|
|
89618
|
-
content = await
|
|
90333
|
+
content = await fs82.readFile(targetPath, "utf-8");
|
|
89619
90334
|
} catch (error93) {
|
|
89620
90335
|
const code = error93.code;
|
|
89621
90336
|
if (code === "ENOENT" || code === "ENOTDIR") {
|
|
@@ -89633,7 +90348,7 @@ async function listLaneEvidence(directory, phase) {
|
|
|
89633
90348
|
const evidenceDir = leanTurboEvidenceDir(directory, phase);
|
|
89634
90349
|
let entries;
|
|
89635
90350
|
try {
|
|
89636
|
-
entries = await
|
|
90351
|
+
entries = await fs82.readdir(evidenceDir);
|
|
89637
90352
|
} catch (error93) {
|
|
89638
90353
|
const code = error93.code;
|
|
89639
90354
|
if (code === "ENOENT" || code === "ENOTDIR") {
|
|
@@ -89649,10 +90364,10 @@ async function listLaneEvidence(directory, phase) {
|
|
|
89649
90364
|
if (entry === "lean-turbo-phase.json") {
|
|
89650
90365
|
continue;
|
|
89651
90366
|
}
|
|
89652
|
-
const filePath =
|
|
90367
|
+
const filePath = path108.join(evidenceDir, entry);
|
|
89653
90368
|
let content;
|
|
89654
90369
|
try {
|
|
89655
|
-
content = await
|
|
90370
|
+
content = await fs82.readFile(filePath, "utf-8");
|
|
89656
90371
|
} catch {
|
|
89657
90372
|
continue;
|
|
89658
90373
|
}
|
|
@@ -89673,10 +90388,10 @@ var DEFAULT_CONFIG2 = {
|
|
|
89673
90388
|
};
|
|
89674
90389
|
function defaultReadPlanJson(dir) {
|
|
89675
90390
|
try {
|
|
89676
|
-
const planPath =
|
|
89677
|
-
if (!
|
|
90391
|
+
const planPath = path109.join(dir, ".swarm", "plan.json");
|
|
90392
|
+
if (!fs83.existsSync(planPath))
|
|
89678
90393
|
return null;
|
|
89679
|
-
const raw =
|
|
90394
|
+
const raw = fs83.readFileSync(planPath, "utf-8");
|
|
89680
90395
|
const plan = JSON.parse(raw);
|
|
89681
90396
|
if (typeof plan !== "object" || plan === null || !Array.isArray(plan.phases)) {
|
|
89682
90397
|
return null;
|
|
@@ -89688,11 +90403,11 @@ function defaultReadPlanJson(dir) {
|
|
|
89688
90403
|
}
|
|
89689
90404
|
function readReviewerEvidenceFromFile(directory, phase) {
|
|
89690
90405
|
try {
|
|
89691
|
-
const evidencePath =
|
|
89692
|
-
if (!
|
|
90406
|
+
const evidencePath = path109.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-reviewer.json");
|
|
90407
|
+
if (!fs83.existsSync(evidencePath)) {
|
|
89693
90408
|
return null;
|
|
89694
90409
|
}
|
|
89695
|
-
const raw =
|
|
90410
|
+
const raw = fs83.readFileSync(evidencePath, "utf-8");
|
|
89696
90411
|
const parsed = JSON.parse(raw);
|
|
89697
90412
|
if (typeof parsed !== "object" || parsed === null || typeof parsed.verdict !== "string") {
|
|
89698
90413
|
return null;
|
|
@@ -89708,11 +90423,11 @@ function readReviewerEvidenceFromFile(directory, phase) {
|
|
|
89708
90423
|
}
|
|
89709
90424
|
function readCriticEvidenceFromFile(directory, phase) {
|
|
89710
90425
|
try {
|
|
89711
|
-
const evidencePath =
|
|
89712
|
-
if (!
|
|
90426
|
+
const evidencePath = path109.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-critic.json");
|
|
90427
|
+
if (!fs83.existsSync(evidencePath)) {
|
|
89713
90428
|
return null;
|
|
89714
90429
|
}
|
|
89715
|
-
const raw =
|
|
90430
|
+
const raw = fs83.readFileSync(evidencePath, "utf-8");
|
|
89716
90431
|
const parsed = JSON.parse(raw);
|
|
89717
90432
|
if (typeof parsed !== "object" || parsed === null || typeof parsed.verdict !== "string") {
|
|
89718
90433
|
return null;
|
|
@@ -89727,10 +90442,10 @@ function readCriticEvidenceFromFile(directory, phase) {
|
|
|
89727
90442
|
}
|
|
89728
90443
|
}
|
|
89729
90444
|
function listLaneEvidenceSync(directory, phase) {
|
|
89730
|
-
const evidenceDir =
|
|
90445
|
+
const evidenceDir = path109.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
|
|
89731
90446
|
let entries;
|
|
89732
90447
|
try {
|
|
89733
|
-
entries =
|
|
90448
|
+
entries = fs83.readdirSync(evidenceDir);
|
|
89734
90449
|
} catch {
|
|
89735
90450
|
return [];
|
|
89736
90451
|
}
|
|
@@ -89743,7 +90458,7 @@ function listLaneEvidenceSync(directory, phase) {
|
|
|
89743
90458
|
}
|
|
89744
90459
|
return laneIds;
|
|
89745
90460
|
}
|
|
89746
|
-
var
|
|
90461
|
+
var _internals43 = {
|
|
89747
90462
|
listActiveLocks,
|
|
89748
90463
|
readPersisted: readPersisted2,
|
|
89749
90464
|
readPlanJson: defaultReadPlanJson,
|
|
@@ -89797,14 +90512,14 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
89797
90512
|
...DEFAULT_CONFIG2,
|
|
89798
90513
|
...actualConfig
|
|
89799
90514
|
};
|
|
89800
|
-
const statePath =
|
|
89801
|
-
if (!
|
|
90515
|
+
const statePath = path109.join(directory, ".swarm", "turbo-state.json");
|
|
90516
|
+
if (!fs83.existsSync(statePath)) {
|
|
89802
90517
|
return {
|
|
89803
90518
|
ok: false,
|
|
89804
90519
|
reason: "Lean Turbo state unreadable or missing"
|
|
89805
90520
|
};
|
|
89806
90521
|
}
|
|
89807
|
-
const persisted =
|
|
90522
|
+
const persisted = _internals43.readPersisted(directory);
|
|
89808
90523
|
if (!persisted) {
|
|
89809
90524
|
return {
|
|
89810
90525
|
ok: false,
|
|
@@ -89868,7 +90583,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
89868
90583
|
}
|
|
89869
90584
|
}
|
|
89870
90585
|
if (runState.lanes.length > 0) {
|
|
89871
|
-
const evidenceLaneIds = new Set(
|
|
90586
|
+
const evidenceLaneIds = new Set(_internals43.listLaneEvidenceSync(directory, phase));
|
|
89872
90587
|
for (const lane of runState.lanes) {
|
|
89873
90588
|
if ((lane.status === "completed" || lane.status === "failed") && !evidenceLaneIds.has(lane.laneId)) {
|
|
89874
90589
|
return {
|
|
@@ -89878,7 +90593,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
89878
90593
|
}
|
|
89879
90594
|
}
|
|
89880
90595
|
}
|
|
89881
|
-
const activeLocks =
|
|
90596
|
+
const activeLocks = _internals43.listActiveLocks(directory);
|
|
89882
90597
|
const phaseLaneIds = new Set(laneIds);
|
|
89883
90598
|
for (const lock of activeLocks) {
|
|
89884
90599
|
if (lock.laneId && phaseLaneIds.has(lock.laneId)) {
|
|
@@ -89898,7 +90613,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
89898
90613
|
}
|
|
89899
90614
|
const serialDegradedTasks = runState.degradedTasks.filter((dt) => !laneTaskIds.has(dt.taskId));
|
|
89900
90615
|
if (serialDegradedTasks.length > 0) {
|
|
89901
|
-
const plan =
|
|
90616
|
+
const plan = _internals43.readPlanJson(directory);
|
|
89902
90617
|
if (!plan) {
|
|
89903
90618
|
return {
|
|
89904
90619
|
ok: false,
|
|
@@ -89942,7 +90657,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
89942
90657
|
}
|
|
89943
90658
|
const serializedTasks = runState.serializedTasks;
|
|
89944
90659
|
if (Array.isArray(serializedTasks) && serializedTasks.length > 0) {
|
|
89945
|
-
const plan =
|
|
90660
|
+
const plan = _internals43.readPlanJson(directory);
|
|
89946
90661
|
if (!plan) {
|
|
89947
90662
|
return {
|
|
89948
90663
|
ok: false,
|
|
@@ -89985,10 +90700,10 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
89985
90700
|
}
|
|
89986
90701
|
}
|
|
89987
90702
|
if (mergedConfig.integrated_diff_required) {
|
|
89988
|
-
const evidencePath =
|
|
90703
|
+
const evidencePath = path109.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-phase.json");
|
|
89989
90704
|
let hasDiff = false;
|
|
89990
90705
|
try {
|
|
89991
|
-
const content =
|
|
90706
|
+
const content = fs83.readFileSync(evidencePath, "utf-8");
|
|
89992
90707
|
const evidence = JSON.parse(content);
|
|
89993
90708
|
hasDiff = !!evidence.integratedDiffSummary;
|
|
89994
90709
|
} catch {}
|
|
@@ -90001,7 +90716,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
90001
90716
|
}
|
|
90002
90717
|
let reviewerVerdict = runState.lastReviewerVerdict;
|
|
90003
90718
|
if (!reviewerVerdict) {
|
|
90004
|
-
const evidence =
|
|
90719
|
+
const evidence = _internals43.readReviewerEvidence(directory, phase);
|
|
90005
90720
|
reviewerVerdict = evidence?.verdict ?? undefined;
|
|
90006
90721
|
}
|
|
90007
90722
|
if (mergedConfig.phase_reviewer) {
|
|
@@ -90014,7 +90729,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
90014
90729
|
}
|
|
90015
90730
|
let criticVerdict = runState.lastCriticVerdict;
|
|
90016
90731
|
if (!criticVerdict) {
|
|
90017
|
-
const evidence =
|
|
90732
|
+
const evidence = _internals43.readCriticEvidence(directory, phase);
|
|
90018
90733
|
criticVerdict = evidence?.verdict ?? undefined;
|
|
90019
90734
|
}
|
|
90020
90735
|
if (mergedConfig.phase_critic) {
|
|
@@ -90038,11 +90753,12 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
90038
90753
|
}
|
|
90039
90754
|
|
|
90040
90755
|
// src/tools/phase-complete.ts
|
|
90756
|
+
init_logger();
|
|
90041
90757
|
init_create_tool();
|
|
90042
90758
|
init_resolve_working_directory();
|
|
90043
90759
|
function safeWarn(message, error93) {
|
|
90044
90760
|
try {
|
|
90045
|
-
|
|
90761
|
+
warn(message, error93 instanceof Error ? error93.message : String(error93));
|
|
90046
90762
|
} catch {}
|
|
90047
90763
|
}
|
|
90048
90764
|
function collectCrossSessionDispatchedAgents(phaseReferenceTimestamp, callerSessionId) {
|
|
@@ -90233,7 +90949,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
90233
90949
|
}, null, 2);
|
|
90234
90950
|
}
|
|
90235
90951
|
if (hasActiveTurboMode(sessionID)) {
|
|
90236
|
-
|
|
90952
|
+
warnings.push(`Turbo mode active — skipped completion-verify, drift-verifier, hallucination-guard, mutation-gate, phase-council, and final-council gates for phase ${phase}.`);
|
|
90237
90953
|
} else {
|
|
90238
90954
|
try {
|
|
90239
90955
|
const completionResultRaw = await executeCompletionVerify({ phase }, dir);
|
|
@@ -90258,8 +90974,8 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
90258
90974
|
let driftCheckEnabled = true;
|
|
90259
90975
|
let driftHasSpecMd = false;
|
|
90260
90976
|
try {
|
|
90261
|
-
const specMdPath =
|
|
90262
|
-
driftHasSpecMd =
|
|
90977
|
+
const specMdPath = path110.join(dir, ".swarm", "spec.md");
|
|
90978
|
+
driftHasSpecMd = fs84.existsSync(specMdPath);
|
|
90263
90979
|
const gatePlan = await loadPlan(dir);
|
|
90264
90980
|
if (gatePlan) {
|
|
90265
90981
|
const gatePlanId = derivePlanId(gatePlan);
|
|
@@ -90275,29 +90991,27 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
90275
90991
|
safeWarn(`[phase_complete] QA gate profile load error, drift_check defaults to enabled:`, gateLoadError);
|
|
90276
90992
|
}
|
|
90277
90993
|
if (!driftCheckEnabled) {
|
|
90278
|
-
console.info(`[phase_complete] drift_check disabled — skipping drift verification gate for phase ${phase}`);
|
|
90279
90994
|
warnings.push(`drift_check gate is disabled. Drift verification was skipped for phase ${phase}.`);
|
|
90280
90995
|
} else {
|
|
90281
90996
|
let phaseType;
|
|
90282
90997
|
try {
|
|
90283
|
-
const planPath =
|
|
90284
|
-
if (
|
|
90285
|
-
const planRaw =
|
|
90998
|
+
const planPath = path110.join(dir, ".swarm", "plan.json");
|
|
90999
|
+
if (fs84.existsSync(planPath)) {
|
|
91000
|
+
const planRaw = fs84.readFileSync(planPath, "utf-8");
|
|
90286
91001
|
const plan = JSON.parse(planRaw);
|
|
90287
91002
|
const targetPhase = plan.phases?.find((p) => p.id === phase);
|
|
90288
91003
|
phaseType = targetPhase?.type;
|
|
90289
91004
|
}
|
|
90290
91005
|
} catch {}
|
|
90291
91006
|
if (phaseType === "non-code") {
|
|
90292
|
-
console.info(`[phase_complete] Phase ${phase} annotated as 'non-code' — drift verification skipped.`);
|
|
90293
91007
|
warnings.push(`Phase ${phase} is annotated as 'non-code'. Drift verification was skipped per phase type annotation.`);
|
|
90294
91008
|
} else {
|
|
90295
91009
|
try {
|
|
90296
|
-
const driftEvidencePath =
|
|
91010
|
+
const driftEvidencePath = path110.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
|
|
90297
91011
|
let driftVerdictFound = false;
|
|
90298
91012
|
let driftVerdictApproved = false;
|
|
90299
91013
|
try {
|
|
90300
|
-
const driftEvidenceContent =
|
|
91014
|
+
const driftEvidenceContent = fs84.readFileSync(driftEvidencePath, "utf-8");
|
|
90301
91015
|
const driftEvidence = JSON.parse(driftEvidenceContent);
|
|
90302
91016
|
const entries = driftEvidence.entries ?? [];
|
|
90303
91017
|
for (const entry of entries) {
|
|
@@ -90331,9 +91045,9 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
90331
91045
|
let incompleteTaskCount = 0;
|
|
90332
91046
|
let planParseable = false;
|
|
90333
91047
|
try {
|
|
90334
|
-
const planPath =
|
|
90335
|
-
if (
|
|
90336
|
-
const planRaw =
|
|
91048
|
+
const planPath = path110.join(dir, ".swarm", "plan.json");
|
|
91049
|
+
if (fs84.existsSync(planPath)) {
|
|
91050
|
+
const planRaw = fs84.readFileSync(planPath, "utf-8");
|
|
90337
91051
|
const plan = JSON.parse(planRaw);
|
|
90338
91052
|
planParseable = true;
|
|
90339
91053
|
const planPhase = plan.phases?.find((p) => p.id === phase);
|
|
@@ -90398,11 +91112,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
90398
91112
|
const overrides = session2?.qaGateSessionOverrides ?? {};
|
|
90399
91113
|
const effective = getEffectiveGates(profile, overrides);
|
|
90400
91114
|
if (effective.hallucination_guard === true) {
|
|
90401
|
-
const hgPath =
|
|
91115
|
+
const hgPath = path110.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
|
|
90402
91116
|
let hgVerdictFound = false;
|
|
90403
91117
|
let hgVerdictApproved = false;
|
|
90404
91118
|
try {
|
|
90405
|
-
const hgContent =
|
|
91119
|
+
const hgContent = fs84.readFileSync(hgPath, "utf-8");
|
|
90406
91120
|
const hgBundle = JSON.parse(hgContent);
|
|
90407
91121
|
for (const entry of hgBundle.entries ?? []) {
|
|
90408
91122
|
if (typeof entry.type === "string" && entry.type.includes("hallucination") && typeof entry.verdict === "string") {
|
|
@@ -90470,11 +91184,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
90470
91184
|
const overrides = session2?.qaGateSessionOverrides ?? {};
|
|
90471
91185
|
const effective = getEffectiveGates(profile, overrides);
|
|
90472
91186
|
if (effective.mutation_test === true) {
|
|
90473
|
-
const mgPath =
|
|
91187
|
+
const mgPath = path110.join(dir, ".swarm", "evidence", String(phase), "mutation-gate.json");
|
|
90474
91188
|
let mgVerdictFound = false;
|
|
90475
91189
|
let mgVerdict;
|
|
90476
91190
|
try {
|
|
90477
|
-
const mgContent =
|
|
91191
|
+
const mgContent = fs84.readFileSync(mgPath, "utf-8");
|
|
90478
91192
|
const mgBundle = JSON.parse(mgContent);
|
|
90479
91193
|
for (const entry of mgBundle.entries ?? []) {
|
|
90480
91194
|
if (typeof entry.type === "string" && entry.type === "mutation-gate" && typeof entry.verdict === "string") {
|
|
@@ -90544,14 +91258,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
90544
91258
|
const effective = getEffectiveGates(profile, overrides);
|
|
90545
91259
|
if (effective.council_mode === true) {
|
|
90546
91260
|
councilModeEnabled = true;
|
|
90547
|
-
const pcPath =
|
|
91261
|
+
const pcPath = path110.join(dir, ".swarm", "evidence", String(phase), "phase-council.json");
|
|
90548
91262
|
let pcVerdictFound = false;
|
|
90549
91263
|
let _pcVerdict;
|
|
90550
91264
|
let pcQuorumSize;
|
|
90551
91265
|
let pcTimestamp;
|
|
90552
91266
|
let pcPhaseNumber;
|
|
90553
91267
|
try {
|
|
90554
|
-
const pcContent =
|
|
91268
|
+
const pcContent = fs84.readFileSync(pcPath, "utf-8");
|
|
90555
91269
|
const pcBundle = JSON.parse(pcContent);
|
|
90556
91270
|
for (const entry of pcBundle.entries ?? []) {
|
|
90557
91271
|
if (typeof entry.type === "string" && entry.type === "phase-council" && typeof entry.verdict === "string") {
|
|
@@ -90752,11 +91466,11 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
90752
91466
|
const effective = getEffectiveGates(profile, overrides);
|
|
90753
91467
|
if (effective.final_council === true) {
|
|
90754
91468
|
finalCouncilEnabled = true;
|
|
90755
|
-
const fcPath =
|
|
91469
|
+
const fcPath = path110.join(dir, ".swarm", "evidence", "final-council.json");
|
|
90756
91470
|
let fcVerdictFound = false;
|
|
90757
91471
|
let _fcVerdict;
|
|
90758
91472
|
try {
|
|
90759
|
-
const fcContent =
|
|
91473
|
+
const fcContent = fs84.readFileSync(fcPath, "utf-8");
|
|
90760
91474
|
const fcBundle = JSON.parse(fcContent);
|
|
90761
91475
|
for (const entry of fcBundle.entries ?? []) {
|
|
90762
91476
|
if (typeof entry.type === "string" && entry.type === "final-council" && typeof entry.verdict === "string") {
|
|
@@ -90917,7 +91631,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
90917
91631
|
phase_critic: leanConfig.phase_critic,
|
|
90918
91632
|
integrated_diff_required: leanConfig.integrated_diff_required
|
|
90919
91633
|
} : undefined;
|
|
90920
|
-
const leanCheck =
|
|
91634
|
+
const leanCheck = _internals43.verifyLeanTurboPhaseReady(dir, phase, sessionID, leanPhaseReadyConfig);
|
|
90921
91635
|
if (!leanCheck.ok) {
|
|
90922
91636
|
return JSON.stringify({
|
|
90923
91637
|
success: false,
|
|
@@ -90940,7 +91654,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
90940
91654
|
}
|
|
90941
91655
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
90942
91656
|
try {
|
|
90943
|
-
const projectName =
|
|
91657
|
+
const projectName = path110.basename(dir);
|
|
90944
91658
|
const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
|
|
90945
91659
|
if (curationResult) {
|
|
90946
91660
|
const sessionState = swarmState.agentSessions.get(sessionID);
|
|
@@ -91020,7 +91734,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
91020
91734
|
let phaseRequiredAgents;
|
|
91021
91735
|
try {
|
|
91022
91736
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
91023
|
-
const planRaw =
|
|
91737
|
+
const planRaw = fs84.readFileSync(planPath, "utf-8");
|
|
91024
91738
|
const plan = JSON.parse(planRaw);
|
|
91025
91739
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
91026
91740
|
phaseRequiredAgents = phaseObj?.required_agents;
|
|
@@ -91035,7 +91749,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
91035
91749
|
if (agentsMissing.length > 0) {
|
|
91036
91750
|
try {
|
|
91037
91751
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
91038
|
-
const planRaw =
|
|
91752
|
+
const planRaw = fs84.readFileSync(planPath, "utf-8");
|
|
91039
91753
|
const plan = JSON.parse(planRaw);
|
|
91040
91754
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
91041
91755
|
if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
|
|
@@ -91075,7 +91789,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
91075
91789
|
if (phaseCompleteConfig.regression_sweep?.enforce) {
|
|
91076
91790
|
try {
|
|
91077
91791
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
91078
|
-
const planRaw =
|
|
91792
|
+
const planRaw = fs84.readFileSync(planPath, "utf-8");
|
|
91079
91793
|
const plan = JSON.parse(planRaw);
|
|
91080
91794
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
91081
91795
|
if (targetPhase) {
|
|
@@ -91129,7 +91843,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
91129
91843
|
}
|
|
91130
91844
|
try {
|
|
91131
91845
|
const eventsPath = validateSwarmPath(dir, "events.jsonl");
|
|
91132
|
-
|
|
91846
|
+
fs84.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
91133
91847
|
`, "utf-8");
|
|
91134
91848
|
} catch (writeError) {
|
|
91135
91849
|
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -91138,7 +91852,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
91138
91852
|
try {
|
|
91139
91853
|
await lockResult.lock._release();
|
|
91140
91854
|
} catch (releaseError) {
|
|
91141
|
-
|
|
91855
|
+
warn("[phase_complete] Lock release failed (non-blocking):", releaseError instanceof Error ? releaseError.message : String(releaseError));
|
|
91142
91856
|
}
|
|
91143
91857
|
}
|
|
91144
91858
|
}
|
|
@@ -91204,12 +91918,12 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
91204
91918
|
warnings.push(`Warning: failed to update plan.json phase status`);
|
|
91205
91919
|
try {
|
|
91206
91920
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
91207
|
-
const planRaw =
|
|
91921
|
+
const planRaw = fs84.readFileSync(planPath, "utf-8");
|
|
91208
91922
|
const plan2 = JSON.parse(planRaw);
|
|
91209
91923
|
const phaseObj = plan2.phases.find((p) => p.id === phase);
|
|
91210
91924
|
if (phaseObj) {
|
|
91211
91925
|
phaseObj.status = "complete";
|
|
91212
|
-
|
|
91926
|
+
fs84.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
|
|
91213
91927
|
}
|
|
91214
91928
|
} catch {}
|
|
91215
91929
|
} else if (plan) {
|
|
@@ -91246,12 +91960,12 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
91246
91960
|
warnings.push(`Warning: failed to update plan.json phase status`);
|
|
91247
91961
|
try {
|
|
91248
91962
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
91249
|
-
const planRaw =
|
|
91963
|
+
const planRaw = fs84.readFileSync(planPath, "utf-8");
|
|
91250
91964
|
const plan = JSON.parse(planRaw);
|
|
91251
91965
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
91252
91966
|
if (phaseObj) {
|
|
91253
91967
|
phaseObj.status = "complete";
|
|
91254
|
-
|
|
91968
|
+
fs84.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
|
|
91255
91969
|
}
|
|
91256
91970
|
} catch {}
|
|
91257
91971
|
}
|
|
@@ -91309,8 +92023,8 @@ init_discovery();
|
|
|
91309
92023
|
init_utils();
|
|
91310
92024
|
init_bun_compat();
|
|
91311
92025
|
init_create_tool();
|
|
91312
|
-
import * as
|
|
91313
|
-
import * as
|
|
92026
|
+
import * as fs85 from "node:fs";
|
|
92027
|
+
import * as path111 from "node:path";
|
|
91314
92028
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
91315
92029
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
91316
92030
|
function isValidEcosystem(value) {
|
|
@@ -91338,31 +92052,31 @@ function validateArgs3(args2) {
|
|
|
91338
92052
|
function detectEcosystems(directory) {
|
|
91339
92053
|
const ecosystems = [];
|
|
91340
92054
|
const cwd = directory;
|
|
91341
|
-
if (
|
|
92055
|
+
if (fs85.existsSync(path111.join(cwd, "package.json"))) {
|
|
91342
92056
|
ecosystems.push("npm");
|
|
91343
92057
|
}
|
|
91344
|
-
if (
|
|
92058
|
+
if (fs85.existsSync(path111.join(cwd, "pyproject.toml")) || fs85.existsSync(path111.join(cwd, "requirements.txt"))) {
|
|
91345
92059
|
ecosystems.push("pip");
|
|
91346
92060
|
}
|
|
91347
|
-
if (
|
|
92061
|
+
if (fs85.existsSync(path111.join(cwd, "Cargo.toml"))) {
|
|
91348
92062
|
ecosystems.push("cargo");
|
|
91349
92063
|
}
|
|
91350
|
-
if (
|
|
92064
|
+
if (fs85.existsSync(path111.join(cwd, "go.mod"))) {
|
|
91351
92065
|
ecosystems.push("go");
|
|
91352
92066
|
}
|
|
91353
92067
|
try {
|
|
91354
|
-
const files =
|
|
92068
|
+
const files = fs85.readdirSync(cwd);
|
|
91355
92069
|
if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
91356
92070
|
ecosystems.push("dotnet");
|
|
91357
92071
|
}
|
|
91358
92072
|
} catch {}
|
|
91359
|
-
if (
|
|
92073
|
+
if (fs85.existsSync(path111.join(cwd, "Gemfile")) || fs85.existsSync(path111.join(cwd, "Gemfile.lock"))) {
|
|
91360
92074
|
ecosystems.push("ruby");
|
|
91361
92075
|
}
|
|
91362
|
-
if (
|
|
92076
|
+
if (fs85.existsSync(path111.join(cwd, "pubspec.yaml"))) {
|
|
91363
92077
|
ecosystems.push("dart");
|
|
91364
92078
|
}
|
|
91365
|
-
if (
|
|
92079
|
+
if (fs85.existsSync(path111.join(cwd, "composer.lock"))) {
|
|
91366
92080
|
ecosystems.push("composer");
|
|
91367
92081
|
}
|
|
91368
92082
|
return ecosystems;
|
|
@@ -92497,8 +93211,8 @@ var pkg_audit = createSwarmTool({
|
|
|
92497
93211
|
// src/tools/placeholder-scan.ts
|
|
92498
93212
|
init_zod();
|
|
92499
93213
|
init_manager2();
|
|
92500
|
-
import * as
|
|
92501
|
-
import * as
|
|
93214
|
+
import * as fs86 from "node:fs";
|
|
93215
|
+
import * as path112 from "node:path";
|
|
92502
93216
|
init_utils();
|
|
92503
93217
|
init_create_tool();
|
|
92504
93218
|
var MAX_FILE_SIZE = 1024 * 1024;
|
|
@@ -92621,7 +93335,7 @@ function isScaffoldFile(filePath) {
|
|
|
92621
93335
|
if (SCAFFOLD_PATH_PATTERNS.some((pattern) => pattern.test(normalizedPath))) {
|
|
92622
93336
|
return true;
|
|
92623
93337
|
}
|
|
92624
|
-
const filename =
|
|
93338
|
+
const filename = path112.basename(filePath);
|
|
92625
93339
|
if (SCAFFOLD_FILENAME_PATTERNS.some((pattern) => pattern.test(filename))) {
|
|
92626
93340
|
return true;
|
|
92627
93341
|
}
|
|
@@ -92638,7 +93352,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
|
|
|
92638
93352
|
if (regex.test(normalizedPath)) {
|
|
92639
93353
|
return true;
|
|
92640
93354
|
}
|
|
92641
|
-
const filename =
|
|
93355
|
+
const filename = path112.basename(filePath);
|
|
92642
93356
|
const filenameRegex = new RegExp(`^${regexPattern}$`, "i");
|
|
92643
93357
|
if (filenameRegex.test(filename)) {
|
|
92644
93358
|
return true;
|
|
@@ -92647,7 +93361,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
|
|
|
92647
93361
|
return false;
|
|
92648
93362
|
}
|
|
92649
93363
|
function isParserSupported(filePath) {
|
|
92650
|
-
const ext =
|
|
93364
|
+
const ext = path112.extname(filePath).toLowerCase();
|
|
92651
93365
|
return SUPPORTED_PARSER_EXTENSIONS.has(ext);
|
|
92652
93366
|
}
|
|
92653
93367
|
function isPlanFile(filePath) {
|
|
@@ -92894,28 +93608,28 @@ async function placeholderScan(input, directory) {
|
|
|
92894
93608
|
let filesScanned = 0;
|
|
92895
93609
|
const filesWithFindings = new Set;
|
|
92896
93610
|
for (const filePath of changed_files) {
|
|
92897
|
-
const fullPath =
|
|
92898
|
-
const resolvedDirectory =
|
|
92899
|
-
if (!fullPath.startsWith(resolvedDirectory +
|
|
93611
|
+
const fullPath = path112.isAbsolute(filePath) ? filePath : path112.resolve(directory, filePath);
|
|
93612
|
+
const resolvedDirectory = path112.resolve(directory);
|
|
93613
|
+
if (!fullPath.startsWith(resolvedDirectory + path112.sep) && fullPath !== resolvedDirectory) {
|
|
92900
93614
|
continue;
|
|
92901
93615
|
}
|
|
92902
|
-
if (!
|
|
93616
|
+
if (!fs86.existsSync(fullPath)) {
|
|
92903
93617
|
continue;
|
|
92904
93618
|
}
|
|
92905
93619
|
if (isAllowedByGlobs(filePath, allow_globs)) {
|
|
92906
93620
|
continue;
|
|
92907
93621
|
}
|
|
92908
|
-
const relativeFilePath =
|
|
93622
|
+
const relativeFilePath = path112.relative(directory, fullPath).replace(/\\/g, "/");
|
|
92909
93623
|
if (FILE_ALLOWLIST.some((allowed) => relativeFilePath.endsWith(allowed))) {
|
|
92910
93624
|
continue;
|
|
92911
93625
|
}
|
|
92912
93626
|
let content;
|
|
92913
93627
|
try {
|
|
92914
|
-
const stat8 =
|
|
93628
|
+
const stat8 = fs86.statSync(fullPath);
|
|
92915
93629
|
if (stat8.size > MAX_FILE_SIZE) {
|
|
92916
93630
|
continue;
|
|
92917
93631
|
}
|
|
92918
|
-
content =
|
|
93632
|
+
content = fs86.readFileSync(fullPath, "utf-8");
|
|
92919
93633
|
} catch {
|
|
92920
93634
|
continue;
|
|
92921
93635
|
}
|
|
@@ -92976,8 +93690,8 @@ var placeholder_scan = createSwarmTool({
|
|
|
92976
93690
|
}
|
|
92977
93691
|
});
|
|
92978
93692
|
// src/tools/pre-check-batch.ts
|
|
92979
|
-
import * as
|
|
92980
|
-
import * as
|
|
93693
|
+
import * as fs90 from "node:fs";
|
|
93694
|
+
import * as path116 from "node:path";
|
|
92981
93695
|
init_zod();
|
|
92982
93696
|
init_manager2();
|
|
92983
93697
|
init_utils();
|
|
@@ -93105,11 +93819,11 @@ var quality_budget = createSwarmTool({
|
|
|
93105
93819
|
}).optional().describe("Quality budget thresholds")
|
|
93106
93820
|
},
|
|
93107
93821
|
async execute(args2, directory) {
|
|
93108
|
-
const result = await
|
|
93822
|
+
const result = await _internals44.qualityBudget(args2, directory);
|
|
93109
93823
|
return JSON.stringify(result);
|
|
93110
93824
|
}
|
|
93111
93825
|
});
|
|
93112
|
-
var
|
|
93826
|
+
var _internals44 = {
|
|
93113
93827
|
qualityBudget
|
|
93114
93828
|
};
|
|
93115
93829
|
|
|
@@ -93117,9 +93831,9 @@ var _internals41 = {
|
|
|
93117
93831
|
init_zod();
|
|
93118
93832
|
init_manager2();
|
|
93119
93833
|
init_detector();
|
|
93120
|
-
import * as
|
|
93121
|
-
import * as
|
|
93122
|
-
import { extname as
|
|
93834
|
+
import * as fs89 from "node:fs";
|
|
93835
|
+
import * as path115 from "node:path";
|
|
93836
|
+
import { extname as extname20 } from "node:path";
|
|
93123
93837
|
|
|
93124
93838
|
// src/sast/rules/c.ts
|
|
93125
93839
|
var cRules = [
|
|
@@ -93833,12 +94547,12 @@ function executeRulesSync(filePath, content, language) {
|
|
|
93833
94547
|
|
|
93834
94548
|
// src/sast/semgrep.ts
|
|
93835
94549
|
import * as child_process9 from "node:child_process";
|
|
93836
|
-
import * as
|
|
93837
|
-
import * as
|
|
94550
|
+
import * as fs87 from "node:fs";
|
|
94551
|
+
import * as path113 from "node:path";
|
|
93838
94552
|
var semgrepAvailableCache = null;
|
|
93839
94553
|
var DEFAULT_RULES_DIR = ".swarm/semgrep-rules";
|
|
93840
94554
|
var DEFAULT_TIMEOUT_MS3 = 30000;
|
|
93841
|
-
var
|
|
94555
|
+
var _internals45 = {
|
|
93842
94556
|
isSemgrepAvailable,
|
|
93843
94557
|
checkSemgrepAvailable,
|
|
93844
94558
|
resetSemgrepCache,
|
|
@@ -93863,7 +94577,7 @@ function isSemgrepAvailable() {
|
|
|
93863
94577
|
}
|
|
93864
94578
|
}
|
|
93865
94579
|
async function checkSemgrepAvailable() {
|
|
93866
|
-
return
|
|
94580
|
+
return _internals45.isSemgrepAvailable();
|
|
93867
94581
|
}
|
|
93868
94582
|
function resetSemgrepCache() {
|
|
93869
94583
|
semgrepAvailableCache = null;
|
|
@@ -93960,12 +94674,12 @@ async function runSemgrep(options) {
|
|
|
93960
94674
|
const timeoutMs = options.timeoutMs || DEFAULT_TIMEOUT_MS3;
|
|
93961
94675
|
if (files.length === 0) {
|
|
93962
94676
|
return {
|
|
93963
|
-
available:
|
|
94677
|
+
available: _internals45.isSemgrepAvailable(),
|
|
93964
94678
|
findings: [],
|
|
93965
94679
|
engine: "tier_a"
|
|
93966
94680
|
};
|
|
93967
94681
|
}
|
|
93968
|
-
if (!
|
|
94682
|
+
if (!_internals45.isSemgrepAvailable()) {
|
|
93969
94683
|
return {
|
|
93970
94684
|
available: false,
|
|
93971
94685
|
findings: [],
|
|
@@ -94021,14 +94735,14 @@ async function runSemgrep(options) {
|
|
|
94021
94735
|
}
|
|
94022
94736
|
function getRulesDirectory(projectRoot) {
|
|
94023
94737
|
if (projectRoot) {
|
|
94024
|
-
return
|
|
94738
|
+
return path113.resolve(projectRoot, DEFAULT_RULES_DIR);
|
|
94025
94739
|
}
|
|
94026
94740
|
return DEFAULT_RULES_DIR;
|
|
94027
94741
|
}
|
|
94028
94742
|
function hasBundledRules(projectRoot) {
|
|
94029
94743
|
const rulesDir = getRulesDirectory(projectRoot);
|
|
94030
94744
|
try {
|
|
94031
|
-
return
|
|
94745
|
+
return fs87.existsSync(rulesDir);
|
|
94032
94746
|
} catch {
|
|
94033
94747
|
return false;
|
|
94034
94748
|
}
|
|
@@ -94040,26 +94754,26 @@ init_create_tool();
|
|
|
94040
94754
|
|
|
94041
94755
|
// src/tools/sast-baseline.ts
|
|
94042
94756
|
init_utils2();
|
|
94043
|
-
import * as
|
|
94044
|
-
import * as
|
|
94045
|
-
import * as
|
|
94757
|
+
import * as crypto10 from "node:crypto";
|
|
94758
|
+
import * as fs88 from "node:fs";
|
|
94759
|
+
import * as path114 from "node:path";
|
|
94046
94760
|
var BASELINE_SCHEMA_VERSION = "1.0.0";
|
|
94047
94761
|
var MAX_BASELINE_FINDINGS = 2000;
|
|
94048
94762
|
var MAX_BASELINE_BYTES = 2 * 1048576;
|
|
94049
94763
|
var LOCK_RETRY_DELAYS_MS = [50, 100, 200, 400, 800];
|
|
94050
94764
|
function normalizeFindingPath(directory, file3) {
|
|
94051
|
-
const resolved =
|
|
94052
|
-
const rel =
|
|
94765
|
+
const resolved = path114.isAbsolute(file3) ? file3 : path114.resolve(directory, file3);
|
|
94766
|
+
const rel = path114.relative(path114.resolve(directory), resolved);
|
|
94053
94767
|
return rel.replace(/\\/g, "/");
|
|
94054
94768
|
}
|
|
94055
94769
|
function baselineRelPath(phase) {
|
|
94056
|
-
return
|
|
94770
|
+
return path114.join("evidence", String(phase), "sast-baseline.json");
|
|
94057
94771
|
}
|
|
94058
94772
|
function tempRelPath(phase) {
|
|
94059
|
-
return
|
|
94773
|
+
return path114.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
|
|
94060
94774
|
}
|
|
94061
94775
|
function lockRelPath(phase) {
|
|
94062
|
-
return
|
|
94776
|
+
return path114.join("evidence", String(phase), "sast-baseline.json.lock");
|
|
94063
94777
|
}
|
|
94064
94778
|
function getLine(lines, idx) {
|
|
94065
94779
|
if (idx < 0 || idx >= lines.length)
|
|
@@ -94076,7 +94790,7 @@ function fingerprintFinding(finding, directory, occurrenceIndex) {
|
|
|
94076
94790
|
}
|
|
94077
94791
|
const lineNum = finding.location.line;
|
|
94078
94792
|
try {
|
|
94079
|
-
const content =
|
|
94793
|
+
const content = fs88.readFileSync(finding.location.file, "utf-8");
|
|
94080
94794
|
const lines = content.split(`
|
|
94081
94795
|
`);
|
|
94082
94796
|
const idx = lineNum - 1;
|
|
@@ -94086,7 +94800,7 @@ function fingerprintFinding(finding, directory, occurrenceIndex) {
|
|
|
94086
94800
|
getLine(lines, idx + 1)
|
|
94087
94801
|
].join(`
|
|
94088
94802
|
`);
|
|
94089
|
-
const hash3 =
|
|
94803
|
+
const hash3 = crypto10.createHash("sha256").update(window2).digest("hex").slice(0, 16);
|
|
94090
94804
|
return {
|
|
94091
94805
|
fingerprint: `${relFile}|${finding.rule_id}|${hash3}|#${occurrenceIndex}`,
|
|
94092
94806
|
stable: true
|
|
@@ -94107,7 +94821,7 @@ function assignOccurrenceIndices(findings, directory) {
|
|
|
94107
94821
|
try {
|
|
94108
94822
|
if (relFile.startsWith(".."))
|
|
94109
94823
|
throw new Error("escapes workspace");
|
|
94110
|
-
const content =
|
|
94824
|
+
const content = fs88.readFileSync(finding.location.file, "utf-8");
|
|
94111
94825
|
const lines = content.split(`
|
|
94112
94826
|
`);
|
|
94113
94827
|
const idx = lineNum - 1;
|
|
@@ -94117,14 +94831,14 @@ function assignOccurrenceIndices(findings, directory) {
|
|
|
94117
94831
|
getLine(lines, idx + 1)
|
|
94118
94832
|
].join(`
|
|
94119
94833
|
`);
|
|
94120
|
-
const hash3 =
|
|
94834
|
+
const hash3 = crypto10.createHash("sha256").update(window2).digest("hex").slice(0, 16);
|
|
94121
94835
|
baseKey = `${relFile}|${finding.rule_id}|${hash3}`;
|
|
94122
94836
|
} catch {
|
|
94123
94837
|
baseKey = `${relFile}|${finding.rule_id}|L${lineNum}|UNSTABLE`;
|
|
94124
94838
|
}
|
|
94125
94839
|
const occIdx = countMap.get(baseKey) ?? 0;
|
|
94126
94840
|
countMap.set(baseKey, occIdx + 1);
|
|
94127
|
-
const fp =
|
|
94841
|
+
const fp = _internals46.fingerprintFinding(finding, directory, occIdx);
|
|
94128
94842
|
return {
|
|
94129
94843
|
finding,
|
|
94130
94844
|
index: occIdx,
|
|
@@ -94136,11 +94850,11 @@ function assignOccurrenceIndices(findings, directory) {
|
|
|
94136
94850
|
async function acquireLock2(lockPath) {
|
|
94137
94851
|
for (let attempt = 0;attempt <= LOCK_RETRY_DELAYS_MS.length; attempt++) {
|
|
94138
94852
|
try {
|
|
94139
|
-
const fd =
|
|
94140
|
-
|
|
94853
|
+
const fd = fs88.openSync(lockPath, "wx");
|
|
94854
|
+
fs88.closeSync(fd);
|
|
94141
94855
|
return () => {
|
|
94142
94856
|
try {
|
|
94143
|
-
|
|
94857
|
+
fs88.unlinkSync(lockPath);
|
|
94144
94858
|
} catch {}
|
|
94145
94859
|
};
|
|
94146
94860
|
} catch {
|
|
@@ -94180,20 +94894,20 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
94180
94894
|
message: e instanceof Error ? e.message : "Path validation failed"
|
|
94181
94895
|
};
|
|
94182
94896
|
}
|
|
94183
|
-
|
|
94184
|
-
|
|
94897
|
+
fs88.mkdirSync(path114.dirname(baselinePath), { recursive: true });
|
|
94898
|
+
fs88.mkdirSync(path114.dirname(tempPath), { recursive: true });
|
|
94185
94899
|
const releaseLock = await acquireLock2(lockPath);
|
|
94186
94900
|
try {
|
|
94187
94901
|
let existing = null;
|
|
94188
94902
|
try {
|
|
94189
|
-
const raw =
|
|
94903
|
+
const raw = fs88.readFileSync(baselinePath, "utf-8");
|
|
94190
94904
|
const parsed = JSON.parse(raw);
|
|
94191
94905
|
if (parsed.schema_version === BASELINE_SCHEMA_VERSION) {
|
|
94192
94906
|
existing = parsed;
|
|
94193
94907
|
}
|
|
94194
94908
|
} catch {}
|
|
94195
94909
|
const scannedRelFiles = new Set(scannedFiles.map((f) => normalizeFindingPath(directory, f)));
|
|
94196
|
-
const indexed =
|
|
94910
|
+
const indexed = _internals46.assignOccurrenceIndices(findings, directory);
|
|
94197
94911
|
if (existing && !opts?.force) {
|
|
94198
94912
|
const prunedFingerprints = existing.fingerprints.filter((fp) => {
|
|
94199
94913
|
const relFile = fp.slice(0, fp.indexOf("|"));
|
|
@@ -94246,8 +94960,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
94246
94960
|
message: `Baseline would exceed size cap (${json4.length} bytes > ${MAX_BASELINE_BYTES})`
|
|
94247
94961
|
};
|
|
94248
94962
|
}
|
|
94249
|
-
|
|
94250
|
-
|
|
94963
|
+
fs88.writeFileSync(tempPath, json4, "utf-8");
|
|
94964
|
+
fs88.renameSync(tempPath, baselinePath);
|
|
94251
94965
|
return {
|
|
94252
94966
|
status: "merged",
|
|
94253
94967
|
path: baselinePath,
|
|
@@ -94278,8 +94992,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
94278
94992
|
message: `Baseline would exceed size cap (${json3.length} bytes > ${MAX_BASELINE_BYTES})`
|
|
94279
94993
|
};
|
|
94280
94994
|
}
|
|
94281
|
-
|
|
94282
|
-
|
|
94995
|
+
fs88.writeFileSync(tempPath, json3, "utf-8");
|
|
94996
|
+
fs88.renameSync(tempPath, baselinePath);
|
|
94283
94997
|
return {
|
|
94284
94998
|
status: "written",
|
|
94285
94999
|
path: baselinePath,
|
|
@@ -94304,7 +95018,7 @@ function loadBaseline(directory, phase) {
|
|
|
94304
95018
|
};
|
|
94305
95019
|
}
|
|
94306
95020
|
try {
|
|
94307
|
-
const raw =
|
|
95021
|
+
const raw = fs88.readFileSync(baselinePath, "utf-8");
|
|
94308
95022
|
const parsed = JSON.parse(raw);
|
|
94309
95023
|
if (parsed.schema_version !== BASELINE_SCHEMA_VERSION) {
|
|
94310
95024
|
return {
|
|
@@ -94333,7 +95047,7 @@ function loadBaseline(directory, phase) {
|
|
|
94333
95047
|
};
|
|
94334
95048
|
}
|
|
94335
95049
|
}
|
|
94336
|
-
var
|
|
95050
|
+
var _internals46 = {
|
|
94337
95051
|
fingerprintFinding,
|
|
94338
95052
|
assignOccurrenceIndices,
|
|
94339
95053
|
captureOrMergeBaseline,
|
|
@@ -94352,17 +95066,17 @@ var SEVERITY_ORDER = {
|
|
|
94352
95066
|
};
|
|
94353
95067
|
function shouldSkipFile(filePath) {
|
|
94354
95068
|
try {
|
|
94355
|
-
const stats =
|
|
95069
|
+
const stats = fs89.statSync(filePath);
|
|
94356
95070
|
if (stats.size > MAX_FILE_SIZE_BYTES8) {
|
|
94357
95071
|
return { skip: true, reason: "file too large" };
|
|
94358
95072
|
}
|
|
94359
95073
|
if (stats.size === 0) {
|
|
94360
95074
|
return { skip: true, reason: "empty file" };
|
|
94361
95075
|
}
|
|
94362
|
-
const fd =
|
|
95076
|
+
const fd = fs89.openSync(filePath, "r");
|
|
94363
95077
|
const buffer = Buffer.alloc(8192);
|
|
94364
|
-
const bytesRead =
|
|
94365
|
-
|
|
95078
|
+
const bytesRead = fs89.readSync(fd, buffer, 0, 8192, 0);
|
|
95079
|
+
fs89.closeSync(fd);
|
|
94366
95080
|
if (bytesRead > 0) {
|
|
94367
95081
|
let nullCount = 0;
|
|
94368
95082
|
for (let i2 = 0;i2 < bytesRead; i2++) {
|
|
@@ -94401,7 +95115,7 @@ function countBySeverity(findings) {
|
|
|
94401
95115
|
}
|
|
94402
95116
|
function scanFileWithTierA(filePath, language) {
|
|
94403
95117
|
try {
|
|
94404
|
-
const content =
|
|
95118
|
+
const content = fs89.readFileSync(filePath, "utf-8");
|
|
94405
95119
|
const findings = executeRulesSync(filePath, content, language);
|
|
94406
95120
|
return findings.map((f) => ({
|
|
94407
95121
|
rule_id: f.rule_id,
|
|
@@ -94454,13 +95168,13 @@ async function sastScan(input, directory, config3) {
|
|
|
94454
95168
|
_filesSkipped++;
|
|
94455
95169
|
continue;
|
|
94456
95170
|
}
|
|
94457
|
-
const resolvedPath =
|
|
94458
|
-
const resolvedDirectory =
|
|
94459
|
-
if (!resolvedPath.startsWith(resolvedDirectory +
|
|
95171
|
+
const resolvedPath = path115.isAbsolute(filePath) ? filePath : path115.resolve(directory, filePath);
|
|
95172
|
+
const resolvedDirectory = path115.resolve(directory);
|
|
95173
|
+
if (!resolvedPath.startsWith(resolvedDirectory + path115.sep) && resolvedPath !== resolvedDirectory) {
|
|
94460
95174
|
_filesSkipped++;
|
|
94461
95175
|
continue;
|
|
94462
95176
|
}
|
|
94463
|
-
if (!
|
|
95177
|
+
if (!fs89.existsSync(resolvedPath)) {
|
|
94464
95178
|
_filesSkipped++;
|
|
94465
95179
|
continue;
|
|
94466
95180
|
}
|
|
@@ -94469,7 +95183,7 @@ async function sastScan(input, directory, config3) {
|
|
|
94469
95183
|
_filesSkipped++;
|
|
94470
95184
|
continue;
|
|
94471
95185
|
}
|
|
94472
|
-
const ext =
|
|
95186
|
+
const ext = extname20(resolvedPath).toLowerCase();
|
|
94473
95187
|
const profile = getProfileForFile(resolvedPath);
|
|
94474
95188
|
const langDef = getLanguageForExtension(ext);
|
|
94475
95189
|
if (!profile && !langDef) {
|
|
@@ -94743,11 +95457,11 @@ var sast_scan = createSwarmTool({
|
|
|
94743
95457
|
capture_baseline: safeArgs.capture_baseline,
|
|
94744
95458
|
phase: safeArgs.phase
|
|
94745
95459
|
};
|
|
94746
|
-
const result = await
|
|
95460
|
+
const result = await _internals47.sastScan(input, directory);
|
|
94747
95461
|
return JSON.stringify(result, null, 2);
|
|
94748
95462
|
}
|
|
94749
95463
|
});
|
|
94750
|
-
var
|
|
95464
|
+
var _internals47 = {
|
|
94751
95465
|
sastScan,
|
|
94752
95466
|
sast_scan
|
|
94753
95467
|
};
|
|
@@ -94771,18 +95485,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
94771
95485
|
let resolved;
|
|
94772
95486
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
94773
95487
|
if (isWinAbs) {
|
|
94774
|
-
resolved =
|
|
94775
|
-
} else if (
|
|
94776
|
-
resolved =
|
|
95488
|
+
resolved = path116.win32.resolve(inputPath);
|
|
95489
|
+
} else if (path116.isAbsolute(inputPath)) {
|
|
95490
|
+
resolved = path116.resolve(inputPath);
|
|
94777
95491
|
} else {
|
|
94778
|
-
resolved =
|
|
95492
|
+
resolved = path116.resolve(baseDir, inputPath);
|
|
94779
95493
|
}
|
|
94780
|
-
const workspaceResolved =
|
|
95494
|
+
const workspaceResolved = path116.resolve(workspaceDir);
|
|
94781
95495
|
let relative24;
|
|
94782
95496
|
if (isWinAbs) {
|
|
94783
|
-
relative24 =
|
|
95497
|
+
relative24 = path116.win32.relative(workspaceResolved, resolved);
|
|
94784
95498
|
} else {
|
|
94785
|
-
relative24 =
|
|
95499
|
+
relative24 = path116.relative(workspaceResolved, resolved);
|
|
94786
95500
|
}
|
|
94787
95501
|
if (relative24.startsWith("..")) {
|
|
94788
95502
|
return "path traversal detected";
|
|
@@ -94847,7 +95561,7 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
94847
95561
|
if (typeof file3 !== "string") {
|
|
94848
95562
|
continue;
|
|
94849
95563
|
}
|
|
94850
|
-
const resolvedPath =
|
|
95564
|
+
const resolvedPath = path116.resolve(file3);
|
|
94851
95565
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
94852
95566
|
if (validationError) {
|
|
94853
95567
|
continue;
|
|
@@ -95004,7 +95718,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
95004
95718
|
skippedFiles++;
|
|
95005
95719
|
continue;
|
|
95006
95720
|
}
|
|
95007
|
-
const resolvedPath =
|
|
95721
|
+
const resolvedPath = path116.resolve(file3);
|
|
95008
95722
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
95009
95723
|
if (validationError) {
|
|
95010
95724
|
skippedFiles++;
|
|
@@ -95022,14 +95736,14 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
95022
95736
|
};
|
|
95023
95737
|
}
|
|
95024
95738
|
for (const file3 of validatedFiles) {
|
|
95025
|
-
const ext =
|
|
95739
|
+
const ext = path116.extname(file3).toLowerCase();
|
|
95026
95740
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
95027
95741
|
skippedFiles++;
|
|
95028
95742
|
continue;
|
|
95029
95743
|
}
|
|
95030
95744
|
let stat8;
|
|
95031
95745
|
try {
|
|
95032
|
-
stat8 =
|
|
95746
|
+
stat8 = fs90.statSync(file3);
|
|
95033
95747
|
} catch {
|
|
95034
95748
|
skippedFiles++;
|
|
95035
95749
|
continue;
|
|
@@ -95040,7 +95754,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
95040
95754
|
}
|
|
95041
95755
|
let content;
|
|
95042
95756
|
try {
|
|
95043
|
-
const buffer =
|
|
95757
|
+
const buffer = fs90.readFileSync(file3);
|
|
95044
95758
|
if (buffer.includes(0)) {
|
|
95045
95759
|
skippedFiles++;
|
|
95046
95760
|
continue;
|
|
@@ -95241,7 +95955,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
|
|
|
95241
95955
|
const preexistingFindings = [];
|
|
95242
95956
|
for (const finding of findings) {
|
|
95243
95957
|
const filePath = finding.location.file;
|
|
95244
|
-
const normalised =
|
|
95958
|
+
const normalised = path116.relative(directory, filePath).replace(/\\/g, "/");
|
|
95245
95959
|
const changedLines = changedLineRanges.get(normalised);
|
|
95246
95960
|
if (changedLines?.has(finding.location.line)) {
|
|
95247
95961
|
newFindings.push(finding);
|
|
@@ -95292,7 +96006,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
|
|
|
95292
96006
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
95293
96007
|
continue;
|
|
95294
96008
|
}
|
|
95295
|
-
changedFiles.push(
|
|
96009
|
+
changedFiles.push(path116.resolve(directory, file3));
|
|
95296
96010
|
}
|
|
95297
96011
|
if (changedFiles.length === 0) {
|
|
95298
96012
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -95493,7 +96207,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
95493
96207
|
};
|
|
95494
96208
|
return JSON.stringify(errorResult, null, 2);
|
|
95495
96209
|
}
|
|
95496
|
-
const resolvedDirectory =
|
|
96210
|
+
const resolvedDirectory = path116.resolve(typedArgs.directory);
|
|
95497
96211
|
const workspaceAnchor = resolvedDirectory;
|
|
95498
96212
|
const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
|
|
95499
96213
|
if (dirError) {
|
|
@@ -95534,7 +96248,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
95534
96248
|
});
|
|
95535
96249
|
// src/tools/repo-map.ts
|
|
95536
96250
|
init_zod();
|
|
95537
|
-
import * as
|
|
96251
|
+
import * as path117 from "node:path";
|
|
95538
96252
|
init_path_security();
|
|
95539
96253
|
init_create_tool();
|
|
95540
96254
|
var VALID_ACTIONS = [
|
|
@@ -95559,7 +96273,7 @@ function validateFile(p) {
|
|
|
95559
96273
|
return "file contains control characters";
|
|
95560
96274
|
if (containsPathTraversal(p))
|
|
95561
96275
|
return "file contains path traversal";
|
|
95562
|
-
if (
|
|
96276
|
+
if (path117.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
|
|
95563
96277
|
return "file must be a workspace-relative path, not absolute";
|
|
95564
96278
|
}
|
|
95565
96279
|
return null;
|
|
@@ -95582,8 +96296,8 @@ function ok(action, payload) {
|
|
|
95582
96296
|
}
|
|
95583
96297
|
function toRelativeGraphPath(input, workspaceRoot) {
|
|
95584
96298
|
const normalized = input.replace(/\\/g, "/");
|
|
95585
|
-
if (
|
|
95586
|
-
const rel =
|
|
96299
|
+
if (path117.isAbsolute(normalized)) {
|
|
96300
|
+
const rel = path117.relative(workspaceRoot, normalized).replace(/\\/g, "/");
|
|
95587
96301
|
return normalizeGraphPath2(rel);
|
|
95588
96302
|
}
|
|
95589
96303
|
return normalizeGraphPath2(normalized);
|
|
@@ -95727,8 +96441,8 @@ var repo_map = createSwarmTool({
|
|
|
95727
96441
|
// src/tools/req-coverage.ts
|
|
95728
96442
|
init_zod();
|
|
95729
96443
|
init_create_tool();
|
|
95730
|
-
import * as
|
|
95731
|
-
import * as
|
|
96444
|
+
import * as fs91 from "node:fs";
|
|
96445
|
+
import * as path118 from "node:path";
|
|
95732
96446
|
var SPEC_FILE = ".swarm/spec.md";
|
|
95733
96447
|
var EVIDENCE_DIR4 = ".swarm/evidence";
|
|
95734
96448
|
var OBLIGATION_KEYWORDS = ["MUST", "SHOULD", "SHALL"];
|
|
@@ -95787,19 +96501,19 @@ function extractObligationAndText(id, lineText) {
|
|
|
95787
96501
|
var PHASE_TASK_ID_REGEX = /^\d+\.\d+(\.\d+)*$/;
|
|
95788
96502
|
function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
95789
96503
|
const touchedFiles = new Set;
|
|
95790
|
-
if (!
|
|
96504
|
+
if (!fs91.existsSync(evidenceDir) || !fs91.statSync(evidenceDir).isDirectory()) {
|
|
95791
96505
|
return [];
|
|
95792
96506
|
}
|
|
95793
96507
|
let entries;
|
|
95794
96508
|
try {
|
|
95795
|
-
entries =
|
|
96509
|
+
entries = fs91.readdirSync(evidenceDir);
|
|
95796
96510
|
} catch {
|
|
95797
96511
|
return [];
|
|
95798
96512
|
}
|
|
95799
96513
|
for (const entry of entries) {
|
|
95800
|
-
const entryPath =
|
|
96514
|
+
const entryPath = path118.join(evidenceDir, entry);
|
|
95801
96515
|
try {
|
|
95802
|
-
const stat8 =
|
|
96516
|
+
const stat8 = fs91.statSync(entryPath);
|
|
95803
96517
|
if (!stat8.isDirectory()) {
|
|
95804
96518
|
continue;
|
|
95805
96519
|
}
|
|
@@ -95813,14 +96527,14 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
95813
96527
|
if (entryPhase !== String(phase)) {
|
|
95814
96528
|
continue;
|
|
95815
96529
|
}
|
|
95816
|
-
const evidenceFilePath =
|
|
96530
|
+
const evidenceFilePath = path118.join(entryPath, "evidence.json");
|
|
95817
96531
|
try {
|
|
95818
|
-
const resolvedPath =
|
|
95819
|
-
const evidenceDirResolved =
|
|
95820
|
-
if (!resolvedPath.startsWith(evidenceDirResolved +
|
|
96532
|
+
const resolvedPath = path118.resolve(evidenceFilePath);
|
|
96533
|
+
const evidenceDirResolved = path118.resolve(evidenceDir);
|
|
96534
|
+
if (!resolvedPath.startsWith(evidenceDirResolved + path118.sep)) {
|
|
95821
96535
|
continue;
|
|
95822
96536
|
}
|
|
95823
|
-
const stat8 =
|
|
96537
|
+
const stat8 = fs91.lstatSync(evidenceFilePath);
|
|
95824
96538
|
if (!stat8.isFile()) {
|
|
95825
96539
|
continue;
|
|
95826
96540
|
}
|
|
@@ -95832,7 +96546,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
95832
96546
|
}
|
|
95833
96547
|
let content;
|
|
95834
96548
|
try {
|
|
95835
|
-
content =
|
|
96549
|
+
content = fs91.readFileSync(evidenceFilePath, "utf-8");
|
|
95836
96550
|
} catch {
|
|
95837
96551
|
continue;
|
|
95838
96552
|
}
|
|
@@ -95851,7 +96565,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
95851
96565
|
if (Array.isArray(diffEntry.files_changed)) {
|
|
95852
96566
|
for (const file3 of diffEntry.files_changed) {
|
|
95853
96567
|
if (typeof file3 === "string") {
|
|
95854
|
-
touchedFiles.add(
|
|
96568
|
+
touchedFiles.add(path118.resolve(cwd, file3));
|
|
95855
96569
|
}
|
|
95856
96570
|
}
|
|
95857
96571
|
}
|
|
@@ -95864,12 +96578,12 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
95864
96578
|
}
|
|
95865
96579
|
function searchFileForKeywords(filePath, keywords, cwd) {
|
|
95866
96580
|
try {
|
|
95867
|
-
const resolvedPath =
|
|
95868
|
-
const cwdResolved =
|
|
96581
|
+
const resolvedPath = path118.resolve(filePath);
|
|
96582
|
+
const cwdResolved = path118.resolve(cwd);
|
|
95869
96583
|
if (!resolvedPath.startsWith(cwdResolved)) {
|
|
95870
96584
|
return false;
|
|
95871
96585
|
}
|
|
95872
|
-
const content =
|
|
96586
|
+
const content = fs91.readFileSync(resolvedPath, "utf-8");
|
|
95873
96587
|
for (const keyword of keywords) {
|
|
95874
96588
|
const regex = new RegExp(`\\b${keyword}\\b`, "i");
|
|
95875
96589
|
if (regex.test(content)) {
|
|
@@ -95999,10 +96713,10 @@ var req_coverage = createSwarmTool({
|
|
|
95999
96713
|
}, null, 2);
|
|
96000
96714
|
}
|
|
96001
96715
|
const cwd = inputDirectory || directory;
|
|
96002
|
-
const specPath =
|
|
96716
|
+
const specPath = path118.join(cwd, SPEC_FILE);
|
|
96003
96717
|
let specContent;
|
|
96004
96718
|
try {
|
|
96005
|
-
specContent =
|
|
96719
|
+
specContent = fs91.readFileSync(specPath, "utf-8");
|
|
96006
96720
|
} catch (readError) {
|
|
96007
96721
|
return JSON.stringify({
|
|
96008
96722
|
success: false,
|
|
@@ -96026,7 +96740,7 @@ var req_coverage = createSwarmTool({
|
|
|
96026
96740
|
message: "No FR requirements found in spec.md"
|
|
96027
96741
|
}, null, 2);
|
|
96028
96742
|
}
|
|
96029
|
-
const evidenceDir =
|
|
96743
|
+
const evidenceDir = path118.join(cwd, EVIDENCE_DIR4);
|
|
96030
96744
|
const touchedFiles = readTouchedFiles(evidenceDir, phase, cwd);
|
|
96031
96745
|
const analyzedRequirements = [];
|
|
96032
96746
|
let coveredCount = 0;
|
|
@@ -96052,12 +96766,12 @@ var req_coverage = createSwarmTool({
|
|
|
96052
96766
|
requirements: analyzedRequirements
|
|
96053
96767
|
};
|
|
96054
96768
|
const reportFilename = `req-coverage-phase-${phase}.json`;
|
|
96055
|
-
const reportPath =
|
|
96769
|
+
const reportPath = path118.join(evidenceDir, reportFilename);
|
|
96056
96770
|
try {
|
|
96057
|
-
if (!
|
|
96058
|
-
|
|
96771
|
+
if (!fs91.existsSync(evidenceDir)) {
|
|
96772
|
+
fs91.mkdirSync(evidenceDir, { recursive: true });
|
|
96059
96773
|
}
|
|
96060
|
-
|
|
96774
|
+
fs91.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8");
|
|
96061
96775
|
} catch (writeError) {
|
|
96062
96776
|
console.warn(`Failed to write coverage report: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
96063
96777
|
}
|
|
@@ -96138,9 +96852,9 @@ init_zod();
|
|
|
96138
96852
|
init_plan_schema();
|
|
96139
96853
|
init_qa_gate_profile();
|
|
96140
96854
|
init_file_locks();
|
|
96141
|
-
import * as
|
|
96142
|
-
import * as
|
|
96143
|
-
import * as
|
|
96855
|
+
import * as crypto11 from "node:crypto";
|
|
96856
|
+
import * as fs92 from "node:fs";
|
|
96857
|
+
import * as path119 from "node:path";
|
|
96144
96858
|
init_ledger();
|
|
96145
96859
|
init_manager();
|
|
96146
96860
|
init_state();
|
|
@@ -96218,17 +96932,17 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
96218
96932
|
};
|
|
96219
96933
|
}
|
|
96220
96934
|
if (args2.working_directory && fallbackDir) {
|
|
96221
|
-
const resolvedTarget =
|
|
96222
|
-
const resolvedRoot =
|
|
96935
|
+
const resolvedTarget = path119.resolve(args2.working_directory);
|
|
96936
|
+
const resolvedRoot = path119.resolve(fallbackDir);
|
|
96223
96937
|
let fallbackExists = false;
|
|
96224
96938
|
try {
|
|
96225
|
-
|
|
96939
|
+
fs92.accessSync(resolvedRoot, fs92.constants.F_OK);
|
|
96226
96940
|
fallbackExists = true;
|
|
96227
96941
|
} catch {
|
|
96228
96942
|
fallbackExists = false;
|
|
96229
96943
|
}
|
|
96230
96944
|
if (fallbackExists) {
|
|
96231
|
-
const isSubdirectory = resolvedTarget.startsWith(resolvedRoot +
|
|
96945
|
+
const isSubdirectory = resolvedTarget.startsWith(resolvedRoot + path119.sep);
|
|
96232
96946
|
if (isSubdirectory) {
|
|
96233
96947
|
return {
|
|
96234
96948
|
success: false,
|
|
@@ -96244,12 +96958,12 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
96244
96958
|
let specMtime;
|
|
96245
96959
|
let specHash;
|
|
96246
96960
|
if (process.env.SWARM_SKIP_SPEC_GATE !== "1") {
|
|
96247
|
-
const specPath =
|
|
96961
|
+
const specPath = path119.join(targetWorkspace, ".swarm", "spec.md");
|
|
96248
96962
|
try {
|
|
96249
|
-
const stat8 = await
|
|
96963
|
+
const stat8 = await fs92.promises.stat(specPath);
|
|
96250
96964
|
specMtime = stat8.mtime.toISOString();
|
|
96251
|
-
const content = await
|
|
96252
|
-
specHash =
|
|
96965
|
+
const content = await fs92.promises.readFile(specPath, "utf8");
|
|
96966
|
+
specHash = crypto11.createHash("sha256").update(content).digest("hex");
|
|
96253
96967
|
} catch {
|
|
96254
96968
|
return {
|
|
96255
96969
|
success: false,
|
|
@@ -96260,10 +96974,10 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
96260
96974
|
}
|
|
96261
96975
|
}
|
|
96262
96976
|
if (process.env.SWARM_SKIP_GATE_SELECTION !== "1") {
|
|
96263
|
-
const contextPath =
|
|
96977
|
+
const contextPath = path119.join(targetWorkspace, ".swarm", "context.md");
|
|
96264
96978
|
let contextContent = "";
|
|
96265
96979
|
try {
|
|
96266
|
-
contextContent = await
|
|
96980
|
+
contextContent = await fs92.promises.readFile(contextPath, "utf8");
|
|
96267
96981
|
} catch {}
|
|
96268
96982
|
const hasPendingSection = contextContent.includes("## Pending QA Gate Selection");
|
|
96269
96983
|
if (!hasPendingSection) {
|
|
@@ -96517,14 +97231,14 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
96517
97231
|
}
|
|
96518
97232
|
await writeCheckpoint(dir).catch(() => {});
|
|
96519
97233
|
try {
|
|
96520
|
-
const markerPath =
|
|
97234
|
+
const markerPath = path119.join(dir, ".swarm", ".plan-write-marker");
|
|
96521
97235
|
const marker = JSON.stringify({
|
|
96522
97236
|
source: "save_plan",
|
|
96523
97237
|
timestamp: new Date().toISOString(),
|
|
96524
97238
|
phases_count: plan.phases.length,
|
|
96525
97239
|
tasks_count: tasksCount
|
|
96526
97240
|
});
|
|
96527
|
-
await
|
|
97241
|
+
await fs92.promises.writeFile(markerPath, marker, "utf8");
|
|
96528
97242
|
} catch {}
|
|
96529
97243
|
const warnings = [];
|
|
96530
97244
|
let criticReviewFound = false;
|
|
@@ -96540,7 +97254,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
96540
97254
|
return {
|
|
96541
97255
|
success: true,
|
|
96542
97256
|
message: "Plan saved successfully",
|
|
96543
|
-
plan_path:
|
|
97257
|
+
plan_path: path119.join(dir, ".swarm", "plan.json"),
|
|
96544
97258
|
phases_count: plan.phases.length,
|
|
96545
97259
|
tasks_count: tasksCount,
|
|
96546
97260
|
...resolvedProfile !== undefined ? { execution_profile: resolvedProfile } : {},
|
|
@@ -96604,8 +97318,8 @@ var save_plan = createSwarmTool({
|
|
|
96604
97318
|
// src/tools/sbom-generate.ts
|
|
96605
97319
|
init_zod();
|
|
96606
97320
|
init_manager2();
|
|
96607
|
-
import * as
|
|
96608
|
-
import * as
|
|
97321
|
+
import * as fs93 from "node:fs";
|
|
97322
|
+
import * as path120 from "node:path";
|
|
96609
97323
|
|
|
96610
97324
|
// src/sbom/detectors/index.ts
|
|
96611
97325
|
init_utils();
|
|
@@ -97453,9 +98167,9 @@ function findManifestFiles(rootDir) {
|
|
|
97453
98167
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
97454
98168
|
function searchDir(dir) {
|
|
97455
98169
|
try {
|
|
97456
|
-
const entries =
|
|
98170
|
+
const entries = fs93.readdirSync(dir, { withFileTypes: true });
|
|
97457
98171
|
for (const entry of entries) {
|
|
97458
|
-
const fullPath =
|
|
98172
|
+
const fullPath = path120.join(dir, entry.name);
|
|
97459
98173
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
97460
98174
|
continue;
|
|
97461
98175
|
}
|
|
@@ -97464,7 +98178,7 @@ function findManifestFiles(rootDir) {
|
|
|
97464
98178
|
} else if (entry.isFile()) {
|
|
97465
98179
|
for (const pattern of patterns) {
|
|
97466
98180
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
97467
|
-
manifestFiles.push(
|
|
98181
|
+
manifestFiles.push(path120.relative(rootDir, fullPath));
|
|
97468
98182
|
break;
|
|
97469
98183
|
}
|
|
97470
98184
|
}
|
|
@@ -97480,13 +98194,13 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
97480
98194
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
97481
98195
|
for (const dir of directories) {
|
|
97482
98196
|
try {
|
|
97483
|
-
const entries =
|
|
98197
|
+
const entries = fs93.readdirSync(dir, { withFileTypes: true });
|
|
97484
98198
|
for (const entry of entries) {
|
|
97485
|
-
const fullPath =
|
|
98199
|
+
const fullPath = path120.join(dir, entry.name);
|
|
97486
98200
|
if (entry.isFile()) {
|
|
97487
98201
|
for (const pattern of patterns) {
|
|
97488
98202
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
97489
|
-
found.push(
|
|
98203
|
+
found.push(path120.relative(workingDir, fullPath));
|
|
97490
98204
|
break;
|
|
97491
98205
|
}
|
|
97492
98206
|
}
|
|
@@ -97499,11 +98213,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
97499
98213
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
97500
98214
|
const dirs = new Set;
|
|
97501
98215
|
for (const file3 of changedFiles) {
|
|
97502
|
-
let currentDir =
|
|
98216
|
+
let currentDir = path120.dirname(file3);
|
|
97503
98217
|
while (true) {
|
|
97504
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
97505
|
-
dirs.add(
|
|
97506
|
-
const parent =
|
|
98218
|
+
if (currentDir && currentDir !== "." && currentDir !== path120.sep) {
|
|
98219
|
+
dirs.add(path120.join(workingDir, currentDir));
|
|
98220
|
+
const parent = path120.dirname(currentDir);
|
|
97507
98221
|
if (parent === currentDir)
|
|
97508
98222
|
break;
|
|
97509
98223
|
currentDir = parent;
|
|
@@ -97517,7 +98231,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
97517
98231
|
}
|
|
97518
98232
|
function ensureOutputDir(outputDir) {
|
|
97519
98233
|
try {
|
|
97520
|
-
|
|
98234
|
+
fs93.mkdirSync(outputDir, { recursive: true });
|
|
97521
98235
|
} catch (error93) {
|
|
97522
98236
|
if (!error93 || error93.code !== "EEXIST") {
|
|
97523
98237
|
throw error93;
|
|
@@ -97587,7 +98301,7 @@ var sbom_generate = createSwarmTool({
|
|
|
97587
98301
|
const changedFiles = obj.changed_files;
|
|
97588
98302
|
const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
|
|
97589
98303
|
const workingDir = directory;
|
|
97590
|
-
const outputDir =
|
|
98304
|
+
const outputDir = path120.isAbsolute(relativeOutputDir) ? relativeOutputDir : path120.join(workingDir, relativeOutputDir);
|
|
97591
98305
|
let manifestFiles = [];
|
|
97592
98306
|
if (scope === "all") {
|
|
97593
98307
|
manifestFiles = findManifestFiles(workingDir);
|
|
@@ -97610,11 +98324,11 @@ var sbom_generate = createSwarmTool({
|
|
|
97610
98324
|
const processedFiles = [];
|
|
97611
98325
|
for (const manifestFile of manifestFiles) {
|
|
97612
98326
|
try {
|
|
97613
|
-
const fullPath =
|
|
97614
|
-
if (!
|
|
98327
|
+
const fullPath = path120.isAbsolute(manifestFile) ? manifestFile : path120.join(workingDir, manifestFile);
|
|
98328
|
+
if (!fs93.existsSync(fullPath)) {
|
|
97615
98329
|
continue;
|
|
97616
98330
|
}
|
|
97617
|
-
const content =
|
|
98331
|
+
const content = fs93.readFileSync(fullPath, "utf-8");
|
|
97618
98332
|
const components = detectComponents(manifestFile, content);
|
|
97619
98333
|
processedFiles.push(manifestFile);
|
|
97620
98334
|
if (components.length > 0) {
|
|
@@ -97627,8 +98341,8 @@ var sbom_generate = createSwarmTool({
|
|
|
97627
98341
|
const bom = generateCycloneDX(allComponents);
|
|
97628
98342
|
const bomJson = serializeCycloneDX(bom);
|
|
97629
98343
|
const filename = generateSbomFilename();
|
|
97630
|
-
const outputPath =
|
|
97631
|
-
|
|
98344
|
+
const outputPath = path120.join(outputDir, filename);
|
|
98345
|
+
fs93.writeFileSync(outputPath, bomJson, "utf-8");
|
|
97632
98346
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
97633
98347
|
try {
|
|
97634
98348
|
const timestamp = new Date().toISOString();
|
|
@@ -97670,8 +98384,8 @@ var sbom_generate = createSwarmTool({
|
|
|
97670
98384
|
// src/tools/schema-drift.ts
|
|
97671
98385
|
init_zod();
|
|
97672
98386
|
init_create_tool();
|
|
97673
|
-
import * as
|
|
97674
|
-
import * as
|
|
98387
|
+
import * as fs94 from "node:fs";
|
|
98388
|
+
import * as path121 from "node:path";
|
|
97675
98389
|
var SPEC_CANDIDATES = [
|
|
97676
98390
|
"openapi.json",
|
|
97677
98391
|
"openapi.yaml",
|
|
@@ -97703,28 +98417,28 @@ function normalizePath4(p) {
|
|
|
97703
98417
|
}
|
|
97704
98418
|
function discoverSpecFile(cwd, specFileArg) {
|
|
97705
98419
|
if (specFileArg) {
|
|
97706
|
-
const resolvedPath =
|
|
97707
|
-
const normalizedCwd = cwd.endsWith(
|
|
98420
|
+
const resolvedPath = path121.resolve(cwd, specFileArg);
|
|
98421
|
+
const normalizedCwd = cwd.endsWith(path121.sep) ? cwd : cwd + path121.sep;
|
|
97708
98422
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
97709
98423
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
97710
98424
|
}
|
|
97711
|
-
const ext =
|
|
98425
|
+
const ext = path121.extname(resolvedPath).toLowerCase();
|
|
97712
98426
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
97713
98427
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
97714
98428
|
}
|
|
97715
|
-
const stats =
|
|
98429
|
+
const stats = fs94.statSync(resolvedPath);
|
|
97716
98430
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
97717
98431
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
97718
98432
|
}
|
|
97719
|
-
if (!
|
|
98433
|
+
if (!fs94.existsSync(resolvedPath)) {
|
|
97720
98434
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
97721
98435
|
}
|
|
97722
98436
|
return resolvedPath;
|
|
97723
98437
|
}
|
|
97724
98438
|
for (const candidate of SPEC_CANDIDATES) {
|
|
97725
|
-
const candidatePath =
|
|
97726
|
-
if (
|
|
97727
|
-
const stats =
|
|
98439
|
+
const candidatePath = path121.resolve(cwd, candidate);
|
|
98440
|
+
if (fs94.existsSync(candidatePath)) {
|
|
98441
|
+
const stats = fs94.statSync(candidatePath);
|
|
97728
98442
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
97729
98443
|
return candidatePath;
|
|
97730
98444
|
}
|
|
@@ -97733,8 +98447,8 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
97733
98447
|
return null;
|
|
97734
98448
|
}
|
|
97735
98449
|
function parseSpec(specFile) {
|
|
97736
|
-
const content =
|
|
97737
|
-
const ext =
|
|
98450
|
+
const content = fs94.readFileSync(specFile, "utf-8");
|
|
98451
|
+
const ext = path121.extname(specFile).toLowerCase();
|
|
97738
98452
|
if (ext === ".json") {
|
|
97739
98453
|
return parseJsonSpec(content);
|
|
97740
98454
|
}
|
|
@@ -97805,12 +98519,12 @@ function extractRoutes(cwd) {
|
|
|
97805
98519
|
function walkDir(dir) {
|
|
97806
98520
|
let entries;
|
|
97807
98521
|
try {
|
|
97808
|
-
entries =
|
|
98522
|
+
entries = fs94.readdirSync(dir, { withFileTypes: true });
|
|
97809
98523
|
} catch {
|
|
97810
98524
|
return;
|
|
97811
98525
|
}
|
|
97812
98526
|
for (const entry of entries) {
|
|
97813
|
-
const fullPath =
|
|
98527
|
+
const fullPath = path121.join(dir, entry.name);
|
|
97814
98528
|
if (entry.isSymbolicLink()) {
|
|
97815
98529
|
continue;
|
|
97816
98530
|
}
|
|
@@ -97820,7 +98534,7 @@ function extractRoutes(cwd) {
|
|
|
97820
98534
|
}
|
|
97821
98535
|
walkDir(fullPath);
|
|
97822
98536
|
} else if (entry.isFile()) {
|
|
97823
|
-
const ext =
|
|
98537
|
+
const ext = path121.extname(entry.name).toLowerCase();
|
|
97824
98538
|
const baseName = entry.name.toLowerCase();
|
|
97825
98539
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
97826
98540
|
continue;
|
|
@@ -97838,7 +98552,7 @@ function extractRoutes(cwd) {
|
|
|
97838
98552
|
}
|
|
97839
98553
|
function extractRoutesFromFile(filePath) {
|
|
97840
98554
|
const routes = [];
|
|
97841
|
-
const content =
|
|
98555
|
+
const content = fs94.readFileSync(filePath, "utf-8");
|
|
97842
98556
|
const lines = content.split(/\r?\n/);
|
|
97843
98557
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
97844
98558
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -97987,8 +98701,8 @@ init_zod();
|
|
|
97987
98701
|
init_bun_compat();
|
|
97988
98702
|
init_path_security();
|
|
97989
98703
|
init_create_tool();
|
|
97990
|
-
import * as
|
|
97991
|
-
import * as
|
|
98704
|
+
import * as fs95 from "node:fs";
|
|
98705
|
+
import * as path122 from "node:path";
|
|
97992
98706
|
var DEFAULT_MAX_RESULTS = 100;
|
|
97993
98707
|
var DEFAULT_MAX_LINES = 200;
|
|
97994
98708
|
var REGEX_TIMEOUT_MS = 5000;
|
|
@@ -98024,11 +98738,11 @@ function containsWindowsAttacks3(str) {
|
|
|
98024
98738
|
}
|
|
98025
98739
|
function isPathInWorkspace3(filePath, workspace) {
|
|
98026
98740
|
try {
|
|
98027
|
-
const resolvedPath =
|
|
98028
|
-
const realWorkspace =
|
|
98029
|
-
const realResolvedPath =
|
|
98030
|
-
const relativePath =
|
|
98031
|
-
if (relativePath.startsWith("..") ||
|
|
98741
|
+
const resolvedPath = path122.resolve(workspace, filePath);
|
|
98742
|
+
const realWorkspace = fs95.realpathSync(workspace);
|
|
98743
|
+
const realResolvedPath = fs95.realpathSync(resolvedPath);
|
|
98744
|
+
const relativePath = path122.relative(realWorkspace, realResolvedPath);
|
|
98745
|
+
if (relativePath.startsWith("..") || path122.isAbsolute(relativePath)) {
|
|
98032
98746
|
return false;
|
|
98033
98747
|
}
|
|
98034
98748
|
return true;
|
|
@@ -98041,12 +98755,12 @@ function validatePathForRead2(filePath, workspace) {
|
|
|
98041
98755
|
}
|
|
98042
98756
|
function findRgInEnvPath() {
|
|
98043
98757
|
const searchPath = process.env.PATH ?? "";
|
|
98044
|
-
for (const dir of searchPath.split(
|
|
98758
|
+
for (const dir of searchPath.split(path122.delimiter)) {
|
|
98045
98759
|
if (!dir)
|
|
98046
98760
|
continue;
|
|
98047
98761
|
const isWindows = process.platform === "win32";
|
|
98048
|
-
const candidate =
|
|
98049
|
-
if (
|
|
98762
|
+
const candidate = path122.join(dir, isWindows ? "rg.exe" : "rg");
|
|
98763
|
+
if (fs95.existsSync(candidate))
|
|
98050
98764
|
return candidate;
|
|
98051
98765
|
}
|
|
98052
98766
|
return null;
|
|
@@ -98173,10 +98887,10 @@ function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
|
|
|
98173
98887
|
return files;
|
|
98174
98888
|
}
|
|
98175
98889
|
try {
|
|
98176
|
-
const entries =
|
|
98890
|
+
const entries = fs95.readdirSync(dir, { withFileTypes: true });
|
|
98177
98891
|
for (const entry of entries) {
|
|
98178
|
-
const fullPath =
|
|
98179
|
-
const relativePath =
|
|
98892
|
+
const fullPath = path122.join(dir, entry.name);
|
|
98893
|
+
const relativePath = path122.relative(workspace, fullPath);
|
|
98180
98894
|
if (!validatePathForRead2(fullPath, workspace)) {
|
|
98181
98895
|
continue;
|
|
98182
98896
|
}
|
|
@@ -98217,13 +98931,13 @@ async function fallbackSearch(opts) {
|
|
|
98217
98931
|
const matches = [];
|
|
98218
98932
|
let total = 0;
|
|
98219
98933
|
for (const file3 of files) {
|
|
98220
|
-
const fullPath =
|
|
98934
|
+
const fullPath = path122.join(opts.workspace, file3);
|
|
98221
98935
|
if (!validatePathForRead2(fullPath, opts.workspace)) {
|
|
98222
98936
|
continue;
|
|
98223
98937
|
}
|
|
98224
98938
|
let stats;
|
|
98225
98939
|
try {
|
|
98226
|
-
stats =
|
|
98940
|
+
stats = fs95.statSync(fullPath);
|
|
98227
98941
|
if (stats.size > MAX_FILE_SIZE_BYTES10) {
|
|
98228
98942
|
continue;
|
|
98229
98943
|
}
|
|
@@ -98232,7 +98946,7 @@ async function fallbackSearch(opts) {
|
|
|
98232
98946
|
}
|
|
98233
98947
|
let content;
|
|
98234
98948
|
try {
|
|
98235
|
-
content =
|
|
98949
|
+
content = fs95.readFileSync(fullPath, "utf-8");
|
|
98236
98950
|
} catch {
|
|
98237
98951
|
continue;
|
|
98238
98952
|
}
|
|
@@ -98344,7 +99058,7 @@ var search = createSwarmTool({
|
|
|
98344
99058
|
message: "Exclude pattern contains invalid Windows-specific sequence"
|
|
98345
99059
|
}, null, 2);
|
|
98346
99060
|
}
|
|
98347
|
-
if (!
|
|
99061
|
+
if (!fs95.existsSync(directory)) {
|
|
98348
99062
|
return JSON.stringify({
|
|
98349
99063
|
error: true,
|
|
98350
99064
|
type: "unknown",
|
|
@@ -98585,7 +99299,7 @@ init_config();
|
|
|
98585
99299
|
init_schema();
|
|
98586
99300
|
init_create_tool();
|
|
98587
99301
|
import { mkdir as mkdir19, rename as rename8, writeFile as writeFile15 } from "node:fs/promises";
|
|
98588
|
-
import * as
|
|
99302
|
+
import * as path123 from "node:path";
|
|
98589
99303
|
var MAX_SPEC_BYTES = 256 * 1024;
|
|
98590
99304
|
var spec_write = createSwarmTool({
|
|
98591
99305
|
description: "Write the canonical project spec to .swarm/spec.md. Atomic write, size-bounded (256 KiB), heading-required. Honors spec_writer.allow_spec_write.",
|
|
@@ -98626,14 +99340,14 @@ var spec_write = createSwarmTool({
|
|
|
98626
99340
|
reason: 'spec must contain at least one top-level "# Heading"'
|
|
98627
99341
|
}, null, 2);
|
|
98628
99342
|
}
|
|
98629
|
-
const target =
|
|
98630
|
-
await mkdir19(
|
|
99343
|
+
const target = path123.join(directory, ".swarm", "spec.md");
|
|
99344
|
+
await mkdir19(path123.dirname(target), { recursive: true });
|
|
98631
99345
|
const tmp = `${target}.tmp-${process.pid}-${Date.now()}`;
|
|
98632
99346
|
let finalContent = content;
|
|
98633
99347
|
if (mode === "append") {
|
|
98634
99348
|
try {
|
|
98635
|
-
const
|
|
98636
|
-
const prior = await
|
|
99349
|
+
const fs96 = await import("node:fs/promises");
|
|
99350
|
+
const prior = await fs96.readFile(target, "utf-8");
|
|
98637
99351
|
finalContent = `${prior.replace(/\s+$/, "")}
|
|
98638
99352
|
|
|
98639
99353
|
${content}
|
|
@@ -98655,14 +99369,14 @@ ${content}
|
|
|
98655
99369
|
init_zod();
|
|
98656
99370
|
init_loader();
|
|
98657
99371
|
import {
|
|
98658
|
-
existsSync as
|
|
98659
|
-
mkdirSync as
|
|
98660
|
-
readFileSync as
|
|
98661
|
-
renameSync as
|
|
99372
|
+
existsSync as existsSync72,
|
|
99373
|
+
mkdirSync as mkdirSync31,
|
|
99374
|
+
readFileSync as readFileSync62,
|
|
99375
|
+
renameSync as renameSync20,
|
|
98662
99376
|
unlinkSync as unlinkSync15,
|
|
98663
|
-
writeFileSync as
|
|
99377
|
+
writeFileSync as writeFileSync24
|
|
98664
99378
|
} from "node:fs";
|
|
98665
|
-
import
|
|
99379
|
+
import path124 from "node:path";
|
|
98666
99380
|
init_create_tool();
|
|
98667
99381
|
init_resolve_working_directory();
|
|
98668
99382
|
var VerdictSchema2 = exports_external.object({
|
|
@@ -98792,9 +99506,9 @@ var submit_phase_council_verdicts = createSwarmTool({
|
|
|
98792
99506
|
}
|
|
98793
99507
|
});
|
|
98794
99508
|
function getPhaseMutationGapFinding(phaseNumber, workingDir) {
|
|
98795
|
-
const mutationGatePath =
|
|
99509
|
+
const mutationGatePath = path124.join(workingDir, ".swarm", "evidence", String(phaseNumber), "mutation-gate.json");
|
|
98796
99510
|
try {
|
|
98797
|
-
const raw =
|
|
99511
|
+
const raw = readFileSync62(mutationGatePath, "utf-8");
|
|
98798
99512
|
const parsed = JSON.parse(raw);
|
|
98799
99513
|
const gateEntry = (parsed.entries ?? []).find((entry) => entry?.type === "mutation-gate");
|
|
98800
99514
|
if (!gateEntry) {
|
|
@@ -98854,9 +99568,9 @@ function getPhaseMutationGapFinding(phaseNumber, workingDir) {
|
|
|
98854
99568
|
}
|
|
98855
99569
|
}
|
|
98856
99570
|
function writePhaseCouncilEvidence(workingDir, synthesis) {
|
|
98857
|
-
const evidenceDir =
|
|
98858
|
-
|
|
98859
|
-
const evidenceFile =
|
|
99571
|
+
const evidenceDir = path124.join(workingDir, ".swarm", "evidence", String(synthesis.phaseNumber));
|
|
99572
|
+
mkdirSync31(evidenceDir, { recursive: true });
|
|
99573
|
+
const evidenceFile = path124.join(evidenceDir, "phase-council.json");
|
|
98860
99574
|
const evidenceBundle = {
|
|
98861
99575
|
entries: [
|
|
98862
99576
|
{
|
|
@@ -98889,10 +99603,10 @@ function writePhaseCouncilEvidence(workingDir, synthesis) {
|
|
|
98889
99603
|
};
|
|
98890
99604
|
const tempFile = `${evidenceFile}.tmp-${Date.now()}`;
|
|
98891
99605
|
try {
|
|
98892
|
-
|
|
98893
|
-
|
|
99606
|
+
writeFileSync24(tempFile, JSON.stringify(evidenceBundle, null, 2), "utf-8");
|
|
99607
|
+
renameSync20(tempFile, evidenceFile);
|
|
98894
99608
|
} finally {
|
|
98895
|
-
if (
|
|
99609
|
+
if (existsSync72(tempFile)) {
|
|
98896
99610
|
unlinkSync15(tempFile);
|
|
98897
99611
|
}
|
|
98898
99612
|
}
|
|
@@ -98941,8 +99655,8 @@ function createSwarmCommandTool(agents) {
|
|
|
98941
99655
|
init_zod();
|
|
98942
99656
|
init_path_security();
|
|
98943
99657
|
init_create_tool();
|
|
98944
|
-
import * as
|
|
98945
|
-
import * as
|
|
99658
|
+
import * as fs96 from "node:fs";
|
|
99659
|
+
import * as path125 from "node:path";
|
|
98946
99660
|
var WINDOWS_RESERVED_NAMES4 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
98947
99661
|
function containsWindowsAttacks4(str) {
|
|
98948
99662
|
if (/:[^\\/]/.test(str))
|
|
@@ -98956,14 +99670,14 @@ function containsWindowsAttacks4(str) {
|
|
|
98956
99670
|
}
|
|
98957
99671
|
function isPathInWorkspace4(filePath, workspace) {
|
|
98958
99672
|
try {
|
|
98959
|
-
const resolvedPath =
|
|
98960
|
-
if (!
|
|
99673
|
+
const resolvedPath = path125.resolve(workspace, filePath);
|
|
99674
|
+
if (!fs96.existsSync(resolvedPath)) {
|
|
98961
99675
|
return true;
|
|
98962
99676
|
}
|
|
98963
|
-
const realWorkspace =
|
|
98964
|
-
const realResolvedPath =
|
|
98965
|
-
const relativePath =
|
|
98966
|
-
if (relativePath.startsWith("..") ||
|
|
99677
|
+
const realWorkspace = fs96.realpathSync(workspace);
|
|
99678
|
+
const realResolvedPath = fs96.realpathSync(resolvedPath);
|
|
99679
|
+
const relativePath = path125.relative(realWorkspace, realResolvedPath);
|
|
99680
|
+
if (relativePath.startsWith("..") || path125.isAbsolute(relativePath)) {
|
|
98967
99681
|
return false;
|
|
98968
99682
|
}
|
|
98969
99683
|
return true;
|
|
@@ -99135,7 +99849,7 @@ var suggestPatch = createSwarmTool({
|
|
|
99135
99849
|
message: "changes cannot be empty"
|
|
99136
99850
|
}, null, 2);
|
|
99137
99851
|
}
|
|
99138
|
-
if (!
|
|
99852
|
+
if (!fs96.existsSync(directory)) {
|
|
99139
99853
|
return JSON.stringify({
|
|
99140
99854
|
success: false,
|
|
99141
99855
|
error: true,
|
|
@@ -99171,8 +99885,8 @@ var suggestPatch = createSwarmTool({
|
|
|
99171
99885
|
});
|
|
99172
99886
|
continue;
|
|
99173
99887
|
}
|
|
99174
|
-
const fullPath =
|
|
99175
|
-
if (!
|
|
99888
|
+
const fullPath = path125.resolve(directory, change.file);
|
|
99889
|
+
if (!fs96.existsSync(fullPath)) {
|
|
99176
99890
|
errors5.push({
|
|
99177
99891
|
success: false,
|
|
99178
99892
|
error: true,
|
|
@@ -99186,7 +99900,7 @@ var suggestPatch = createSwarmTool({
|
|
|
99186
99900
|
}
|
|
99187
99901
|
let content;
|
|
99188
99902
|
try {
|
|
99189
|
-
content =
|
|
99903
|
+
content = fs96.readFileSync(fullPath, "utf-8");
|
|
99190
99904
|
} catch (err3) {
|
|
99191
99905
|
errors5.push({
|
|
99192
99906
|
success: false,
|
|
@@ -99474,12 +100188,12 @@ var lean_turbo_acquire_locks = createSwarmTool({
|
|
|
99474
100188
|
// src/tools/lean-turbo-plan-lanes.ts
|
|
99475
100189
|
init_zod();
|
|
99476
100190
|
init_constants();
|
|
99477
|
-
import * as
|
|
99478
|
-
import * as
|
|
100191
|
+
import * as fs98 from "node:fs";
|
|
100192
|
+
import * as path127 from "node:path";
|
|
99479
100193
|
|
|
99480
100194
|
// src/turbo/lean/conflicts.ts
|
|
99481
|
-
import * as
|
|
99482
|
-
import * as
|
|
100195
|
+
import * as fs97 from "node:fs";
|
|
100196
|
+
import * as path126 from "node:path";
|
|
99483
100197
|
var DEFAULT_GLOBAL_FILES = [
|
|
99484
100198
|
"package.json",
|
|
99485
100199
|
"package-lock.json",
|
|
@@ -99606,12 +100320,12 @@ function isProtectedPath2(normalizedPath) {
|
|
|
99606
100320
|
return false;
|
|
99607
100321
|
}
|
|
99608
100322
|
function readTaskScopes(directory, taskId) {
|
|
99609
|
-
const scopePath =
|
|
100323
|
+
const scopePath = path126.join(directory, ".swarm", "scopes", `scope-${taskId}.json`);
|
|
99610
100324
|
try {
|
|
99611
|
-
if (!
|
|
100325
|
+
if (!fs97.existsSync(scopePath)) {
|
|
99612
100326
|
return null;
|
|
99613
100327
|
}
|
|
99614
|
-
const raw =
|
|
100328
|
+
const raw = fs97.readFileSync(scopePath, "utf-8");
|
|
99615
100329
|
const parsed = JSON.parse(raw);
|
|
99616
100330
|
if (!parsed || !Array.isArray(parsed.files)) {
|
|
99617
100331
|
return null;
|
|
@@ -99994,12 +100708,12 @@ function createEmptyPlan(phaseNumber, planId) {
|
|
|
99994
100708
|
// src/tools/lean-turbo-plan-lanes.ts
|
|
99995
100709
|
init_create_tool();
|
|
99996
100710
|
function readPlanJson(directory) {
|
|
99997
|
-
const planPath =
|
|
99998
|
-
if (!
|
|
100711
|
+
const planPath = path127.join(directory, ".swarm", "plan.json");
|
|
100712
|
+
if (!fs98.existsSync(planPath)) {
|
|
99999
100713
|
return null;
|
|
100000
100714
|
}
|
|
100001
100715
|
try {
|
|
100002
|
-
return JSON.parse(
|
|
100716
|
+
return JSON.parse(fs98.readFileSync(planPath, "utf-8"));
|
|
100003
100717
|
} catch {
|
|
100004
100718
|
return null;
|
|
100005
100719
|
}
|
|
@@ -100048,8 +100762,8 @@ init_config();
|
|
|
100048
100762
|
|
|
100049
100763
|
// src/turbo/lean/reviewer.ts
|
|
100050
100764
|
init_state();
|
|
100051
|
-
import * as
|
|
100052
|
-
import * as
|
|
100765
|
+
import * as fs99 from "node:fs/promises";
|
|
100766
|
+
import * as path128 from "node:path";
|
|
100053
100767
|
init_state3();
|
|
100054
100768
|
var DEFAULT_CONFIG3 = {
|
|
100055
100769
|
reviewerAgent: "",
|
|
@@ -100071,7 +100785,7 @@ function resolveDefaultReviewerAgent(generatedAgentNames) {
|
|
|
100071
100785
|
}
|
|
100072
100786
|
async function compileReviewPackage(directory, phase, sessionID, requireDiffSummary) {
|
|
100073
100787
|
const lanes = await listLaneEvidence(directory, phase);
|
|
100074
|
-
const persisted =
|
|
100788
|
+
const persisted = _internals48.readPersisted?.(directory) ?? null;
|
|
100075
100789
|
if (persisted) {
|
|
100076
100790
|
let matchingRunState = null;
|
|
100077
100791
|
for (const sessionState of Object.values(persisted.sessions)) {
|
|
@@ -100165,9 +100879,9 @@ function parseReviewerVerdict(responseText) {
|
|
|
100165
100879
|
return { verdict, reason };
|
|
100166
100880
|
}
|
|
100167
100881
|
async function writeReviewerEvidence(directory, phase, verdict, reason) {
|
|
100168
|
-
const evidenceDir =
|
|
100169
|
-
await
|
|
100170
|
-
const evidencePath =
|
|
100882
|
+
const evidenceDir = path128.join(directory, ".swarm", "evidence", String(phase));
|
|
100883
|
+
await fs99.mkdir(evidenceDir, { recursive: true });
|
|
100884
|
+
const evidencePath = path128.join(evidenceDir, "lean-turbo-reviewer.json");
|
|
100171
100885
|
const content = JSON.stringify({
|
|
100172
100886
|
phase,
|
|
100173
100887
|
verdict,
|
|
@@ -100176,11 +100890,11 @@ async function writeReviewerEvidence(directory, phase, verdict, reason) {
|
|
|
100176
100890
|
}, null, 2);
|
|
100177
100891
|
const tempPath = `${evidencePath}.tmp.${process.pid}.${Date.now()}`;
|
|
100178
100892
|
try {
|
|
100179
|
-
await
|
|
100180
|
-
await
|
|
100893
|
+
await fs99.writeFile(tempPath, content, "utf-8");
|
|
100894
|
+
await fs99.rename(tempPath, evidencePath);
|
|
100181
100895
|
} catch (error93) {
|
|
100182
100896
|
try {
|
|
100183
|
-
await
|
|
100897
|
+
await fs99.unlink(tempPath);
|
|
100184
100898
|
} catch {}
|
|
100185
100899
|
throw error93;
|
|
100186
100900
|
}
|
|
@@ -100263,7 +100977,7 @@ Be specific and evidence-based. Do not approve a phase with unresolved degraded
|
|
|
100263
100977
|
client.session.delete({ path: { id: sessionId } }).catch(() => {});
|
|
100264
100978
|
}
|
|
100265
100979
|
}
|
|
100266
|
-
var
|
|
100980
|
+
var _internals48 = {
|
|
100267
100981
|
compileReviewPackage,
|
|
100268
100982
|
parseReviewerVerdict,
|
|
100269
100983
|
writeReviewerEvidence,
|
|
@@ -100280,28 +100994,28 @@ async function dispatchPhaseReviewer(directory, phase, sessionID, config3) {
|
|
|
100280
100994
|
};
|
|
100281
100995
|
const generatedAgentNames = swarmState.generatedAgentNames;
|
|
100282
100996
|
const agentName = mergedConfig.reviewerAgent || resolveDefaultReviewerAgent(generatedAgentNames);
|
|
100283
|
-
const pkg = await
|
|
100997
|
+
const pkg = await _internals48.compileReviewPackage(directory, phase, sessionID, mergedConfig.requireDiffSummary);
|
|
100284
100998
|
let responseText;
|
|
100285
100999
|
try {
|
|
100286
|
-
responseText = await
|
|
101000
|
+
responseText = await _internals48.dispatchReviewerAgent(directory, pkg, agentName, mergedConfig.timeoutMs);
|
|
100287
101001
|
} catch (error93) {
|
|
100288
|
-
const evidencePath2 = await
|
|
101002
|
+
const evidencePath2 = await _internals48.writeReviewerEvidence(directory, phase, "REJECTED", error93 instanceof Error ? error93.message : String(error93));
|
|
100289
101003
|
return {
|
|
100290
101004
|
verdict: "REJECTED",
|
|
100291
101005
|
reason: `Reviewer dispatch failed: ${error93 instanceof Error ? error93.message : String(error93)}`,
|
|
100292
101006
|
evidencePath: evidencePath2
|
|
100293
101007
|
};
|
|
100294
101008
|
}
|
|
100295
|
-
const parsed =
|
|
101009
|
+
const parsed = _internals48.parseReviewerVerdict(responseText);
|
|
100296
101010
|
if (!parsed) {
|
|
100297
|
-
const evidencePath2 = await
|
|
101011
|
+
const evidencePath2 = await _internals48.writeReviewerEvidence(directory, phase, "REJECTED", "Reviewer response could not be parsed");
|
|
100298
101012
|
return {
|
|
100299
101013
|
verdict: "REJECTED",
|
|
100300
101014
|
reason: "Reviewer response could not be parsed",
|
|
100301
101015
|
evidencePath: evidencePath2
|
|
100302
101016
|
};
|
|
100303
101017
|
}
|
|
100304
|
-
const evidencePath = await
|
|
101018
|
+
const evidencePath = await _internals48.writeReviewerEvidence(directory, phase, parsed.verdict, parsed.reason);
|
|
100305
101019
|
return {
|
|
100306
101020
|
verdict: parsed.verdict,
|
|
100307
101021
|
reason: parsed.reason,
|
|
@@ -100807,7 +101521,7 @@ ${fileList}
|
|
|
100807
101521
|
|
|
100808
101522
|
// src/tools/lean-turbo-run-phase.ts
|
|
100809
101523
|
init_create_tool();
|
|
100810
|
-
var
|
|
101524
|
+
var _internals49 = {
|
|
100811
101525
|
LeanTurboRunner,
|
|
100812
101526
|
loadPluginConfigWithMeta
|
|
100813
101527
|
};
|
|
@@ -100817,9 +101531,9 @@ async function executeLeanTurboRunPhase(args2) {
|
|
|
100817
101531
|
let runError = null;
|
|
100818
101532
|
let runner = null;
|
|
100819
101533
|
try {
|
|
100820
|
-
const { config: config3 } =
|
|
101534
|
+
const { config: config3 } = _internals49.loadPluginConfigWithMeta(directory);
|
|
100821
101535
|
const leanConfig = config3.turbo?.strategy === "lean" ? config3.turbo.lean : undefined;
|
|
100822
|
-
runner = new
|
|
101536
|
+
runner = new _internals49.LeanTurboRunner({
|
|
100823
101537
|
directory,
|
|
100824
101538
|
sessionID,
|
|
100825
101539
|
opencodeClient: swarmState.opencodeClient ?? null,
|
|
@@ -100971,8 +101685,8 @@ var lean_turbo_status = createSwarmTool({
|
|
|
100971
101685
|
// src/tools/lint-spec.ts
|
|
100972
101686
|
init_spec_schema();
|
|
100973
101687
|
init_create_tool();
|
|
100974
|
-
import * as
|
|
100975
|
-
import * as
|
|
101688
|
+
import * as fs100 from "node:fs";
|
|
101689
|
+
import * as path129 from "node:path";
|
|
100976
101690
|
var SPEC_FILE_NAME = "spec.md";
|
|
100977
101691
|
var SWARM_DIR2 = ".swarm";
|
|
100978
101692
|
var OBLIGATION_KEYWORDS2 = ["MUST", "SHALL", "SHOULD", "MAY"];
|
|
@@ -101025,8 +101739,8 @@ var lint_spec = createSwarmTool({
|
|
|
101025
101739
|
async execute(_args, directory) {
|
|
101026
101740
|
const errors5 = [];
|
|
101027
101741
|
const warnings = [];
|
|
101028
|
-
const specPath =
|
|
101029
|
-
if (!
|
|
101742
|
+
const specPath = path129.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
|
|
101743
|
+
if (!fs100.existsSync(specPath)) {
|
|
101030
101744
|
const result2 = {
|
|
101031
101745
|
valid: false,
|
|
101032
101746
|
specMtime: null,
|
|
@@ -101045,12 +101759,12 @@ var lint_spec = createSwarmTool({
|
|
|
101045
101759
|
}
|
|
101046
101760
|
let specMtime = null;
|
|
101047
101761
|
try {
|
|
101048
|
-
const stats =
|
|
101762
|
+
const stats = fs100.statSync(specPath);
|
|
101049
101763
|
specMtime = stats.mtime.toISOString();
|
|
101050
101764
|
} catch {}
|
|
101051
101765
|
let content;
|
|
101052
101766
|
try {
|
|
101053
|
-
content =
|
|
101767
|
+
content = fs100.readFileSync(specPath, "utf-8");
|
|
101054
101768
|
} catch (e) {
|
|
101055
101769
|
const result2 = {
|
|
101056
101770
|
valid: false,
|
|
@@ -101095,13 +101809,13 @@ var lint_spec = createSwarmTool({
|
|
|
101095
101809
|
});
|
|
101096
101810
|
// src/tools/mutation-test.ts
|
|
101097
101811
|
init_zod();
|
|
101098
|
-
import * as
|
|
101099
|
-
import * as
|
|
101812
|
+
import * as fs101 from "node:fs";
|
|
101813
|
+
import * as path131 from "node:path";
|
|
101100
101814
|
|
|
101101
101815
|
// src/mutation/engine.ts
|
|
101102
101816
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
101103
|
-
import { unlinkSync as unlinkSync16, writeFileSync as
|
|
101104
|
-
import * as
|
|
101817
|
+
import { unlinkSync as unlinkSync16, writeFileSync as writeFileSync25 } from "node:fs";
|
|
101818
|
+
import * as path130 from "node:path";
|
|
101105
101819
|
|
|
101106
101820
|
// src/mutation/equivalence.ts
|
|
101107
101821
|
function isStaticallyEquivalent(originalCode, mutatedCode) {
|
|
@@ -101173,7 +101887,7 @@ function isStaticallyEquivalent(originalCode, mutatedCode) {
|
|
|
101173
101887
|
const strippedMutated = stripCode(mutatedCode);
|
|
101174
101888
|
return strippedOriginal === strippedMutated;
|
|
101175
101889
|
}
|
|
101176
|
-
var
|
|
101890
|
+
var _internals50 = {
|
|
101177
101891
|
isStaticallyEquivalent,
|
|
101178
101892
|
checkEquivalence,
|
|
101179
101893
|
batchCheckEquivalence
|
|
@@ -101213,7 +101927,7 @@ async function batchCheckEquivalence(patches, llmJudge) {
|
|
|
101213
101927
|
const results = [];
|
|
101214
101928
|
for (const { patch, originalCode, mutatedCode } of patches) {
|
|
101215
101929
|
try {
|
|
101216
|
-
const result = await
|
|
101930
|
+
const result = await _internals50.checkEquivalence(patch, originalCode, mutatedCode, llmJudge);
|
|
101217
101931
|
results.push(result);
|
|
101218
101932
|
} catch (err3) {
|
|
101219
101933
|
results.push({
|
|
@@ -101241,9 +101955,9 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
|
|
|
101241
101955
|
let patchFile;
|
|
101242
101956
|
try {
|
|
101243
101957
|
const safeId2 = patch.id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
101244
|
-
patchFile =
|
|
101958
|
+
patchFile = path130.join(workingDir, `.mutation_patch_${safeId2}.diff`);
|
|
101245
101959
|
try {
|
|
101246
|
-
|
|
101960
|
+
writeFileSync25(patchFile, patch.patch);
|
|
101247
101961
|
} catch (writeErr) {
|
|
101248
101962
|
error93 = `Failed to write patch file: ${writeErr}`;
|
|
101249
101963
|
outcome = "error";
|
|
@@ -101513,7 +102227,7 @@ async function executeMutationSuite(patches, testCommand, testFiles, workingDir,
|
|
|
101513
102227
|
}
|
|
101514
102228
|
|
|
101515
102229
|
// src/mutation/gate.ts
|
|
101516
|
-
var
|
|
102230
|
+
var _internals51 = {
|
|
101517
102231
|
evaluateMutationGate,
|
|
101518
102232
|
buildTestImprovementPrompt,
|
|
101519
102233
|
buildMessage
|
|
@@ -101534,8 +102248,8 @@ function evaluateMutationGate(report, passThreshold = PASS_THRESHOLD, warnThresh
|
|
|
101534
102248
|
} else {
|
|
101535
102249
|
verdict = "fail";
|
|
101536
102250
|
}
|
|
101537
|
-
const testImprovementPrompt =
|
|
101538
|
-
const message =
|
|
102251
|
+
const testImprovementPrompt = _internals51.buildTestImprovementPrompt(report, passThreshold, verdict);
|
|
102252
|
+
const message = _internals51.buildMessage(verdict, adjustedKillRate, report.killed, report.totalMutants, report.equivalent, warnThreshold);
|
|
101539
102253
|
return {
|
|
101540
102254
|
verdict,
|
|
101541
102255
|
killRate: report.killRate,
|
|
@@ -101640,8 +102354,8 @@ var mutation_test = createSwarmTool({
|
|
|
101640
102354
|
];
|
|
101641
102355
|
for (const filePath of uniquePaths) {
|
|
101642
102356
|
try {
|
|
101643
|
-
const resolvedPath =
|
|
101644
|
-
sourceFiles.set(filePath,
|
|
102357
|
+
const resolvedPath = path131.resolve(cwd, filePath);
|
|
102358
|
+
sourceFiles.set(filePath, fs101.readFileSync(resolvedPath, "utf-8"));
|
|
101645
102359
|
} catch {}
|
|
101646
102360
|
}
|
|
101647
102361
|
const report = await executeMutationSuite(typedArgs.patches, typedArgs.test_command, typedArgs.files, cwd, undefined, undefined, sourceFiles.size > 0 ? sourceFiles : undefined);
|
|
@@ -101659,8 +102373,8 @@ var mutation_test = createSwarmTool({
|
|
|
101659
102373
|
init_zod();
|
|
101660
102374
|
init_manager2();
|
|
101661
102375
|
init_detector();
|
|
101662
|
-
import * as
|
|
101663
|
-
import * as
|
|
102376
|
+
import * as fs102 from "node:fs";
|
|
102377
|
+
import * as path132 from "node:path";
|
|
101664
102378
|
init_create_tool();
|
|
101665
102379
|
var MAX_FILE_SIZE2 = 2 * 1024 * 1024;
|
|
101666
102380
|
var BINARY_CHECK_BYTES = 8192;
|
|
@@ -101726,7 +102440,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
101726
102440
|
if (languages?.length) {
|
|
101727
102441
|
const lowerLangs = languages.map((l) => l.toLowerCase());
|
|
101728
102442
|
filesToCheck = filesToCheck.filter((file3) => {
|
|
101729
|
-
const ext =
|
|
102443
|
+
const ext = path132.extname(file3.path).toLowerCase();
|
|
101730
102444
|
const langDef = getLanguageForExtension(ext);
|
|
101731
102445
|
const fileProfile = getProfileForFile(file3.path);
|
|
101732
102446
|
const langId = fileProfile?.id || langDef?.id;
|
|
@@ -101739,7 +102453,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
101739
102453
|
let skippedCount = 0;
|
|
101740
102454
|
for (const fileInfo of filesToCheck) {
|
|
101741
102455
|
const { path: filePath } = fileInfo;
|
|
101742
|
-
const fullPath =
|
|
102456
|
+
const fullPath = path132.isAbsolute(filePath) ? filePath : path132.join(directory, filePath);
|
|
101743
102457
|
const result = {
|
|
101744
102458
|
path: filePath,
|
|
101745
102459
|
language: "",
|
|
@@ -101769,7 +102483,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
101769
102483
|
}
|
|
101770
102484
|
let content;
|
|
101771
102485
|
try {
|
|
101772
|
-
content =
|
|
102486
|
+
content = fs102.readFileSync(fullPath, "utf8");
|
|
101773
102487
|
} catch {
|
|
101774
102488
|
result.skipped_reason = "file_read_error";
|
|
101775
102489
|
skippedCount++;
|
|
@@ -101788,7 +102502,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
101788
102502
|
results.push(result);
|
|
101789
102503
|
continue;
|
|
101790
102504
|
}
|
|
101791
|
-
const ext =
|
|
102505
|
+
const ext = path132.extname(filePath).toLowerCase();
|
|
101792
102506
|
const langDef = getLanguageForExtension(ext);
|
|
101793
102507
|
result.language = profile?.id || langDef?.id || "unknown";
|
|
101794
102508
|
const errors5 = extractSyntaxErrors(parser, content);
|
|
@@ -101880,8 +102594,8 @@ init_zod();
|
|
|
101880
102594
|
init_utils();
|
|
101881
102595
|
init_create_tool();
|
|
101882
102596
|
init_path_security();
|
|
101883
|
-
import * as
|
|
101884
|
-
import * as
|
|
102597
|
+
import * as fs103 from "node:fs";
|
|
102598
|
+
import * as path133 from "node:path";
|
|
101885
102599
|
var MAX_TEXT_LENGTH = 200;
|
|
101886
102600
|
var MAX_FILE_SIZE_BYTES11 = 1024 * 1024;
|
|
101887
102601
|
var SUPPORTED_EXTENSIONS4 = new Set([
|
|
@@ -101947,9 +102661,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
101947
102661
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
101948
102662
|
}
|
|
101949
102663
|
try {
|
|
101950
|
-
const resolvedPath =
|
|
101951
|
-
const normalizedCwd =
|
|
101952
|
-
const normalizedResolved =
|
|
102664
|
+
const resolvedPath = path133.resolve(paths);
|
|
102665
|
+
const normalizedCwd = path133.resolve(cwd);
|
|
102666
|
+
const normalizedResolved = path133.resolve(resolvedPath);
|
|
101953
102667
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
101954
102668
|
return {
|
|
101955
102669
|
error: "paths must be within the current working directory",
|
|
@@ -101965,13 +102679,13 @@ function validatePathsInput(paths, cwd) {
|
|
|
101965
102679
|
}
|
|
101966
102680
|
}
|
|
101967
102681
|
function isSupportedExtension(filePath) {
|
|
101968
|
-
const ext =
|
|
102682
|
+
const ext = path133.extname(filePath).toLowerCase();
|
|
101969
102683
|
return SUPPORTED_EXTENSIONS4.has(ext);
|
|
101970
102684
|
}
|
|
101971
102685
|
function findSourceFiles3(dir, files = []) {
|
|
101972
102686
|
let entries;
|
|
101973
102687
|
try {
|
|
101974
|
-
entries =
|
|
102688
|
+
entries = fs103.readdirSync(dir);
|
|
101975
102689
|
} catch {
|
|
101976
102690
|
return files;
|
|
101977
102691
|
}
|
|
@@ -101980,10 +102694,10 @@ function findSourceFiles3(dir, files = []) {
|
|
|
101980
102694
|
if (SKIP_DIRECTORIES5.has(entry)) {
|
|
101981
102695
|
continue;
|
|
101982
102696
|
}
|
|
101983
|
-
const fullPath =
|
|
102697
|
+
const fullPath = path133.join(dir, entry);
|
|
101984
102698
|
let stat8;
|
|
101985
102699
|
try {
|
|
101986
|
-
stat8 =
|
|
102700
|
+
stat8 = fs103.statSync(fullPath);
|
|
101987
102701
|
} catch {
|
|
101988
102702
|
continue;
|
|
101989
102703
|
}
|
|
@@ -102076,7 +102790,7 @@ var todo_extract = createSwarmTool({
|
|
|
102076
102790
|
return JSON.stringify(errorResult, null, 2);
|
|
102077
102791
|
}
|
|
102078
102792
|
const scanPath = resolvedPath;
|
|
102079
|
-
if (!
|
|
102793
|
+
if (!fs103.existsSync(scanPath)) {
|
|
102080
102794
|
const errorResult = {
|
|
102081
102795
|
error: `path not found: ${pathsInput}`,
|
|
102082
102796
|
total: 0,
|
|
@@ -102086,13 +102800,13 @@ var todo_extract = createSwarmTool({
|
|
|
102086
102800
|
return JSON.stringify(errorResult, null, 2);
|
|
102087
102801
|
}
|
|
102088
102802
|
const filesToScan = [];
|
|
102089
|
-
const stat8 =
|
|
102803
|
+
const stat8 = fs103.statSync(scanPath);
|
|
102090
102804
|
if (stat8.isFile()) {
|
|
102091
102805
|
if (isSupportedExtension(scanPath)) {
|
|
102092
102806
|
filesToScan.push(scanPath);
|
|
102093
102807
|
} else {
|
|
102094
102808
|
const errorResult = {
|
|
102095
|
-
error: `unsupported file extension: ${
|
|
102809
|
+
error: `unsupported file extension: ${path133.extname(scanPath)}`,
|
|
102096
102810
|
total: 0,
|
|
102097
102811
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
102098
102812
|
entries: []
|
|
@@ -102105,11 +102819,11 @@ var todo_extract = createSwarmTool({
|
|
|
102105
102819
|
const allEntries = [];
|
|
102106
102820
|
for (const filePath of filesToScan) {
|
|
102107
102821
|
try {
|
|
102108
|
-
const fileStat =
|
|
102822
|
+
const fileStat = fs103.statSync(filePath);
|
|
102109
102823
|
if (fileStat.size > MAX_FILE_SIZE_BYTES11) {
|
|
102110
102824
|
continue;
|
|
102111
102825
|
}
|
|
102112
|
-
const content =
|
|
102826
|
+
const content = fs103.readFileSync(filePath, "utf-8");
|
|
102113
102827
|
const entries = parseTodoComments(content, filePath, tagsSet);
|
|
102114
102828
|
allEntries.push(...entries);
|
|
102115
102829
|
} catch {}
|
|
@@ -102140,19 +102854,19 @@ init_loader();
|
|
|
102140
102854
|
init_schema();
|
|
102141
102855
|
init_qa_gate_profile();
|
|
102142
102856
|
init_gate_evidence();
|
|
102143
|
-
import * as
|
|
102144
|
-
import * as
|
|
102857
|
+
import * as fs107 from "node:fs";
|
|
102858
|
+
import * as path137 from "node:path";
|
|
102145
102859
|
|
|
102146
102860
|
// src/hooks/diff-scope.ts
|
|
102147
102861
|
init_bun_compat();
|
|
102148
|
-
import * as
|
|
102149
|
-
import * as
|
|
102862
|
+
import * as fs105 from "node:fs";
|
|
102863
|
+
import * as path135 from "node:path";
|
|
102150
102864
|
|
|
102151
102865
|
// src/utils/gitignore-warning.ts
|
|
102152
102866
|
init_bun_compat();
|
|
102153
|
-
import * as
|
|
102154
|
-
import * as
|
|
102155
|
-
var
|
|
102867
|
+
import * as fs104 from "node:fs";
|
|
102868
|
+
import * as path134 from "node:path";
|
|
102869
|
+
var _internals52 = { bunSpawn };
|
|
102156
102870
|
var _swarmGitExcludedChecked = false;
|
|
102157
102871
|
function fileCoversSwarm(content) {
|
|
102158
102872
|
for (const rawLine of content.split(`
|
|
@@ -102185,7 +102899,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
102185
102899
|
checkIgnoreExitCode
|
|
102186
102900
|
] = await Promise.all([
|
|
102187
102901
|
(async () => {
|
|
102188
|
-
const proc =
|
|
102902
|
+
const proc = _internals52.bunSpawn(["git", "-C", directory, "rev-parse", "--show-toplevel"], GIT_SPAWN_OPTIONS);
|
|
102189
102903
|
try {
|
|
102190
102904
|
return await Promise.all([proc.exited, proc.stdout.text()]);
|
|
102191
102905
|
} finally {
|
|
@@ -102195,7 +102909,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
102195
102909
|
}
|
|
102196
102910
|
})(),
|
|
102197
102911
|
(async () => {
|
|
102198
|
-
const proc =
|
|
102912
|
+
const proc = _internals52.bunSpawn(["git", "-C", directory, "rev-parse", "--git-path", "info/exclude"], GIT_SPAWN_OPTIONS);
|
|
102199
102913
|
try {
|
|
102200
102914
|
return await Promise.all([proc.exited, proc.stdout.text()]);
|
|
102201
102915
|
} finally {
|
|
@@ -102205,7 +102919,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
102205
102919
|
}
|
|
102206
102920
|
})(),
|
|
102207
102921
|
(async () => {
|
|
102208
|
-
const proc =
|
|
102922
|
+
const proc = _internals52.bunSpawn(["git", "-C", directory, "check-ignore", "-q", ".swarm/.gitkeep"], GIT_SPAWN_OPTIONS);
|
|
102209
102923
|
try {
|
|
102210
102924
|
return await proc.exited;
|
|
102211
102925
|
} finally {
|
|
@@ -102225,16 +102939,16 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
102225
102939
|
const excludeRelPath = excludePathRaw.trim();
|
|
102226
102940
|
if (!excludeRelPath)
|
|
102227
102941
|
return;
|
|
102228
|
-
const excludePath =
|
|
102942
|
+
const excludePath = path134.isAbsolute(excludeRelPath) ? excludeRelPath : path134.join(directory, excludeRelPath);
|
|
102229
102943
|
if (checkIgnoreExitCode !== 0) {
|
|
102230
102944
|
try {
|
|
102231
|
-
|
|
102945
|
+
fs104.mkdirSync(path134.dirname(excludePath), { recursive: true });
|
|
102232
102946
|
let existing = "";
|
|
102233
102947
|
try {
|
|
102234
|
-
existing =
|
|
102948
|
+
existing = fs104.readFileSync(excludePath, "utf8");
|
|
102235
102949
|
} catch {}
|
|
102236
102950
|
if (!fileCoversSwarm(existing)) {
|
|
102237
|
-
|
|
102951
|
+
fs104.appendFileSync(excludePath, `
|
|
102238
102952
|
# opencode-swarm local runtime state
|
|
102239
102953
|
.swarm/
|
|
102240
102954
|
`, "utf8");
|
|
@@ -102244,7 +102958,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
102244
102958
|
}
|
|
102245
102959
|
} catch {}
|
|
102246
102960
|
}
|
|
102247
|
-
const trackedProc =
|
|
102961
|
+
const trackedProc = _internals52.bunSpawn(["git", "-C", directory, "ls-files", "--", ".swarm"], GIT_SPAWN_OPTIONS);
|
|
102248
102962
|
let trackedExitCode;
|
|
102249
102963
|
let trackedOutput;
|
|
102250
102964
|
try {
|
|
@@ -102269,13 +102983,13 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
102269
102983
|
}
|
|
102270
102984
|
|
|
102271
102985
|
// src/hooks/diff-scope.ts
|
|
102272
|
-
var
|
|
102986
|
+
var _internals53 = { bunSpawn };
|
|
102273
102987
|
function getDeclaredScope(taskId, directory) {
|
|
102274
102988
|
try {
|
|
102275
|
-
const planPath =
|
|
102276
|
-
if (!
|
|
102989
|
+
const planPath = path135.join(directory, ".swarm", "plan.json");
|
|
102990
|
+
if (!fs105.existsSync(planPath))
|
|
102277
102991
|
return null;
|
|
102278
|
-
const raw =
|
|
102992
|
+
const raw = fs105.readFileSync(planPath, "utf-8");
|
|
102279
102993
|
const plan = JSON.parse(raw);
|
|
102280
102994
|
for (const phase of plan.phases ?? []) {
|
|
102281
102995
|
for (const task of phase.tasks ?? []) {
|
|
@@ -102304,7 +103018,7 @@ var GIT_DIFF_SPAWN_OPTIONS = {
|
|
|
102304
103018
|
};
|
|
102305
103019
|
async function getChangedFiles(directory) {
|
|
102306
103020
|
try {
|
|
102307
|
-
const proc =
|
|
103021
|
+
const proc = _internals53.bunSpawn(["git", "diff", "--name-only", "HEAD~1"], {
|
|
102308
103022
|
cwd: directory,
|
|
102309
103023
|
...GIT_DIFF_SPAWN_OPTIONS
|
|
102310
103024
|
});
|
|
@@ -102321,7 +103035,7 @@ async function getChangedFiles(directory) {
|
|
|
102321
103035
|
return stdout.trim().split(`
|
|
102322
103036
|
`).map((f) => f.trim()).filter((f) => f.length > 0);
|
|
102323
103037
|
}
|
|
102324
|
-
const proc2 =
|
|
103038
|
+
const proc2 = _internals53.bunSpawn(["git", "diff", "--name-only", "HEAD"], {
|
|
102325
103039
|
cwd: directory,
|
|
102326
103040
|
...GIT_DIFF_SPAWN_OPTIONS
|
|
102327
103041
|
});
|
|
@@ -102377,9 +103091,9 @@ init_telemetry();
|
|
|
102377
103091
|
|
|
102378
103092
|
// src/turbo/lean/task-completion.ts
|
|
102379
103093
|
init_file_locks();
|
|
102380
|
-
import * as
|
|
102381
|
-
import * as
|
|
102382
|
-
var
|
|
103094
|
+
import * as fs106 from "node:fs";
|
|
103095
|
+
import * as path136 from "node:path";
|
|
103096
|
+
var _internals54 = {
|
|
102383
103097
|
listActiveLocks,
|
|
102384
103098
|
verifyLeanTurboTaskCompletion
|
|
102385
103099
|
};
|
|
@@ -102397,7 +103111,7 @@ var TIER_3_PATTERNS = [
|
|
|
102397
103111
|
];
|
|
102398
103112
|
function matchesTier3Pattern(files) {
|
|
102399
103113
|
for (const file3 of files) {
|
|
102400
|
-
const fileName =
|
|
103114
|
+
const fileName = path136.basename(file3);
|
|
102401
103115
|
for (const pattern of TIER_3_PATTERNS) {
|
|
102402
103116
|
if (pattern.test(fileName)) {
|
|
102403
103117
|
return true;
|
|
@@ -102409,14 +103123,14 @@ function matchesTier3Pattern(files) {
|
|
|
102409
103123
|
function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
|
|
102410
103124
|
let persisted = null;
|
|
102411
103125
|
try {
|
|
102412
|
-
const statePath =
|
|
102413
|
-
if (!
|
|
103126
|
+
const statePath = path136.join(directory, ".swarm", "turbo-state.json");
|
|
103127
|
+
if (!fs106.existsSync(statePath)) {
|
|
102414
103128
|
return {
|
|
102415
103129
|
ok: false,
|
|
102416
103130
|
reason: "Lean Turbo state file not found"
|
|
102417
103131
|
};
|
|
102418
103132
|
}
|
|
102419
|
-
const raw =
|
|
103133
|
+
const raw = fs106.readFileSync(statePath, "utf-8");
|
|
102420
103134
|
persisted = JSON.parse(raw);
|
|
102421
103135
|
} catch {
|
|
102422
103136
|
return {
|
|
@@ -102493,11 +103207,11 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
|
|
|
102493
103207
|
};
|
|
102494
103208
|
}
|
|
102495
103209
|
const phase = runState.phase ?? 0;
|
|
102496
|
-
const evidencePath =
|
|
102497
|
-
const expectedDir =
|
|
102498
|
-
const resolvedPath =
|
|
102499
|
-
const resolvedDir =
|
|
102500
|
-
if (!resolvedPath.startsWith(resolvedDir +
|
|
103210
|
+
const evidencePath = path136.join(directory, ".swarm", "evidence", String(phase), "lean-turbo", `${lane.laneId}.json`);
|
|
103211
|
+
const expectedDir = path136.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
|
|
103212
|
+
const resolvedPath = path136.resolve(evidencePath);
|
|
103213
|
+
const resolvedDir = path136.resolve(expectedDir);
|
|
103214
|
+
if (!resolvedPath.startsWith(resolvedDir + path136.sep) && resolvedPath !== resolvedDir) {
|
|
102501
103215
|
return {
|
|
102502
103216
|
ok: false,
|
|
102503
103217
|
reason: `Lane ID causes path traversal: ${lane.laneId}`,
|
|
@@ -102509,7 +103223,7 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
|
|
|
102509
103223
|
}
|
|
102510
103224
|
};
|
|
102511
103225
|
}
|
|
102512
|
-
if (!
|
|
103226
|
+
if (!fs106.existsSync(evidencePath)) {
|
|
102513
103227
|
return {
|
|
102514
103228
|
ok: false,
|
|
102515
103229
|
reason: `Lane ${lane.laneId} evidence file not found: ${evidencePath}`,
|
|
@@ -102521,7 +103235,7 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
|
|
|
102521
103235
|
}
|
|
102522
103236
|
};
|
|
102523
103237
|
}
|
|
102524
|
-
const activeLocks =
|
|
103238
|
+
const activeLocks = _internals54.listActiveLocks(directory);
|
|
102525
103239
|
const laneLocks = activeLocks.filter((lock) => lock.laneId === lane.laneId);
|
|
102526
103240
|
if (laneLocks.length > 0) {
|
|
102527
103241
|
return {
|
|
@@ -102537,8 +103251,8 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
|
|
|
102537
103251
|
}
|
|
102538
103252
|
let filesTouched = [];
|
|
102539
103253
|
try {
|
|
102540
|
-
const planPath =
|
|
102541
|
-
const planRaw =
|
|
103254
|
+
const planPath = path136.join(directory, ".swarm", "plan.json");
|
|
103255
|
+
const planRaw = fs106.readFileSync(planPath, "utf-8");
|
|
102542
103256
|
const plan = JSON.parse(planRaw);
|
|
102543
103257
|
for (const planPhase of plan.phases ?? []) {
|
|
102544
103258
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -102620,7 +103334,7 @@ var TIER_3_PATTERNS2 = [
|
|
|
102620
103334
|
];
|
|
102621
103335
|
function matchesTier3Pattern2(files) {
|
|
102622
103336
|
for (const file3 of files) {
|
|
102623
|
-
const fileName =
|
|
103337
|
+
const fileName = path137.basename(file3);
|
|
102624
103338
|
for (const pattern of TIER_3_PATTERNS2) {
|
|
102625
103339
|
if (pattern.test(fileName)) {
|
|
102626
103340
|
return true;
|
|
@@ -102652,8 +103366,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
102652
103366
|
if (!skipStandardTurboBypass && hasActiveTurboMode()) {
|
|
102653
103367
|
const resolvedDir2 = workingDirectory;
|
|
102654
103368
|
try {
|
|
102655
|
-
const planPath =
|
|
102656
|
-
const planRaw =
|
|
103369
|
+
const planPath = path137.join(resolvedDir2, ".swarm", "plan.json");
|
|
103370
|
+
const planRaw = fs107.readFileSync(planPath, "utf-8");
|
|
102657
103371
|
const plan = JSON.parse(planRaw);
|
|
102658
103372
|
for (const planPhase of plan.phases ?? []) {
|
|
102659
103373
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -102719,8 +103433,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
102719
103433
|
}
|
|
102720
103434
|
try {
|
|
102721
103435
|
const resolvedDir2 = workingDirectory;
|
|
102722
|
-
const planPath =
|
|
102723
|
-
const planRaw =
|
|
103436
|
+
const planPath = path137.join(resolvedDir2, ".swarm", "plan.json");
|
|
103437
|
+
const planRaw = fs107.readFileSync(planPath, "utf-8");
|
|
102724
103438
|
const plan = JSON.parse(planRaw);
|
|
102725
103439
|
for (const planPhase of plan.phases ?? []) {
|
|
102726
103440
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -102904,8 +103618,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
|
|
|
102904
103618
|
};
|
|
102905
103619
|
}
|
|
102906
103620
|
}
|
|
102907
|
-
normalizedDir =
|
|
102908
|
-
const pathParts = normalizedDir.split(
|
|
103621
|
+
normalizedDir = path137.normalize(args2.working_directory);
|
|
103622
|
+
const pathParts = normalizedDir.split(path137.sep);
|
|
102909
103623
|
if (pathParts.includes("..")) {
|
|
102910
103624
|
return {
|
|
102911
103625
|
success: false,
|
|
@@ -102915,11 +103629,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
|
|
|
102915
103629
|
]
|
|
102916
103630
|
};
|
|
102917
103631
|
}
|
|
102918
|
-
const resolvedDir =
|
|
103632
|
+
const resolvedDir = path137.resolve(normalizedDir);
|
|
102919
103633
|
try {
|
|
102920
|
-
const realPath =
|
|
102921
|
-
const planPath =
|
|
102922
|
-
if (!
|
|
103634
|
+
const realPath = fs107.realpathSync(resolvedDir);
|
|
103635
|
+
const planPath = path137.join(realPath, ".swarm", "plan.json");
|
|
103636
|
+
if (!fs107.existsSync(planPath)) {
|
|
102923
103637
|
return {
|
|
102924
103638
|
success: false,
|
|
102925
103639
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -102950,22 +103664,22 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
|
|
|
102950
103664
|
}
|
|
102951
103665
|
if (args2.status === "in_progress") {
|
|
102952
103666
|
try {
|
|
102953
|
-
const evidencePath =
|
|
102954
|
-
|
|
102955
|
-
const fd =
|
|
103667
|
+
const evidencePath = path137.join(directory, ".swarm", "evidence", `${args2.task_id}.json`);
|
|
103668
|
+
fs107.mkdirSync(path137.dirname(evidencePath), { recursive: true });
|
|
103669
|
+
const fd = fs107.openSync(evidencePath, "wx");
|
|
102956
103670
|
let writeOk = false;
|
|
102957
103671
|
try {
|
|
102958
|
-
|
|
103672
|
+
fs107.writeSync(fd, JSON.stringify({
|
|
102959
103673
|
taskId: args2.task_id,
|
|
102960
103674
|
required_gates: ["reviewer", "test_engineer"],
|
|
102961
103675
|
gates: {}
|
|
102962
103676
|
}, null, 2));
|
|
102963
103677
|
writeOk = true;
|
|
102964
103678
|
} finally {
|
|
102965
|
-
|
|
103679
|
+
fs107.closeSync(fd);
|
|
102966
103680
|
if (!writeOk) {
|
|
102967
103681
|
try {
|
|
102968
|
-
|
|
103682
|
+
fs107.unlinkSync(evidencePath);
|
|
102969
103683
|
} catch {}
|
|
102970
103684
|
}
|
|
102971
103685
|
}
|
|
@@ -102975,8 +103689,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
|
|
|
102975
103689
|
recoverTaskStateFromDelegations(args2.task_id);
|
|
102976
103690
|
let phaseRequiresReviewer = true;
|
|
102977
103691
|
try {
|
|
102978
|
-
const planPath =
|
|
102979
|
-
const planRaw =
|
|
103692
|
+
const planPath = path137.join(directory, ".swarm", "plan.json");
|
|
103693
|
+
const planRaw = fs107.readFileSync(planPath, "utf-8");
|
|
102980
103694
|
const plan = JSON.parse(planRaw);
|
|
102981
103695
|
const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
|
|
102982
103696
|
if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
|
|
@@ -103286,8 +104000,8 @@ init_utils2();
|
|
|
103286
104000
|
init_ledger();
|
|
103287
104001
|
init_manager();
|
|
103288
104002
|
init_create_tool();
|
|
103289
|
-
import
|
|
103290
|
-
import
|
|
104003
|
+
import fs108 from "node:fs";
|
|
104004
|
+
import path138 from "node:path";
|
|
103291
104005
|
function normalizeVerdict(verdict) {
|
|
103292
104006
|
switch (verdict) {
|
|
103293
104007
|
case "APPROVED":
|
|
@@ -103335,7 +104049,7 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
103335
104049
|
entries: [evidenceEntry]
|
|
103336
104050
|
};
|
|
103337
104051
|
const filename = "drift-verifier.json";
|
|
103338
|
-
const relativePath =
|
|
104052
|
+
const relativePath = path138.join("evidence", String(phase), filename);
|
|
103339
104053
|
let validatedPath;
|
|
103340
104054
|
try {
|
|
103341
104055
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -103346,12 +104060,12 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
103346
104060
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
103347
104061
|
}, null, 2);
|
|
103348
104062
|
}
|
|
103349
|
-
const evidenceDir =
|
|
104063
|
+
const evidenceDir = path138.dirname(validatedPath);
|
|
103350
104064
|
try {
|
|
103351
|
-
await
|
|
103352
|
-
const tempPath =
|
|
103353
|
-
await
|
|
103354
|
-
await
|
|
104065
|
+
await fs108.promises.mkdir(evidenceDir, { recursive: true });
|
|
104066
|
+
const tempPath = path138.join(evidenceDir, `.${filename}.tmp`);
|
|
104067
|
+
await fs108.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
104068
|
+
await fs108.promises.rename(tempPath, validatedPath);
|
|
103355
104069
|
let snapshotInfo;
|
|
103356
104070
|
let snapshotError;
|
|
103357
104071
|
let qaProfileLocked;
|
|
@@ -103444,8 +104158,8 @@ var write_drift_evidence = createSwarmTool({
|
|
|
103444
104158
|
// src/tools/write-final-council-evidence.ts
|
|
103445
104159
|
init_zod();
|
|
103446
104160
|
init_loader();
|
|
103447
|
-
import
|
|
103448
|
-
import
|
|
104161
|
+
import fs109 from "node:fs";
|
|
104162
|
+
import path139 from "node:path";
|
|
103449
104163
|
init_utils2();
|
|
103450
104164
|
init_manager();
|
|
103451
104165
|
init_create_tool();
|
|
@@ -103533,7 +104247,7 @@ async function executeWriteFinalCouncilEvidence(args2, directory) {
|
|
|
103533
104247
|
timestamp: synthesis.timestamp
|
|
103534
104248
|
};
|
|
103535
104249
|
const filename = "final-council.json";
|
|
103536
|
-
const relativePath =
|
|
104250
|
+
const relativePath = path139.join("evidence", filename);
|
|
103537
104251
|
let validatedPath;
|
|
103538
104252
|
try {
|
|
103539
104253
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -103547,12 +104261,12 @@ async function executeWriteFinalCouncilEvidence(args2, directory) {
|
|
|
103547
104261
|
const evidenceContent = {
|
|
103548
104262
|
entries: [evidenceEntry]
|
|
103549
104263
|
};
|
|
103550
|
-
const evidenceDir =
|
|
104264
|
+
const evidenceDir = path139.dirname(validatedPath);
|
|
103551
104265
|
try {
|
|
103552
|
-
await
|
|
103553
|
-
const tempPath =
|
|
103554
|
-
await
|
|
103555
|
-
await
|
|
104266
|
+
await fs109.promises.mkdir(evidenceDir, { recursive: true });
|
|
104267
|
+
const tempPath = path139.join(evidenceDir, `.${filename}.tmp`);
|
|
104268
|
+
await fs109.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
104269
|
+
await fs109.promises.rename(tempPath, validatedPath);
|
|
103556
104270
|
return JSON.stringify({
|
|
103557
104271
|
success: true,
|
|
103558
104272
|
phase: input.phase,
|
|
@@ -103608,8 +104322,8 @@ var write_final_council_evidence = createSwarmTool({
|
|
|
103608
104322
|
init_zod();
|
|
103609
104323
|
init_utils2();
|
|
103610
104324
|
init_create_tool();
|
|
103611
|
-
import
|
|
103612
|
-
import
|
|
104325
|
+
import fs110 from "node:fs";
|
|
104326
|
+
import path140 from "node:path";
|
|
103613
104327
|
function normalizeVerdict2(verdict) {
|
|
103614
104328
|
switch (verdict) {
|
|
103615
104329
|
case "APPROVED":
|
|
@@ -103657,7 +104371,7 @@ async function executeWriteHallucinationEvidence(args2, directory) {
|
|
|
103657
104371
|
entries: [evidenceEntry]
|
|
103658
104372
|
};
|
|
103659
104373
|
const filename = "hallucination-guard.json";
|
|
103660
|
-
const relativePath =
|
|
104374
|
+
const relativePath = path140.join("evidence", String(phase), filename);
|
|
103661
104375
|
let validatedPath;
|
|
103662
104376
|
try {
|
|
103663
104377
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -103668,12 +104382,12 @@ async function executeWriteHallucinationEvidence(args2, directory) {
|
|
|
103668
104382
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
103669
104383
|
}, null, 2);
|
|
103670
104384
|
}
|
|
103671
|
-
const evidenceDir =
|
|
104385
|
+
const evidenceDir = path140.dirname(validatedPath);
|
|
103672
104386
|
try {
|
|
103673
|
-
await
|
|
103674
|
-
const tempPath =
|
|
103675
|
-
await
|
|
103676
|
-
await
|
|
104387
|
+
await fs110.promises.mkdir(evidenceDir, { recursive: true });
|
|
104388
|
+
const tempPath = path140.join(evidenceDir, `.${filename}.tmp`);
|
|
104389
|
+
await fs110.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
104390
|
+
await fs110.promises.rename(tempPath, validatedPath);
|
|
103677
104391
|
return JSON.stringify({
|
|
103678
104392
|
success: true,
|
|
103679
104393
|
phase,
|
|
@@ -103719,8 +104433,8 @@ var write_hallucination_evidence = createSwarmTool({
|
|
|
103719
104433
|
init_zod();
|
|
103720
104434
|
init_utils2();
|
|
103721
104435
|
init_create_tool();
|
|
103722
|
-
import
|
|
103723
|
-
import
|
|
104436
|
+
import fs111 from "node:fs";
|
|
104437
|
+
import path141 from "node:path";
|
|
103724
104438
|
function normalizeVerdict3(verdict) {
|
|
103725
104439
|
switch (verdict) {
|
|
103726
104440
|
case "PASS":
|
|
@@ -103794,7 +104508,7 @@ async function executeWriteMutationEvidence(args2, directory) {
|
|
|
103794
104508
|
entries: [evidenceEntry]
|
|
103795
104509
|
};
|
|
103796
104510
|
const filename = "mutation-gate.json";
|
|
103797
|
-
const relativePath =
|
|
104511
|
+
const relativePath = path141.join("evidence", String(phase), filename);
|
|
103798
104512
|
let validatedPath;
|
|
103799
104513
|
try {
|
|
103800
104514
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -103805,12 +104519,12 @@ async function executeWriteMutationEvidence(args2, directory) {
|
|
|
103805
104519
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
103806
104520
|
}, null, 2);
|
|
103807
104521
|
}
|
|
103808
|
-
const evidenceDir =
|
|
104522
|
+
const evidenceDir = path141.dirname(validatedPath);
|
|
103809
104523
|
try {
|
|
103810
|
-
await
|
|
103811
|
-
const tempPath =
|
|
103812
|
-
await
|
|
103813
|
-
await
|
|
104524
|
+
await fs111.promises.mkdir(evidenceDir, { recursive: true });
|
|
104525
|
+
const tempPath = path141.join(evidenceDir, `.${filename}.tmp`);
|
|
104526
|
+
await fs111.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
104527
|
+
await fs111.promises.rename(tempPath, validatedPath);
|
|
103814
104528
|
return JSON.stringify({
|
|
103815
104529
|
success: true,
|
|
103816
104530
|
phase,
|
|
@@ -104153,7 +104867,7 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
104153
104867
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
104154
104868
|
preflightTriggerManager = new PTM(automationConfig);
|
|
104155
104869
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
104156
|
-
const swarmDir =
|
|
104870
|
+
const swarmDir = path143.resolve(ctx.directory, ".swarm");
|
|
104157
104871
|
statusArtifact = new ASA(swarmDir);
|
|
104158
104872
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
104159
104873
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|
|
@@ -104552,6 +105266,14 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
104552
105266
|
return Promise.resolve();
|
|
104553
105267
|
}
|
|
104554
105268
|
},
|
|
105269
|
+
(input, output) => {
|
|
105270
|
+
try {
|
|
105271
|
+
const p = input;
|
|
105272
|
+
return skillPropagationTransformScan(ctx.directory, output, p.sessionID);
|
|
105273
|
+
} catch {
|
|
105274
|
+
return Promise.resolve();
|
|
105275
|
+
}
|
|
105276
|
+
},
|
|
104555
105277
|
(_input, output) => {
|
|
104556
105278
|
if (output.messages) {
|
|
104557
105279
|
output.messages = consolidateSystemMessages(output.messages);
|
|
@@ -104625,6 +105347,12 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
104625
105347
|
agent: input.agent,
|
|
104626
105348
|
sessionID: input.sessionID
|
|
104627
105349
|
}, KnowledgeApplicationConfigSchema.parse(config3.knowledge_application ?? {}));
|
|
105350
|
+
await skillPropagationGateBefore(ctx.directory, {
|
|
105351
|
+
tool: input.tool,
|
|
105352
|
+
agent: input.agent,
|
|
105353
|
+
sessionID: input.sessionID,
|
|
105354
|
+
args: input.args
|
|
105355
|
+
}, { enabled: true });
|
|
104628
105356
|
if (swarmState.lastBudgetPct >= 50) {
|
|
104629
105357
|
const pressureSession = ensureAgentSession(input.sessionID, swarmState.activeAgent.get(input.sessionID) ?? ORCHESTRATOR_NAME);
|
|
104630
105358
|
if (!pressureSession.contextPressureWarningSent) {
|