opencode-swarm 7.107.0 → 7.107.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.
Files changed (39) hide show
  1. package/dist/agents/explorer.d.ts +2 -2
  2. package/dist/cli/curator-6zvpn7fs.js +51 -0
  3. package/dist/cli/curator-drift-6ad8mxxb.js +211 -0
  4. package/dist/cli/curator-llm-factory-r3m5e7n8.js +31 -0
  5. package/dist/cli/{evidence-summary-service-zhw4rkjb.js → evidence-summary-service-7nwhd8s4.js} +4 -3
  6. package/dist/cli/{explorer-rwfvbbx5.js → explorer-ksr3xq7n.js} +1 -1
  7. package/dist/cli/{guardrail-explain-6xt0pb56.js → guardrail-explain-zajegz3a.js} +13 -11
  8. package/dist/cli/hive-promoter-nwcsha2j.js +39 -0
  9. package/dist/cli/{index-ydgy7vg5.js → index-09xpycan.js} +31 -5
  10. package/dist/cli/{index-fhw0jm5c.js → index-168p3bfr.js} +22952 -21022
  11. package/dist/cli/index-357p0baj.js +719 -0
  12. package/dist/cli/{index-vwyjkzgs.js → index-9wstcavp.js} +1 -1
  13. package/dist/cli/index-c8s9a3zh.js +73 -0
  14. package/dist/cli/{index-25pev4e7.js → index-f12bmedv.js} +132 -843
  15. package/dist/cli/{index-wa6at603.js → index-jr54w7pb.js} +1 -1
  16. package/dist/cli/{index-v90bnn0f.js → index-r87xhtmx.js} +14 -12
  17. package/dist/cli/{index-e9n3xsk0.js → index-t4hbye3v.js} +1 -1
  18. package/dist/cli/index.js +12 -10
  19. package/dist/cli/{pending-delegations-dvprsdfy.js → pending-delegations-46xf2n2e.js} +2 -2
  20. package/dist/cli/{pr-subscriptions-zfxjtyzw.js → pr-subscriptions-3c34rnm1.js} +3 -3
  21. package/dist/cli/{skill-generator-99rrfwae.js → skill-generator-y6mmq8n5.js} +1 -1
  22. package/dist/commands/curate.d.ts +38 -1
  23. package/dist/commands/handoff.d.ts +2 -1
  24. package/dist/commands/registry.d.ts +6 -6
  25. package/dist/config/bundled-skills.d.ts +3 -5
  26. package/dist/hooks/curator-postmortem.d.ts +52 -3
  27. package/dist/hooks/curator.d.ts +2 -1
  28. package/dist/index.js +438 -393
  29. package/dist/session/snapshot-writer.d.ts +4 -0
  30. package/dist/tools/external-skill-discover.d.ts +11 -0
  31. package/dist/tools/pre-check-batch.d.ts +4 -0
  32. package/dist/turbo/lean/evidence.d.ts +22 -0
  33. package/dist/turbo/lean/integration.d.ts +6 -1
  34. package/dist/turbo/lean/reviewer.d.ts +6 -1
  35. package/dist/turbo/lean/runner.d.ts +10 -1
  36. package/dist/utils/untrusted-markdown.d.ts +1 -0
  37. package/dist/worktree/merge.d.ts +1 -0
  38. package/package.json +1 -1
  39. package/dist/cli/{index-7ztmmqpt.js → index-mpe0yk9s.js} +3 -3
@@ -1,4 +1,7 @@
1
1
  // @bun
2
+ import {
3
+ readEffectiveSpecSync
4
+ } from "./index-357p0baj.js";
2
5
  import {
3
6
  isValidTaskId,
4
7
  readTaskEvidence,
@@ -8,7 +11,7 @@ import {
8
11
  import {
9
12
  readSwarmFileAsync,
10
13
  validateSwarmPath
11
- } from "./index-7ztmmqpt.js";
14
+ } from "./index-mpe0yk9s.js";
12
15
  import {
13
16
  readCachedParsedFile
14
17
  } from "./index-jtqkh8jf.js";
@@ -36,13 +39,13 @@ import {
36
39
  // src/plan/manager.ts
37
40
  import {
38
41
  copyFileSync,
39
- existsSync as existsSync6,
40
- readdirSync as readdirSync2,
41
- renameSync as renameSync5,
42
+ existsSync as existsSync5,
43
+ readdirSync,
44
+ renameSync as renameSync4,
42
45
  unlinkSync as unlinkSync3
43
46
  } from "fs";
44
47
  import * as fsPromises from "fs/promises";
45
- import * as path6 from "path";
48
+ import * as path5 from "path";
46
49
 
47
50
  // src/config/plan-schema.ts
48
51
  var ExecutionProfileSchema = exports_external.object({
@@ -1084,729 +1087,14 @@ function readTaskScopes(directory, taskId) {
1084
1087
  }
1085
1088
 
1086
1089
  // src/utils/spec-hash.ts
1087
- import { createHash as createHash2 } from "crypto";
1088
- import * as fsSync from "fs";
1089
- import { join as join4 } from "path";
1090
-
1091
- // src/sdd/effective-spec.ts
1092
1090
  import { createHash } from "crypto";
1093
- import * as fs4 from "fs";
1094
- import * as path4 from "path";
1095
-
1096
- // src/config/spec-schema.ts
1097
- var ObligationSchema = exports_external.enum(["MUST", "SHALL", "SHOULD", "MAY"]);
1098
- var SpecRequirementSchema = exports_external.object({
1099
- id: exports_external.string().regex(/^FR-(?!000)\d{3}$/, "Requirement ID must match FR-### pattern (e.g., FR-001)"),
1100
- obligation: ObligationSchema,
1101
- text: exports_external.string().min(1)
1102
- });
1103
- var SpecScenarioSchema = exports_external.object({
1104
- name: exports_external.string().min(1),
1105
- given: exports_external.array(exports_external.string()).optional().default([]),
1106
- when: exports_external.array(exports_external.string()).min(1, 'Scenario must have at least one "when" clause'),
1107
- thenClauses: exports_external.array(exports_external.string()).min(1, 'Scenario must have at least one "then" clause')
1108
- });
1109
- var SpecSectionSchema = exports_external.object({
1110
- name: exports_external.string().min(1),
1111
- requirements: exports_external.array(SpecRequirementSchema).default([])
1112
- });
1113
- var SwarmSpecSchema = exports_external.object({
1114
- title: exports_external.string().min(1),
1115
- purpose: exports_external.string().min(1),
1116
- sections: exports_external.array(SpecSectionSchema).min(1, "Spec must have at least one section")
1117
- });
1118
- var SpecDeltaSchema = exports_external.object({
1119
- added: exports_external.array(SpecRequirementSchema).default([]),
1120
- modified: exports_external.array(SpecRequirementSchema).default([]),
1121
- removed: exports_external.array(SpecRequirementSchema).default([])
1122
- });
1123
- var DeltaSpecSchema = exports_external.union([
1124
- SwarmSpecSchema,
1125
- SpecDeltaSchema
1126
- ]);
1127
- var FENCED_BLOCK_PATTERN = /```[\s\S]*?```/g;
1128
- var INLINE_CODE_PATTERN = /`[^`]*`/g;
1129
- var FR_ID_PATTERN = /\bFR-\d{3}\b/g;
1130
- var OBLIGATION_PATTERN = /\b(MUST|SHALL|SHOULD|MAY)\b/g;
1131
- var SECTION_HEADER_PATTERN = /^##\s+.+$/gm;
1132
- function stripCodeBlocks(content) {
1133
- return content.replace(FENCED_BLOCK_PATTERN, "").replace(INLINE_CODE_PATTERN, "");
1134
- }
1135
- function getLineNumber(content, position) {
1136
- const prefix = content.substring(0, position);
1137
- return (prefix.match(/\n/g) || []).length + 1;
1138
- }
1139
- function validateSpecContent(content) {
1140
- const issues = [];
1141
- if (!content || content.trim().length === 0) {
1142
- return { valid: false, issues: [{ line: 1, message: "Content is empty" }] };
1143
- }
1144
- const strippedContent = stripCodeBlocks(content);
1145
- const frMatches = strippedContent.match(FR_ID_PATTERN);
1146
- if (!frMatches || frMatches.length === 0) {
1147
- issues.push({
1148
- line: 1,
1149
- message: "No FR-### requirement IDs found in spec content"
1150
- });
1151
- }
1152
- const obligationMatches = strippedContent.match(OBLIGATION_PATTERN);
1153
- if (!obligationMatches || obligationMatches.length === 0) {
1154
- issues.push({
1155
- line: 1,
1156
- message: "No obligation keywords (MUST, SHALL, SHOULD, MAY) found in spec content"
1157
- });
1158
- }
1159
- const sectionMatches = strippedContent.match(SECTION_HEADER_PATTERN);
1160
- if (!sectionMatches || sectionMatches.length === 0) {
1161
- issues.push({
1162
- line: 1,
1163
- message: "No section headers (## Section Name) found in spec content"
1164
- });
1165
- }
1166
- const idMatches = strippedContent.matchAll(/\bFR-(\d{3})\b/g);
1167
- for (const idMatch of idMatches) {
1168
- const num = parseInt(idMatch[1], 10);
1169
- if (num === 0) {
1170
- const pos = idMatch.index;
1171
- issues.push({
1172
- line: getLineNumber(strippedContent, pos),
1173
- message: `Invalid FR-ID "${idMatch[0]}" \u2014 number must be 001-999`
1174
- });
1175
- }
1176
- }
1177
- return {
1178
- valid: issues.length === 0,
1179
- issues
1180
- };
1181
- }
1182
-
1183
- // src/sdd/effective-spec.ts
1184
- var SWARM_SPEC_REL = path4.join(".swarm", "spec.md");
1185
- var OPENSPEC_ROOT = "openspec";
1186
- var SPECKIT_MARKER = ".specify";
1187
- var SPECKIT_SPECS_DIR = "specs";
1188
- var MAX_SPEC_BYTES = 256 * 1024;
1189
- var MAX_SOURCE_BYTES = 512 * 1024;
1190
- var MAX_SPEC_FILES = 100;
1191
- var MAX_WALK_DEPTH = 10;
1192
- var SPECKIT_REQUIRED_SECTIONS = [
1193
- "## Functional Requirements",
1194
- "## Success Criteria"
1195
- ];
1196
- function toPosix(relPath) {
1197
- return relPath.split(path4.sep).join("/");
1198
- }
1199
- function hash(content) {
1200
- return createHash("sha256").update(content, "utf-8").digest("hex");
1201
- }
1202
- function readTextBounded(absPath) {
1203
- let stat;
1204
- try {
1205
- stat = fs4.lstatSync(absPath);
1206
- } catch {
1207
- return null;
1208
- }
1209
- if (!stat.isFile() || stat.size > MAX_SOURCE_BYTES) {
1210
- return null;
1211
- }
1212
- try {
1213
- return fs4.readFileSync(absPath, "utf-8");
1214
- } catch {
1215
- return null;
1216
- }
1217
- }
1218
- function fileArtifact(root, absPath) {
1219
- try {
1220
- const stat = fs4.lstatSync(absPath);
1221
- if (!stat.isFile() || stat.size > MAX_SOURCE_BYTES)
1222
- return null;
1223
- return {
1224
- relPath: toPosix(path4.relative(root, absPath)),
1225
- bytes: stat.size,
1226
- mtimeMs: stat.mtimeMs
1227
- };
1228
- } catch {
1229
- return null;
1230
- }
1231
- }
1232
- function walkSpecFiles(root, startRel) {
1233
- const start = path4.join(root, startRel);
1234
- if (!fs4.existsSync(start))
1235
- return [];
1236
- const artifacts = [];
1237
- const stack = [
1238
- { abs: start, depth: 0 }
1239
- ];
1240
- while (stack.length > 0 && artifacts.length < MAX_SPEC_FILES) {
1241
- const item = stack.pop();
1242
- if (!item || item.depth > MAX_WALK_DEPTH)
1243
- continue;
1244
- let entries;
1245
- try {
1246
- entries = fs4.readdirSync(item.abs, { withFileTypes: true });
1247
- } catch {
1248
- continue;
1249
- }
1250
- const dirents = entries.filter((entry) => typeof entry?.name === "string");
1251
- for (const entry of dirents.sort((a, b) => b.name.localeCompare(a.name))) {
1252
- const abs = path4.join(item.abs, entry.name);
1253
- if (entry.isSymbolicLink())
1254
- continue;
1255
- if (entry.isDirectory()) {
1256
- stack.push({ abs, depth: item.depth + 1 });
1257
- } else if (entry.isFile() && entry.name === "spec.md") {
1258
- const artifact = fileArtifact(root, abs);
1259
- if (artifact)
1260
- artifacts.push(artifact);
1261
- if (artifacts.length >= MAX_SPEC_FILES)
1262
- break;
1263
- }
1264
- }
1265
- }
1266
- return artifacts.sort((a, b) => a.relPath.localeCompare(b.relPath));
1267
- }
1268
- function listOpenSpecChanges(root) {
1269
- const changesDir = path4.join(root, OPENSPEC_ROOT, "changes");
1270
- if (!fs4.existsSync(changesDir))
1271
- return [];
1272
- let entries;
1273
- try {
1274
- entries = fs4.readdirSync(changesDir, { withFileTypes: true });
1275
- } catch {
1276
- return [];
1277
- }
1278
- return entries.filter((entry) => entry.isDirectory() && entry.name !== "archive").sort((a, b) => a.name.localeCompare(b.name)).map((entry) => {
1279
- const rel = path4.join(OPENSPEC_ROOT, "changes", entry.name);
1280
- return {
1281
- id: entry.name,
1282
- proposal: fs4.existsSync(path4.join(root, rel, "proposal.md")),
1283
- design: fs4.existsSync(path4.join(root, rel, "design.md")),
1284
- tasks: fs4.existsSync(path4.join(root, rel, "tasks.md")),
1285
- specs: walkSpecFiles(root, path4.join(rel, "specs"))
1286
- };
1287
- });
1288
- }
1289
- function detectKind(line, current) {
1290
- const upper = line.toUpperCase();
1291
- if (/^#{2,6}\s+ADDED\b/.test(upper))
1292
- return "ADDED";
1293
- if (/^#{2,6}\s+MODIFIED\b/.test(upper))
1294
- return "MODIFIED";
1295
- if (/^#{2,6}\s+REMOVED\b/.test(upper))
1296
- return "REMOVED";
1297
- return current;
1298
- }
1299
- function requirementTextFromBlock(title, block, kind) {
1300
- const joined = block.join(" ").replace(/\s+/g, " ").trim();
1301
- const obligation = joined.match(/\b(MUST|SHALL|SHOULD|MAY)\b/i)?.[1];
1302
- if (obligation)
1303
- return joined;
1304
- if (kind === "REMOVED") {
1305
- return `MAY remove or retire behavior for ${title}.`;
1306
- }
1307
- return `MUST satisfy OpenSpec requirement ${title}.`;
1308
- }
1309
- function parseRequirements(content, sourceRel, defaultKind) {
1310
- const requirements = [];
1311
- const lines = content.replace(/\r\n/g, `
1312
- `).split(`
1313
- `);
1314
- let kind = defaultKind;
1315
- for (let i = 0;i < lines.length; i++) {
1316
- const line = lines[i];
1317
- kind = detectKind(line, kind);
1318
- const explicit = line.match(/\b(FR-(?!000)\d{3})\b/);
1319
- if (explicit && /\b(MUST|SHALL|SHOULD|MAY)\b/i.test(line)) {
1320
- requirements.push({
1321
- id: explicit[1].toUpperCase(),
1322
- kind,
1323
- title: explicit[1].toUpperCase(),
1324
- text: line.trim().replace(/^\s*[-*]\s*/, ""),
1325
- sourceRel
1326
- });
1327
- continue;
1328
- }
1329
- const openSpecReq = line.match(/^#{3,4}\s+Requirement:\s*(.+)$/i);
1330
- if (!openSpecReq)
1331
- continue;
1332
- const title = openSpecReq[1].trim();
1333
- const block = [];
1334
- for (let j = i + 1;j < lines.length; j++) {
1335
- if (/^##\s+/.test(lines[j]))
1336
- break;
1337
- if (/^#{3,4}\s+Requirement:/i.test(lines[j]))
1338
- break;
1339
- const trimmed = lines[j].trim();
1340
- if (trimmed)
1341
- block.push(trimmed);
1342
- }
1343
- const id = block.join(`
1344
- `).match(/\b(FR-(?!000)\d{3})\b/)?.[1] ?? null;
1345
- requirements.push({
1346
- id: id?.toUpperCase() ?? null,
1347
- kind,
1348
- title,
1349
- text: requirementTextFromBlock(title, block, kind),
1350
- sourceRel
1351
- });
1352
- }
1353
- return requirements;
1354
- }
1355
- function nextFrId(used, warnings, reserved) {
1356
- for (let n = 1;n <= 999; n++) {
1357
- const id = `FR-${String(n).padStart(3, "0")}`;
1358
- if (!used.has(id) && !reserved?.has(id)) {
1359
- used.add(id);
1360
- return id;
1361
- }
1362
- }
1363
- warnings.push("More than 999 FR identifiers are required; reusing FR-999.");
1364
- return "FR-999";
1365
- }
1366
- function renderRequirement(req, used, warnings, reserved) {
1367
- const id = req.id && !used.has(req.id) ? req.id : nextFrId(used, warnings, reserved);
1368
- if (req.id && req.id !== id) {
1369
- warnings.push(`Duplicate requirement id ${req.id} in ${req.sourceRel}; generated ${id}.`);
1370
- }
1371
- if (req.id === id)
1372
- used.add(id);
1373
- let text = req.text;
1374
- if (!text.includes(id)) {
1375
- text = `${id}: ${text}`;
1376
- }
1377
- return `- ${text} _(source: ${req.sourceRel})_`;
1378
- }
1379
- function detectSpeckit(directory) {
1380
- const root = path4.resolve(directory);
1381
- const markerPath = path4.join(root, SPECKIT_MARKER);
1382
- const markerPresent = fs4.statSync(markerPath, { throwIfNoEntry: false })?.isDirectory() ?? false;
1383
- if (!markerPresent) {
1384
- return { markerPresent: false, features: [] };
1385
- }
1386
- const specsRoot = path4.join(root, SPECKIT_SPECS_DIR);
1387
- if (!fs4.existsSync(specsRoot)) {
1388
- return { markerPresent: true, features: [] };
1389
- }
1390
- let entries;
1391
- try {
1392
- entries = fs4.readdirSync(specsRoot, { withFileTypes: true });
1393
- } catch {
1394
- return { markerPresent: true, features: [] };
1395
- }
1396
- const featureDirs = entries.filter((entry) => typeof entry?.name === "string" && !entry.isSymbolicLink() && entry.isDirectory()).sort((a, b) => a.name.localeCompare(b.name));
1397
- const features = [];
1398
- for (const entry of featureDirs) {
1399
- if (features.length >= MAX_SPEC_FILES)
1400
- break;
1401
- const specAbs = path4.join(specsRoot, entry.name, "spec.md");
1402
- let stat;
1403
- try {
1404
- stat = fs4.lstatSync(specAbs);
1405
- } catch {
1406
- continue;
1407
- }
1408
- if (!stat.isFile() || stat.size > MAX_SOURCE_BYTES)
1409
- continue;
1410
- features.push({
1411
- featureId: entry.name,
1412
- specRelPath: toPosix(path4.relative(root, specAbs))
1413
- });
1414
- }
1415
- return { markerPresent: true, features };
1416
- }
1417
- function parseSpeckitRequirements(content, sourceRel) {
1418
- const requirements = [];
1419
- const lines = content.replace(/\r\n/g, `
1420
- `).split(`
1421
- `);
1422
- let inFrSection = false;
1423
- for (const line of lines) {
1424
- if (/^##\s+/.test(line)) {
1425
- inFrSection = /^##\s+Functional Requirements\s*$/i.test(line);
1426
- continue;
1427
- }
1428
- if (!inFrSection)
1429
- continue;
1430
- if (!/^\s*[-*]\s+/.test(line))
1431
- continue;
1432
- if (!/\b(MUST|SHALL|SHOULD|MAY)\b/i.test(line))
1433
- continue;
1434
- const text = line.trim().replace(/^\s*[-*]\s+/, "");
1435
- const explicit = line.match(/\b(FR-(?!000)\d{3})\b/);
1436
- if (explicit) {
1437
- requirements.push({
1438
- id: explicit[1].toUpperCase(),
1439
- kind: "CURRENT",
1440
- title: explicit[1].toUpperCase(),
1441
- text,
1442
- sourceRel
1443
- });
1444
- continue;
1445
- }
1446
- requirements.push({
1447
- id: null,
1448
- kind: "CURRENT",
1449
- title: text,
1450
- text,
1451
- sourceRel
1452
- });
1453
- }
1454
- return requirements;
1455
- }
1456
- function resolveSpeckitProjection(directory, options = {}) {
1457
- const root = path4.resolve(directory);
1458
- const detection = detectSpeckit(root);
1459
- if (!detection.markerPresent) {
1460
- return { kind: "not_speckit" };
1461
- }
1462
- if (detection.features.length === 0) {
1463
- return { kind: "empty" };
1464
- }
1465
- let selectedFeature;
1466
- if (options.feature) {
1467
- const found = detection.features.find((f) => f.featureId === options.feature);
1468
- if (!found) {
1469
- return {
1470
- kind: "unknown_feature",
1471
- feature: options.feature,
1472
- available: detection.features.map((f) => f.featureId)
1473
- };
1474
- }
1475
- selectedFeature = found;
1476
- } else if (detection.features.length === 1) {
1477
- selectedFeature = detection.features[0];
1478
- } else {
1479
- return {
1480
- kind: "ambiguous",
1481
- features: detection.features.map((f) => f.featureId)
1482
- };
1483
- }
1484
- const specAbs = path4.join(root, selectedFeature.specRelPath);
1485
- const content = readTextBounded(specAbs);
1486
- if (content === null) {
1487
- return { kind: "zero_requirements", feature: selectedFeature.featureId };
1488
- }
1489
- const warnings = [];
1490
- const usedIds = new Set;
1491
- const requirements = parseSpeckitRequirements(content, selectedFeature.specRelPath);
1492
- if (requirements.length === 0) {
1493
- return { kind: "zero_requirements", feature: selectedFeature.featureId };
1494
- }
1495
- const reservedIds = new Set;
1496
- for (const req of requirements) {
1497
- if (req.id)
1498
- reservedIds.add(req.id);
1499
- }
1500
- let mtimeMs = 0;
1501
- try {
1502
- mtimeMs = fs4.lstatSync(specAbs).mtimeMs;
1503
- } catch {}
1504
- const lines = [
1505
- "# Specification: Effective SDD Projection",
1506
- "",
1507
- "Generated from Spec-Kit feature artifacts. Update the source artifacts, then run `/swarm sdd project` to refresh this projection.",
1508
- "",
1509
- "## Source Artifacts",
1510
- `- ${selectedFeature.specRelPath}`,
1511
- "",
1512
- "## Functional Requirements"
1513
- ];
1514
- for (const req of requirements) {
1515
- lines.push(renderRequirement(req, usedIds, warnings, reservedIds));
1516
- }
1517
- const projected = `${lines.join(`
1518
- `)}
1519
- `;
1520
- if (projected.length > MAX_SPEC_BYTES) {
1521
- return {
1522
- kind: "too_large",
1523
- feature: selectedFeature.featureId,
1524
- bytes: projected.length
1525
- };
1526
- }
1527
- const validation = validateSpecContent(projected);
1528
- if (!validation.valid) {
1529
- warnings.push(...validation.issues.map((issue) => `Projection line ${issue.line}: ${issue.message}`));
1530
- }
1531
- const spec = {
1532
- source: "speckit_projection",
1533
- content: projected,
1534
- hash: hash(projected),
1535
- mtime: mtimeMs > 0 ? new Date(mtimeMs).toISOString() : null,
1536
- sourcePaths: [selectedFeature.specRelPath],
1537
- warnings
1538
- };
1539
- return { kind: "ok", spec, feature: selectedFeature.featureId };
1540
- }
1541
- function buildSpeckitProjectionSync(directory, options = {}) {
1542
- const resolution = resolveSpeckitProjection(directory, options);
1543
- return resolution.kind === "ok" ? resolution.spec : null;
1544
- }
1545
- function loadSddStatusSync(directory, opts) {
1546
- const root = path4.resolve(directory);
1547
- const swSpecPath = path4.join(root, SWARM_SPEC_REL);
1548
- const openSpecPath = path4.join(root, OPENSPEC_ROOT);
1549
- const errors = [];
1550
- const warnings = [];
1551
- const swSpecExists = fs4.existsSync(swSpecPath);
1552
- const openSpecExists = fs4.existsSync(openSpecPath);
1553
- const currentSpecs = walkSpecFiles(root, path4.join(OPENSPEC_ROOT, "specs"));
1554
- const changes = listOpenSpecChanges(root);
1555
- const effectiveSpec = readEffectiveSpecSync(root, opts);
1556
- if (openSpecExists && currentSpecs.length === 0 && changes.length === 0) {
1557
- errors.push("openspec/ exists but contains no specs or active changes.");
1558
- }
1559
- for (const change of changes) {
1560
- if (!change.proposal) {
1561
- warnings.push(`Change ${change.id} is missing proposal.md.`);
1562
- }
1563
- if (!change.tasks) {
1564
- warnings.push(`Change ${change.id} is missing tasks.md; tasks remain proposal input, not plan state.`);
1565
- }
1566
- if (change.specs.length === 0) {
1567
- errors.push(`Change ${change.id} has no specs/**/spec.md delta files.`);
1568
- }
1569
- }
1570
- return {
1571
- provider: effectiveSpec?.source ?? "none",
1572
- swSpecExists,
1573
- openSpecExists,
1574
- currentSpecs,
1575
- changes,
1576
- effectiveSpec,
1577
- errors,
1578
- warnings
1579
- };
1580
- }
1581
- function buildOpenSpecProjectionSync(directory, options = {}) {
1582
- const root = path4.resolve(directory);
1583
- const currentSpecs = walkSpecFiles(root, path4.join(OPENSPEC_ROOT, "specs"));
1584
- const allChanges = listOpenSpecChanges(root);
1585
- const changes = options.changeId ? allChanges.filter((change) => change.id === options.changeId) : allChanges;
1586
- const sourcePaths = [];
1587
- const warnings = [];
1588
- const usedIds = new Set;
1589
- const currentRequirements = [];
1590
- const changeRequirements = new Map;
1591
- let parsedRequirementCount = 0;
1592
- let mtimeMs = 0;
1593
- if (options.changeId && changes.length === 0)
1594
- return null;
1595
- if (currentSpecs.length === 0 && changes.length === 0)
1596
- return null;
1597
- for (const artifact of currentSpecs) {
1598
- const abs = path4.join(root, artifact.relPath);
1599
- const content2 = readTextBounded(abs);
1600
- if (content2 === null) {
1601
- warnings.push(`Skipped unreadable or oversized spec ${artifact.relPath}.`);
1602
- continue;
1603
- }
1604
- sourcePaths.push(artifact.relPath);
1605
- mtimeMs = Math.max(mtimeMs, artifact.mtimeMs);
1606
- const parsed = parseRequirements(content2, artifact.relPath, "CURRENT");
1607
- currentRequirements.push(...parsed);
1608
- parsedRequirementCount += parsed.length;
1609
- }
1610
- for (const change of changes) {
1611
- const reqs = [];
1612
- for (const artifact of change.specs) {
1613
- const abs = path4.join(root, artifact.relPath);
1614
- const content2 = readTextBounded(abs);
1615
- if (content2 === null) {
1616
- warnings.push(`Skipped unreadable or oversized spec ${artifact.relPath}.`);
1617
- continue;
1618
- }
1619
- sourcePaths.push(artifact.relPath);
1620
- mtimeMs = Math.max(mtimeMs, artifact.mtimeMs);
1621
- const parsed = parseRequirements(content2, artifact.relPath, "ADDED");
1622
- reqs.push(...parsed);
1623
- parsedRequirementCount += parsed.length;
1624
- }
1625
- changeRequirements.set(change.id, reqs);
1626
- }
1627
- if (sourcePaths.length > 0 && parsedRequirementCount === 0) {
1628
- return null;
1629
- }
1630
- const lines = [
1631
- "# Specification: Effective SDD Projection",
1632
- "",
1633
- "Generated from OpenSpec-compatible artifacts. Update the source artifacts, then run `/swarm sdd project` to refresh this projection.",
1634
- "",
1635
- "## Source Artifacts",
1636
- ...sourcePaths.map((rel) => `- ${rel}`),
1637
- "",
1638
- "## Current Requirements"
1639
- ];
1640
- if (currentRequirements.length === 0) {
1641
- lines.push("- No current OpenSpec requirements found in source artifacts.");
1642
- warnings.push("No current requirements found; projection includes an advisory note only.");
1643
- } else {
1644
- for (const req of currentRequirements) {
1645
- lines.push(renderRequirement(req, usedIds, warnings));
1646
- }
1647
- }
1648
- for (const [changeId, reqs] of changeRequirements.entries()) {
1649
- lines.push("", `## Pending Change: ${changeId}`);
1650
- if (reqs.length === 0) {
1651
- lines.push(`- ${nextFrId(usedIds, warnings)} SHOULD add OpenSpec delta requirements for change ${changeId}.`);
1652
- warnings.push(`Change ${changeId} contains no parsable requirements.`);
1653
- continue;
1654
- }
1655
- for (const req of reqs) {
1656
- lines.push(renderRequirement(req, usedIds, warnings));
1657
- }
1658
- }
1659
- const content = `${lines.join(`
1660
- `)}
1661
- `;
1662
- if (content.length > MAX_SPEC_BYTES) {
1663
- warnings.push(`Projected spec exceeds ${MAX_SPEC_BYTES} bytes; refusing to use projection.`);
1664
- return null;
1665
- }
1666
- const validation = validateSpecContent(content);
1667
- if (!validation.valid) {
1668
- warnings.push(...validation.issues.map((issue) => `Projection line ${issue.line}: ${issue.message}`));
1669
- }
1670
- return {
1671
- source: "openspec_projection",
1672
- content,
1673
- hash: hash(content),
1674
- mtime: mtimeMs > 0 ? new Date(mtimeMs).toISOString() : null,
1675
- sourcePaths,
1676
- warnings
1677
- };
1678
- }
1679
- function readEffectiveSpecSync(directory, opts) {
1680
- const root = path4.resolve(directory);
1681
- const swSpecPath = path4.join(root, SWARM_SPEC_REL);
1682
- try {
1683
- const stat = fs4.lstatSync(swSpecPath);
1684
- if (stat.isFile() && stat.size <= MAX_SPEC_BYTES) {
1685
- const content = fs4.readFileSync(swSpecPath, "utf-8");
1686
- return {
1687
- source: "swarm",
1688
- content,
1689
- hash: hash(content),
1690
- mtime: stat.mtime.toISOString(),
1691
- sourcePaths: [toPosix(SWARM_SPEC_REL)],
1692
- warnings: []
1693
- };
1694
- }
1695
- } catch (error2) {
1696
- if (error2.code !== "ENOENT") {
1697
- throw error2;
1698
- }
1699
- }
1700
- if (opts?.source) {
1701
- switch (opts.source) {
1702
- case "openspec":
1703
- return buildOpenSpecProjectionSync(root);
1704
- case "speckit":
1705
- return buildSpeckitProjectionSync(root, { feature: opts.feature });
1706
- case "swarm":
1707
- return null;
1708
- }
1709
- }
1710
- const speckitDetection = detectSpeckit(root);
1711
- if (!speckitDetection.markerPresent) {
1712
- return buildOpenSpecProjectionSync(root);
1713
- }
1714
- const speckitPresent = speckitDetection.features.length > 0;
1715
- if (!speckitPresent) {
1716
- return buildOpenSpecProjectionSync(root);
1717
- }
1718
- const openspecProjection = buildOpenSpecProjectionSync(root);
1719
- const openspecPresent = openspecProjection !== null;
1720
- if (openspecPresent) {
1721
- console.warn("[opencode-swarm] Multiple SDD sources detected (openspec and speckit). " + "Enforcement/projection is suppressed until you disambiguate. " + "Pass --source openspec or --source speckit to select a provider.");
1722
- return null;
1723
- }
1724
- return buildSpeckitProjectionSync(root, { feature: opts?.feature });
1725
- }
1726
- function writeProjectedSpecSync(directory, options = {}) {
1727
- const root = path4.resolve(directory);
1728
- const projection = options.source === "speckit" ? buildSpeckitProjectionSync(root, { feature: options.feature }) : buildOpenSpecProjectionSync(root, { changeId: options.changeId });
1729
- const target = path4.join(root, SWARM_SPEC_REL);
1730
- if (!projection || options.dryRun) {
1731
- return { written: false, projection, path: target };
1732
- }
1733
- fs4.mkdirSync(path4.dirname(target), { recursive: true });
1734
- let archivePath;
1735
- if (fs4.existsSync(target)) {
1736
- const prior = fs4.readFileSync(target, "utf-8");
1737
- if (prior !== projection.content) {
1738
- const archiveDir = path4.join(root, ".swarm", "spec-archive");
1739
- fs4.mkdirSync(archiveDir, { recursive: true });
1740
- const stamp = new Date().toISOString().replace(/[:.]/g, "-");
1741
- archivePath = path4.join(archiveDir, `sdd-projection-${stamp}.md`);
1742
- fs4.writeFileSync(archivePath, prior, "utf-8");
1743
- }
1744
- }
1745
- const tmp = `${target}.tmp-${process.pid}-${Date.now()}`;
1746
- fs4.writeFileSync(tmp, projection.content, "utf-8");
1747
- fs4.renameSync(tmp, target);
1748
- return { written: true, projection, archivePath, path: target };
1749
- }
1750
- function validateSpeckit(directory, options = {}) {
1751
- const root = path4.resolve(directory);
1752
- const resolution = resolveSpeckitProjection(root, options);
1753
- const problems = [];
1754
- if (resolution.kind !== "ok" && resolution.kind !== "zero_requirements") {
1755
- return { resolution, problems };
1756
- }
1757
- if (resolution.kind === "zero_requirements") {
1758
- problems.push(`Feature '${resolution.feature}' contains no parsable functional requirements.`);
1759
- }
1760
- const detection = detectSpeckit(root);
1761
- const featureEntry = detection.features.find((f) => f.featureId === resolution.feature);
1762
- if (!featureEntry) {
1763
- return { resolution, problems };
1764
- }
1765
- const specAbs = path4.join(root, featureEntry.specRelPath);
1766
- let specContent = null;
1767
- try {
1768
- specContent = readTextBounded(specAbs);
1769
- } catch {}
1770
- if (specContent !== null) {
1771
- const specLines = specContent.replace(/\r\n/g, `
1772
- `).split(`
1773
- `);
1774
- for (const requiredHeader of SPECKIT_REQUIRED_SECTIONS) {
1775
- if (!specLines.some((line) => line.trimEnd() === requiredHeader)) {
1776
- problems.push(`Missing required spec.md section: ${requiredHeader}`);
1777
- }
1778
- }
1779
- }
1780
- const tasksAbs = path4.join(path4.dirname(specAbs), "tasks.md");
1781
- let tasksContent = null;
1782
- try {
1783
- tasksContent = readTextBounded(tasksAbs);
1784
- } catch {}
1785
- if (tasksContent !== null) {
1786
- const tasksLines = tasksContent.replace(/\r\n/g, `
1787
- `).split(`
1788
- `);
1789
- for (const line of tasksLines) {
1790
- const taskMatch = line.match(/^\s*-\s+\[[ xX]\]\s+(T\d+)/);
1791
- if (!taskMatch)
1792
- continue;
1793
- const taskId = taskMatch[1];
1794
- const hasStoryRef = /\[US\d+\]/i.test(line);
1795
- const hasReqRef = /\bFR-(?!000)\d{3}\b/i.test(line);
1796
- if (!hasStoryRef && !hasReqRef) {
1797
- problems.push(`Task ${taskId} has no spec/requirement reference.`);
1798
- }
1799
- }
1800
- }
1801
- return { resolution, problems };
1802
- }
1803
-
1804
- // src/utils/spec-hash.ts
1091
+ import * as fsSync from "fs";
1092
+ import { join as join3 } from "path";
1805
1093
  async function computeSpecHash(directory) {
1806
1094
  const spec = _internals3.readEffectiveSpecSync(directory);
1807
1095
  if (!spec)
1808
1096
  return null;
1809
- return createHash2("sha256").update(spec.content, "utf-8").digest("hex");
1097
+ return createHash("sha256").update(spec.content, "utf-8").digest("hex");
1810
1098
  }
1811
1099
  async function isSpecStale(directory, plan) {
1812
1100
  const currentHash = await _internals3.computeSpecHash(directory);
@@ -1830,7 +1118,7 @@ async function isSpecStale(directory, plan) {
1830
1118
  return { stale: false };
1831
1119
  }
1832
1120
  function isObligationPreserving(directory) {
1833
- const snapshotPath = join4(directory, ".swarm", "spec-snapshot.md");
1121
+ const snapshotPath = join3(directory, ".swarm", "spec-snapshot.md");
1834
1122
  try {
1835
1123
  let recordedContent;
1836
1124
  try {
@@ -1876,7 +1164,7 @@ var _internals3 = {
1876
1164
  readEffectiveSpecSync
1877
1165
  };
1878
1166
  function computeSpecDiff(directory) {
1879
- const snapshotPath = join4(directory, ".swarm", "spec-snapshot.md");
1167
+ const snapshotPath = join3(directory, ".swarm", "spec-snapshot.md");
1880
1168
  let recordedContent;
1881
1169
  try {
1882
1170
  const snapshotSize = fsSync.statSync(snapshotPath).size;
@@ -1963,8 +1251,8 @@ function computeLcsDiff(oldLines, newLines) {
1963
1251
 
1964
1252
  // src/plan/ledger.ts
1965
1253
  import * as crypto from "crypto";
1966
- import * as fs5 from "fs";
1967
- import * as path5 from "path";
1254
+ import * as fs4 from "fs";
1255
+ import * as path4 from "path";
1968
1256
 
1969
1257
  // src/plan/utils.ts
1970
1258
  function derivePlanId(plan) {
@@ -1974,7 +1262,7 @@ function derivePlanId(plan) {
1974
1262
  // src/plan/ledger.ts
1975
1263
  var LEDGER_SCHEMA_VERSION = "1.1.0";
1976
1264
  var LEDGER_FILENAME = "plan-ledger.jsonl";
1977
- var LEDGER_LOCK_PATH = path5.join(".swarm", LEDGER_FILENAME);
1265
+ var LEDGER_LOCK_PATH = path4.join(".swarm", LEDGER_FILENAME);
1978
1266
  var PLAN_JSON_FILENAME = "plan.json";
1979
1267
 
1980
1268
  class LedgerStaleWriterError extends Error {
@@ -1984,10 +1272,10 @@ class LedgerStaleWriterError extends Error {
1984
1272
  }
1985
1273
  }
1986
1274
  function getLedgerPath(directory) {
1987
- return path5.join(directory, ".swarm", LEDGER_FILENAME);
1275
+ return path4.join(directory, ".swarm", LEDGER_FILENAME);
1988
1276
  }
1989
1277
  function getPlanJsonPath(directory) {
1990
- return path5.join(directory, ".swarm", PLAN_JSON_FILENAME);
1278
+ return path4.join(directory, ".swarm", PLAN_JSON_FILENAME);
1991
1279
  }
1992
1280
  function computePlanHash(plan) {
1993
1281
  const normalized = {
@@ -2022,7 +1310,7 @@ function computePlanHash(plan) {
2022
1310
  function computeCurrentPlanHash(directory) {
2023
1311
  const planPath = getPlanJsonPath(directory);
2024
1312
  try {
2025
- const content = fs5.readFileSync(planPath, "utf8");
1313
+ const content = fs4.readFileSync(planPath, "utf8");
2026
1314
  const plan = JSON.parse(content);
2027
1315
  return computePlanHash(plan);
2028
1316
  } catch {
@@ -2031,15 +1319,15 @@ function computeCurrentPlanHash(directory) {
2031
1319
  }
2032
1320
  async function ledgerExists(directory) {
2033
1321
  const ledgerPath = getLedgerPath(directory);
2034
- return fs5.existsSync(ledgerPath);
1322
+ return fs4.existsSync(ledgerPath);
2035
1323
  }
2036
1324
  async function getLatestLedgerSeq(directory) {
2037
1325
  const ledgerPath = getLedgerPath(directory);
2038
- if (!fs5.existsSync(ledgerPath)) {
1326
+ if (!fs4.existsSync(ledgerPath)) {
2039
1327
  return 0;
2040
1328
  }
2041
1329
  try {
2042
- const content = fs5.readFileSync(ledgerPath, "utf8");
1330
+ const content = fs4.readFileSync(ledgerPath, "utf8");
2043
1331
  const lines = content.trim().split(`
2044
1332
  `).filter((line) => line.trim() !== "");
2045
1333
  if (lines.length === 0) {
@@ -2061,11 +1349,11 @@ async function getLatestLedgerSeq(directory) {
2061
1349
  }
2062
1350
  async function readLedgerEvents(directory) {
2063
1351
  const ledgerPath = getLedgerPath(directory);
2064
- if (!fs5.existsSync(ledgerPath)) {
1352
+ if (!fs4.existsSync(ledgerPath)) {
2065
1353
  return [];
2066
1354
  }
2067
1355
  try {
2068
- const content = fs5.readFileSync(ledgerPath, "utf8");
1356
+ const content = fs4.readFileSync(ledgerPath, "utf8");
2069
1357
  const lines = content.trim().split(`
2070
1358
  `).filter((line) => line.trim() !== "");
2071
1359
  const events = [];
@@ -2090,15 +1378,15 @@ async function readLedgerEvents(directory) {
2090
1378
  async function initLedger(directory, planId, initialPlanHash, initialPlan) {
2091
1379
  const ledgerPath = getLedgerPath(directory);
2092
1380
  const planJsonPath = getPlanJsonPath(directory);
2093
- if (fs5.existsSync(ledgerPath)) {
1381
+ if (fs4.existsSync(ledgerPath)) {
2094
1382
  throw new Error("Ledger already initialized. Use appendLedgerEvent to add events.");
2095
1383
  }
2096
1384
  let planHashAfter = initialPlanHash ?? "";
2097
1385
  let embeddedPlan = initialPlan;
2098
1386
  if (!initialPlanHash) {
2099
1387
  try {
2100
- if (fs5.existsSync(planJsonPath)) {
2101
- const content = fs5.readFileSync(planJsonPath, "utf8");
1388
+ if (fs4.existsSync(planJsonPath)) {
1389
+ const content = fs4.readFileSync(planJsonPath, "utf8");
2102
1390
  const plan = JSON.parse(content);
2103
1391
  planHashAfter = computePlanHash(plan);
2104
1392
  if (!embeddedPlan)
@@ -2118,12 +1406,12 @@ async function initLedger(directory, planId, initialPlanHash, initialPlan) {
2118
1406
  schema_version: LEDGER_SCHEMA_VERSION,
2119
1407
  ...payload ? { payload } : {}
2120
1408
  };
2121
- fs5.mkdirSync(path5.join(directory, ".swarm"), { recursive: true });
1409
+ fs4.mkdirSync(path4.join(directory, ".swarm"), { recursive: true });
2122
1410
  const tempPath = `${ledgerPath}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`;
2123
1411
  const line = `${JSON.stringify(event)}
2124
1412
  `;
2125
- fs5.writeFileSync(tempPath, line, "utf8");
2126
- fs5.renameSync(tempPath, ledgerPath);
1413
+ fs4.writeFileSync(tempPath, line, "utf8");
1414
+ fs4.renameSync(tempPath, ledgerPath);
2127
1415
  }
2128
1416
  async function appendLedgerEvent(directory, eventInput, options) {
2129
1417
  return withEvidenceLock(directory, LEDGER_LOCK_PATH, "plan-ledger", "append-ledger-event", async () => {
@@ -2146,17 +1434,17 @@ async function appendLedgerEvent(directory, eventInput, options) {
2146
1434
  plan_hash_after: planHashAfter,
2147
1435
  schema_version: LEDGER_SCHEMA_VERSION
2148
1436
  };
2149
- fs5.mkdirSync(path5.join(directory, ".swarm"), { recursive: true });
1437
+ fs4.mkdirSync(path4.join(directory, ".swarm"), { recursive: true });
2150
1438
  const tempPath = `${ledgerPath}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`;
2151
1439
  const line = `${JSON.stringify(event)}
2152
1440
  `;
2153
- if (fs5.existsSync(ledgerPath)) {
2154
- const existingContent = fs5.readFileSync(ledgerPath, "utf8");
2155
- fs5.writeFileSync(tempPath, existingContent + line, "utf8");
1441
+ if (fs4.existsSync(ledgerPath)) {
1442
+ const existingContent = fs4.readFileSync(ledgerPath, "utf8");
1443
+ fs4.writeFileSync(tempPath, existingContent + line, "utf8");
2156
1444
  } else {
2157
1445
  throw new Error("Ledger not initialized. Call initLedger() first.");
2158
1446
  }
2159
- fs5.renameSync(tempPath, ledgerPath);
1447
+ fs4.renameSync(tempPath, ledgerPath);
2160
1448
  return event;
2161
1449
  });
2162
1450
  }
@@ -2244,12 +1532,12 @@ async function replayFromLedger(directory, _options) {
2244
1532
  }
2245
1533
  }
2246
1534
  const planJsonPath = getPlanJsonPath(directory);
2247
- if (!fs5.existsSync(planJsonPath)) {
1535
+ if (!fs4.existsSync(planJsonPath)) {
2248
1536
  return null;
2249
1537
  }
2250
1538
  let plan;
2251
1539
  try {
2252
- const content = fs5.readFileSync(planJsonPath, "utf8");
1540
+ const content = fs4.readFileSync(planJsonPath, "utf8");
2253
1541
  plan = JSON.parse(content);
2254
1542
  } catch {
2255
1543
  return null;
@@ -2344,11 +1632,11 @@ function applyEventToPlan(plan, event) {
2344
1632
  }
2345
1633
  async function readLedgerEventsWithIntegrity(directory) {
2346
1634
  const ledgerPath = getLedgerPath(directory);
2347
- if (!fs5.existsSync(ledgerPath)) {
1635
+ if (!fs4.existsSync(ledgerPath)) {
2348
1636
  return { events: [], truncated: false, badSuffix: null };
2349
1637
  }
2350
1638
  try {
2351
- const content = fs5.readFileSync(ledgerPath, "utf8");
1639
+ const content = fs4.readFileSync(ledgerPath, "utf8");
2352
1640
  const lines = content.split(`
2353
1641
  `);
2354
1642
  const events = [];
@@ -2377,9 +1665,9 @@ async function readLedgerEventsWithIntegrity(directory) {
2377
1665
  }
2378
1666
  async function quarantineLedgerSuffix(directory, badSuffix) {
2379
1667
  try {
2380
- const quarantinePath = path5.join(directory, ".swarm", "plan-ledger.quarantine");
2381
- fs5.writeFileSync(quarantinePath, badSuffix, "utf8");
2382
- console.warn(`[ledger] Corrupted suffix quarantined to ${path5.relative(directory, quarantinePath)}`);
1668
+ const quarantinePath = path4.join(directory, ".swarm", "plan-ledger.quarantine");
1669
+ fs4.writeFileSync(quarantinePath, badSuffix, "utf8");
1670
+ console.warn(`[ledger] Corrupted suffix quarantined to ${path4.relative(directory, quarantinePath)}`);
2383
1671
  } catch {}
2384
1672
  }
2385
1673
  async function loadLastApprovedPlan(directory, expectedPlanId) {
@@ -2475,7 +1763,7 @@ async function retryCasWithBackoff(directory, eventInput, options) {
2475
1763
  expectedHashPrefix: currentExpected.slice(0, 8),
2476
1764
  delayMs
2477
1765
  });
2478
- await new Promise((resolve4) => setTimeout(resolve4, delayMs));
1766
+ await new Promise((resolve3) => setTimeout(resolve3, delayMs));
2479
1767
  if (options.verifyValid) {
2480
1768
  const stillValid = await options.verifyValid();
2481
1769
  if (!stillValid)
@@ -2518,7 +1806,7 @@ async function getLatestLedgerHash(directory) {
2518
1806
  }
2519
1807
  }
2520
1808
  async function surfaceLedgerStaleIfPersisted(directory, plan) {
2521
- const resolvedWorkspace = path6.resolve(directory);
1809
+ const resolvedWorkspace = path5.resolve(directory);
2522
1810
  if (!ledgerStaleWorkspaces.has(resolvedWorkspace)) {
2523
1811
  return plan;
2524
1812
  }
@@ -2537,7 +1825,7 @@ async function surfaceLedgerStaleIfPersisted(directory, plan) {
2537
1825
  return plan;
2538
1826
  }
2539
1827
  async function parsePlanJsonCached(directory) {
2540
- const planJsonPath = path6.resolve(directory, ".swarm", "plan.json");
1828
+ const planJsonPath = path5.resolve(directory, ".swarm", "plan.json");
2541
1829
  return readCachedParsedFile(planJsonPath, PLAN_JSON_CACHE_NAMESPACE, () => readSwarmFileAsync(directory, "plan.json"), (planJsonContent) => {
2542
1830
  if (planJsonContent.includes("\x00") || planJsonContent.includes("\uFFFD")) {
2543
1831
  throw new Error("Plan rejected: .swarm/plan.json contains null bytes or invalid encoding");
@@ -2597,16 +1885,16 @@ async function isPlanMdInSync(directory, plan, cache) {
2597
1885
  return false;
2598
1886
  }
2599
1887
  async function regeneratePlanMarkdown(directory, plan) {
2600
- const swarmDir = path6.resolve(directory, ".swarm");
1888
+ const swarmDir = path5.resolve(directory, ".swarm");
2601
1889
  const contentHash = computePlanContentHash(plan);
2602
1890
  const markdown = derivePlanMarkdown(plan);
2603
1891
  const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
2604
1892
  ${markdown}`;
2605
- const mdPath = path6.join(swarmDir, "plan.md");
2606
- const mdTempPath = path6.join(swarmDir, `plan.md.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
1893
+ const mdPath = path5.join(swarmDir, "plan.md");
1894
+ const mdTempPath = path5.join(swarmDir, `plan.md.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
2607
1895
  try {
2608
1896
  await bunWrite(mdTempPath, markdownWithHash);
2609
- renameSync5(mdTempPath, mdPath);
1897
+ renameSync4(mdTempPath, mdPath);
2610
1898
  } finally {
2611
1899
  try {
2612
1900
  unlinkSync3(mdTempPath);
@@ -2635,7 +1923,7 @@ async function loadPlan(directory, cache) {
2635
1923
  if (await ledgerExists(directory)) {
2636
1924
  const planHash = computePlanHash(validated);
2637
1925
  const ledgerHash = await getLatestLedgerHash(directory);
2638
- const resolvedWorkspace = path6.resolve(directory);
1926
+ const resolvedWorkspace = path5.resolve(directory);
2639
1927
  if (!startupLedgerCheckedWorkspaces.has(resolvedWorkspace)) {
2640
1928
  startupLedgerCheckedWorkspaces.add(resolvedWorkspace);
2641
1929
  if (ledgerHash !== "" && planHash !== ledgerHash) {
@@ -2701,7 +1989,7 @@ async function loadPlan(directory, cache) {
2701
1989
  if (!preserving) {
2702
1990
  try {
2703
1991
  const diffInfo = computeSpecDiff(directory);
2704
- const specStalenessPath = path6.join(directory, ".swarm", "spec-staleness.json");
1992
+ const specStalenessPath = path5.join(directory, ".swarm", "spec-staleness.json");
2705
1993
  await fsPromises.writeFile(specStalenessPath, JSON.stringify({
2706
1994
  type: "spec_stale_detected",
2707
1995
  timestamp: new Date().toISOString(),
@@ -2715,7 +2003,7 @@ async function loadPlan(directory, cache) {
2715
2003
  }, null, 2), "utf-8");
2716
2004
  } catch {}
2717
2005
  try {
2718
- const eventsPath = path6.join(directory, ".swarm", "events.jsonl");
2006
+ const eventsPath = path5.join(directory, ".swarm", "events.jsonl");
2719
2007
  const event = {
2720
2008
  type: "spec_stale_detected",
2721
2009
  timestamp: new Date().toISOString(),
@@ -2781,7 +2069,7 @@ async function loadPlan(directory, cache) {
2781
2069
  return migrated;
2782
2070
  }
2783
2071
  if (await ledgerExists(directory)) {
2784
- const resolvedDir = path6.resolve(directory);
2072
+ const resolvedDir = path5.resolve(directory);
2785
2073
  const existingMutex = recoveryMutexes.get(resolvedDir);
2786
2074
  if (existingMutex) {
2787
2075
  await existingMutex;
@@ -2921,13 +2209,13 @@ async function savePlan(directory, plan, options) {
2921
2209
  } else {
2922
2210
  const existingEvents = await readLedgerEvents(directory);
2923
2211
  if (existingEvents.length > 0 && existingEvents[0].plan_id !== planId) {
2924
- const swarmDir2 = path6.resolve(directory, ".swarm");
2925
- const oldLedgerPath = path6.join(swarmDir2, "plan-ledger.jsonl");
2926
- const oldLedgerBackupPath = path6.join(swarmDir2, `plan-ledger.backup-${Date.now()}-${Math.floor(Math.random() * 1e9)}.jsonl`);
2212
+ const swarmDir2 = path5.resolve(directory, ".swarm");
2213
+ const oldLedgerPath = path5.join(swarmDir2, "plan-ledger.jsonl");
2214
+ const oldLedgerBackupPath = path5.join(swarmDir2, `plan-ledger.backup-${Date.now()}-${Math.floor(Math.random() * 1e9)}.jsonl`);
2927
2215
  let backupExists = false;
2928
- if (existsSync6(oldLedgerPath)) {
2216
+ if (existsSync5(oldLedgerPath)) {
2929
2217
  try {
2930
- renameSync5(oldLedgerPath, oldLedgerBackupPath);
2218
+ renameSync4(oldLedgerPath, oldLedgerBackupPath);
2931
2219
  backupExists = true;
2932
2220
  } catch (renameErr) {
2933
2221
  throw new Error(`[savePlan] Cannot reinitialize ledger: could not move old ledger aside (rename failed: ${renameErr instanceof Error ? renameErr.message : String(renameErr)}). The existing ledger has plan_id="${existingEvents[0].plan_id}" which does not match the current plan="${planId}". To proceed, close any programs that may have the ledger file open, or run /swarm reset-session to clear the ledger.`);
@@ -2942,13 +2230,13 @@ async function savePlan(directory, plan, options) {
2942
2230
  const errorMessage2 = String(initErr);
2943
2231
  if (errorMessage2.includes("already initialized")) {
2944
2232
  try {
2945
- if (existsSync6(oldLedgerBackupPath))
2233
+ if (existsSync5(oldLedgerBackupPath))
2946
2234
  unlinkSync3(oldLedgerBackupPath);
2947
2235
  } catch {}
2948
2236
  } else {
2949
- if (existsSync6(oldLedgerBackupPath)) {
2237
+ if (existsSync5(oldLedgerBackupPath)) {
2950
2238
  try {
2951
- renameSync5(oldLedgerBackupPath, oldLedgerPath);
2239
+ renameSync4(oldLedgerBackupPath, oldLedgerPath);
2952
2240
  } catch {
2953
2241
  copyFileSync(oldLedgerBackupPath, oldLedgerPath);
2954
2242
  try {
@@ -2961,32 +2249,32 @@ async function savePlan(directory, plan, options) {
2961
2249
  }
2962
2250
  }
2963
2251
  if (initSucceeded && backupExists) {
2964
- const archivePath = path6.join(swarmDir2, `plan-ledger.archived-${Date.now()}-${Math.floor(Math.random() * 1e9)}.jsonl`);
2252
+ const archivePath = path5.join(swarmDir2, `plan-ledger.archived-${Date.now()}-${Math.floor(Math.random() * 1e9)}.jsonl`);
2965
2253
  try {
2966
- renameSync5(oldLedgerBackupPath, archivePath);
2254
+ renameSync4(oldLedgerBackupPath, archivePath);
2967
2255
  warn(`[savePlan] Ledger identity mismatch (was "${existingEvents[0].plan_id}", now "${planId}") \u2014 archived old ledger to ${archivePath} and reinitializing.`);
2968
2256
  } catch (renameErr) {
2969
2257
  warn(`[savePlan] Could not archive old ledger (rename failed: ${renameErr instanceof Error ? renameErr.message : String(renameErr)}). Old ledger may still exist at ${oldLedgerBackupPath}.`);
2970
2258
  try {
2971
- if (existsSync6(oldLedgerBackupPath))
2259
+ if (existsSync5(oldLedgerBackupPath))
2972
2260
  unlinkSync3(oldLedgerBackupPath);
2973
2261
  } catch {}
2974
2262
  }
2975
2263
  } else if (!initSucceeded && backupExists) {
2976
2264
  try {
2977
- if (existsSync6(oldLedgerBackupPath))
2265
+ if (existsSync5(oldLedgerBackupPath))
2978
2266
  unlinkSync3(oldLedgerBackupPath);
2979
2267
  } catch {}
2980
2268
  }
2981
2269
  const MAX_ARCHIVED_SIBLINGS = 5;
2982
2270
  try {
2983
- const allFiles = readdirSync2(swarmDir2);
2271
+ const allFiles = readdirSync(swarmDir2);
2984
2272
  const archivedSiblings = allFiles.filter((f) => f.startsWith("plan-ledger.archived-") && f.endsWith(".jsonl")).sort();
2985
2273
  if (archivedSiblings.length > MAX_ARCHIVED_SIBLINGS) {
2986
2274
  const toRemove = archivedSiblings.slice(0, archivedSiblings.length - MAX_ARCHIVED_SIBLINGS);
2987
2275
  for (const file of toRemove) {
2988
2276
  try {
2989
- unlinkSync3(path6.join(swarmDir2, file));
2277
+ unlinkSync3(path5.join(swarmDir2, file));
2990
2278
  } catch {}
2991
2279
  }
2992
2280
  }
@@ -3111,46 +2399,47 @@ async function savePlan(directory, plan, options) {
3111
2399
  throw error2;
3112
2400
  }
3113
2401
  }
2402
+ const projectedPlan = await replayFromLedger(directory) ?? validated;
3114
2403
  const SNAPSHOT_INTERVAL = 50;
3115
2404
  const latestSeq = await getLatestLedgerSeq(directory);
3116
2405
  if (latestSeq > 0 && latestSeq % SNAPSHOT_INTERVAL === 0) {
3117
- await takeSnapshotWithRetry(directory, validated, {
3118
- planHashAfter: hashAfter,
2406
+ await takeSnapshotWithRetry(directory, projectedPlan, {
2407
+ planHashAfter: computePlanHash(projectedPlan),
3119
2408
  source: "savePlan_manager"
3120
2409
  });
3121
2410
  }
3122
- const swarmDir = path6.resolve(directory, ".swarm");
3123
- const planPath = path6.join(swarmDir, "plan.json");
3124
- const tempPath = path6.join(swarmDir, `plan.json.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
2411
+ const swarmDir = path5.resolve(directory, ".swarm");
2412
+ const planPath = path5.join(swarmDir, "plan.json");
2413
+ const tempPath = path5.join(swarmDir, `plan.json.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
3125
2414
  try {
3126
- await bunWrite(tempPath, JSON.stringify(validated, null, 2));
3127
- renameSync5(tempPath, planPath);
2415
+ await bunWrite(tempPath, JSON.stringify(projectedPlan, null, 2));
2416
+ renameSync4(tempPath, planPath);
3128
2417
  } finally {
3129
2418
  try {
3130
2419
  unlinkSync3(tempPath);
3131
2420
  } catch {}
3132
2421
  }
3133
2422
  try {
3134
- const markerPath = path6.join(swarmDir, ".plan-write-marker");
2423
+ const markerPath = path5.join(swarmDir, ".plan-write-marker");
3135
2424
  const inProgressMarker = JSON.stringify({
3136
2425
  source: "plan_manager",
3137
2426
  timestamp: new Date().toISOString(),
3138
- phases_count: validated.phases.length,
3139
- tasks_count: validated.phases.reduce((sum, p) => sum + p.tasks.length, 0),
2427
+ phases_count: projectedPlan.phases.length,
2428
+ tasks_count: projectedPlan.phases.reduce((sum, p) => sum + p.tasks.length, 0),
3140
2429
  in_progress: true
3141
2430
  });
3142
2431
  await bunWrite(markerPath, inProgressMarker);
3143
2432
  } catch {}
3144
2433
  try {
3145
- const contentHash = computePlanContentHash(validated);
3146
- const markdown = derivePlanMarkdown(validated);
2434
+ const contentHash = computePlanContentHash(projectedPlan);
2435
+ const markdown = derivePlanMarkdown(projectedPlan);
3147
2436
  const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
3148
2437
  ${markdown}`;
3149
- const mdPath = path6.join(swarmDir, "plan.md");
3150
- const mdTempPath = path6.join(swarmDir, `plan.md.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
2438
+ const mdPath = path5.join(swarmDir, "plan.md");
2439
+ const mdTempPath = path5.join(swarmDir, `plan.md.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
3151
2440
  try {
3152
2441
  await bunWrite(mdTempPath, markdownWithHash);
3153
- renameSync5(mdTempPath, mdPath);
2442
+ renameSync4(mdTempPath, mdPath);
3154
2443
  } finally {
3155
2444
  try {
3156
2445
  unlinkSync3(mdTempPath);
@@ -3168,12 +2457,12 @@ ${markdown}`;
3168
2457
  } catch {}
3169
2458
  }
3170
2459
  try {
3171
- const markerPath = path6.join(swarmDir, ".plan-write-marker");
3172
- const tasksCount = validated.phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
2460
+ const markerPath = path5.join(swarmDir, ".plan-write-marker");
2461
+ const tasksCount = projectedPlan.phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
3173
2462
  const marker = JSON.stringify({
3174
2463
  source: "plan_manager",
3175
2464
  timestamp: new Date().toISOString(),
3176
- phases_count: validated.phases.length,
2465
+ phases_count: projectedPlan.phases.length,
3177
2466
  tasks_count: tasksCount,
3178
2467
  in_progress: false
3179
2468
  });
@@ -3184,14 +2473,14 @@ async function rebuildPlan(directory, plan, options) {
3184
2473
  const targetPlan = plan ?? await replayFromLedger(directory);
3185
2474
  if (!targetPlan)
3186
2475
  return null;
3187
- const swarmDir = path6.join(directory, ".swarm");
3188
- const planPath = path6.join(swarmDir, "plan.json");
3189
- const mdPath = path6.join(swarmDir, "plan.md");
3190
- const tempPlanPath = path6.join(swarmDir, `plan.json.rebuild.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
2476
+ const swarmDir = path5.join(directory, ".swarm");
2477
+ const planPath = path5.join(swarmDir, "plan.json");
2478
+ const mdPath = path5.join(swarmDir, "plan.md");
2479
+ const tempPlanPath = path5.join(swarmDir, `plan.json.rebuild.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
3191
2480
  await bunWrite(tempPlanPath, JSON.stringify(targetPlan, null, 2));
3192
- renameSync5(tempPlanPath, planPath);
2481
+ renameSync4(tempPlanPath, planPath);
3193
2482
  try {
3194
- const markerPath = path6.join(swarmDir, ".plan-write-marker");
2483
+ const markerPath = path5.join(swarmDir, ".plan-write-marker");
3195
2484
  const inProgressMarker = JSON.stringify({
3196
2485
  source: "plan_manager",
3197
2486
  timestamp: new Date().toISOString(),
@@ -3206,12 +2495,12 @@ async function rebuildPlan(directory, plan, options) {
3206
2495
  const markdown = derivePlanMarkdown(targetPlan);
3207
2496
  const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
3208
2497
  ${markdown}`;
3209
- const tempMdPath = path6.join(swarmDir, `plan.md.rebuild.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
2498
+ const tempMdPath = path5.join(swarmDir, `plan.md.rebuild.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
3210
2499
  await bunWrite(tempMdPath, markdownWithHash);
3211
- renameSync5(tempMdPath, mdPath);
2500
+ renameSync4(tempMdPath, mdPath);
3212
2501
  } finally {
3213
2502
  try {
3214
- const markerPath = path6.join(swarmDir, ".plan-write-marker");
2503
+ const markerPath = path5.join(swarmDir, ".plan-write-marker");
3215
2504
  const tasksCount = targetPlan.phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
3216
2505
  const marker = JSON.stringify({
3217
2506
  source: "plan_manager",
@@ -3274,13 +2563,13 @@ async function closePlanTerminalState(directory, plan, options) {
3274
2563
  planHashAfter: hashAfter,
3275
2564
  source: "close_terminal"
3276
2565
  });
3277
- const swarmDir = path6.join(directory, ".swarm");
3278
- const planPath = path6.join(swarmDir, "plan.json");
3279
- const tempPlanPath = path6.join(swarmDir, `plan.json.close.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
2566
+ const swarmDir = path5.join(directory, ".swarm");
2567
+ const planPath = path5.join(swarmDir, "plan.json");
2568
+ const tempPlanPath = path5.join(swarmDir, `plan.json.close.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
3280
2569
  await bunWrite(tempPlanPath, JSON.stringify(validated, null, 2));
3281
- renameSync5(tempPlanPath, planPath);
2570
+ renameSync4(tempPlanPath, planPath);
3282
2571
  try {
3283
- const markerPath = path6.join(swarmDir, ".plan-write-marker");
2572
+ const markerPath = path5.join(swarmDir, ".plan-write-marker");
3284
2573
  const inProgressMarker = JSON.stringify({
3285
2574
  source: "plan_manager_close",
3286
2575
  timestamp: new Date().toISOString(),
@@ -3291,17 +2580,17 @@ async function closePlanTerminalState(directory, plan, options) {
3291
2580
  await bunWrite(markerPath, inProgressMarker);
3292
2581
  } catch {}
3293
2582
  try {
3294
- const mdPath = path6.join(swarmDir, "plan.md");
2583
+ const mdPath = path5.join(swarmDir, "plan.md");
3295
2584
  const contentHash = computePlanContentHash(validated);
3296
2585
  const markdown = derivePlanMarkdown(validated);
3297
2586
  const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
3298
2587
  ${markdown}`;
3299
- const mdTempPath = path6.join(swarmDir, `plan.md.close.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
2588
+ const mdTempPath = path5.join(swarmDir, `plan.md.close.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
3300
2589
  await bunWrite(mdTempPath, markdownWithHash);
3301
- renameSync5(mdTempPath, mdPath);
2590
+ renameSync4(mdTempPath, mdPath);
3302
2591
  } finally {
3303
2592
  try {
3304
- const markerPath = path6.join(swarmDir, ".plan-write-marker");
2593
+ const markerPath = path5.join(swarmDir, ".plan-write-marker");
3305
2594
  const tasksCount = validated.phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
3306
2595
  const marker = JSON.stringify({
3307
2596
  source: "plan_manager_close",
@@ -3585,14 +2874,14 @@ function migrateLegacyPlan(planContent, swarmId) {
3585
2874
 
3586
2875
  // src/evidence/manager.ts
3587
2876
  import {
3588
- mkdirSync as mkdirSync5,
3589
- readdirSync as readdirSync3,
2877
+ mkdirSync as mkdirSync4,
2878
+ readdirSync as readdirSync2,
3590
2879
  realpathSync,
3591
2880
  rmSync,
3592
- statSync as statSync3
2881
+ statSync as statSync2
3593
2882
  } from "fs";
3594
- import * as fs6 from "fs/promises";
3595
- import * as path7 from "path";
2883
+ import * as fs5 from "fs/promises";
2884
+ import * as path6 from "path";
3596
2885
 
3597
2886
  // src/config/evidence-schema.ts
3598
2887
  var EVIDENCE_MAX_JSON_BYTES = 500 * 1024;
@@ -3924,16 +3213,16 @@ function validateProjectRoot(directory) {
3924
3213
  if (depth >= MAX_DEPTH)
3925
3214
  break;
3926
3215
  depth++;
3927
- const parent = path7.dirname(current);
3216
+ const parent = path6.dirname(current);
3928
3217
  if (parent === current)
3929
3218
  break;
3930
- const parentSwarm = path7.join(parent, ".swarm");
3219
+ const parentSwarm = path6.join(parent, ".swarm");
3931
3220
  try {
3932
- if (statSync3(parentSwarm).isDirectory()) {
3221
+ if (statSync2(parentSwarm).isDirectory()) {
3933
3222
  let hasProjectIndicator = false;
3934
3223
  for (const indicator of PROJECT_INDICATORS) {
3935
3224
  try {
3936
- const indicatorStat = statSync3(path7.join(parent, indicator));
3225
+ const indicatorStat = statSync2(path6.join(parent, indicator));
3937
3226
  if (indicatorStat.isFile() || indicatorStat.isDirectory()) {
3938
3227
  hasProjectIndicator = true;
3939
3228
  break;
@@ -3961,12 +3250,12 @@ function validateProjectRoot(directory) {
3961
3250
  async function saveEvidence(directory, taskId, evidence) {
3962
3251
  _internals5.validateProjectRoot(directory);
3963
3252
  const sanitizedTaskId = sanitizeTaskId2(taskId);
3964
- const relativePath = path7.join("evidence", sanitizedTaskId, "evidence.json");
3253
+ const relativePath = path6.join("evidence", sanitizedTaskId, "evidence.json");
3965
3254
  validateSwarmPath(directory, relativePath);
3966
3255
  _internals5.validateEvidence(evidence);
3967
3256
  return withEvidenceLock(directory, relativePath, "evidence-manager", sanitizedTaskId, async () => {
3968
3257
  const evidencePath = validateSwarmPath(directory, relativePath);
3969
- const evidenceDir = path7.dirname(evidencePath);
3258
+ const evidenceDir = path6.dirname(evidencePath);
3970
3259
  let bundle;
3971
3260
  const existingContent = await readSwarmFileAsync(directory, relativePath);
3972
3261
  if (existingContent !== null) {
@@ -4008,11 +3297,11 @@ async function saveEvidence(directory, taskId, evidence) {
4008
3297
  if (bundleJson.length > EVIDENCE_MAX_JSON_BYTES) {
4009
3298
  throw new Error(`Evidence bundle size (${bundleJson.length} bytes) exceeds maximum (${EVIDENCE_MAX_JSON_BYTES} bytes)`);
4010
3299
  }
4011
- mkdirSync5(evidenceDir, { recursive: true });
4012
- const tempPath = path7.join(evidenceDir, `evidence.json.tmp.${Date.now()}.${process.pid}`);
3300
+ mkdirSync4(evidenceDir, { recursive: true });
3301
+ const tempPath = path6.join(evidenceDir, `evidence.json.tmp.${Date.now()}.${process.pid}`);
4013
3302
  try {
4014
3303
  await bunWrite(tempPath, bundleJson);
4015
- await fs6.rename(tempPath, evidencePath);
3304
+ await fs5.rename(tempPath, evidencePath);
4016
3305
  } catch (error2) {
4017
3306
  try {
4018
3307
  rmSync(tempPath, { force: true });
@@ -4053,7 +3342,7 @@ function wrapFlatRetrospective(flatEntry, taskId) {
4053
3342
  }
4054
3343
  async function loadEvidence(directory, taskId) {
4055
3344
  const sanitizedTaskId = sanitizeTaskId2(taskId);
4056
- const relativePath = path7.join("evidence", sanitizedTaskId, "evidence.json");
3345
+ const relativePath = path6.join("evidence", sanitizedTaskId, "evidence.json");
4057
3346
  if (relativePath.length > 4096) {
4058
3347
  return { status: "not_found" };
4059
3348
  }
@@ -4074,12 +3363,12 @@ async function loadEvidence(directory, taskId) {
4074
3363
  const validated = EvidenceBundleSchema.parse(wrappedBundle);
4075
3364
  try {
4076
3365
  await withEvidenceLock(directory, relativePath, "evidence-loader", sanitizedTaskId, async () => {
4077
- const evidenceDir = path7.dirname(evidencePath);
3366
+ const evidenceDir = path6.dirname(evidencePath);
4078
3367
  const bundleJson = JSON.stringify(validated);
4079
- const tempPath = path7.join(evidenceDir, `evidence.json.tmp.${Date.now()}.${process.pid}`);
3368
+ const tempPath = path6.join(evidenceDir, `evidence.json.tmp.${Date.now()}.${process.pid}`);
4080
3369
  try {
4081
3370
  await bunWrite(tempPath, bundleJson);
4082
- await fs6.rename(tempPath, evidencePath);
3371
+ await fs5.rename(tempPath, evidencePath);
4083
3372
  } catch (writeError) {
4084
3373
  try {
4085
3374
  rmSync(tempPath, { force: true });
@@ -4109,21 +3398,21 @@ async function loadEvidence(directory, taskId) {
4109
3398
  async function listEvidenceTaskIds(directory) {
4110
3399
  const evidenceBasePath = validateSwarmPath(directory, "evidence");
4111
3400
  try {
4112
- statSync3(evidenceBasePath);
3401
+ statSync2(evidenceBasePath);
4113
3402
  } catch {
4114
3403
  return [];
4115
3404
  }
4116
3405
  let entries;
4117
3406
  try {
4118
- entries = readdirSync3(evidenceBasePath);
3407
+ entries = readdirSync2(evidenceBasePath);
4119
3408
  } catch {
4120
3409
  return [];
4121
3410
  }
4122
3411
  const taskIds = [];
4123
3412
  for (const entry of entries) {
4124
- const entryPath = path7.join(evidenceBasePath, entry);
3413
+ const entryPath = path6.join(evidenceBasePath, entry);
4125
3414
  try {
4126
- const stats = statSync3(entryPath);
3415
+ const stats = statSync2(entryPath);
4127
3416
  if (!stats.isDirectory()) {
4128
3417
  continue;
4129
3418
  }
@@ -4139,10 +3428,10 @@ async function listEvidenceTaskIds(directory) {
4139
3428
  }
4140
3429
  async function deleteEvidence(directory, taskId) {
4141
3430
  const sanitizedTaskId = sanitizeTaskId2(taskId);
4142
- const relativePath = path7.join("evidence", sanitizedTaskId);
3431
+ const relativePath = path6.join("evidence", sanitizedTaskId);
4143
3432
  const evidenceDir = validateSwarmPath(directory, relativePath);
4144
3433
  try {
4145
- statSync3(evidenceDir);
3434
+ statSync2(evidenceDir);
4146
3435
  } catch {
4147
3436
  return false;
4148
3437
  }
@@ -4155,10 +3444,10 @@ async function deleteEvidence(directory, taskId) {
4155
3444
  }
4156
3445
  }
4157
3446
  async function checkRequirementCoverage(phase, directory) {
4158
- const relativePath = path7.join("evidence", `req-coverage-phase-${phase}.json`);
4159
- const absolutePath = path7.resolve(directory, ".swarm", relativePath);
3447
+ const relativePath = path6.join("evidence", `req-coverage-phase-${phase}.json`);
3448
+ const absolutePath = path6.resolve(directory, ".swarm", relativePath);
4160
3449
  try {
4161
- await fs6.access(absolutePath);
3450
+ await fs5.access(absolutePath);
4162
3451
  return { exists: true, path: absolutePath };
4163
3452
  } catch {
4164
3453
  return { exists: false, path: absolutePath };
@@ -4322,4 +3611,4 @@ function mergeDurableGateEntriesFromEvidence(taskId, entries, evidence) {
4322
3611
  return merged;
4323
3612
  }
4324
3613
 
4325
- export { PlanSchema, MAX_TRANSIENT_RETRIES, isTransientSpawnError, transientBackoff, getGitRepositoryStatus, isGitRepo, resetToRemoteBranch, resetToMainAfterMerge, isStateUnreadable, loadEpicSessionState, isEpicModeActive, enableEpicMode, disableEpicMode, normalizePath, pathsConflict, isGlobalFile, isProtectedPath, readTaskScopes, detectSpeckit, resolveSpeckitProjection, loadSddStatusSync, buildOpenSpecProjectionSync, readEffectiveSpecSync, writeProjectedSpecSync, validateSpeckit, computeSpecHash, derivePlanId, computePlanHash, initLedger, appendLedgerEvent, loadPlanJsonOnly, loadPlan, savePlan, closePlanTerminalState, derivePlanMarkdown, RetrospectiveEvidenceSchema, isValidEvidenceType, sanitizeTaskId2 as sanitizeTaskId, validateProjectRoot, saveEvidence, loadEvidence, listEvidenceTaskIds, checkRequirementCoverage, archiveEvidence, readDurableGateEvidence, getDurableGateEvidenceStatus, getDurableGateEvidenceStatusForTask, mergeDurableGateEntriesFromEvidence };
3614
+ export { PlanSchema, MAX_TRANSIENT_RETRIES, isTransientSpawnError, transientBackoff, getGitRepositoryStatus, isGitRepo, resetToRemoteBranch, resetToMainAfterMerge, isStateUnreadable, loadEpicSessionState, isEpicModeActive, enableEpicMode, disableEpicMode, normalizePath, pathsConflict, isGlobalFile, isProtectedPath, readTaskScopes, computeSpecHash, derivePlanId, computePlanHash, initLedger, appendLedgerEvent, loadPlanJsonOnly, loadPlan, savePlan, closePlanTerminalState, derivePlanMarkdown, RetrospectiveEvidenceSchema, isValidEvidenceType, sanitizeTaskId2 as sanitizeTaskId, validateProjectRoot, saveEvidence, loadEvidence, listEvidenceTaskIds, checkRequirementCoverage, archiveEvidence, readDurableGateEvidence, getDurableGateEvidenceStatus, getDurableGateEvidenceStatusForTask, mergeDurableGateEntriesFromEvidence };