opencode-swarm 7.139.0 → 7.139.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.opencode/skills/swarm-pr-review/SKILL.md +15 -0
- package/README.md +7 -6
- package/dist/cli/{config-doctor-aszp7z1h.js → config-doctor-hrb61yqe.js} +2 -2
- package/dist/cli/{core-3s832mxx.js → core-g2dfh9fq.js} +1 -1
- package/dist/cli/{curation-policy-a3hs73f7.js → curation-policy-4tp0mbcb.js} +7 -7
- package/dist/cli/{curator-drift-jpap6hv4.js → curator-drift-vfh07mqy.js} +5 -2
- package/dist/cli/{curator-llm-factory-e8ngwyjm.js → curator-llm-factory-hvw13hmr.js} +28 -28
- package/dist/cli/{curator-zxjqcc8r.js → curator-vpcs1p1v.js} +28 -28
- package/dist/cli/{evidence-summary-service-qfhjfxdz.js → evidence-summary-service-kzxr71yd.js} +9 -9
- package/dist/cli/{gate-evidence-m2grv70v.js → gate-evidence-z2b1ymnw.js} +5 -5
- package/dist/cli/{guardrail-explain-rqpmzxyy.js → guardrail-explain-k62h3c92.js} +29 -29
- package/dist/cli/{guardrail-log-vd4a0ng5.js → guardrail-log-2ftew0p3.js} +3 -3
- package/dist/cli/{hive-promoter-jc5vym27.js → hive-promoter-mpf0cfkk.js} +28 -28
- package/dist/cli/{index-4ft523nb.js → index-0wp67gqj.js} +143 -89
- package/dist/cli/{index-ymszzvnr.js → index-3eddtgxt.js} +1 -1
- package/dist/cli/{index-67yqywan.js → index-3radty3f.js} +2 -2
- package/dist/cli/{index-p2dz85tv.js → index-4xbyy6aw.js} +2 -2
- package/dist/cli/{index-a614s16f.js → index-5j6chvj8.js} +1 -1
- package/dist/cli/{index-tcdcj1g2.js → index-5w7ekpy3.js} +2 -2
- package/dist/cli/{index-nbgw5dxa.js → index-5zyk8qgv.js} +2 -2
- package/dist/cli/{index-tyh0p5e8.js → index-668dpw5e.js} +1 -1
- package/dist/cli/{index-6q240xgm.js → index-6c5f309q.js} +2 -2
- package/dist/cli/{index-s428dmy6.js → index-6w1re1qn.js} +2 -2
- package/dist/cli/{index-nsnfvckc.js → index-8gftfvpp.js} +1 -1
- package/dist/cli/{index-rtetrxxq.js → index-8p9pasnp.js} +8 -3
- package/dist/cli/{index-85hstja2.js → index-a12906mj.js} +1 -1
- package/dist/cli/{index-chvqee1j.js → index-a5eba0t8.js} +2 -2
- package/dist/cli/{index-r3pth9a7.js → index-a7nh382r.js} +508 -441
- package/dist/cli/{index-t31cc7kv.js → index-cyw81ngh.js} +7 -7
- package/dist/cli/{index-kv36s0x0.js → index-e9tx99ds.js} +6 -3
- package/dist/cli/{index-fsrp8wp3.js → index-ed5ykebp.js} +25 -2
- package/dist/cli/{index-0tsetsxs.js → index-ffpmqx30.js} +4 -4
- package/dist/cli/{index-nc544sfw.js → index-gvhvz176.js} +2 -2
- package/dist/cli/{index-3nr2sn32.js → index-ktagrqxw.js} +3 -3
- package/dist/cli/{index-t26nfmcs.js → index-prmb5qfp.js} +2 -2
- package/dist/cli/{index-q3qtgtd0.js → index-q11t5erh.js} +1 -1
- package/dist/cli/{index-x20cgr2q.js → index-q7ezzgwq.js} +16 -2
- package/dist/cli/{index-z1tkxzq4.js → index-s608d3hw.js} +2 -2
- package/dist/cli/{index-y46anh5e.js → index-se8xc78k.js} +30 -30
- package/dist/cli/{index-84s6x604.js → index-w71cq27a.js} +5 -5
- package/dist/cli/{index-ddmnhv4h.js → index-wrt6m5ze.js} +1 -1
- package/dist/cli/{index-4qzeef9h.js → index-x9q4bbhd.js} +1 -1
- package/dist/cli/{index-zd15ya1w.js → index-y47dwge1.js} +1 -1
- package/dist/cli/{index-5bkpyvdf.js → index-y64jv2pe.js} +1 -1
- package/dist/cli/{index-gytyqv1d.js → index-yr6x707c.js} +2 -2
- package/dist/cli/index.js +28 -28
- package/dist/cli/{knowledge-escalator-6473ey4c.js → knowledge-escalator-n9pmx4qr.js} +8 -8
- package/dist/cli/{knowledge-events-wwzpz8m4.js → knowledge-events-raevm18w.js} +6 -6
- package/dist/cli/{knowledge-link-trfydkzm.js → knowledge-link-3tq8w6gs.js} +5 -5
- package/dist/cli/{knowledge-store-99gd42jy.js → knowledge-store-bcfqz8fr.js} +6 -6
- package/dist/cli/{knowledge-validator-v2eevvdg.js → knowledge-validator-jxqj96cx.js} +9 -9
- package/dist/cli/{pending-delegations-p6n83x67.js → pending-delegations-tmyf18p4.js} +5 -5
- package/dist/cli/{pr-subscriptions-xbrfr51c.js → pr-subscriptions-hhx6yk24.js} +5 -5
- package/dist/cli/{runner-9an52tmz.js → runner-w30gazew.js} +6 -6
- package/dist/cli/{scan-cursor-39zxpw34.js → scan-cursor-ah5swtyh.js} +7 -7
- package/dist/cli/{schema-xhfwr6b2.js → schema-f7jgrtxj.js} +3 -1
- package/dist/cli/{scope-persistence-nsa6ra9s.js → scope-persistence-3f0d4fwv.js} +4 -4
- package/dist/cli/{skill-generator-5px81476.js → skill-generator-hp7as46c.js} +10 -10
- package/dist/cli/{telemetry-7nt7zhyp.js → telemetry-4tgrfhaz.js} +1 -1
- package/dist/cli/{worktree-collision-ownership-9x4s4890.js → worktree-collision-ownership-vexb0b6r.js} +38 -8
- package/dist/config/context-window.d.ts +210 -0
- package/dist/config/schema.d.ts +18 -0
- package/dist/evaluation/ephemeral-agent-dispatcher.d.ts +18 -0
- package/dist/evaluation/model-dispatcher.d.ts +1 -0
- package/dist/hooks/delegate-ack-collector.d.ts +1 -1
- package/dist/hooks/delegation-gate/worktree-collision-ownership.d.ts +7 -0
- package/dist/hooks/delegation-gate/worktree-isolation.d.ts +2 -1
- package/dist/hooks/delegation-gate/worktree-provisioning-owner.d.ts +6 -0
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/init-orphan-recovery.d.ts +4 -1
- package/dist/hooks/knowledge-application-gate.d.ts +2 -1
- package/dist/hooks/knowledge-application.d.ts +5 -4
- package/dist/hooks/knowledge-injector.d.ts +16 -0
- package/dist/hooks/knowledge-types.d.ts +1 -1
- package/dist/hooks/messages-transform.d.ts +18 -0
- package/dist/hooks/model-limits.d.ts +88 -30
- package/dist/hooks/pr-workflow-gate.d.ts +8 -1
- package/dist/index.js +455 -452
- package/dist/memory/injector.d.ts +2 -0
- package/dist/services/context-budget-service.d.ts +6 -1
- package/dist/services/status-service.d.ts +14 -0
- package/dist/state.d.ts +37 -0
- package/dist/tools/context-status.d.ts +3 -1
- package/dist/turbo/lean/runner.d.ts +10 -0
- package/dist/utils/ephemeral-session-teardown.d.ts +98 -0
- package/dist/utils/path-security.d.ts +75 -5
- package/dist/utils/swarm-artifact-cache.d.ts +13 -0
- package/dist/worktree/index.d.ts +1 -1
- package/dist/worktree/merge.d.ts +36 -3
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
EvaluationRunV1Schema,
|
|
4
4
|
GateAuditResultV1Schema,
|
|
5
5
|
getProtectedEvaluationRunIds
|
|
6
|
-
} from "./index-
|
|
6
|
+
} from "./index-s608d3hw.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-5w7ekpy3.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-4xbyy6aw.js";
|
|
44
44
|
import {
|
|
45
45
|
PlanSchema
|
|
46
46
|
} from "./index-1kz6da87.js";
|
|
@@ -50,16 +50,17 @@ import {
|
|
|
50
50
|
import {
|
|
51
51
|
readSwarmFileAsync,
|
|
52
52
|
validateSwarmPath
|
|
53
|
-
} from "./index-
|
|
53
|
+
} from "./index-x9q4bbhd.js";
|
|
54
54
|
import {
|
|
55
|
+
invalidateCachedArtifact,
|
|
55
56
|
readCachedParsedFile
|
|
56
|
-
} from "./index-
|
|
57
|
+
} from "./index-ed5ykebp.js";
|
|
57
58
|
import {
|
|
58
59
|
withEvidenceLock
|
|
59
|
-
} from "./index-
|
|
60
|
+
} from "./index-5j6chvj8.js";
|
|
60
61
|
import {
|
|
61
62
|
emit
|
|
62
|
-
} from "./index-
|
|
63
|
+
} from "./index-a5eba0t8.js";
|
|
63
64
|
import {
|
|
64
65
|
ZodError,
|
|
65
66
|
init_zod
|
|
@@ -980,7 +981,7 @@ import {
|
|
|
980
981
|
writeFileSync as writeFileSync4
|
|
981
982
|
} from "fs";
|
|
982
983
|
import * as fsPromises from "fs/promises";
|
|
983
|
-
import * as
|
|
984
|
+
import * as path8 from "path";
|
|
984
985
|
|
|
985
986
|
// src/git/branch.ts
|
|
986
987
|
init_executor();
|
|
@@ -1602,6 +1603,7 @@ function sanitizeContextText(text) {
|
|
|
1602
1603
|
init_logger();
|
|
1603
1604
|
|
|
1604
1605
|
// src/utils/path-security.ts
|
|
1606
|
+
import * as path5 from "path";
|
|
1605
1607
|
function containsPathTraversal(str) {
|
|
1606
1608
|
if (/\.\.[/\\]/.test(str))
|
|
1607
1609
|
return true;
|
|
@@ -1642,14 +1644,56 @@ function containsControlChars(str) {
|
|
|
1642
1644
|
return false;
|
|
1643
1645
|
}
|
|
1644
1646
|
function validateWorkspaceRoot(directory) {
|
|
1647
|
+
validateProjectDirectory(directory);
|
|
1648
|
+
}
|
|
1649
|
+
function validateProjectDirectory(directory) {
|
|
1645
1650
|
if (!directory || directory.trim() === "") {
|
|
1646
|
-
throw new Error("Invalid directory: empty");
|
|
1651
|
+
throw new Error("Invalid project directory: empty");
|
|
1647
1652
|
}
|
|
1648
1653
|
if (containsPathTraversal(directory)) {
|
|
1649
|
-
throw new Error("Invalid directory: path traversal detected");
|
|
1654
|
+
throw new Error("Invalid project directory: path traversal detected");
|
|
1650
1655
|
}
|
|
1651
1656
|
if (containsControlChars(directory)) {
|
|
1652
|
-
throw new Error("Invalid directory: control characters detected");
|
|
1657
|
+
throw new Error("Invalid project directory: control characters detected");
|
|
1658
|
+
}
|
|
1659
|
+
if (!path5.isAbsolute(directory) && !/^[A-Za-z]:[/\\]/.test(directory)) {
|
|
1660
|
+
throw new Error("Invalid project directory: must be an absolute path");
|
|
1661
|
+
}
|
|
1662
|
+
assertNotSystemLocation(directory);
|
|
1663
|
+
}
|
|
1664
|
+
var DENIED_ROOT_SUBTREES = new Set([
|
|
1665
|
+
"etc",
|
|
1666
|
+
"usr",
|
|
1667
|
+
"bin",
|
|
1668
|
+
"sbin",
|
|
1669
|
+
"lib",
|
|
1670
|
+
"lib64",
|
|
1671
|
+
"boot",
|
|
1672
|
+
"dev",
|
|
1673
|
+
"proc",
|
|
1674
|
+
"sys",
|
|
1675
|
+
"windows",
|
|
1676
|
+
"winnt",
|
|
1677
|
+
"program files",
|
|
1678
|
+
"program files (x86)",
|
|
1679
|
+
"programdata",
|
|
1680
|
+
"system volume information"
|
|
1681
|
+
]);
|
|
1682
|
+
var DENIED_EXACT_ROOT_CHILDREN = new Set(["users", "home", "root"]);
|
|
1683
|
+
function assertNotSystemLocation(directory) {
|
|
1684
|
+
for (const parser of [path5.win32, path5.posix]) {
|
|
1685
|
+
if (!parser.isAbsolute(directory))
|
|
1686
|
+
continue;
|
|
1687
|
+
const normalized = parser.normalize(directory);
|
|
1688
|
+
const { root } = parser.parse(normalized);
|
|
1689
|
+
const segments = normalized.slice(root.length).split(/[/\\]/).filter((segment) => segment.length > 0);
|
|
1690
|
+
if (segments.length === 0) {
|
|
1691
|
+
throw new Error(`Invalid project directory: filesystem root is not a project root (${directory})`);
|
|
1692
|
+
}
|
|
1693
|
+
const first = (segments[0] ?? "").toLowerCase();
|
|
1694
|
+
if (DENIED_ROOT_SUBTREES.has(first) || segments.length === 1 && DENIED_EXACT_ROOT_CHILDREN.has(first)) {
|
|
1695
|
+
throw new Error(`Invalid project directory: system location is not a project root (${directory})`);
|
|
1696
|
+
}
|
|
1653
1697
|
}
|
|
1654
1698
|
}
|
|
1655
1699
|
|
|
@@ -1827,13 +1871,13 @@ var _internals6 = {
|
|
|
1827
1871
|
// src/turbo/epic/state.ts
|
|
1828
1872
|
init_logger();
|
|
1829
1873
|
import * as fs3 from "fs";
|
|
1830
|
-
import * as
|
|
1874
|
+
import * as path6 from "path";
|
|
1831
1875
|
var STATE_FILE = "epic-state.json";
|
|
1832
1876
|
function nowISO() {
|
|
1833
1877
|
return new Date().toISOString();
|
|
1834
1878
|
}
|
|
1835
1879
|
function ensureSwarmDir(directory) {
|
|
1836
|
-
const swarmDir =
|
|
1880
|
+
const swarmDir = path6.resolve(directory, ".swarm");
|
|
1837
1881
|
if (!fs3.existsSync(swarmDir)) {
|
|
1838
1882
|
fs3.mkdirSync(swarmDir, { recursive: true });
|
|
1839
1883
|
}
|
|
@@ -1855,7 +1899,7 @@ function markStateUnreadable(directory, reason) {
|
|
|
1855
1899
|
}
|
|
1856
1900
|
function readPersisted(directory) {
|
|
1857
1901
|
try {
|
|
1858
|
-
const filePath =
|
|
1902
|
+
const filePath = path6.join(directory, ".swarm", STATE_FILE);
|
|
1859
1903
|
if (!fs3.existsSync(filePath)) {
|
|
1860
1904
|
const seed = emptyPersisted();
|
|
1861
1905
|
try {
|
|
@@ -1891,7 +1935,7 @@ function writePersisted(directory, persisted) {
|
|
|
1891
1935
|
let payload;
|
|
1892
1936
|
try {
|
|
1893
1937
|
ensureSwarmDir(directory);
|
|
1894
|
-
filePath =
|
|
1938
|
+
filePath = path6.join(directory, ".swarm", STATE_FILE);
|
|
1895
1939
|
tmpPath = `${filePath}.tmp.${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1896
1940
|
persisted.updatedAt = nowISO();
|
|
1897
1941
|
payload = `${JSON.stringify(persisted, null, 2)}
|
|
@@ -1940,7 +1984,7 @@ function isEpicModeActive(directory, sessionID) {
|
|
|
1940
1984
|
function isEpicModeActiveForProject(directory) {
|
|
1941
1985
|
if (stateUnreadableMap.get(directory))
|
|
1942
1986
|
return false;
|
|
1943
|
-
if (!fs3.existsSync(
|
|
1987
|
+
if (!fs3.existsSync(path6.join(directory, ".swarm", STATE_FILE))) {
|
|
1944
1988
|
return false;
|
|
1945
1989
|
}
|
|
1946
1990
|
const persisted = readPersisted(directory);
|
|
@@ -2049,7 +2093,7 @@ var _internals7 = {
|
|
|
2049
2093
|
gitHeadSha: (cwd) => {
|
|
2050
2094
|
return _internals5.gitExec(["rev-parse", "HEAD"], cwd).trim();
|
|
2051
2095
|
},
|
|
2052
|
-
sleep: (ms) => new Promise((
|
|
2096
|
+
sleep: (ms) => new Promise((resolve3) => setTimeout(resolve3, ms)),
|
|
2053
2097
|
hasExistingTaskCommit: (cwd, taskId) => {
|
|
2054
2098
|
const safeId = scrubTaskIdForGitSubject(taskId);
|
|
2055
2099
|
const escaped = safeId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -2067,7 +2111,7 @@ var _internals7 = {
|
|
|
2067
2111
|
|
|
2068
2112
|
// src/turbo/lean/conflicts.ts
|
|
2069
2113
|
import * as fs4 from "fs";
|
|
2070
|
-
import * as
|
|
2114
|
+
import * as path7 from "path";
|
|
2071
2115
|
|
|
2072
2116
|
// src/utils/path.ts
|
|
2073
2117
|
function normalizePath(p) {
|
|
@@ -2195,7 +2239,7 @@ function isProtectedPath(normalizedPath) {
|
|
|
2195
2239
|
return false;
|
|
2196
2240
|
}
|
|
2197
2241
|
function readTaskScopes(directory, taskId) {
|
|
2198
|
-
const scopePath =
|
|
2242
|
+
const scopePath = path7.join(directory, ".swarm", "scopes", `scope-${taskId}.json`);
|
|
2199
2243
|
try {
|
|
2200
2244
|
if (!fs4.existsSync(scopePath)) {
|
|
2201
2245
|
return null;
|
|
@@ -2214,7 +2258,7 @@ function readTaskScopes(directory, taskId) {
|
|
|
2214
2258
|
// src/utils/spec-hash.ts
|
|
2215
2259
|
import { createHash as createHash2 } from "crypto";
|
|
2216
2260
|
import * as fsSync2 from "fs";
|
|
2217
|
-
import { join as
|
|
2261
|
+
import { join as join6 } from "path";
|
|
2218
2262
|
async function computeSpecHash(directory) {
|
|
2219
2263
|
const spec = _internals8.readEffectiveSpecSync(directory);
|
|
2220
2264
|
if (!spec)
|
|
@@ -2243,7 +2287,7 @@ async function isSpecStale(directory, plan) {
|
|
|
2243
2287
|
return { stale: false };
|
|
2244
2288
|
}
|
|
2245
2289
|
function isObligationPreserving(directory) {
|
|
2246
|
-
const snapshotPath =
|
|
2290
|
+
const snapshotPath = join6(directory, ".swarm", "spec-snapshot.md");
|
|
2247
2291
|
try {
|
|
2248
2292
|
let recordedContent;
|
|
2249
2293
|
try {
|
|
@@ -2256,10 +2300,10 @@ function isObligationPreserving(directory) {
|
|
|
2256
2300
|
return false;
|
|
2257
2301
|
}
|
|
2258
2302
|
const currentContent = currentResult.content;
|
|
2259
|
-
const
|
|
2303
|
+
const normalize2 = (text) => text.replace(/\r\n/g, `
|
|
2260
2304
|
`);
|
|
2261
|
-
const recordedNorm =
|
|
2262
|
-
const currentNorm =
|
|
2305
|
+
const recordedNorm = normalize2(recordedContent);
|
|
2306
|
+
const currentNorm = normalize2(currentContent);
|
|
2263
2307
|
const splitParagraphs = (text) => text.split(/\n\s*\n/).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
2264
2308
|
const recordedParagraphs = splitParagraphs(recordedNorm);
|
|
2265
2309
|
const currentParagraphs = splitParagraphs(currentNorm);
|
|
@@ -2289,7 +2333,7 @@ var _internals8 = {
|
|
|
2289
2333
|
readEffectiveSpecSync
|
|
2290
2334
|
};
|
|
2291
2335
|
function computeSpecDiff(directory) {
|
|
2292
|
-
const snapshotPath =
|
|
2336
|
+
const snapshotPath = join6(directory, ".swarm", "spec-snapshot.md");
|
|
2293
2337
|
let recordedContent;
|
|
2294
2338
|
try {
|
|
2295
2339
|
const snapshotSize = fsSync2.statSync(snapshotPath).size;
|
|
@@ -2306,11 +2350,11 @@ function computeSpecDiff(directory) {
|
|
|
2306
2350
|
return null;
|
|
2307
2351
|
}
|
|
2308
2352
|
const currentContent = spec.content;
|
|
2309
|
-
const
|
|
2353
|
+
const normalize2 = (text) => text.replace(/\r\n/g, `
|
|
2310
2354
|
`);
|
|
2311
|
-
const recordedLines =
|
|
2355
|
+
const recordedLines = normalize2(recordedContent).split(`
|
|
2312
2356
|
`);
|
|
2313
|
-
const currentLines =
|
|
2357
|
+
const currentLines = normalize2(currentContent).split(`
|
|
2314
2358
|
`);
|
|
2315
2359
|
const diffLines = computeLcsDiff(recordedLines, currentLines);
|
|
2316
2360
|
const MAX_DIFF_LINES = 300;
|
|
@@ -2493,7 +2537,7 @@ async function retryCasWithBackoff(directory, eventInput, options) {
|
|
|
2493
2537
|
expectedHashPrefix: currentExpected.slice(0, 8),
|
|
2494
2538
|
delayMs
|
|
2495
2539
|
});
|
|
2496
|
-
await new Promise((
|
|
2540
|
+
await new Promise((resolve4) => setTimeout(resolve4, delayMs));
|
|
2497
2541
|
if (options.verifyValid) {
|
|
2498
2542
|
const stillValid = await options.verifyValid();
|
|
2499
2543
|
if (!stillValid)
|
|
@@ -2536,7 +2580,7 @@ async function getLatestLedgerHash(directory) {
|
|
|
2536
2580
|
}
|
|
2537
2581
|
}
|
|
2538
2582
|
async function surfaceLedgerStaleIfPersisted(directory, plan) {
|
|
2539
|
-
const resolvedWorkspace =
|
|
2583
|
+
const resolvedWorkspace = path8.resolve(directory);
|
|
2540
2584
|
if (!ledgerStaleWorkspaces.has(resolvedWorkspace)) {
|
|
2541
2585
|
return plan;
|
|
2542
2586
|
}
|
|
@@ -2555,7 +2599,7 @@ async function surfaceLedgerStaleIfPersisted(directory, plan) {
|
|
|
2555
2599
|
return plan;
|
|
2556
2600
|
}
|
|
2557
2601
|
async function parsePlanJsonCached(directory) {
|
|
2558
|
-
const planJsonPath =
|
|
2602
|
+
const planJsonPath = path8.resolve(directory, ".swarm", "plan.json");
|
|
2559
2603
|
return readCachedParsedFile(planJsonPath, PLAN_JSON_CACHE_NAMESPACE, () => readSwarmFileAsync(directory, "plan.json"), (planJsonContent) => {
|
|
2560
2604
|
if (planJsonContent.includes("\x00") || planJsonContent.includes("\uFFFD")) {
|
|
2561
2605
|
throw new Error("Plan rejected: .swarm/plan.json contains null bytes or invalid encoding");
|
|
@@ -2615,13 +2659,13 @@ async function isPlanMdInSync(directory, plan, cache) {
|
|
|
2615
2659
|
return false;
|
|
2616
2660
|
}
|
|
2617
2661
|
async function regeneratePlanMarkdown(directory, plan) {
|
|
2618
|
-
const swarmDir =
|
|
2662
|
+
const swarmDir = path8.resolve(directory, ".swarm");
|
|
2619
2663
|
const contentHash = computePlanContentHash(plan);
|
|
2620
2664
|
const markdown = derivePlanMarkdown(plan);
|
|
2621
2665
|
const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
|
|
2622
2666
|
${markdown}`;
|
|
2623
|
-
const mdPath =
|
|
2624
|
-
const mdTempPath =
|
|
2667
|
+
const mdPath = path8.join(swarmDir, "plan.md");
|
|
2668
|
+
const mdTempPath = path8.join(swarmDir, `plan.md.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
2625
2669
|
try {
|
|
2626
2670
|
await bunWrite(mdTempPath, markdownWithHash);
|
|
2627
2671
|
renameSync2(mdTempPath, mdPath);
|
|
@@ -2630,6 +2674,7 @@ ${markdown}`;
|
|
|
2630
2674
|
unlinkSync2(mdTempPath);
|
|
2631
2675
|
} catch {}
|
|
2632
2676
|
}
|
|
2677
|
+
invalidateCachedArtifact(mdPath);
|
|
2633
2678
|
}
|
|
2634
2679
|
async function loadPlan(directory, cache) {
|
|
2635
2680
|
const planJsonContent = await readSwarmFileAsync(directory, "plan.json", cache);
|
|
@@ -2653,7 +2698,7 @@ async function loadPlan(directory, cache) {
|
|
|
2653
2698
|
if (await ledgerExists(directory)) {
|
|
2654
2699
|
const planHash = computePlanHash(validated);
|
|
2655
2700
|
const ledgerHash = await getLatestLedgerHash(directory);
|
|
2656
|
-
const resolvedWorkspace =
|
|
2701
|
+
const resolvedWorkspace = path8.resolve(directory);
|
|
2657
2702
|
if (!startupLedgerCheckedWorkspaces.has(resolvedWorkspace)) {
|
|
2658
2703
|
startupLedgerCheckedWorkspaces.add(resolvedWorkspace);
|
|
2659
2704
|
if (ledgerHash !== "" && planHash !== ledgerHash) {
|
|
@@ -2727,7 +2772,7 @@ async function loadPlan(directory, cache) {
|
|
|
2727
2772
|
if (!preserving) {
|
|
2728
2773
|
try {
|
|
2729
2774
|
const diffInfo = computeSpecDiff(directory);
|
|
2730
|
-
const specStalenessPath =
|
|
2775
|
+
const specStalenessPath = path8.join(directory, ".swarm", "spec-staleness.json");
|
|
2731
2776
|
await fsPromises.writeFile(specStalenessPath, JSON.stringify({
|
|
2732
2777
|
type: "spec_stale_detected",
|
|
2733
2778
|
timestamp: new Date().toISOString(),
|
|
@@ -2739,9 +2784,10 @@ async function loadPlan(directory, cache) {
|
|
|
2739
2784
|
diff: diffInfo?.diff ?? null,
|
|
2740
2785
|
changedSections: diffInfo?.changedSections ?? []
|
|
2741
2786
|
}, null, 2), "utf-8");
|
|
2787
|
+
invalidateCachedArtifact(specStalenessPath);
|
|
2742
2788
|
} catch {}
|
|
2743
2789
|
try {
|
|
2744
|
-
const eventsPath =
|
|
2790
|
+
const eventsPath = path8.join(directory, ".swarm", "events.jsonl");
|
|
2745
2791
|
const event = {
|
|
2746
2792
|
type: "spec_stale_detected",
|
|
2747
2793
|
timestamp: new Date().toISOString(),
|
|
@@ -2807,7 +2853,7 @@ async function loadPlan(directory, cache) {
|
|
|
2807
2853
|
return migrated;
|
|
2808
2854
|
}
|
|
2809
2855
|
if (await ledgerExists(directory)) {
|
|
2810
|
-
const resolvedDir =
|
|
2856
|
+
const resolvedDir = path8.resolve(directory);
|
|
2811
2857
|
const existingMutex = recoveryMutexes.get(resolvedDir);
|
|
2812
2858
|
if (existingMutex) {
|
|
2813
2859
|
await existingMutex;
|
|
@@ -2936,9 +2982,9 @@ async function savePlan(directory, plan, options) {
|
|
|
2936
2982
|
} else {
|
|
2937
2983
|
const existingEvents = await readLedgerEvents(directory);
|
|
2938
2984
|
if (existingEvents.length > 0 && existingEvents[0].plan_id !== planId) {
|
|
2939
|
-
const swarmDir2 =
|
|
2940
|
-
const oldLedgerPath =
|
|
2941
|
-
const oldLedgerBackupPath =
|
|
2985
|
+
const swarmDir2 = path8.resolve(directory, ".swarm");
|
|
2986
|
+
const oldLedgerPath = path8.join(swarmDir2, "plan-ledger.jsonl");
|
|
2987
|
+
const oldLedgerBackupPath = path8.join(swarmDir2, `plan-ledger.backup-${Date.now()}-${Math.floor(Math.random() * 1e9)}.jsonl`);
|
|
2942
2988
|
let backupExists = false;
|
|
2943
2989
|
if (existsSync3(oldLedgerPath)) {
|
|
2944
2990
|
try {
|
|
@@ -2976,7 +3022,7 @@ async function savePlan(directory, plan, options) {
|
|
|
2976
3022
|
}
|
|
2977
3023
|
}
|
|
2978
3024
|
if (initSucceeded && backupExists) {
|
|
2979
|
-
const archivePath =
|
|
3025
|
+
const archivePath = path8.join(swarmDir2, `plan-ledger.archived-${Date.now()}-${Math.floor(Math.random() * 1e9)}.jsonl`);
|
|
2980
3026
|
try {
|
|
2981
3027
|
renameSync2(oldLedgerBackupPath, archivePath);
|
|
2982
3028
|
warn(`[savePlan] Ledger identity mismatch (was "${existingEvents[0].plan_id}", now "${planId}") \u2014 archived old ledger to ${archivePath} and reinitializing.`);
|
|
@@ -3001,7 +3047,7 @@ async function savePlan(directory, plan, options) {
|
|
|
3001
3047
|
const toRemove = archivedSiblings.slice(0, archivedSiblings.length - MAX_ARCHIVED_SIBLINGS);
|
|
3002
3048
|
for (const file of toRemove) {
|
|
3003
3049
|
try {
|
|
3004
|
-
unlinkSync2(
|
|
3050
|
+
unlinkSync2(path8.join(swarmDir2, file));
|
|
3005
3051
|
} catch {}
|
|
3006
3052
|
}
|
|
3007
3053
|
}
|
|
@@ -3144,9 +3190,9 @@ async function savePlan(directory, plan, options) {
|
|
|
3144
3190
|
source: "savePlan_manager"
|
|
3145
3191
|
});
|
|
3146
3192
|
}
|
|
3147
|
-
const swarmDir =
|
|
3148
|
-
const planPath =
|
|
3149
|
-
const tempPath =
|
|
3193
|
+
const swarmDir = path8.resolve(directory, ".swarm");
|
|
3194
|
+
const planPath = path8.join(swarmDir, "plan.json");
|
|
3195
|
+
const tempPath = path8.join(swarmDir, `plan.json.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
3150
3196
|
try {
|
|
3151
3197
|
await bunWrite(tempPath, JSON.stringify(projectedPlan, null, 2));
|
|
3152
3198
|
renameSync2(tempPath, planPath);
|
|
@@ -3155,8 +3201,9 @@ async function savePlan(directory, plan, options) {
|
|
|
3155
3201
|
unlinkSync2(tempPath);
|
|
3156
3202
|
} catch {}
|
|
3157
3203
|
}
|
|
3204
|
+
invalidateCachedArtifact(planPath);
|
|
3158
3205
|
try {
|
|
3159
|
-
const markerPath =
|
|
3206
|
+
const markerPath = path8.join(swarmDir, ".plan-write-marker");
|
|
3160
3207
|
const inProgressMarker = JSON.stringify({
|
|
3161
3208
|
source: "plan_manager",
|
|
3162
3209
|
timestamp: new Date().toISOString(),
|
|
@@ -3171,8 +3218,8 @@ async function savePlan(directory, plan, options) {
|
|
|
3171
3218
|
const markdown = derivePlanMarkdown(projectedPlan);
|
|
3172
3219
|
const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
|
|
3173
3220
|
${markdown}`;
|
|
3174
|
-
const mdPath =
|
|
3175
|
-
const mdTempPath =
|
|
3221
|
+
const mdPath = path8.join(swarmDir, "plan.md");
|
|
3222
|
+
const mdTempPath = path8.join(swarmDir, `plan.md.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
3176
3223
|
try {
|
|
3177
3224
|
await bunWrite(mdTempPath, markdownWithHash);
|
|
3178
3225
|
renameSync2(mdTempPath, mdPath);
|
|
@@ -3181,6 +3228,7 @@ ${markdown}`;
|
|
|
3181
3228
|
unlinkSync2(mdTempPath);
|
|
3182
3229
|
} catch {}
|
|
3183
3230
|
}
|
|
3231
|
+
invalidateCachedArtifact(mdPath);
|
|
3184
3232
|
} catch (mdError) {
|
|
3185
3233
|
const message = mdError instanceof Error ? mdError.message : String(mdError);
|
|
3186
3234
|
warn(`[savePlan] plan.md write failed (non-fatal, plan.json is authoritative): ${message}`);
|
|
@@ -3193,7 +3241,7 @@ ${markdown}`;
|
|
|
3193
3241
|
} catch {}
|
|
3194
3242
|
}
|
|
3195
3243
|
try {
|
|
3196
|
-
const markerPath =
|
|
3244
|
+
const markerPath = path8.join(swarmDir, ".plan-write-marker");
|
|
3197
3245
|
const tasksCount = projectedPlan.phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
|
|
3198
3246
|
const marker = JSON.stringify({
|
|
3199
3247
|
source: "plan_manager",
|
|
@@ -3209,11 +3257,11 @@ async function rebuildPlan(directory, plan, options) {
|
|
|
3209
3257
|
const targetPlan = plan ?? await replayFromLedger(directory);
|
|
3210
3258
|
if (!targetPlan)
|
|
3211
3259
|
return null;
|
|
3212
|
-
const swarmDir =
|
|
3213
|
-
const planPath =
|
|
3214
|
-
const mdPath =
|
|
3260
|
+
const swarmDir = path8.join(directory, ".swarm");
|
|
3261
|
+
const planPath = path8.join(swarmDir, "plan.json");
|
|
3262
|
+
const mdPath = path8.join(swarmDir, "plan.md");
|
|
3215
3263
|
mkdirSync3(swarmDir, { recursive: true });
|
|
3216
|
-
const tempPlanPath =
|
|
3264
|
+
const tempPlanPath = path8.join(swarmDir, `plan.json.rebuild.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
3217
3265
|
{
|
|
3218
3266
|
const fd = openSync(tempPlanPath, "w");
|
|
3219
3267
|
try {
|
|
@@ -3224,8 +3272,9 @@ async function rebuildPlan(directory, plan, options) {
|
|
|
3224
3272
|
}
|
|
3225
3273
|
}
|
|
3226
3274
|
renameSync2(tempPlanPath, planPath);
|
|
3275
|
+
invalidateCachedArtifact(planPath);
|
|
3227
3276
|
try {
|
|
3228
|
-
const markerPath =
|
|
3277
|
+
const markerPath = path8.join(swarmDir, ".plan-write-marker");
|
|
3229
3278
|
const inProgressMarker = JSON.stringify({
|
|
3230
3279
|
source: "plan_manager",
|
|
3231
3280
|
timestamp: new Date().toISOString(),
|
|
@@ -3240,12 +3289,13 @@ async function rebuildPlan(directory, plan, options) {
|
|
|
3240
3289
|
const markdown = derivePlanMarkdown(targetPlan);
|
|
3241
3290
|
const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
|
|
3242
3291
|
${markdown}`;
|
|
3243
|
-
const tempMdPath =
|
|
3292
|
+
const tempMdPath = path8.join(swarmDir, `plan.md.rebuild.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
3244
3293
|
await bunWrite(tempMdPath, markdownWithHash);
|
|
3245
3294
|
renameSync2(tempMdPath, mdPath);
|
|
3295
|
+
invalidateCachedArtifact(mdPath);
|
|
3246
3296
|
} finally {
|
|
3247
3297
|
try {
|
|
3248
|
-
const markerPath =
|
|
3298
|
+
const markerPath = path8.join(swarmDir, ".plan-write-marker");
|
|
3249
3299
|
const tasksCount = targetPlan.phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
|
|
3250
3300
|
const marker = JSON.stringify({
|
|
3251
3301
|
source: "plan_manager",
|
|
@@ -3308,13 +3358,14 @@ async function closePlanTerminalState(directory, plan, options) {
|
|
|
3308
3358
|
planHashAfter: hashAfter,
|
|
3309
3359
|
source: "close_terminal"
|
|
3310
3360
|
});
|
|
3311
|
-
const swarmDir =
|
|
3312
|
-
const planPath =
|
|
3313
|
-
const tempPlanPath =
|
|
3361
|
+
const swarmDir = path8.join(directory, ".swarm");
|
|
3362
|
+
const planPath = path8.join(swarmDir, "plan.json");
|
|
3363
|
+
const tempPlanPath = path8.join(swarmDir, `plan.json.close.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
3314
3364
|
await bunWrite(tempPlanPath, JSON.stringify(validated, null, 2));
|
|
3315
3365
|
renameSync2(tempPlanPath, planPath);
|
|
3366
|
+
invalidateCachedArtifact(planPath);
|
|
3316
3367
|
try {
|
|
3317
|
-
const markerPath =
|
|
3368
|
+
const markerPath = path8.join(swarmDir, ".plan-write-marker");
|
|
3318
3369
|
const inProgressMarker = JSON.stringify({
|
|
3319
3370
|
source: "plan_manager_close",
|
|
3320
3371
|
timestamp: new Date().toISOString(),
|
|
@@ -3325,17 +3376,18 @@ async function closePlanTerminalState(directory, plan, options) {
|
|
|
3325
3376
|
await bunWrite(markerPath, inProgressMarker);
|
|
3326
3377
|
} catch {}
|
|
3327
3378
|
try {
|
|
3328
|
-
const mdPath =
|
|
3379
|
+
const mdPath = path8.join(swarmDir, "plan.md");
|
|
3329
3380
|
const contentHash = computePlanContentHash(validated);
|
|
3330
3381
|
const markdown = derivePlanMarkdown(validated);
|
|
3331
3382
|
const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
|
|
3332
3383
|
${markdown}`;
|
|
3333
|
-
const mdTempPath =
|
|
3384
|
+
const mdTempPath = path8.join(swarmDir, `plan.md.close.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
3334
3385
|
await bunWrite(mdTempPath, markdownWithHash);
|
|
3335
3386
|
renameSync2(mdTempPath, mdPath);
|
|
3387
|
+
invalidateCachedArtifact(mdPath);
|
|
3336
3388
|
} finally {
|
|
3337
3389
|
try {
|
|
3338
|
-
const markerPath =
|
|
3390
|
+
const markerPath = path8.join(swarmDir, ".plan-write-marker");
|
|
3339
3391
|
const tasksCount = validated.phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
|
|
3340
3392
|
const marker = JSON.stringify({
|
|
3341
3393
|
source: "plan_manager_close",
|
|
@@ -3632,11 +3684,11 @@ import {
|
|
|
3632
3684
|
} from "fs";
|
|
3633
3685
|
import * as fs7 from "fs/promises";
|
|
3634
3686
|
import * as os4 from "os";
|
|
3635
|
-
import * as
|
|
3687
|
+
import * as path10 from "path";
|
|
3636
3688
|
|
|
3637
3689
|
// src/evaluation/retention.ts
|
|
3638
3690
|
import * as fs5 from "fs/promises";
|
|
3639
|
-
import * as
|
|
3691
|
+
import * as path9 from "path";
|
|
3640
3692
|
function artifactKey(artifact) {
|
|
3641
3693
|
return `${artifact.namespace}/${artifact.id}`;
|
|
3642
3694
|
}
|
|
@@ -3644,7 +3696,7 @@ function validId(value) {
|
|
|
3644
3696
|
return /^[A-Za-z0-9][A-Za-z0-9._-]{0,159}$/.test(value);
|
|
3645
3697
|
}
|
|
3646
3698
|
async function evaluationRunCandidates(directory) {
|
|
3647
|
-
const root =
|
|
3699
|
+
const root = path9.join(directory, ".swarm", "evolution", "runs");
|
|
3648
3700
|
let entries = [];
|
|
3649
3701
|
try {
|
|
3650
3702
|
entries = await fs5.readdir(root, { withFileTypes: true });
|
|
@@ -3663,7 +3715,7 @@ async function evaluationRunCandidates(directory) {
|
|
|
3663
3715
|
if (!validId(id))
|
|
3664
3716
|
continue;
|
|
3665
3717
|
const artifact = { namespace: "evaluation-run", id };
|
|
3666
|
-
const target =
|
|
3718
|
+
const target = path9.join(root, entry.name);
|
|
3667
3719
|
try {
|
|
3668
3720
|
const run = EvaluationRunV1Schema.parse(JSON.parse(await fs5.readFile(target, "utf8")));
|
|
3669
3721
|
if (run.runId !== id)
|
|
@@ -3681,7 +3733,7 @@ async function evaluationRunCandidates(directory) {
|
|
|
3681
3733
|
return { candidates, corrupt };
|
|
3682
3734
|
}
|
|
3683
3735
|
async function gateAuditCandidates(directory) {
|
|
3684
|
-
const root =
|
|
3736
|
+
const root = path9.join(directory, ".swarm", "evidence", "gate-audit");
|
|
3685
3737
|
let entries = [];
|
|
3686
3738
|
try {
|
|
3687
3739
|
entries = await fs5.readdir(root, { withFileTypes: true });
|
|
@@ -3697,9 +3749,9 @@ async function gateAuditCandidates(directory) {
|
|
|
3697
3749
|
if (!entry.isDirectory() || !validId(entry.name))
|
|
3698
3750
|
continue;
|
|
3699
3751
|
const artifact = { namespace: "gate-audit", id: entry.name };
|
|
3700
|
-
const target =
|
|
3752
|
+
const target = path9.join(root, entry.name);
|
|
3701
3753
|
try {
|
|
3702
|
-
const result = GateAuditResultV1Schema.parse(JSON.parse(await fs5.readFile(
|
|
3754
|
+
const result = GateAuditResultV1Schema.parse(JSON.parse(await fs5.readFile(path9.join(target, "results.json"), "utf8")));
|
|
3703
3755
|
if (result.runId !== entry.name)
|
|
3704
3756
|
throw new Error("run id/path mismatch");
|
|
3705
3757
|
candidates.push({
|
|
@@ -3740,7 +3792,7 @@ var _retentionInternals = {
|
|
|
3740
3792
|
removeCandidate
|
|
3741
3793
|
};
|
|
3742
3794
|
async function archiveEvaluationArtifacts(args) {
|
|
3743
|
-
return withEvidenceLock(args.directory,
|
|
3795
|
+
return withEvidenceLock(args.directory, path9.join("evolution", "retention-index"), "evaluation-retention", "archive", async () => {
|
|
3744
3796
|
const inventory = await retentionCandidates(args.directory);
|
|
3745
3797
|
let protectedKeys = await _retentionInternals.protectedArtifacts(args.directory);
|
|
3746
3798
|
const protectedRefs = inventory.candidates.filter((candidate) => protectedKeys.has(artifactKey(candidate.artifact))).map((candidate) => candidate.artifact);
|
|
@@ -3820,7 +3872,7 @@ async function atomicRenameWithRetry(src, dst, renameFn = fsp.rename) {
|
|
|
3820
3872
|
throw err;
|
|
3821
3873
|
}
|
|
3822
3874
|
if (attempt < RENAME_MAX_ATTEMPTS - 1) {
|
|
3823
|
-
await new Promise((
|
|
3875
|
+
await new Promise((resolve4) => setTimeout(resolve4, RENAME_BACKOFF_MS));
|
|
3824
3876
|
}
|
|
3825
3877
|
}
|
|
3826
3878
|
}
|
|
@@ -4063,8 +4115,8 @@ function isWeakConfigContainerRoot(directory) {
|
|
|
4063
4115
|
const resolved = realpathSync(directory);
|
|
4064
4116
|
return resolved === realpathSync(os4.tmpdir()) || resolved === realpathSync(os4.homedir());
|
|
4065
4117
|
} catch {
|
|
4066
|
-
const resolved =
|
|
4067
|
-
return resolved ===
|
|
4118
|
+
const resolved = path10.resolve(directory);
|
|
4119
|
+
return resolved === path10.resolve(os4.tmpdir()) || resolved === path10.resolve(os4.homedir());
|
|
4068
4120
|
}
|
|
4069
4121
|
}
|
|
4070
4122
|
function hasAccessibleProjectIndicator(directory, options = {}) {
|
|
@@ -4074,7 +4126,7 @@ function hasAccessibleProjectIndicator(directory, options = {}) {
|
|
|
4074
4126
|
continue;
|
|
4075
4127
|
}
|
|
4076
4128
|
try {
|
|
4077
|
-
const indicatorStat = statSync2(
|
|
4129
|
+
const indicatorStat = statSync2(path10.join(directory, indicator));
|
|
4078
4130
|
if (indicatorStat.isFile() || indicatorStat.isDirectory()) {
|
|
4079
4131
|
return true;
|
|
4080
4132
|
}
|
|
@@ -4096,14 +4148,14 @@ function validateProjectRoot(directory) {
|
|
|
4096
4148
|
if (depth >= MAX_DEPTH)
|
|
4097
4149
|
break;
|
|
4098
4150
|
depth++;
|
|
4099
|
-
const parent =
|
|
4151
|
+
const parent = path10.dirname(current);
|
|
4100
4152
|
if (parent === current)
|
|
4101
4153
|
break;
|
|
4102
|
-
if (
|
|
4154
|
+
if (path10.dirname(parent) === parent) {
|
|
4103
4155
|
current = parent;
|
|
4104
4156
|
continue;
|
|
4105
4157
|
}
|
|
4106
|
-
const parentSwarm =
|
|
4158
|
+
const parentSwarm = path10.join(parent, ".swarm");
|
|
4107
4159
|
try {
|
|
4108
4160
|
if (statSync2(parentSwarm).isDirectory()) {
|
|
4109
4161
|
if (hasAccessibleProjectIndicator(parent, {
|
|
@@ -4124,12 +4176,12 @@ function validateProjectRoot(directory) {
|
|
|
4124
4176
|
async function saveEvidence(directory, taskId, evidence) {
|
|
4125
4177
|
_internals11.validateProjectRoot(directory);
|
|
4126
4178
|
const sanitizedTaskId = sanitizeTaskId2(taskId);
|
|
4127
|
-
const relativePath =
|
|
4179
|
+
const relativePath = path10.join("evidence", sanitizedTaskId, "evidence.json");
|
|
4128
4180
|
validateSwarmPath(directory, relativePath);
|
|
4129
4181
|
_internals11.validateEvidence(evidence);
|
|
4130
4182
|
return withEvidenceLock(directory, relativePath, "evidence-manager", sanitizedTaskId, async () => {
|
|
4131
4183
|
const evidencePath = validateSwarmPath(directory, relativePath);
|
|
4132
|
-
const evidenceDir =
|
|
4184
|
+
const evidenceDir = path10.dirname(evidencePath);
|
|
4133
4185
|
let bundle;
|
|
4134
4186
|
const existingContent = await readSwarmFileAsync(directory, relativePath);
|
|
4135
4187
|
if (existingContent !== null) {
|
|
@@ -4172,7 +4224,7 @@ async function saveEvidence(directory, taskId, evidence) {
|
|
|
4172
4224
|
throw new Error(`Evidence bundle size (${bundleJson.length} bytes) exceeds maximum (${EVIDENCE_MAX_JSON_BYTES} bytes)`);
|
|
4173
4225
|
}
|
|
4174
4226
|
mkdirSync4(evidenceDir, { recursive: true });
|
|
4175
|
-
const tempPath =
|
|
4227
|
+
const tempPath = path10.join(evidenceDir, `evidence.json.tmp.${Date.now()}.${process.pid}`);
|
|
4176
4228
|
try {
|
|
4177
4229
|
await bunWrite(tempPath, bundleJson);
|
|
4178
4230
|
await fs7.rename(tempPath, evidencePath);
|
|
@@ -4182,6 +4234,7 @@ async function saveEvidence(directory, taskId, evidence) {
|
|
|
4182
4234
|
} catch {}
|
|
4183
4235
|
throw error2;
|
|
4184
4236
|
}
|
|
4237
|
+
invalidateCachedArtifact(evidencePath);
|
|
4185
4238
|
return updatedBundle;
|
|
4186
4239
|
});
|
|
4187
4240
|
}
|
|
@@ -4216,7 +4269,7 @@ function wrapFlatRetrospective(flatEntry, taskId) {
|
|
|
4216
4269
|
}
|
|
4217
4270
|
async function loadEvidence(directory, taskId, options) {
|
|
4218
4271
|
const sanitizedTaskId = sanitizeTaskId2(taskId);
|
|
4219
|
-
const relativePath =
|
|
4272
|
+
const relativePath = path10.join("evidence", sanitizedTaskId, "evidence.json");
|
|
4220
4273
|
if (relativePath.length > 4096) {
|
|
4221
4274
|
return { status: "not_found" };
|
|
4222
4275
|
}
|
|
@@ -4240,12 +4293,13 @@ async function loadEvidence(directory, taskId, options) {
|
|
|
4240
4293
|
}
|
|
4241
4294
|
try {
|
|
4242
4295
|
await withEvidenceLock(directory, relativePath, "evidence-loader", sanitizedTaskId, async () => {
|
|
4243
|
-
const evidenceDir =
|
|
4296
|
+
const evidenceDir = path10.dirname(evidencePath);
|
|
4244
4297
|
const bundleJson = JSON.stringify(validated);
|
|
4245
|
-
const tempPath =
|
|
4298
|
+
const tempPath = path10.join(evidenceDir, `evidence.json.tmp.${Date.now()}.${process.pid}`);
|
|
4246
4299
|
try {
|
|
4247
4300
|
await bunWrite(tempPath, bundleJson);
|
|
4248
4301
|
await fs7.rename(tempPath, evidencePath);
|
|
4302
|
+
invalidateCachedArtifact(evidencePath);
|
|
4249
4303
|
} catch (writeError) {
|
|
4250
4304
|
try {
|
|
4251
4305
|
rmSync(tempPath, { force: true });
|
|
@@ -4287,7 +4341,7 @@ async function listEvidenceTaskIds(directory) {
|
|
|
4287
4341
|
}
|
|
4288
4342
|
const taskIds = [];
|
|
4289
4343
|
for (const entry of entries) {
|
|
4290
|
-
const entryPath =
|
|
4344
|
+
const entryPath = path10.join(evidenceBasePath, entry);
|
|
4291
4345
|
try {
|
|
4292
4346
|
const stats = statSync2(entryPath);
|
|
4293
4347
|
if (!stats.isDirectory()) {
|
|
@@ -4305,7 +4359,7 @@ async function listEvidenceTaskIds(directory) {
|
|
|
4305
4359
|
}
|
|
4306
4360
|
async function deleteEvidence(directory, taskId) {
|
|
4307
4361
|
const sanitizedTaskId = sanitizeTaskId2(taskId);
|
|
4308
|
-
const relativePath =
|
|
4362
|
+
const relativePath = path10.join("evidence", sanitizedTaskId);
|
|
4309
4363
|
const evidenceDir = validateSwarmPath(directory, relativePath);
|
|
4310
4364
|
try {
|
|
4311
4365
|
statSync2(evidenceDir);
|
|
@@ -4321,8 +4375,8 @@ async function deleteEvidence(directory, taskId) {
|
|
|
4321
4375
|
}
|
|
4322
4376
|
}
|
|
4323
4377
|
async function checkRequirementCoverage(phase, directory) {
|
|
4324
|
-
const relativePath =
|
|
4325
|
-
const absolutePath =
|
|
4378
|
+
const relativePath = path10.join("evidence", `req-coverage-phase-${phase}.json`);
|
|
4379
|
+
const absolutePath = path10.resolve(directory, ".swarm", relativePath);
|
|
4326
4380
|
try {
|
|
4327
4381
|
await fs7.access(absolutePath);
|
|
4328
4382
|
return { exists: true, path: absolutePath };
|