opencode-swarm 7.138.3 → 7.139.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/.opencode/skills/execute/SKILL.md +11 -2
- package/.opencode/skills/swarm-implement/SKILL.md +1 -1
- package/dist/cli/{config-doctor-2mwgdbsn.js → config-doctor-aszp7z1h.js} +2 -2
- package/dist/cli/{core-v6bte964.js → core-3s832mxx.js} +1 -1
- package/dist/cli/{curation-policy-5dqexw5j.js → curation-policy-a3hs73f7.js} +6 -6
- package/dist/cli/{curator-llm-factory-wkjme59b.js → curator-llm-factory-e8ngwyjm.js} +26 -25
- package/dist/cli/{curator-jjtp9hn2.js → curator-zxjqcc8r.js} +26 -25
- package/dist/cli/{evidence-summary-service-6cttrkzw.js → evidence-summary-service-qfhjfxdz.js} +7 -7
- package/dist/cli/{gate-evidence-ecx4djaw.js → gate-evidence-m2grv70v.js} +4 -4
- package/dist/cli/{guardrail-explain-xppwfnxr.js → guardrail-explain-rqpmzxyy.js} +27 -26
- package/dist/cli/{guardrail-log-swet7rch.js → guardrail-log-vd4a0ng5.js} +4 -3
- package/dist/cli/{hive-promoter-xvq8jzbs.js → hive-promoter-jc5vym27.js} +26 -25
- package/dist/cli/{index-tc61fybd.js → index-0tsetsxs.js} +4 -4
- package/dist/cli/{index-jhb8kjc5.js → index-3nr2sn32.js} +3 -3
- package/dist/cli/{index-y06a43sk.js → index-4ft523nb.js} +323 -80
- package/dist/cli/index-556ja8an.js +62 -0
- package/dist/cli/{index-31vfewmn.js → index-5bkpyvdf.js} +271 -94
- package/dist/cli/{index-wqg74mwj.js → index-67yqywan.js} +2 -2
- package/dist/cli/{index-gda7cwqz.js → index-6q240xgm.js} +30 -68
- package/dist/cli/{index-adde7nm2.js → index-84s6x604.js} +5 -5
- package/dist/cli/{index-j0xx9wpj.js → index-85hstja2.js} +1 -1
- package/dist/cli/{index-xybtaph7.js → index-a614s16f.js} +1 -1
- package/dist/cli/{index-10mz5js6.js → index-chvqee1j.js} +2 -2
- package/dist/cli/{index-rrxcfxrd.js → index-ddmnhv4h.js} +1 -1
- package/dist/cli/{index-1v89yst3.js → index-gytyqv1d.js} +2 -2
- package/dist/cli/{index-93ky909v.js → index-kv36s0x0.js} +3 -3
- package/dist/cli/{index-z7jgvm9b.js → index-nbgw5dxa.js} +1 -1
- package/dist/cli/{index-tqshdzaw.js → index-nc544sfw.js} +1 -1
- package/dist/cli/{index-js7th5my.js → index-nsnfvckc.js} +1 -1
- package/dist/cli/{index-4fmztnrq.js → index-p2dz85tv.js} +2 -2
- package/dist/cli/{index-y6dvs5tt.js → index-q3qtgtd0.js} +1 -1
- package/dist/cli/{index-99af5gvd.js → index-r3pth9a7.js} +230 -118
- package/dist/cli/{index-ab57h0yq.js → index-rtetrxxq.js} +1 -1
- package/dist/cli/{index-rjratees.js → index-s428dmy6.js} +2 -2
- package/dist/cli/{index-q344kj84.js → index-t26nfmcs.js} +1 -1
- package/dist/cli/{index-1djv5684.js → index-t31cc7kv.js} +6 -6
- package/dist/cli/{index-39k6y018.js → index-tcdcj1g2.js} +2 -2
- package/dist/cli/{index-en4fb04r.js → index-tyh0p5e8.js} +1 -1
- package/dist/cli/{index-xgmx9had.js → index-y46anh5e.js} +28 -27
- package/dist/cli/index-ymszzvnr.js +1725 -0
- package/dist/cli/{index-ngqxzkqm.js → index-z1tkxzq4.js} +2 -2
- package/dist/cli/{index-btx8j39p.js → index-zd15ya1w.js} +1 -1
- package/dist/cli/index.js +26 -25
- package/dist/cli/{knowledge-escalator-7n384ys1.js → knowledge-escalator-6473ey4c.js} +7 -7
- package/dist/cli/{knowledge-events-yaj0yjd6.js → knowledge-events-wwzpz8m4.js} +5 -5
- package/dist/cli/{knowledge-link-xc6yhxmz.js → knowledge-link-trfydkzm.js} +4 -4
- package/dist/cli/{knowledge-store-d99k0z2d.js → knowledge-store-99gd42jy.js} +5 -5
- package/dist/cli/{knowledge-validator-e5fqy9h4.js → knowledge-validator-v2eevvdg.js} +8 -8
- package/dist/cli/{pending-delegations-7dbc0j2a.js → pending-delegations-p6n83x67.js} +3 -3
- package/dist/cli/{pr-subscriptions-m943zn6g.js → pr-subscriptions-xbrfr51c.js} +3 -3
- package/dist/cli/{runner-x1hy047y.js → runner-9an52tmz.js} +5 -5
- package/dist/cli/{scan-cursor-9y9msabt.js → scan-cursor-39zxpw34.js} +6 -6
- package/dist/cli/{schema-xg5f11md.js → schema-xhfwr6b2.js} +1 -1
- package/dist/cli/scope-persistence-nsa6ra9s.js +61 -0
- package/dist/cli/{skill-generator-arvwfdfh.js → skill-generator-5px81476.js} +9 -9
- package/dist/cli/{telemetry-0yqed3jv.js → telemetry-7nt7zhyp.js} +1 -1
- package/dist/cli/{worktree-collision-ownership-hjrt5hx2.js → worktree-collision-ownership-9x4s4890.js} +3 -3
- package/dist/hooks/guardrails/destructive-command.d.ts +35 -0
- package/dist/hooks/guardrails/file-authority.d.ts +71 -26
- package/dist/hooks/guardrails/index.d.ts +2 -0
- package/dist/hooks/guardrails/tool-before.d.ts +5 -0
- package/dist/hooks/scope-guard.d.ts +3 -1
- package/dist/index.js +533 -522
- package/dist/plan/manager.d.ts +2 -0
- package/dist/scope/path-identity.d.ts +27 -0
- package/dist/scope/scope-binding.d.ts +90 -2
- package/dist/scope/scope-lease-renewal.d.ts +28 -0
- package/dist/scope/scope-persistence.d.ts +102 -19
- package/dist/scope/scope-resolution-diagnostic.d.ts +7 -0
- package/dist/services/run-memory.d.ts +53 -5
- package/dist/tools/declare-scope.d.ts +3 -1
- package/dist/tools/save-plan.d.ts +2 -0
- package/dist/tools/update-task-status.d.ts +2 -0
- package/dist/turbo/lean/lane-scope.d.ts +1 -1
- package/dist/utils/path-security.d.ts +25 -1
- package/package.json +1 -1
- package/dist/cli/index-2y4jy0de.js +0 -642
- package/dist/cli/scope-persistence-n1bryhzf.js +0 -38
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
EvaluationRunV1Schema,
|
|
4
4
|
GateAuditResultV1Schema,
|
|
5
5
|
getProtectedEvaluationRunIds
|
|
6
|
-
} from "./index-
|
|
6
|
+
} from "./index-z1tkxzq4.js";
|
|
7
7
|
import {
|
|
8
8
|
readEffectiveSpecSync
|
|
9
9
|
} from "./index-9ss2m4rs.js";
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
readTaskEvidence,
|
|
13
13
|
readTaskEvidenceRaw,
|
|
14
14
|
sanitizeTaskId
|
|
15
|
-
} from "./index-
|
|
15
|
+
} from "./index-tcdcj1g2.js";
|
|
16
16
|
import {
|
|
17
17
|
EVIDENCE_MAX_JSON_BYTES,
|
|
18
18
|
EvidenceBundleSchema,
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
replayFromLedgerWithStatus,
|
|
41
41
|
takeSnapshotEvent,
|
|
42
42
|
takeSnapshotWithRetry
|
|
43
|
-
} from "./index-
|
|
43
|
+
} from "./index-p2dz85tv.js";
|
|
44
44
|
import {
|
|
45
45
|
PlanSchema
|
|
46
46
|
} from "./index-1kz6da87.js";
|
|
@@ -56,10 +56,10 @@ import {
|
|
|
56
56
|
} from "./index-fsrp8wp3.js";
|
|
57
57
|
import {
|
|
58
58
|
withEvidenceLock
|
|
59
|
-
} from "./index-
|
|
59
|
+
} from "./index-a614s16f.js";
|
|
60
60
|
import {
|
|
61
61
|
emit
|
|
62
|
-
} from "./index-
|
|
62
|
+
} from "./index-chvqee1j.js";
|
|
63
63
|
import {
|
|
64
64
|
ZodError,
|
|
65
65
|
init_zod
|
|
@@ -1586,9 +1586,247 @@ var _internals5 = {
|
|
|
1586
1586
|
readLaneEnvFileFromDiskSync
|
|
1587
1587
|
};
|
|
1588
1588
|
|
|
1589
|
+
// src/services/run-memory.ts
|
|
1590
|
+
import * as crypto2 from "crypto";
|
|
1591
|
+
import * as fs2 from "fs/promises";
|
|
1592
|
+
|
|
1593
|
+
// src/hooks/context-sanitizer.ts
|
|
1594
|
+
function sanitizeContextText(text) {
|
|
1595
|
+
return text.split("").filter((char) => {
|
|
1596
|
+
const code = char.charCodeAt(0);
|
|
1597
|
+
return code === 9 || code === 10 || code === 13 || code > 31 && code !== 127;
|
|
1598
|
+
}).join("").replace(/[\u00AD\u200B-\u200F\u2060-\u2064\uFEFF]/g, "").replace(/[\u202A-\u202E\u2066-\u2069]/g, "").replace(/```/g, "` ` `").replace(/^system\s*:/gim, "[BLOCKED]:").replace(/<system\b[^>]*>/gi, "[BLOCKED-TAG]").replace(/<\/system>/gi, "[/BLOCKED-TAG]").replace(/<tool_call\b[^>]*>/gi, "[BLOCKED-TOOL]").replace(/<\/tool_call>/gi, "[/BLOCKED-TOOL]").replace(/<\/\w+>/g, "[/BLOCKED-TAG]");
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
// src/services/run-memory.ts
|
|
1602
|
+
init_logger();
|
|
1603
|
+
|
|
1604
|
+
// src/utils/path-security.ts
|
|
1605
|
+
function containsPathTraversal(str) {
|
|
1606
|
+
if (/\.\.[/\\]/.test(str))
|
|
1607
|
+
return true;
|
|
1608
|
+
if (/(?:^|[/\\])\.\.(?:[/\\]|$)/.test(str))
|
|
1609
|
+
return true;
|
|
1610
|
+
if (/%2e%2e/i.test(str))
|
|
1611
|
+
return true;
|
|
1612
|
+
if (/%2e\./i.test(str))
|
|
1613
|
+
return true;
|
|
1614
|
+
if (/%2e/i.test(str) && /\.\./.test(str))
|
|
1615
|
+
return true;
|
|
1616
|
+
if (/%252e%252e/i.test(str))
|
|
1617
|
+
return true;
|
|
1618
|
+
if (/\uff0e/.test(str))
|
|
1619
|
+
return true;
|
|
1620
|
+
if (/\u3002/.test(str))
|
|
1621
|
+
return true;
|
|
1622
|
+
if (/\uff65/.test(str))
|
|
1623
|
+
return true;
|
|
1624
|
+
if (/%2f/i.test(str))
|
|
1625
|
+
return true;
|
|
1626
|
+
if (/%5c/i.test(str))
|
|
1627
|
+
return true;
|
|
1628
|
+
return false;
|
|
1629
|
+
}
|
|
1630
|
+
function containsControlChars(str) {
|
|
1631
|
+
for (const ch of str) {
|
|
1632
|
+
const code = ch.codePointAt(0);
|
|
1633
|
+
if (code === undefined)
|
|
1634
|
+
continue;
|
|
1635
|
+
if (code <= 31 || code >= 127 && code <= 159)
|
|
1636
|
+
return true;
|
|
1637
|
+
if (code >= 8234 && code <= 8238)
|
|
1638
|
+
return true;
|
|
1639
|
+
if (code >= 8294 && code <= 8297)
|
|
1640
|
+
return true;
|
|
1641
|
+
}
|
|
1642
|
+
return false;
|
|
1643
|
+
}
|
|
1644
|
+
function validateWorkspaceRoot(directory) {
|
|
1645
|
+
if (!directory || directory.trim() === "") {
|
|
1646
|
+
throw new Error("Invalid directory: empty");
|
|
1647
|
+
}
|
|
1648
|
+
if (containsPathTraversal(directory)) {
|
|
1649
|
+
throw new Error("Invalid directory: path traversal detected");
|
|
1650
|
+
}
|
|
1651
|
+
if (containsControlChars(directory)) {
|
|
1652
|
+
throw new Error("Invalid directory: control characters detected");
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
// src/services/run-memory.ts
|
|
1657
|
+
var RUN_MEMORY_FILENAME = "run-memory.jsonl";
|
|
1658
|
+
var MAX_SUMMARY_TOKENS = 500;
|
|
1659
|
+
function generateTaskFingerprint(taskId, fileTargets) {
|
|
1660
|
+
const sortedFiles = [...fileTargets].sort().join(",");
|
|
1661
|
+
const hash = crypto2.createHash("sha256").update(taskId + sortedFiles).digest("hex");
|
|
1662
|
+
return hash.slice(0, 8);
|
|
1663
|
+
}
|
|
1664
|
+
async function recordOutcome(directory, entry) {
|
|
1665
|
+
validateWorkspaceRoot(directory);
|
|
1666
|
+
const resolvedPath = validateSwarmPath(directory, RUN_MEMORY_FILENAME);
|
|
1667
|
+
const line = `${JSON.stringify(entry)}
|
|
1668
|
+
`;
|
|
1669
|
+
await fs2.appendFile(resolvedPath, line, { encoding: "utf-8" });
|
|
1670
|
+
}
|
|
1671
|
+
async function getTaskHistory(directory, taskId) {
|
|
1672
|
+
validateWorkspaceRoot(directory);
|
|
1673
|
+
const content = await readSwarmFileAsync(directory, RUN_MEMORY_FILENAME);
|
|
1674
|
+
if (!content) {
|
|
1675
|
+
return [];
|
|
1676
|
+
}
|
|
1677
|
+
const entries = [];
|
|
1678
|
+
const lines = content.split(`
|
|
1679
|
+
`);
|
|
1680
|
+
for (const line of lines) {
|
|
1681
|
+
if (!line.trim())
|
|
1682
|
+
continue;
|
|
1683
|
+
try {
|
|
1684
|
+
const entry = JSON.parse(line);
|
|
1685
|
+
if (entry.taskId === taskId) {
|
|
1686
|
+
entries.push(entry);
|
|
1687
|
+
}
|
|
1688
|
+
} catch {}
|
|
1689
|
+
}
|
|
1690
|
+
return entries;
|
|
1691
|
+
}
|
|
1692
|
+
async function recordTaskAttempt(directory, input) {
|
|
1693
|
+
try {
|
|
1694
|
+
let history = [];
|
|
1695
|
+
try {
|
|
1696
|
+
history = await _internals6.getTaskHistory(directory, input.taskId);
|
|
1697
|
+
} catch (err) {
|
|
1698
|
+
warn(`[run-memory] history read for task ${input.taskId} failed; recording with attemptNumber 1: ${err instanceof Error ? err.message : String(err)}`);
|
|
1699
|
+
}
|
|
1700
|
+
const entry = {
|
|
1701
|
+
timestamp: new Date().toISOString(),
|
|
1702
|
+
taskId: input.taskId,
|
|
1703
|
+
taskFingerprint: _internals6.generateTaskFingerprint(input.taskId, input.fileTargets ?? []),
|
|
1704
|
+
agent: input.agent,
|
|
1705
|
+
outcome: input.outcome,
|
|
1706
|
+
attemptNumber: history.length + 1
|
|
1707
|
+
};
|
|
1708
|
+
if (input.failureReason) {
|
|
1709
|
+
entry.failureReason = input.failureReason;
|
|
1710
|
+
}
|
|
1711
|
+
if (input.fileTargets && input.fileTargets.length > 0) {
|
|
1712
|
+
entry.filesModified = input.fileTargets;
|
|
1713
|
+
}
|
|
1714
|
+
if (typeof input.durationMs === "number") {
|
|
1715
|
+
entry.durationMs = input.durationMs;
|
|
1716
|
+
}
|
|
1717
|
+
await _internals6.recordOutcome(directory, entry);
|
|
1718
|
+
} catch (err) {
|
|
1719
|
+
warn(`[run-memory] failed to record ${input.outcome} for task ${input.taskId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
function groupByTaskId(entries) {
|
|
1723
|
+
const groups = new Map;
|
|
1724
|
+
for (const entry of entries) {
|
|
1725
|
+
const existing = groups.get(entry.taskId) || [];
|
|
1726
|
+
existing.push(entry);
|
|
1727
|
+
groups.set(entry.taskId, existing);
|
|
1728
|
+
}
|
|
1729
|
+
return groups;
|
|
1730
|
+
}
|
|
1731
|
+
function summarizeTask(taskId, entries) {
|
|
1732
|
+
let lastFailure;
|
|
1733
|
+
let lastFailureIndex = -1;
|
|
1734
|
+
let lastPassIndex = -1;
|
|
1735
|
+
let lastPass;
|
|
1736
|
+
let failCount = 0;
|
|
1737
|
+
entries.forEach((entry, index) => {
|
|
1738
|
+
if (entry.outcome === "fail" || entry.outcome === "retry") {
|
|
1739
|
+
failCount++;
|
|
1740
|
+
lastFailure = entry;
|
|
1741
|
+
lastFailureIndex = index;
|
|
1742
|
+
} else if (entry.outcome === "pass") {
|
|
1743
|
+
lastPass = entry;
|
|
1744
|
+
lastPassIndex = index;
|
|
1745
|
+
}
|
|
1746
|
+
});
|
|
1747
|
+
if (!lastFailure) {
|
|
1748
|
+
return null;
|
|
1749
|
+
}
|
|
1750
|
+
const passResolvesFailure = lastPassIndex > lastFailureIndex;
|
|
1751
|
+
if (lastPass && passResolvesFailure) {
|
|
1752
|
+
const passAttempt = lastPass.attemptNumber;
|
|
1753
|
+
const failAttempt = lastFailure.attemptNumber;
|
|
1754
|
+
const reason = sanitizeContextText(lastFailure.failureReason || "unknown");
|
|
1755
|
+
return `Task ${taskId}: FAILED attempt ${failAttempt} \u2014 ${reason}. Passed on attempt ${passAttempt}.`;
|
|
1756
|
+
} else {
|
|
1757
|
+
const reason = sanitizeContextText(lastFailure.failureReason || "unknown");
|
|
1758
|
+
return `Task ${taskId}: FAILED ${failCount} times \u2014 last: ${reason}. Still failing.`;
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
async function getRunMemorySummary(directory) {
|
|
1762
|
+
validateWorkspaceRoot(directory);
|
|
1763
|
+
const content = await readSwarmFileAsync(directory, RUN_MEMORY_FILENAME);
|
|
1764
|
+
if (!content) {
|
|
1765
|
+
return null;
|
|
1766
|
+
}
|
|
1767
|
+
const entries = [];
|
|
1768
|
+
const lines = content.split(`
|
|
1769
|
+
`);
|
|
1770
|
+
for (const line of lines) {
|
|
1771
|
+
if (!line.trim())
|
|
1772
|
+
continue;
|
|
1773
|
+
try {
|
|
1774
|
+
const entry = JSON.parse(line);
|
|
1775
|
+
entries.push(entry);
|
|
1776
|
+
} catch {}
|
|
1777
|
+
}
|
|
1778
|
+
if (entries.length === 0) {
|
|
1779
|
+
return null;
|
|
1780
|
+
}
|
|
1781
|
+
const groups = _internals6.groupByTaskId(entries);
|
|
1782
|
+
const summaries = [];
|
|
1783
|
+
for (const [taskId, taskEntries] of groups) {
|
|
1784
|
+
const summary = _internals6.summarizeTask(taskId, taskEntries);
|
|
1785
|
+
if (summary) {
|
|
1786
|
+
summaries.push(summary);
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
if (summaries.length === 0) {
|
|
1790
|
+
return null;
|
|
1791
|
+
}
|
|
1792
|
+
const prefix = `[FOR: architect, coder]
|
|
1793
|
+
## RUN MEMORY \u2014 Previous Task Outcomes
|
|
1794
|
+
`;
|
|
1795
|
+
const suffix = `
|
|
1796
|
+
Use this data to avoid repeating known failure patterns.`;
|
|
1797
|
+
let summaryText = summaries.join(`
|
|
1798
|
+
`);
|
|
1799
|
+
const estimateTokens = (text) => {
|
|
1800
|
+
return Math.ceil(text.length * 0.33);
|
|
1801
|
+
};
|
|
1802
|
+
const totalText = prefix + summaryText + suffix;
|
|
1803
|
+
const estimatedTokens = estimateTokens(totalText);
|
|
1804
|
+
if (estimatedTokens > MAX_SUMMARY_TOKENS) {
|
|
1805
|
+
const prefixTokens = estimateTokens(prefix);
|
|
1806
|
+
const suffixTokens = estimateTokens(suffix);
|
|
1807
|
+
const availableContentTokens = MAX_SUMMARY_TOKENS - prefixTokens - suffixTokens;
|
|
1808
|
+
if (availableContentTokens > 0) {
|
|
1809
|
+
const maxContentChars = Math.floor(availableContentTokens / 0.33);
|
|
1810
|
+
summaryText = summaryText.slice(0, maxContentChars);
|
|
1811
|
+
} else {
|
|
1812
|
+
summaryText = "";
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
return prefix + summaryText + suffix;
|
|
1816
|
+
}
|
|
1817
|
+
var _internals6 = {
|
|
1818
|
+
generateTaskFingerprint,
|
|
1819
|
+
recordOutcome,
|
|
1820
|
+
recordTaskAttempt,
|
|
1821
|
+
getTaskHistory,
|
|
1822
|
+
getRunMemorySummary,
|
|
1823
|
+
groupByTaskId,
|
|
1824
|
+
summarizeTask
|
|
1825
|
+
};
|
|
1826
|
+
|
|
1589
1827
|
// src/turbo/epic/state.ts
|
|
1590
1828
|
init_logger();
|
|
1591
|
-
import * as
|
|
1829
|
+
import * as fs3 from "fs";
|
|
1592
1830
|
import * as path5 from "path";
|
|
1593
1831
|
var STATE_FILE = "epic-state.json";
|
|
1594
1832
|
function nowISO() {
|
|
@@ -1596,8 +1834,8 @@ function nowISO() {
|
|
|
1596
1834
|
}
|
|
1597
1835
|
function ensureSwarmDir(directory) {
|
|
1598
1836
|
const swarmDir = path5.resolve(directory, ".swarm");
|
|
1599
|
-
if (!
|
|
1600
|
-
|
|
1837
|
+
if (!fs3.existsSync(swarmDir)) {
|
|
1838
|
+
fs3.mkdirSync(swarmDir, { recursive: true });
|
|
1601
1839
|
}
|
|
1602
1840
|
return swarmDir;
|
|
1603
1841
|
}
|
|
@@ -1618,16 +1856,16 @@ function markStateUnreadable(directory, reason) {
|
|
|
1618
1856
|
function readPersisted(directory) {
|
|
1619
1857
|
try {
|
|
1620
1858
|
const filePath = path5.join(directory, ".swarm", STATE_FILE);
|
|
1621
|
-
if (!
|
|
1859
|
+
if (!fs3.existsSync(filePath)) {
|
|
1622
1860
|
const seed = emptyPersisted();
|
|
1623
1861
|
try {
|
|
1624
1862
|
ensureSwarmDir(directory);
|
|
1625
|
-
|
|
1863
|
+
fs3.writeFileSync(filePath, `${JSON.stringify(seed, null, 2)}
|
|
1626
1864
|
`, "utf-8");
|
|
1627
1865
|
} catch {}
|
|
1628
1866
|
return seed;
|
|
1629
1867
|
}
|
|
1630
|
-
const raw =
|
|
1868
|
+
const raw = fs3.readFileSync(filePath, "utf-8");
|
|
1631
1869
|
const parsed = JSON.parse(raw);
|
|
1632
1870
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || parsed.version !== 1 || !parsed.sessions || typeof parsed.sessions !== "object" || Array.isArray(parsed.sessions)) {
|
|
1633
1871
|
markStateUnreadable(directory, `malformed shape (version=${parsed?.version}, sessions type=${Array.isArray(parsed?.sessions) ? "array" : typeof parsed?.sessions})`);
|
|
@@ -1664,14 +1902,14 @@ function writePersisted(directory, persisted) {
|
|
|
1664
1902
|
throw new Error(`Epic state persistence prepare failed: ${msg}`);
|
|
1665
1903
|
}
|
|
1666
1904
|
try {
|
|
1667
|
-
|
|
1668
|
-
|
|
1905
|
+
fs3.writeFileSync(tmpPath, payload, "utf-8");
|
|
1906
|
+
fs3.renameSync(tmpPath, filePath);
|
|
1669
1907
|
} catch (error2) {
|
|
1670
1908
|
const msg = error2 instanceof Error ? error2.message : String(error2);
|
|
1671
1909
|
error(`[turbo/epic/state] Failed to persist ${STATE_FILE} atomically: ${msg}`);
|
|
1672
1910
|
try {
|
|
1673
|
-
if (
|
|
1674
|
-
|
|
1911
|
+
if (fs3.existsSync(tmpPath))
|
|
1912
|
+
fs3.unlinkSync(tmpPath);
|
|
1675
1913
|
} catch {}
|
|
1676
1914
|
throw new Error(`Epic state persistence failed: ${msg}`);
|
|
1677
1915
|
}
|
|
@@ -1702,7 +1940,7 @@ function isEpicModeActive(directory, sessionID) {
|
|
|
1702
1940
|
function isEpicModeActiveForProject(directory) {
|
|
1703
1941
|
if (stateUnreadableMap.get(directory))
|
|
1704
1942
|
return false;
|
|
1705
|
-
if (!
|
|
1943
|
+
if (!fs3.existsSync(path5.join(directory, ".swarm", STATE_FILE))) {
|
|
1706
1944
|
return false;
|
|
1707
1945
|
}
|
|
1708
1946
|
const persisted = readPersisted(directory);
|
|
@@ -1753,11 +1991,11 @@ function isLockContentionError(err) {
|
|
|
1753
1991
|
return INDEX_LOCK_ERROR_RE.test(msg);
|
|
1754
1992
|
}
|
|
1755
1993
|
async function commitTaskCompletion(directory, taskId, description, scopePaths) {
|
|
1756
|
-
if (!
|
|
1994
|
+
if (!_internals7.isGitRepo(directory)) {
|
|
1757
1995
|
return { committed: false, reason: "no-git" };
|
|
1758
1996
|
}
|
|
1759
1997
|
try {
|
|
1760
|
-
if (
|
|
1998
|
+
if (_internals7.hasExistingTaskCommit(directory, taskId)) {
|
|
1761
1999
|
return { committed: true, reason: "idempotent-skip" };
|
|
1762
2000
|
}
|
|
1763
2001
|
} catch {}
|
|
@@ -1778,15 +2016,15 @@ async function commitTaskCompletion(directory, taskId, description, scopePaths)
|
|
|
1778
2016
|
for (let attempt = 0;attempt <= INDEX_LOCK_BACKOFF_MS.length; attempt++) {
|
|
1779
2017
|
try {
|
|
1780
2018
|
if (paths.length > 0) {
|
|
1781
|
-
|
|
2019
|
+
_internals7.stageScopedPaths(directory, paths);
|
|
1782
2020
|
}
|
|
1783
|
-
|
|
1784
|
-
const sha =
|
|
2021
|
+
_internals7.commitAllowEmpty(directory, message);
|
|
2022
|
+
const sha = _internals7.gitHeadSha(directory);
|
|
1785
2023
|
return { committed: true, reason: "success", sha };
|
|
1786
2024
|
} catch (err) {
|
|
1787
2025
|
lastError = err;
|
|
1788
2026
|
if (attempt < INDEX_LOCK_BACKOFF_MS.length && isLockContentionError(err)) {
|
|
1789
|
-
await
|
|
2027
|
+
await _internals7.sleep(INDEX_LOCK_BACKOFF_MS[attempt]);
|
|
1790
2028
|
continue;
|
|
1791
2029
|
}
|
|
1792
2030
|
break;
|
|
@@ -1796,7 +2034,7 @@ async function commitTaskCompletion(directory, taskId, description, scopePaths)
|
|
|
1796
2034
|
criticalWarn(`[epic:task-commit] commit for task ${taskId} failed (non-fatal): ${msg}`);
|
|
1797
2035
|
return { committed: false, reason: "commit-failed", error: msg };
|
|
1798
2036
|
}
|
|
1799
|
-
var
|
|
2037
|
+
var _internals7 = {
|
|
1800
2038
|
isGitRepo: (cwd) => isGitRepo(cwd),
|
|
1801
2039
|
stageScopedPaths: (cwd, paths) => {
|
|
1802
2040
|
const CHUNK = 200;
|
|
@@ -1828,7 +2066,7 @@ var _internals6 = {
|
|
|
1828
2066
|
};
|
|
1829
2067
|
|
|
1830
2068
|
// src/turbo/lean/conflicts.ts
|
|
1831
|
-
import * as
|
|
2069
|
+
import * as fs4 from "fs";
|
|
1832
2070
|
import * as path6 from "path";
|
|
1833
2071
|
|
|
1834
2072
|
// src/utils/path.ts
|
|
@@ -1959,10 +2197,10 @@ function isProtectedPath(normalizedPath) {
|
|
|
1959
2197
|
function readTaskScopes(directory, taskId) {
|
|
1960
2198
|
const scopePath = path6.join(directory, ".swarm", "scopes", `scope-${taskId}.json`);
|
|
1961
2199
|
try {
|
|
1962
|
-
if (!
|
|
2200
|
+
if (!fs4.existsSync(scopePath)) {
|
|
1963
2201
|
return null;
|
|
1964
2202
|
}
|
|
1965
|
-
const raw =
|
|
2203
|
+
const raw = fs4.readFileSync(scopePath, "utf-8");
|
|
1966
2204
|
const parsed = JSON.parse(raw);
|
|
1967
2205
|
if (!parsed || !Array.isArray(parsed.files)) {
|
|
1968
2206
|
return null;
|
|
@@ -1974,17 +2212,17 @@ function readTaskScopes(directory, taskId) {
|
|
|
1974
2212
|
}
|
|
1975
2213
|
|
|
1976
2214
|
// src/utils/spec-hash.ts
|
|
1977
|
-
import { createHash } from "crypto";
|
|
2215
|
+
import { createHash as createHash2 } from "crypto";
|
|
1978
2216
|
import * as fsSync2 from "fs";
|
|
1979
2217
|
import { join as join5 } from "path";
|
|
1980
2218
|
async function computeSpecHash(directory) {
|
|
1981
|
-
const spec =
|
|
2219
|
+
const spec = _internals8.readEffectiveSpecSync(directory);
|
|
1982
2220
|
if (!spec)
|
|
1983
2221
|
return null;
|
|
1984
|
-
return
|
|
2222
|
+
return createHash2("sha256").update(spec.content, "utf-8").digest("hex");
|
|
1985
2223
|
}
|
|
1986
2224
|
async function isSpecStale(directory, plan) {
|
|
1987
|
-
const currentHash = await
|
|
2225
|
+
const currentHash = await _internals8.computeSpecHash(directory);
|
|
1988
2226
|
if (!plan.specHash) {
|
|
1989
2227
|
return { stale: false };
|
|
1990
2228
|
}
|
|
@@ -2013,7 +2251,7 @@ function isObligationPreserving(directory) {
|
|
|
2013
2251
|
} catch {
|
|
2014
2252
|
return false;
|
|
2015
2253
|
}
|
|
2016
|
-
const currentResult =
|
|
2254
|
+
const currentResult = _internals8.readEffectiveSpecSync(directory);
|
|
2017
2255
|
if (!currentResult || !currentResult.content) {
|
|
2018
2256
|
return false;
|
|
2019
2257
|
}
|
|
@@ -2043,7 +2281,7 @@ function isObligationPreserving(directory) {
|
|
|
2043
2281
|
return false;
|
|
2044
2282
|
}
|
|
2045
2283
|
}
|
|
2046
|
-
var
|
|
2284
|
+
var _internals8 = {
|
|
2047
2285
|
computeSpecDiff,
|
|
2048
2286
|
computeSpecHash,
|
|
2049
2287
|
isObligationPreserving,
|
|
@@ -2063,7 +2301,7 @@ function computeSpecDiff(directory) {
|
|
|
2063
2301
|
} catch {
|
|
2064
2302
|
return null;
|
|
2065
2303
|
}
|
|
2066
|
-
const spec =
|
|
2304
|
+
const spec = _internals8.readEffectiveSpecSync(directory);
|
|
2067
2305
|
if (!spec) {
|
|
2068
2306
|
return null;
|
|
2069
2307
|
}
|
|
@@ -2157,7 +2395,7 @@ var startupLedgerCheckedWorkspaces = new Set;
|
|
|
2157
2395
|
var ledgerStaleWorkspaces = new Set;
|
|
2158
2396
|
var recoveryMutexes = new Map;
|
|
2159
2397
|
var PLAN_JSON_CACHE_NAMESPACE = "plan-json:validated:v1";
|
|
2160
|
-
var
|
|
2398
|
+
var _internals9 = {
|
|
2161
2399
|
loadPlan,
|
|
2162
2400
|
loadPlanJsonOnly,
|
|
2163
2401
|
regeneratePlanMarkdown,
|
|
@@ -2165,7 +2403,8 @@ var _internals8 = {
|
|
|
2165
2403
|
isEpicModeActiveForProject,
|
|
2166
2404
|
readTaskScopes,
|
|
2167
2405
|
commitTaskCompletion,
|
|
2168
|
-
getWorktreeMergeFailure
|
|
2406
|
+
getWorktreeMergeFailure,
|
|
2407
|
+
recordTaskAttempt
|
|
2169
2408
|
};
|
|
2170
2409
|
var CAS_BACKOFF_START_MS = 5;
|
|
2171
2410
|
var CAS_BACKOFF_CAP_MS = 250;
|
|
@@ -2406,7 +2645,7 @@ async function loadPlan(directory, cache) {
|
|
|
2406
2645
|
const inSync = await isPlanMdInSync(directory, validated, cache);
|
|
2407
2646
|
if (!inSync) {
|
|
2408
2647
|
try {
|
|
2409
|
-
await
|
|
2648
|
+
await _internals9.regeneratePlanMarkdown(directory, validated);
|
|
2410
2649
|
} catch (regenError) {
|
|
2411
2650
|
warn(`Failed to regenerate plan.md: ${regenError instanceof Error ? regenError.message : String(regenError)}. Proceeding with plan.json only.`);
|
|
2412
2651
|
}
|
|
@@ -2572,7 +2811,7 @@ async function loadPlan(directory, cache) {
|
|
|
2572
2811
|
const existingMutex = recoveryMutexes.get(resolvedDir);
|
|
2573
2812
|
if (existingMutex) {
|
|
2574
2813
|
await existingMutex;
|
|
2575
|
-
const postRecoveryPlan = await
|
|
2814
|
+
const postRecoveryPlan = await _internals9.loadPlanJsonOnly(directory);
|
|
2576
2815
|
if (postRecoveryPlan)
|
|
2577
2816
|
return postRecoveryPlan;
|
|
2578
2817
|
}
|
|
@@ -2632,7 +2871,7 @@ async function loadPlan(directory, cache) {
|
|
|
2632
2871
|
return null;
|
|
2633
2872
|
}
|
|
2634
2873
|
async function savePlanWithAutoAcknowledgedRemovals(directory, plan, source, reason, options) {
|
|
2635
|
-
const existing = await
|
|
2874
|
+
const existing = await _internals9.loadPlanJsonOnly(directory);
|
|
2636
2875
|
const newIds = new Set;
|
|
2637
2876
|
for (const phase of plan.phases) {
|
|
2638
2877
|
for (const task of phase.tasks)
|
|
@@ -2660,7 +2899,7 @@ async function savePlan(directory, plan, options) {
|
|
|
2660
2899
|
const validated = PlanSchema.parse(plan);
|
|
2661
2900
|
if (options?.preserveCompletedStatuses !== false) {
|
|
2662
2901
|
try {
|
|
2663
|
-
const currentPlan2 = await
|
|
2902
|
+
const currentPlan2 = await _internals9.loadPlanJsonOnly(directory);
|
|
2664
2903
|
if (currentPlan2) {
|
|
2665
2904
|
const completedTaskIds = new Set;
|
|
2666
2905
|
for (const phase of currentPlan2.phases) {
|
|
@@ -2682,7 +2921,7 @@ async function savePlan(directory, plan, options) {
|
|
|
2682
2921
|
} catch {}
|
|
2683
2922
|
}
|
|
2684
2923
|
derivePhaseStatusesInPlace(validated);
|
|
2685
|
-
const currentPlan = await
|
|
2924
|
+
const currentPlan = await _internals9.loadPlanJsonOnly(directory);
|
|
2686
2925
|
const planId = derivePlanId(validated);
|
|
2687
2926
|
const planHashForInit = computePlanHash(validated);
|
|
2688
2927
|
if (!await ledgerExists(directory)) {
|
|
@@ -2827,7 +3066,7 @@ async function savePlan(directory, plan, options) {
|
|
|
2827
3066
|
expectedHash: currentHash,
|
|
2828
3067
|
planHashAfter: hashAfter,
|
|
2829
3068
|
verifyValid: async () => {
|
|
2830
|
-
const onDisk = await
|
|
3069
|
+
const onDisk = await _internals9.loadPlanJsonOnly(directory);
|
|
2831
3070
|
if (!onDisk)
|
|
2832
3071
|
return true;
|
|
2833
3072
|
for (const p of onDisk.phases) {
|
|
@@ -2865,7 +3104,7 @@ async function savePlan(directory, plan, options) {
|
|
|
2865
3104
|
expectedHash: currentHash,
|
|
2866
3105
|
planHashAfter: hashAfter,
|
|
2867
3106
|
verifyValid: async () => {
|
|
2868
|
-
const onDisk = await
|
|
3107
|
+
const onDisk = await _internals9.loadPlanJsonOnly(directory);
|
|
2869
3108
|
if (!onDisk)
|
|
2870
3109
|
return true;
|
|
2871
3110
|
for (const p of onDisk.phases) {
|
|
@@ -3151,6 +3390,10 @@ Phase: ${currentPhase} [${phaseStatus}] | Updated: ${now}
|
|
|
3151
3390
|
const sortedDepends = [...task.depends].sort();
|
|
3152
3391
|
suffix += ` (depends: ${sortedDepends.join(", ")})`;
|
|
3153
3392
|
}
|
|
3393
|
+
if (task.files_touched.length > 0) {
|
|
3394
|
+
const sortedFiles = [...task.files_touched].sort();
|
|
3395
|
+
suffix += ` (files_touched: ${JSON.stringify(sortedFiles)})`;
|
|
3396
|
+
}
|
|
3154
3397
|
if (phase.id === plan.current_phase && task.status === "in_progress" && !currentTaskMarked) {
|
|
3155
3398
|
suffix += " \u2190 CURRENT";
|
|
3156
3399
|
currentTaskMarked = true;
|
|
@@ -3387,12 +3630,12 @@ import {
|
|
|
3387
3630
|
rmSync,
|
|
3388
3631
|
statSync as statSync2
|
|
3389
3632
|
} from "fs";
|
|
3390
|
-
import * as
|
|
3633
|
+
import * as fs7 from "fs/promises";
|
|
3391
3634
|
import * as os4 from "os";
|
|
3392
3635
|
import * as path9 from "path";
|
|
3393
3636
|
|
|
3394
3637
|
// src/evaluation/retention.ts
|
|
3395
|
-
import * as
|
|
3638
|
+
import * as fs5 from "fs/promises";
|
|
3396
3639
|
import * as path8 from "path";
|
|
3397
3640
|
function artifactKey(artifact) {
|
|
3398
3641
|
return `${artifact.namespace}/${artifact.id}`;
|
|
@@ -3404,7 +3647,7 @@ async function evaluationRunCandidates(directory) {
|
|
|
3404
3647
|
const root = path8.join(directory, ".swarm", "evolution", "runs");
|
|
3405
3648
|
let entries = [];
|
|
3406
3649
|
try {
|
|
3407
|
-
entries = await
|
|
3650
|
+
entries = await fs5.readdir(root, { withFileTypes: true });
|
|
3408
3651
|
} catch (error2) {
|
|
3409
3652
|
if (error2.code === "ENOENT") {
|
|
3410
3653
|
return { candidates: [], corrupt: [] };
|
|
@@ -3422,7 +3665,7 @@ async function evaluationRunCandidates(directory) {
|
|
|
3422
3665
|
const artifact = { namespace: "evaluation-run", id };
|
|
3423
3666
|
const target = path8.join(root, entry.name);
|
|
3424
3667
|
try {
|
|
3425
|
-
const run = EvaluationRunV1Schema.parse(JSON.parse(await
|
|
3668
|
+
const run = EvaluationRunV1Schema.parse(JSON.parse(await fs5.readFile(target, "utf8")));
|
|
3426
3669
|
if (run.runId !== id)
|
|
3427
3670
|
throw new Error("run id/path mismatch");
|
|
3428
3671
|
candidates.push({
|
|
@@ -3441,7 +3684,7 @@ async function gateAuditCandidates(directory) {
|
|
|
3441
3684
|
const root = path8.join(directory, ".swarm", "evidence", "gate-audit");
|
|
3442
3685
|
let entries = [];
|
|
3443
3686
|
try {
|
|
3444
|
-
entries = await
|
|
3687
|
+
entries = await fs5.readdir(root, { withFileTypes: true });
|
|
3445
3688
|
} catch (error2) {
|
|
3446
3689
|
if (error2.code === "ENOENT") {
|
|
3447
3690
|
return { candidates: [], corrupt: [] };
|
|
@@ -3456,7 +3699,7 @@ async function gateAuditCandidates(directory) {
|
|
|
3456
3699
|
const artifact = { namespace: "gate-audit", id: entry.name };
|
|
3457
3700
|
const target = path8.join(root, entry.name);
|
|
3458
3701
|
try {
|
|
3459
|
-
const result = GateAuditResultV1Schema.parse(JSON.parse(await
|
|
3702
|
+
const result = GateAuditResultV1Schema.parse(JSON.parse(await fs5.readFile(path8.join(target, "results.json"), "utf8")));
|
|
3460
3703
|
if (result.runId !== entry.name)
|
|
3461
3704
|
throw new Error("run id/path mismatch");
|
|
3462
3705
|
candidates.push({
|
|
@@ -3487,10 +3730,10 @@ async function protectedArtifacts(directory) {
|
|
|
3487
3730
|
}
|
|
3488
3731
|
async function removeCandidate(candidate) {
|
|
3489
3732
|
if (candidate.kind === "directory") {
|
|
3490
|
-
await
|
|
3733
|
+
await fs5.rm(candidate.target, { recursive: true, force: true });
|
|
3491
3734
|
return;
|
|
3492
3735
|
}
|
|
3493
|
-
await
|
|
3736
|
+
await fs5.unlink(candidate.target);
|
|
3494
3737
|
}
|
|
3495
3738
|
var _retentionInternals = {
|
|
3496
3739
|
protectedArtifacts,
|
|
@@ -3546,7 +3789,7 @@ async function archiveEvaluationArtifacts(args) {
|
|
|
3546
3789
|
}
|
|
3547
3790
|
|
|
3548
3791
|
// src/evidence/documents-retention.ts
|
|
3549
|
-
import * as
|
|
3792
|
+
import * as fs6 from "fs";
|
|
3550
3793
|
import * as fsp from "fs/promises";
|
|
3551
3794
|
import * as readline from "readline";
|
|
3552
3795
|
var EVIDENCE_CACHE_FILE = "evidence-cache/documents.jsonl";
|
|
@@ -3554,13 +3797,13 @@ var MAX_READ_BYTES = 100 * 1024 * 1024;
|
|
|
3554
3797
|
var RENAME_MAX_ATTEMPTS = 5;
|
|
3555
3798
|
var RENAME_BACKOFF_MS = 10;
|
|
3556
3799
|
var RENAME_RETRY_CODES = new Set(["EPERM", "EBUSY", "ENOTEMPTY", "EACCES"]);
|
|
3557
|
-
var
|
|
3800
|
+
var _internals10 = {
|
|
3558
3801
|
stat: (p) => fsp.stat(p),
|
|
3559
|
-
createReadStream: (p, options) =>
|
|
3560
|
-
openSync: (p, flags) =>
|
|
3561
|
-
writeSync: (fd, data, position) =>
|
|
3562
|
-
fsyncSync: (fd) =>
|
|
3563
|
-
closeSync: (fd) =>
|
|
3802
|
+
createReadStream: (p, options) => fs6.createReadStream(p, options),
|
|
3803
|
+
openSync: (p, flags) => fs6.openSync(p, flags),
|
|
3804
|
+
writeSync: (fd, data, position) => fs6.writeSync(fd, data, position),
|
|
3805
|
+
fsyncSync: (fd) => fs6.fsyncSync(fd),
|
|
3806
|
+
closeSync: (fd) => fs6.closeSync(fd),
|
|
3564
3807
|
renameWithRetry: atomicRenameWithRetry,
|
|
3565
3808
|
unlink: (p) => fsp.unlink(p)
|
|
3566
3809
|
};
|
|
@@ -3596,9 +3839,9 @@ function emptyResult(dryRun) {
|
|
|
3596
3839
|
};
|
|
3597
3840
|
}
|
|
3598
3841
|
async function readCacheRows(filePath) {
|
|
3599
|
-
const stat2 = await
|
|
3842
|
+
const stat2 = await _internals10.stat(filePath);
|
|
3600
3843
|
const bytesBefore = stat2.size;
|
|
3601
|
-
const stream =
|
|
3844
|
+
const stream = _internals10.createReadStream(filePath, {
|
|
3602
3845
|
encoding: "utf8",
|
|
3603
3846
|
highWaterMark: 64 * 1024
|
|
3604
3847
|
});
|
|
@@ -3674,23 +3917,23 @@ async function rewriteAtomic(filePath, survivors) {
|
|
|
3674
3917
|
`)}
|
|
3675
3918
|
` : "";
|
|
3676
3919
|
let succeeded = false;
|
|
3677
|
-
const fd =
|
|
3920
|
+
const fd = _internals10.openSync(tmpPath, "w");
|
|
3678
3921
|
try {
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
await
|
|
3922
|
+
_internals10.writeSync(fd, payload, 0);
|
|
3923
|
+
_internals10.fsyncSync(fd);
|
|
3924
|
+
_internals10.closeSync(fd);
|
|
3925
|
+
await _internals10.renameWithRetry(tmpPath, filePath);
|
|
3683
3926
|
succeeded = true;
|
|
3684
3927
|
} catch (err) {
|
|
3685
3928
|
try {
|
|
3686
|
-
|
|
3929
|
+
_internals10.closeSync(fd);
|
|
3687
3930
|
} catch {}
|
|
3688
3931
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3689
3932
|
throw new Error(`documents-cache rewrite failed: ${msg}`);
|
|
3690
3933
|
} finally {
|
|
3691
3934
|
if (!succeeded) {
|
|
3692
3935
|
try {
|
|
3693
|
-
await
|
|
3936
|
+
await _internals10.unlink(tmpPath);
|
|
3694
3937
|
} catch {}
|
|
3695
3938
|
}
|
|
3696
3939
|
}
|
|
@@ -3702,7 +3945,7 @@ async function pruneEvidenceDocuments(args) {
|
|
|
3702
3945
|
const filePath = validateSwarmPath(args.directory, EVIDENCE_CACHE_FILE);
|
|
3703
3946
|
let stat2;
|
|
3704
3947
|
try {
|
|
3705
|
-
stat2 = await
|
|
3948
|
+
stat2 = await _internals10.stat(filePath);
|
|
3706
3949
|
} catch (err) {
|
|
3707
3950
|
const code = err?.code;
|
|
3708
3951
|
if (code === "ENOENT")
|
|
@@ -3879,11 +4122,11 @@ function validateProjectRoot(directory) {
|
|
|
3879
4122
|
}
|
|
3880
4123
|
}
|
|
3881
4124
|
async function saveEvidence(directory, taskId, evidence) {
|
|
3882
|
-
|
|
4125
|
+
_internals11.validateProjectRoot(directory);
|
|
3883
4126
|
const sanitizedTaskId = sanitizeTaskId2(taskId);
|
|
3884
4127
|
const relativePath = path9.join("evidence", sanitizedTaskId, "evidence.json");
|
|
3885
4128
|
validateSwarmPath(directory, relativePath);
|
|
3886
|
-
|
|
4129
|
+
_internals11.validateEvidence(evidence);
|
|
3887
4130
|
return withEvidenceLock(directory, relativePath, "evidence-manager", sanitizedTaskId, async () => {
|
|
3888
4131
|
const evidencePath = validateSwarmPath(directory, relativePath);
|
|
3889
4132
|
const evidenceDir = path9.dirname(evidencePath);
|
|
@@ -3932,7 +4175,7 @@ async function saveEvidence(directory, taskId, evidence) {
|
|
|
3932
4175
|
const tempPath = path9.join(evidenceDir, `evidence.json.tmp.${Date.now()}.${process.pid}`);
|
|
3933
4176
|
try {
|
|
3934
4177
|
await bunWrite(tempPath, bundleJson);
|
|
3935
|
-
await
|
|
4178
|
+
await fs7.rename(tempPath, evidencePath);
|
|
3936
4179
|
} catch (error2) {
|
|
3937
4180
|
try {
|
|
3938
4181
|
rmSync(tempPath, { force: true });
|
|
@@ -3989,7 +4232,7 @@ async function loadEvidence(directory, taskId, options) {
|
|
|
3989
4232
|
return { status: "invalid_schema", errors: ["Invalid JSON"] };
|
|
3990
4233
|
}
|
|
3991
4234
|
if (isFlatRetrospective(parsed)) {
|
|
3992
|
-
const wrappedBundle =
|
|
4235
|
+
const wrappedBundle = _internals11.wrapFlatRetrospective(parsed, sanitizedTaskId);
|
|
3993
4236
|
try {
|
|
3994
4237
|
const validated = EvidenceBundleSchema.parse(wrappedBundle);
|
|
3995
4238
|
if (options?.migrate === false) {
|
|
@@ -4002,7 +4245,7 @@ async function loadEvidence(directory, taskId, options) {
|
|
|
4002
4245
|
const tempPath = path9.join(evidenceDir, `evidence.json.tmp.${Date.now()}.${process.pid}`);
|
|
4003
4246
|
try {
|
|
4004
4247
|
await bunWrite(tempPath, bundleJson);
|
|
4005
|
-
await
|
|
4248
|
+
await fs7.rename(tempPath, evidencePath);
|
|
4006
4249
|
} catch (writeError) {
|
|
4007
4250
|
try {
|
|
4008
4251
|
rmSync(tempPath, { force: true });
|
|
@@ -4081,15 +4324,15 @@ async function checkRequirementCoverage(phase, directory) {
|
|
|
4081
4324
|
const relativePath = path9.join("evidence", `req-coverage-phase-${phase}.json`);
|
|
4082
4325
|
const absolutePath = path9.resolve(directory, ".swarm", relativePath);
|
|
4083
4326
|
try {
|
|
4084
|
-
await
|
|
4327
|
+
await fs7.access(absolutePath);
|
|
4085
4328
|
return { exists: true, path: absolutePath };
|
|
4086
4329
|
} catch {
|
|
4087
4330
|
return { exists: false, path: absolutePath };
|
|
4088
4331
|
}
|
|
4089
4332
|
}
|
|
4090
4333
|
async function archiveEvidence(directory, maxAgeDays, maxBundles, options) {
|
|
4091
|
-
const taskIds = await
|
|
4092
|
-
const cutoffDate = options?.now ? new Date(options.now) :
|
|
4334
|
+
const taskIds = await _internals11.listEvidenceTaskIds(directory);
|
|
4335
|
+
const cutoffDate = options?.now ? new Date(options.now) : _internals11.now();
|
|
4093
4336
|
cutoffDate.setDate(cutoffDate.getDate() - maxAgeDays);
|
|
4094
4337
|
const cutoffIso = cutoffDate.toISOString();
|
|
4095
4338
|
const selected = new Set;
|
|
@@ -4101,7 +4344,7 @@ async function archiveEvidence(directory, maxAgeDays, maxBundles, options) {
|
|
|
4101
4344
|
for (const taskId of taskIds) {
|
|
4102
4345
|
let result;
|
|
4103
4346
|
try {
|
|
4104
|
-
result = await
|
|
4347
|
+
result = await _internals11.loadEvidence(directory, taskId);
|
|
4105
4348
|
} catch {
|
|
4106
4349
|
warn("archive: skipping corrupt or unreadable evidence for task", taskId);
|
|
4107
4350
|
continue;
|
|
@@ -4129,7 +4372,7 @@ async function archiveEvidence(directory, maxAgeDays, maxBundles, options) {
|
|
|
4129
4372
|
}
|
|
4130
4373
|
if (!options?.dryRun) {
|
|
4131
4374
|
for (const taskId of [...selected].sort()) {
|
|
4132
|
-
const deleted = await
|
|
4375
|
+
const deleted = await _internals11.deleteEvidence(directory, taskId);
|
|
4133
4376
|
if (deleted)
|
|
4134
4377
|
archived.push(taskId);
|
|
4135
4378
|
else
|
|
@@ -4155,7 +4398,7 @@ async function archiveEvidence(directory, maxAgeDays, maxBundles, options) {
|
|
|
4155
4398
|
};
|
|
4156
4399
|
if (typeof options?.cacheMaxBytes === "number" && options.cacheMaxBytes > 0 || typeof options?.cacheMaxRecords === "number" && options.cacheMaxRecords > 0) {
|
|
4157
4400
|
try {
|
|
4158
|
-
documentsCache = await
|
|
4401
|
+
documentsCache = await _internals11.pruneEvidenceDocuments({
|
|
4159
4402
|
directory,
|
|
4160
4403
|
maxBytes: options?.cacheMaxBytes,
|
|
4161
4404
|
maxRecords: options?.cacheMaxRecords,
|
|
@@ -4183,7 +4426,7 @@ async function archiveEvidence(directory, maxAgeDays, maxBundles, options) {
|
|
|
4183
4426
|
function validateEvidence(evidence) {
|
|
4184
4427
|
return EvidenceSchema.parse(evidence);
|
|
4185
4428
|
}
|
|
4186
|
-
var
|
|
4429
|
+
var _internals11 = {
|
|
4187
4430
|
wrapFlatRetrospective,
|
|
4188
4431
|
loadEvidence,
|
|
4189
4432
|
listEvidenceTaskIds,
|
|
@@ -4305,4 +4548,4 @@ function mergeDurableGateEntriesFromEvidence(taskId, entries, evidence) {
|
|
|
4305
4548
|
return merged;
|
|
4306
4549
|
}
|
|
4307
4550
|
|
|
4308
|
-
export { getExecutor, init_executor, MAX_TRANSIENT_RETRIES, isTransientSpawnError, transientBackoff, getGitRepositoryStatus, isGitRepo, getDefaultBaseBranch, resetToRemoteBranch, resetToMainAfterMerge, isStateUnreadable, loadEpicSessionState, isEpicModeActive, enableEpicMode, disableEpicMode, normalizePath, pathsConflict, isGlobalFile, isProtectedPath, readTaskScopes, computeSpecHash, loadPlanJsonOnly, loadPlan, savePlan, closePlanTerminalState, derivePlanMarkdown, isValidEvidenceType, sanitizeTaskId2 as sanitizeTaskId, validateProjectRoot, saveEvidence, loadEvidence, listEvidenceTaskIds, checkRequirementCoverage, archiveEvidence, readDurableGateEvidence, getDurableGateEvidenceStatus, getDurableGateEvidenceStatusForTask, mergeDurableGateEntriesFromEvidence };
|
|
4551
|
+
export { getExecutor, init_executor, MAX_TRANSIENT_RETRIES, isTransientSpawnError, transientBackoff, getGitRepositoryStatus, isGitRepo, getDefaultBaseBranch, resetToRemoteBranch, resetToMainAfterMerge, containsPathTraversal, containsControlChars, isStateUnreadable, loadEpicSessionState, isEpicModeActive, enableEpicMode, disableEpicMode, normalizePath, pathsConflict, isGlobalFile, isProtectedPath, readTaskScopes, computeSpecHash, loadPlanJsonOnly, loadPlan, savePlan, closePlanTerminalState, derivePlanMarkdown, isValidEvidenceType, sanitizeTaskId2 as sanitizeTaskId, validateProjectRoot, saveEvidence, loadEvidence, listEvidenceTaskIds, checkRequirementCoverage, archiveEvidence, readDurableGateEvidence, getDurableGateEvidenceStatus, getDurableGateEvidenceStatusForTask, mergeDurableGateEntriesFromEvidence };
|