syntaur 0.18.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dashboard/dist/assets/{_basePickBy-Cx0q44iE.js → _basePickBy-CFyquBjL.js} +1 -1
  2. package/dashboard/dist/assets/{_baseUniq-CfFbkKif.js → _baseUniq-S9hlXGZI.js} +1 -1
  3. package/dashboard/dist/assets/{arc-XluBomWz.js → arc-DNRWeoWH.js} +1 -1
  4. package/dashboard/dist/assets/{architectureDiagram-2XIMDMQ5-CihGybG6.js → architectureDiagram-2XIMDMQ5-BujnKgOd.js} +1 -1
  5. package/dashboard/dist/assets/{blockDiagram-WCTKOSBZ-BPUKO5fj.js → blockDiagram-WCTKOSBZ-DOaDmG_o.js} +1 -1
  6. package/dashboard/dist/assets/{c4Diagram-IC4MRINW-DKVq_j1f.js → c4Diagram-IC4MRINW-BeBwVhQx.js} +1 -1
  7. package/dashboard/dist/assets/channel-yUe8n53Y.js +1 -0
  8. package/dashboard/dist/assets/{chunk-4BX2VUAB-DAaE8oN2.js → chunk-4BX2VUAB-CtzM4Epf.js} +1 -1
  9. package/dashboard/dist/assets/{chunk-55IACEB6-BZoVpy5G.js → chunk-55IACEB6-D2cd1TFn.js} +1 -1
  10. package/dashboard/dist/assets/{chunk-FMBD7UC4-Cuo9M0jI.js → chunk-FMBD7UC4-DAqRATzJ.js} +1 -1
  11. package/dashboard/dist/assets/{chunk-JSJVCQXG-DGzypY5S.js → chunk-JSJVCQXG-CIEi981s.js} +1 -1
  12. package/dashboard/dist/assets/{chunk-KX2RTZJC-DfxYbrKI.js → chunk-KX2RTZJC-BMv4Xwdm.js} +1 -1
  13. package/dashboard/dist/assets/{chunk-NQ4KR5QH-BEbwpe5N.js → chunk-NQ4KR5QH-BKTm5ctg.js} +1 -1
  14. package/dashboard/dist/assets/{chunk-QZHKN3VN-DDjrkJqg.js → chunk-QZHKN3VN-DjmLZcpF.js} +1 -1
  15. package/dashboard/dist/assets/{chunk-WL4C6EOR-BSMHQ3p4.js → chunk-WL4C6EOR-CphX8dKS.js} +1 -1
  16. package/dashboard/dist/assets/classDiagram-VBA2DB6C-C0f25bKl.js +1 -0
  17. package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-C0f25bKl.js +1 -0
  18. package/dashboard/dist/assets/clone-D-aj2eAK.js +1 -0
  19. package/dashboard/dist/assets/{cose-bilkent-S5V4N54A-BgUyyImN.js → cose-bilkent-S5V4N54A-BZ-8TY36.js} +1 -1
  20. package/dashboard/dist/assets/{dagre-KLK3FWXG-zAe7pq6F.js → dagre-KLK3FWXG-Bx5whsTp.js} +1 -1
  21. package/dashboard/dist/assets/{diagram-E7M64L7V-B1bVb4ll.js → diagram-E7M64L7V-BVOQiv2e.js} +1 -1
  22. package/dashboard/dist/assets/{diagram-IFDJBPK2-DZCxJIkJ.js → diagram-IFDJBPK2-D7bQBDL_.js} +1 -1
  23. package/dashboard/dist/assets/{diagram-P4PSJMXO-BuPgL5q1.js → diagram-P4PSJMXO-CwO6aafO.js} +1 -1
  24. package/dashboard/dist/assets/{erDiagram-INFDFZHY-l3YvnHT9.js → erDiagram-INFDFZHY-DCNz82wG.js} +1 -1
  25. package/dashboard/dist/assets/{flowDiagram-PKNHOUZH-CLOLQLdW.js → flowDiagram-PKNHOUZH-Dq6yNscM.js} +1 -1
  26. package/dashboard/dist/assets/{ganttDiagram-A5KZAMGK-D1yLx2Ap.js → ganttDiagram-A5KZAMGK-B2xtuK0X.js} +1 -1
  27. package/dashboard/dist/assets/{gitGraphDiagram-K3NZZRJ6-uC4rY3UQ.js → gitGraphDiagram-K3NZZRJ6-D8mNkQd3.js} +1 -1
  28. package/dashboard/dist/assets/{graph-DvUnLFOz.js → graph-DMbUUtaR.js} +1 -1
  29. package/dashboard/dist/assets/index-BlikGvSd.js +550 -0
  30. package/dashboard/dist/assets/index-CsyJIOqR.css +1 -0
  31. package/dashboard/dist/assets/{infoDiagram-LFFYTUFH-B6jLLOUk.js → infoDiagram-LFFYTUFH-BsrDYNxL.js} +1 -1
  32. package/dashboard/dist/assets/{ishikawaDiagram-PHBUUO56-CDvhubqL.js → ishikawaDiagram-PHBUUO56-DlUJjWQM.js} +1 -1
  33. package/dashboard/dist/assets/{journeyDiagram-4ABVD52K-BOtMcoBj.js → journeyDiagram-4ABVD52K-DBbVdCE_.js} +1 -1
  34. package/dashboard/dist/assets/{kanban-definition-K7BYSVSG-DC05q9p4.js → kanban-definition-K7BYSVSG-Cuv3IHJ_.js} +1 -1
  35. package/dashboard/dist/assets/{layout-B4jiZlj6.js → layout-CgL4rycu.js} +1 -1
  36. package/dashboard/dist/assets/{linear-DpQXVSyZ.js → linear-CgnhFMi4.js} +1 -1
  37. package/dashboard/dist/assets/{mermaid.core-aNcWKq-4.js → mermaid.core-C3eCFd8P.js} +4 -4
  38. package/dashboard/dist/assets/{mindmap-definition-YRQLILUH-Dv4qo7wQ.js → mindmap-definition-YRQLILUH-Bsm6cGkL.js} +1 -1
  39. package/dashboard/dist/assets/{pieDiagram-SKSYHLDU-ByRY4ahm.js → pieDiagram-SKSYHLDU-DBRLfMtc.js} +1 -1
  40. package/dashboard/dist/assets/{quadrantDiagram-337W2JSQ-Dt5_Xjwp.js → quadrantDiagram-337W2JSQ-CES4NNws.js} +1 -1
  41. package/dashboard/dist/assets/{requirementDiagram-Z7DCOOCP-CSRV6VcE.js → requirementDiagram-Z7DCOOCP-B0cUyFW2.js} +1 -1
  42. package/dashboard/dist/assets/{sankeyDiagram-WA2Y5GQK-DA8gxGEq.js → sankeyDiagram-WA2Y5GQK-LVaVg6wF.js} +1 -1
  43. package/dashboard/dist/assets/{sequenceDiagram-2WXFIKYE-CVZr9aKv.js → sequenceDiagram-2WXFIKYE-BISSySYI.js} +1 -1
  44. package/dashboard/dist/assets/{stateDiagram-RAJIS63D-yIU4X0e8.js → stateDiagram-RAJIS63D-rdMNHAXE.js} +1 -1
  45. package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-ti7j33kD.js +1 -0
  46. package/dashboard/dist/assets/{timeline-definition-YZTLITO2-DnfvRVEJ.js → timeline-definition-YZTLITO2-fVRyntnZ.js} +1 -1
  47. package/dashboard/dist/assets/{treemap-KZPCXAKY-p5sbmBwK.js → treemap-KZPCXAKY-ECgEamZF.js} +1 -1
  48. package/dashboard/dist/assets/{vennDiagram-LZ73GAT5-Do2Vp3nv.js → vennDiagram-LZ73GAT5-DkL5XCcJ.js} +1 -1
  49. package/dashboard/dist/assets/{xychartDiagram-JWTSCODW-BrfAGQWt.js → xychartDiagram-JWTSCODW-DSQCD2gS.js} +1 -1
  50. package/dashboard/dist/index.html +2 -2
  51. package/dist/dashboard/server.js +328 -123
  52. package/dist/dashboard/server.js.map +1 -1
  53. package/dist/index.js +795 -488
  54. package/dist/index.js.map +1 -1
  55. package/dist/launch/index.js +75 -10
  56. package/dist/launch/index.js.map +1 -1
  57. package/package.json +1 -1
  58. package/dashboard/dist/assets/channel-mNClnLVi.js +0 -1
  59. package/dashboard/dist/assets/classDiagram-VBA2DB6C-Dv6vdcHm.js +0 -1
  60. package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-Dv6vdcHm.js +0 -1
  61. package/dashboard/dist/assets/clone-CRLXHkrd.js +0 -1
  62. package/dashboard/dist/assets/index-BoVXMp5e.js +0 -535
  63. package/dashboard/dist/assets/index-XappA8I7.css +0 -1
  64. package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-DMBx3hAg.js +0 -1
package/dist/index.js CHANGED
@@ -311,6 +311,9 @@ function parseAssignmentFull(fileContent) {
311
311
  },
312
312
  externalIds: parseExternalIds(fm),
313
313
  tags: parseListField(fm, "tags"),
314
+ archived: getField(fm, "archived") === "true",
315
+ archivedAt: getField(fm, "archivedAt"),
316
+ archivedReason: getField(fm, "archivedReason"),
314
317
  created: getField(fm, "created") ?? "",
315
318
  updated: getField(fm, "updated") ?? "",
316
319
  body
@@ -506,6 +509,53 @@ async function migrateLegacyProjectFiles(projectsDir2) {
506
509
  }
507
510
  return result;
508
511
  }
512
+ function setFrontmatterField(content, key, value) {
513
+ const formatted = value === null ? "null" : typeof value === "boolean" ? String(value) : value;
514
+ const fieldRegex = new RegExp(`^(${key}:)\\s*.*$`, "m");
515
+ if (fieldRegex.test(content)) {
516
+ return content.replace(fieldRegex, `$1 ${formatted}`);
517
+ }
518
+ const closingIdx = content.indexOf("\n---", 4);
519
+ if (closingIdx === -1) return content;
520
+ return `${content.slice(0, closingIdx)}
521
+ ${key}: ${formatted}${content.slice(closingIdx)}`;
522
+ }
523
+ function readFrontmatterField(content, key) {
524
+ const match = content.match(new RegExp(`^${key}:\\s*(.*)$`, "m"));
525
+ if (!match) return null;
526
+ const raw = match[1].trim().replace(/^['"]|['"]$/g, "");
527
+ return raw === "" || raw === "null" ? null : raw;
528
+ }
529
+ async function migrateLegacyArchivedProjects(projectsDir2) {
530
+ const result = { reconciled: [] };
531
+ if (!await fileExists(projectsDir2)) return result;
532
+ let entries;
533
+ try {
534
+ entries = await readdir(projectsDir2, { withFileTypes: true });
535
+ } catch {
536
+ return result;
537
+ }
538
+ for (const entry of entries) {
539
+ if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
540
+ const projectMd = resolve2(projectsDir2, entry.name, "project.md");
541
+ try {
542
+ if (!await fileExists(projectMd)) continue;
543
+ const content = await readFile(projectMd, "utf-8");
544
+ if (readFrontmatterField(content, "statusOverride") !== "archived") continue;
545
+ let next = setFrontmatterField(content, "archived", true);
546
+ if (readFrontmatterField(content, "archivedAt") === null) {
547
+ next = setFrontmatterField(next, "archivedAt", nowTimestamp());
548
+ }
549
+ next = setFrontmatterField(next, "statusOverride", null);
550
+ next = setFrontmatterField(next, "updated", nowTimestamp());
551
+ await writeFile2(projectMd, next, "utf-8");
552
+ result.reconciled.push(entry.name);
553
+ } catch {
554
+ continue;
555
+ }
556
+ }
557
+ return result;
558
+ }
509
559
  async function migrateLegacyConfig(configPath) {
510
560
  const result = {
511
561
  renamedField: false,
@@ -599,6 +649,7 @@ var init_fs_migration = __esm({
599
649
  "src/utils/fs-migration.ts"() {
600
650
  "use strict";
601
651
  init_fs();
652
+ init_timestamp();
602
653
  }
603
654
  });
604
655
 
@@ -2047,7 +2098,7 @@ import { readdir as readdir2, readFile as readFile3, unlink } from "fs/promises"
2047
2098
  function escapeRegExp(value) {
2048
2099
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2049
2100
  }
2050
- function setFrontmatterField(content, key, value) {
2101
+ function setFrontmatterField2(content, key, value) {
2051
2102
  const regex = new RegExp(`^(${escapeRegExp(key)}:)\\s*.*$`, "m");
2052
2103
  if (regex.test(content)) {
2053
2104
  return content.replace(regex, `$1 ${value}`);
@@ -2196,8 +2247,8 @@ async function renamePlaybook(playbooksDir3, oldSlug, newSlug) {
2196
2247
  }
2197
2248
  }
2198
2249
  const raw = await readFile3(oldPath, "utf-8");
2199
- let next = setFrontmatterField(raw, "slug", newSlug);
2200
- next = setFrontmatterField(next, "updated", `"${nowTimestamp()}"`);
2250
+ let next = setFrontmatterField2(raw, "slug", newSlug);
2251
+ next = setFrontmatterField2(next, "updated", `"${nowTimestamp()}"`);
2201
2252
  await writeFileForce(newPath, next);
2202
2253
  if (!renamedInPlace) {
2203
2254
  await unlink(oldPath);
@@ -2375,6 +2426,9 @@ workspace:
2375
2426
  branch: null
2376
2427
  parentBranch: null
2377
2428
  tags: []
2429
+ archived: false
2430
+ archivedAt: null
2431
+ archivedReason: null
2378
2432
  ---
2379
2433
 
2380
2434
  # ${params2.title}
@@ -3568,10 +3622,14 @@ function parseAssignmentFrontmatter(fileContent) {
3568
3622
  links: parseLinks(frontmatter),
3569
3623
  blockedReason: getField2("blockedReason"),
3570
3624
  workspace: parseWorkspace(frontmatter),
3571
- tags: parseTags(frontmatter)
3625
+ tags: parseTags(frontmatter),
3626
+ archived: getField2("archived") === "true",
3627
+ archivedAt: getField2("archivedAt"),
3628
+ archivedReason: getField2("archivedReason")
3572
3629
  };
3573
3630
  }
3574
3631
  function formatYamlValue(value) {
3632
+ if (typeof value === "boolean") return value ? "true" : "false";
3575
3633
  if (value === null) return "null";
3576
3634
  if (/^\d{4}-\d{2}-\d{2}T/.test(value)) {
3577
3635
  return `"${value}"`;
@@ -3590,6 +3648,12 @@ function updateAssignmentFile(fileContent, updates) {
3590
3648
  const fieldRegex = new RegExp(`^(${key}:)\\s*.*$`, "m");
3591
3649
  if (fieldRegex.test(result)) {
3592
3650
  result = result.replace(fieldRegex, `$1 ${formatted}`);
3651
+ } else {
3652
+ const closeIdx = result.indexOf("\n---", 4);
3653
+ if (closeIdx !== -1) {
3654
+ result = `${result.slice(0, closeIdx)}
3655
+ ${key}: ${formatted}${result.slice(closeIdx)}`;
3656
+ }
3593
3657
  }
3594
3658
  }
3595
3659
  return result;
@@ -5042,8 +5106,8 @@ async function migrateFromMarkdown(projectsDir2) {
5042
5106
  return allSessions.length;
5043
5107
  }
5044
5108
  async function parseMarkdownSessionsIndex(filePath, projectSlug) {
5045
- const { readFile: readFile53 } = await import("fs/promises");
5046
- const raw = await readFile53(filePath, "utf-8");
5109
+ const { readFile: readFile54 } = await import("fs/promises");
5110
+ const raw = await readFile54(filePath, "utf-8");
5047
5111
  const sessions = [];
5048
5112
  const lines = raw.split("\n");
5049
5113
  let inTable = false;
@@ -5475,8 +5539,8 @@ function scanKey(serversDir2, projectsDir2, assignmentsDir2) {
5475
5539
  return `${serversDir2}\0${projectsDir2}\0${assignmentsDir2 ?? ""}`;
5476
5540
  }
5477
5541
  function delay(ms) {
5478
- return new Promise((resolve78) => {
5479
- const timer2 = setTimeout(resolve78, ms);
5542
+ return new Promise((resolve79) => {
5543
+ const timer2 = setTimeout(resolve79, ms);
5480
5544
  if (typeof timer2.unref === "function") {
5481
5545
  timer2.unref();
5482
5546
  }
@@ -5935,6 +5999,12 @@ function setUpdatedField(content, value) {
5935
5999
  function escapeRegExp2(value) {
5936
6000
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5937
6001
  }
6002
+ function isProjectArchived(p) {
6003
+ return p.archived === true;
6004
+ }
6005
+ function activeAssignments(items) {
6006
+ return items.filter((item) => item.archived !== true);
6007
+ }
5938
6008
  function createTraces() {
5939
6009
  return { entries: [], subPhases: /* @__PURE__ */ new Map() };
5940
6010
  }
@@ -6072,7 +6142,7 @@ function clearStatusConfigCache() {
6072
6142
  }
6073
6143
  async function listProjects(projectsDir2) {
6074
6144
  const projectRecords = await listProjectRecords(projectsDir2);
6075
- return projectRecords.map((record) => record.summary);
6145
+ return projectRecords.filter((record) => !isProjectArchived(record.summary)).map((record) => record.summary);
6076
6146
  }
6077
6147
  async function readWorkspaceRegistry(projectsDir2) {
6078
6148
  const registryPath = resolve16(dirname3(projectsDir2), "workspaces.json");
@@ -6204,7 +6274,9 @@ async function getOverview(projectsDir2, serversDir2, assignmentsDir2, options =
6204
6274
  "list-standalone-records",
6205
6275
  () => listStandaloneRecords(assignmentsDir2)
6206
6276
  );
6207
- const recentActivity = buildRecentActivity(projectRecords, standaloneRecords);
6277
+ const activeProjectRecords = projectRecords.filter((record) => !isProjectArchived(record.summary));
6278
+ const activeStandaloneRecords = standaloneRecords.filter((sr) => sr.record.archived !== true);
6279
+ const recentActivity = buildRecentActivity(activeProjectRecords, activeStandaloneRecords);
6208
6280
  const staleLimit = clamp(
6209
6281
  Number.isFinite(options.staleLimit) ? Number(options.staleLimit) : STALE_LIMIT_DEFAULT,
6210
6282
  1,
@@ -6263,56 +6335,111 @@ async function getOverview(projectsDir2, serversDir2, assignmentsDir2, options =
6263
6335
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
6264
6336
  firstRun: projectRecords.length === 0 && standaloneRecords.length === 0,
6265
6337
  stats: {
6266
- activeProjects: projectRecords.filter((record) => record.summary.status === "active").length,
6267
- inProgressAssignments: projectRecords.reduce(
6338
+ activeProjects: activeProjectRecords.filter((record) => record.summary.status === "active").length,
6339
+ inProgressAssignments: activeProjectRecords.reduce(
6268
6340
  (total, record) => total + (record.summary.progress["in_progress"] ?? 0),
6269
6341
  0
6270
6342
  ),
6271
- blockedAssignments: projectRecords.reduce(
6343
+ blockedAssignments: activeProjectRecords.reduce(
6272
6344
  (total, record) => total + (record.summary.progress["blocked"] ?? 0),
6273
6345
  0
6274
6346
  ),
6275
- reviewAssignments: projectRecords.reduce(
6347
+ reviewAssignments: activeProjectRecords.reduce(
6276
6348
  (total, record) => total + (record.summary.progress["review"] ?? 0),
6277
6349
  0
6278
6350
  ),
6279
- failedAssignments: projectRecords.reduce(
6351
+ failedAssignments: activeProjectRecords.reduce(
6280
6352
  (total, record) => total + (record.summary.progress["failed"] ?? 0),
6281
6353
  0
6282
6354
  ),
6283
- staleAssignments: projectRecords.reduce(
6284
- (total, record) => total + record.assignments.filter((assignment) => isStale(assignment.updated)).length,
6355
+ staleAssignments: activeProjectRecords.reduce(
6356
+ (total, record) => total + activeAssignments(record.assignments).filter((assignment) => isStale(assignment.updated)).length,
6285
6357
  0
6286
- ) + standaloneRecords.filter((sr) => isStale(sr.record.updated)).length
6358
+ ) + activeStandaloneRecords.filter((sr) => isStale(sr.record.updated)).length
6287
6359
  },
6288
6360
  hero,
6289
6361
  segments,
6290
6362
  recentSessions,
6291
- recentProjects: projectRecords.map((record) => record.summary).sort((left, right) => compareTimestamps(right.updated, left.updated)).slice(0, RECENT_PROJECTS_LIMIT),
6363
+ recentProjects: activeProjectRecords.map((record) => record.summary).sort((left, right) => compareTimestamps(right.updated, left.updated)).slice(0, RECENT_PROJECTS_LIMIT),
6292
6364
  recentActivity: recentActivity.slice(0, RECENT_ACTIVITY_LIMIT),
6293
6365
  serverStats
6294
6366
  };
6295
6367
  }
6296
- async function listAssignmentsBoard(projectsDir2, assignmentsDir2) {
6368
+ async function listAssignmentsBoard(projectsDir2, assignmentsDir2, options = {}) {
6369
+ const mode = options.archived ?? "exclude";
6297
6370
  const projectRecords = await listProjectRecords(projectsDir2);
6298
6371
  const projectItems = await Promise.all(
6299
- projectRecords.flatMap(
6300
- async (record) => Promise.all(
6301
- record.assignments.map(
6372
+ projectRecords.flatMap(async (record) => {
6373
+ if (mode === "only") {
6374
+ return Promise.all(
6375
+ record.assignments.filter((assignment) => assignment.archived === true).map(async (assignment) => toAssignmentBoardItem(projectsDir2, record, assignment))
6376
+ );
6377
+ }
6378
+ if (isProjectArchived(record.summary)) return [];
6379
+ return Promise.all(
6380
+ activeAssignments(record.assignments).map(
6302
6381
  async (assignment) => toAssignmentBoardItem(projectsDir2, record, assignment)
6303
6382
  )
6304
- )
6305
- )
6383
+ );
6384
+ })
6306
6385
  );
6307
6386
  const standaloneRecords = await listStandaloneRecords(assignmentsDir2);
6387
+ const filteredStandalone = mode === "only" ? standaloneRecords.filter((sr) => sr.record.archived === true) : standaloneRecords.filter((sr) => sr.record.archived !== true);
6308
6388
  const standaloneItems = await Promise.all(
6309
- standaloneRecords.map(async (sr) => toStandaloneBoardItem(sr))
6389
+ filteredStandalone.map(async (sr) => toStandaloneBoardItem(sr))
6310
6390
  );
6311
6391
  return {
6312
6392
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
6313
6393
  assignments: [...projectItems.flat(), ...standaloneItems].sort((left, right) => compareTimestamps(right.updated, left.updated))
6314
6394
  };
6315
6395
  }
6396
+ function toArchivedAssignmentItem(assignment, projectSlug, projectTitle) {
6397
+ return {
6398
+ id: assignment.id,
6399
+ slug: assignment.slug,
6400
+ title: assignment.title,
6401
+ status: assignment.status,
6402
+ type: assignment.type,
6403
+ priority: assignment.priority,
6404
+ projectSlug,
6405
+ projectTitle,
6406
+ archived: assignment.archived,
6407
+ archivedAt: assignment.archivedAt,
6408
+ archivedReason: assignment.archivedReason,
6409
+ updated: assignment.updated
6410
+ };
6411
+ }
6412
+ async function listArchived(projectsDir2, assignmentsDir2) {
6413
+ const projectRecords = await listProjectRecords(projectsDir2);
6414
+ const standaloneRecords = await listStandaloneRecords(assignmentsDir2);
6415
+ const projects = projectRecords.filter((record) => isProjectArchived(record.summary)).map((record) => ({
6416
+ slug: record.summary.slug,
6417
+ title: record.summary.title,
6418
+ archivedAt: record.summary.archivedAt,
6419
+ archivedReason: record.summary.archivedReason,
6420
+ assignments: record.assignments.map(
6421
+ (assignment) => toArchivedAssignmentItem(assignment, record.summary.slug, record.summary.title)
6422
+ ).sort((left, right) => compareTimestamps(right.updated, left.updated))
6423
+ })).sort((left, right) => compareTimestamps(right.archivedAt ?? "", left.archivedAt ?? ""));
6424
+ const individuallyArchived = [];
6425
+ for (const record of projectRecords) {
6426
+ if (isProjectArchived(record.summary)) continue;
6427
+ for (const assignment of record.assignments) {
6428
+ if (assignment.archived === true) {
6429
+ individuallyArchived.push(
6430
+ toArchivedAssignmentItem(assignment, record.summary.slug, record.summary.title)
6431
+ );
6432
+ }
6433
+ }
6434
+ }
6435
+ for (const sr of standaloneRecords) {
6436
+ if (sr.record.archived === true) {
6437
+ individuallyArchived.push(toArchivedAssignmentItem(sr.record, null, null));
6438
+ }
6439
+ }
6440
+ individuallyArchived.sort((left, right) => compareTimestamps(right.updated, left.updated));
6441
+ return { projects, assignments: individuallyArchived };
6442
+ }
6316
6443
  async function toStandaloneBoardItem(sr) {
6317
6444
  return {
6318
6445
  ...toAssignmentSummary(sr.record),
@@ -6407,7 +6534,7 @@ async function getProjectDetail(projectsDir2, slug) {
6407
6534
  const dependencyGraph = await loadDependencyGraph(projectPath, assignments);
6408
6535
  const resources = await listResources(projectPath);
6409
6536
  const memories = await listMemories(projectPath);
6410
- const updated = getProjectActivityTimestamp(project.updated, assignments);
6537
+ const updated = getProjectActivityTimestamp(project.updated, activeAssignments(assignments));
6411
6538
  return {
6412
6539
  slug: project.slug || slug,
6413
6540
  title: project.title,
@@ -6528,6 +6655,9 @@ async function getAssignmentDetail(projectsDir2, projectSlug, assignmentSlug) {
6528
6655
  projectWorkspace,
6529
6656
  externalIds: assignment.externalIds,
6530
6657
  tags: assignment.tags,
6658
+ archived: assignment.archived,
6659
+ archivedAt: assignment.archivedAt,
6660
+ archivedReason: assignment.archivedReason,
6531
6661
  created: assignment.created,
6532
6662
  updated: assignment.updated,
6533
6663
  body: assignment.body,
@@ -6778,6 +6908,9 @@ async function buildStandaloneAssignmentDetail(resolved) {
6778
6908
  projectWorkspace: assignment.workspaceGroup,
6779
6909
  externalIds: assignment.externalIds,
6780
6910
  tags: assignment.tags,
6911
+ archived: assignment.archived,
6912
+ archivedAt: assignment.archivedAt,
6913
+ archivedReason: assignment.archivedReason,
6781
6914
  created: assignment.created,
6782
6915
  updated: assignment.updated,
6783
6916
  body: assignment.body,
@@ -6807,6 +6940,7 @@ async function computeProjectRecords(projectsDir2, traces) {
6807
6940
  if (!migratedProjectsDirs.has(projectsDir2)) {
6808
6941
  migratedProjectsDirs.add(projectsDir2);
6809
6942
  await migrateLegacyProjectFiles(projectsDir2);
6943
+ await migrateLegacyArchivedProjects(projectsDir2);
6810
6944
  }
6811
6945
  const entries = await readdir8(projectsDir2, { withFileTypes: true });
6812
6946
  const projectDirs = entries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
@@ -6827,7 +6961,7 @@ async function computeProjectRecords(projectsDir2, traces) {
6827
6961
  const t2 = traces ? performance.now() : 0;
6828
6962
  const rollup = await buildProjectRollup(projectPath, project, assignments, traces);
6829
6963
  if (traces) accumulatePhase(traces, "build-rollup", performance.now() - t2);
6830
- const updated = getProjectActivityTimestamp(project.updated, assignments);
6964
+ const updated = getProjectActivityTimestamp(project.updated, activeAssignments(assignments));
6831
6965
  const t3 = traces ? performance.now() : 0;
6832
6966
  const dependencyGraph = await loadDependencyGraph(projectPath, assignments);
6833
6967
  if (traces) accumulatePhase(traces, "load-dep-graph", performance.now() - t3);
@@ -7037,9 +7171,10 @@ async function loadDependencyGraph(projectPath, assignments) {
7037
7171
  return buildDependencyGraph(assignments);
7038
7172
  }
7039
7173
  async function buildProjectRollup(projectPath, project, assignments, traces) {
7040
- const progress = { total: assignments.length };
7174
+ const active = activeAssignments(assignments);
7175
+ const progress = { total: active.length };
7041
7176
  const perAssignment = await Promise.all(
7042
- assignments.map(async (assignment) => {
7177
+ active.map(async (assignment) => {
7043
7178
  const t0 = traces ? performance.now() : 0;
7044
7179
  const openQuestions2 = await countOpenQuestions(projectPath, assignment.slug);
7045
7180
  if (traces) accumulatePhase(traces, "count-open-questions", performance.now() - t0);
@@ -7087,7 +7222,12 @@ function toAssignmentSummary(assignment) {
7087
7222
  assignee: assignment.assignee,
7088
7223
  dependsOn: assignment.dependsOn,
7089
7224
  links: assignment.links,
7090
- updated: assignment.updated
7225
+ tags: assignment.tags,
7226
+ created: assignment.created,
7227
+ updated: assignment.updated,
7228
+ archived: assignment.archived,
7229
+ archivedAt: assignment.archivedAt,
7230
+ archivedReason: assignment.archivedReason
7091
7231
  };
7092
7232
  }
7093
7233
  async function toAssignmentBoardItem(projectsDir2, projectRecord, assignment) {
@@ -7225,12 +7365,14 @@ async function buildOverviewSegmentBuckets(projectsDir2, projectRecords, standal
7225
7365
  const buckets = emptyBuckets();
7226
7366
  const newestPool = [];
7227
7367
  for (const record of projectRecords) {
7368
+ if (isProjectArchived(record.summary)) continue;
7228
7369
  const depMap = /* @__PURE__ */ new Map();
7229
7370
  for (const a of record.assignments) {
7230
7371
  depMap.set(a.slug, a.status);
7231
7372
  }
7373
+ const visibleAssignments = activeAssignments(record.assignments);
7232
7374
  const resolvedTransitions = await Promise.all(
7233
- record.assignments.map(async (assignment) => {
7375
+ visibleAssignments.map(async (assignment) => {
7234
7376
  const t0 = traces ? performance.now() : 0;
7235
7377
  const availableTransitions = await getAvailableTransitions(
7236
7378
  projectsDir2,
@@ -7299,7 +7441,7 @@ async function buildOverviewSegmentBuckets(projectsDir2, projectRecords, standal
7299
7441
  }
7300
7442
  }
7301
7443
  const resolvedStandaloneTransitions = await Promise.all(
7302
- standaloneRecords.map(async (sr) => {
7444
+ standaloneRecords.filter((sr) => sr.record.archived !== true).map(async (sr) => {
7303
7445
  const t0 = traces ? performance.now() : 0;
7304
7446
  const availableTransitions = await getStandaloneAvailableTransitions(sr.record);
7305
7447
  if (traces) accumulatePhase(traces, "get-available-transitions", performance.now() - t0);
@@ -7425,7 +7567,7 @@ function buildRecentActivity(projectRecords, standaloneRecords = []) {
7425
7567
  assignmentSlug: null,
7426
7568
  summary: `Project status is ${record.summary.status}.`
7427
7569
  });
7428
- for (const assignment of record.assignments) {
7570
+ for (const assignment of activeAssignments(record.assignments)) {
7429
7571
  activity.push({
7430
7572
  id: `assignment:${record.summary.slug}:${assignment.slug}`,
7431
7573
  type: "assignment",
@@ -8128,8 +8270,8 @@ __export(launch_exports, {
8128
8270
  shellQuote: () => shellQuote
8129
8271
  });
8130
8272
  import { spawn as spawn3 } from "child_process";
8131
- import { mkdir as mkdir6, writeFile as writeFile10 } from "fs/promises";
8132
- import { isAbsolute as isAbsolute5, resolve as resolve43 } from "path";
8273
+ import { mkdir as mkdir6, writeFile as writeFile11 } from "fs/promises";
8274
+ import { isAbsolute as isAbsolute5, resolve as resolve44 } from "path";
8133
8275
  function shellQuote(arg) {
8134
8276
  if (arg === "") return "''";
8135
8277
  return `'${arg.replace(/'/g, `'\\''`)}'`;
@@ -8165,8 +8307,8 @@ async function launchAgent(options) {
8165
8307
  console.error(`Assignment not found: ${projectSlug}/${assignmentSlug}`);
8166
8308
  process.exit(1);
8167
8309
  }
8168
- const projectDir = resolve43(projectsDir2, projectSlug);
8169
- const assignmentDir = resolve43(projectDir, "assignments", assignmentSlug);
8310
+ const projectDir = resolve44(projectsDir2, projectSlug);
8311
+ const assignmentDir = resolve44(projectDir, "assignments", assignmentSlug);
8170
8312
  let workspaceDir;
8171
8313
  if (cwdOverride) {
8172
8314
  if (!isExistingDir(cwdOverride)) {
@@ -8198,7 +8340,7 @@ async function launchAgent(options) {
8198
8340
  });
8199
8341
  if (warning) console.warn(warning);
8200
8342
  }
8201
- const contextDir = resolve43(workspaceDir, ".syntaur");
8343
+ const contextDir = resolve44(workspaceDir, ".syntaur");
8202
8344
  await mkdir6(contextDir, { recursive: true });
8203
8345
  const context = {
8204
8346
  projectSlug,
@@ -8210,8 +8352,8 @@ async function launchAgent(options) {
8210
8352
  branch: detail.workspace.branch ?? null,
8211
8353
  grabbedAt: (/* @__PURE__ */ new Date()).toISOString()
8212
8354
  };
8213
- await writeFile10(
8214
- resolve43(contextDir, "context.json"),
8355
+ await writeFile11(
8356
+ resolve44(contextDir, "context.json"),
8215
8357
  JSON.stringify(context, null, 2) + "\n"
8216
8358
  );
8217
8359
  const { argv, shellFallbackWarning } = buildAgentArgv(
@@ -8286,7 +8428,7 @@ import {
8286
8428
  unlinkSync
8287
8429
  } from "fs";
8288
8430
  import { fileURLToPath as fileURLToPath6, pathToFileURL } from "url";
8289
- import { dirname as dirname14, resolve as resolve45, join as join6 } from "path";
8431
+ import { dirname as dirname14, resolve as resolve46, join as join6 } from "path";
8290
8432
  import { homedir as homedir7, tmpdir as tmpdir2 } from "os";
8291
8433
  import { spawnSync as spawnSync6 } from "child_process";
8292
8434
  function syntaurRootMjs() {
@@ -8308,7 +8450,7 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
8308
8450
  }
8309
8451
  const stateRoot = syntaurRootMjs();
8310
8452
  mkdirSync2(stateRoot, { recursive: true });
8311
- const lockPath = resolve45(stateRoot, "install-url-handler.lock");
8453
+ const lockPath = resolve46(stateRoot, "install-url-handler.lock");
8312
8454
  let lockFd;
8313
8455
  try {
8314
8456
  lockFd = openSync(lockPath, "wx");
@@ -8324,8 +8466,8 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
8324
8466
  throw err2;
8325
8467
  }
8326
8468
  try {
8327
- const pkgRoot = resolve45(dirname14(fileURLToPath6(import.meta.url)), "..");
8328
- const cliBin = realpathSync2(resolve45(pkgRoot, "bin/syntaur.js"));
8469
+ const pkgRoot = resolve46(dirname14(fileURLToPath6(import.meta.url)), "..");
8470
+ const cliBin = realpathSync2(resolve46(pkgRoot, "bin/syntaur.js"));
8329
8471
  const nodeBin = process.execPath;
8330
8472
  const bundleParent = join6(
8331
8473
  homedir7(),
@@ -8675,7 +8817,7 @@ function useProjects(projectsDir2) {
8675
8817
  if (cancelled) return;
8676
8818
  const tree = projects.map((m, i) => {
8677
8819
  const detail = details[i];
8678
- const children = (detail?.assignments ?? []).map((a) => ({
8820
+ const children = (detail?.assignments ?? []).filter((a) => !a.archived).map((a) => ({
8679
8821
  id: `a:${m.slug}:${a.slug}`,
8680
8822
  kind: "assignment",
8681
8823
  label: a.title,
@@ -9653,6 +9795,7 @@ var SORT_FIELDS = [
9653
9795
  "priority",
9654
9796
  "assignee",
9655
9797
  "dependencies",
9798
+ "created",
9656
9799
  "updated"
9657
9800
  ];
9658
9801
  var SORT_DIRECTIONS = ["asc", "desc"];
@@ -9666,6 +9809,37 @@ var GROUPINGS = [
9666
9809
  "project"
9667
9810
  ];
9668
9811
  var ACTIVITIES = ["all", "stale", "fresh"];
9812
+ var DATE_RANGE_FIELDS = ["created", "updated"];
9813
+ var DATE_RANGE_PRESETS = [
9814
+ "last_24h",
9815
+ "last_7d",
9816
+ "last_30d",
9817
+ "last_90d",
9818
+ "older_7d",
9819
+ "older_30d"
9820
+ ];
9821
+ var YMD_RE = /^\d{4}-\d{2}-\d{2}$/;
9822
+ function isDateRangeField(v) {
9823
+ return typeof v === "string" && DATE_RANGE_FIELDS.includes(v);
9824
+ }
9825
+ function isDateRangePreset(v) {
9826
+ return typeof v === "string" && DATE_RANGE_PRESETS.includes(v);
9827
+ }
9828
+ function isDateRange(v) {
9829
+ if (!v || typeof v !== "object" || Array.isArray(v)) return false;
9830
+ const r = v;
9831
+ if (!isDateRangeField(r.field)) return false;
9832
+ for (const key of Object.keys(r)) {
9833
+ if (key !== "field" && key !== "preset" && key !== "from" && key !== "to") return false;
9834
+ }
9835
+ const hasPreset = r.preset !== void 0;
9836
+ const hasAbsolute = r.from !== void 0 || r.to !== void 0;
9837
+ if (hasPreset && hasAbsolute) return false;
9838
+ if (hasPreset && !isDateRangePreset(r.preset)) return false;
9839
+ if (r.from !== void 0 && (typeof r.from !== "string" || !YMD_RE.test(r.from))) return false;
9840
+ if (r.to !== void 0 && (typeof r.to !== "string" || !YMD_RE.test(r.to))) return false;
9841
+ return true;
9842
+ }
9669
9843
  function toFilterValues(v) {
9670
9844
  const arr = v === void 0 ? [] : Array.isArray(v) ? v : [v];
9671
9845
  const out = [];
@@ -9841,7 +10015,7 @@ function isViewPrefsDefaults(file) {
9841
10015
  if (g.density !== d.density) return false;
9842
10016
  if (g.grouping !== d.grouping) return false;
9843
10017
  const gf = g.filters;
9844
- for (const key of ["status", "type", "priority", "assignee", "project"]) {
10018
+ for (const key of ["status", "type", "priority", "assignee", "project", "tags"]) {
9845
10019
  if (toFilterValues(gf[key]).length > 0) return false;
9846
10020
  }
9847
10021
  if (gf.activity !== void 0 && gf.activity !== "all") return false;
@@ -9858,6 +10032,7 @@ var TABLE_COLUMN_IDS = [
9858
10032
  "priority",
9859
10033
  "assignee",
9860
10034
  "dependencies",
10035
+ "created",
9861
10036
  "updated"
9862
10037
  ];
9863
10038
  function isTableColumnId(value) {
@@ -9933,10 +10108,12 @@ function isTableColumnVisibility(value) {
9933
10108
  function isViewFilters(value) {
9934
10109
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
9935
10110
  const obj = value;
9936
- for (const key of ["status", "type", "priority", "assignee", "project"]) {
10111
+ for (const key of ["status", "type", "priority", "assignee", "project", "tags"]) {
9937
10112
  if (obj[key] !== void 0 && !isFilterValue(obj[key])) return false;
9938
10113
  }
9939
10114
  if (obj.activity !== void 0 && !isActivity(obj.activity)) return false;
10115
+ if (obj.dateRange !== void 0 && !isDateRange(obj.dateRange)) return false;
10116
+ if (obj.search !== void 0 && typeof obj.search !== "string") return false;
9940
10117
  return true;
9941
10118
  }
9942
10119
  function isSavedViewConfig(value) {
@@ -10614,6 +10791,13 @@ ${key}: ${formatted}${content.slice(closingIdx)}`;
10614
10791
  function escapeRegExp3(value) {
10615
10792
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
10616
10793
  }
10794
+ function applyArchiveFields(content, archived, reason) {
10795
+ let next = setTopLevelField(content, "archived", archived);
10796
+ next = setTopLevelField(next, "archivedAt", archived ? nowTimestamp() : null);
10797
+ next = setTopLevelField(next, "archivedReason", archived ? reason : null);
10798
+ next = setTopLevelField(next, "updated", nowTimestamp());
10799
+ return next;
10800
+ }
10617
10801
  function appendLogEntry2(existingContent, countField, nextCount, heading, body, emptyPlaceholder) {
10618
10802
  const timestamp = nowTimestamp();
10619
10803
  let next = setTopLevelField(existingContent, "updated", timestamp);
@@ -11907,7 +12091,7 @@ ${entry}`;
11907
12091
  }
11908
12092
  const { status } = req.body || {};
11909
12093
  const config = await getStatusConfig();
11910
- const validStatuses = ["active", "archived", ...config.statuses.map((s) => s.id)];
12094
+ const validStatuses = ["active", ...config.statuses.map((s) => s.id)];
11911
12095
  if (status !== null && (typeof status !== "string" || !validStatuses.includes(status))) {
11912
12096
  res.status(400).json({ error: `Invalid status. Must be one of: ${validStatuses.join(", ")}, or null to clear.` });
11913
12097
  return;
@@ -11959,6 +12143,106 @@ ${entry}`;
11959
12143
  res.status(500).json({ error: `Failed to override status: ${error.message}` });
11960
12144
  }
11961
12145
  });
12146
+ function archiveReason(body) {
12147
+ const reason = body?.reason;
12148
+ return typeof reason === "string" && reason.trim() ? reason : null;
12149
+ }
12150
+ router.post("/api/projects/:slug/archive", async (req, res) => {
12151
+ try {
12152
+ const projectSlug = getParam(req.params.slug);
12153
+ const projectPath = resolve21(projectsDir2, projectSlug, "project.md");
12154
+ if (!await fileExists(projectPath)) {
12155
+ res.status(404).json({ error: `Project "${projectSlug}" not found` });
12156
+ return;
12157
+ }
12158
+ const content = await readFile15(projectPath, "utf-8");
12159
+ await writeFileForce(projectPath, applyArchiveFields(content, true, archiveReason(req.body)));
12160
+ const project = await getProjectDetail(projectsDir2, projectSlug);
12161
+ res.json({ project });
12162
+ } catch (error) {
12163
+ console.error("Error archiving project:", error);
12164
+ res.status(500).json({ error: `Failed to archive project: ${error.message}` });
12165
+ }
12166
+ });
12167
+ router.post("/api/projects/:slug/unarchive", async (req, res) => {
12168
+ try {
12169
+ const projectSlug = getParam(req.params.slug);
12170
+ const projectPath = resolve21(projectsDir2, projectSlug, "project.md");
12171
+ if (!await fileExists(projectPath)) {
12172
+ res.status(404).json({ error: `Project "${projectSlug}" not found` });
12173
+ return;
12174
+ }
12175
+ const content = await readFile15(projectPath, "utf-8");
12176
+ await writeFileForce(projectPath, applyArchiveFields(content, false, null));
12177
+ const project = await getProjectDetail(projectsDir2, projectSlug);
12178
+ res.json({ project });
12179
+ } catch (error) {
12180
+ console.error("Error restoring project:", error);
12181
+ res.status(500).json({ error: `Failed to restore project: ${error.message}` });
12182
+ }
12183
+ });
12184
+ async function handleAssignmentArchive(req, res, archived) {
12185
+ const projectSlug = getParam(req.params.slug);
12186
+ const assignmentSlug = getParam(req.params.aslug);
12187
+ const assignmentPath = resolve21(projectsDir2, projectSlug, "assignments", assignmentSlug, "assignment.md");
12188
+ if (!await fileExists(assignmentPath)) {
12189
+ res.status(404).json({ error: "Assignment not found" });
12190
+ return;
12191
+ }
12192
+ const content = await readFile15(assignmentPath, "utf-8");
12193
+ await writeFileForce(assignmentPath, applyArchiveFields(content, archived, archived ? archiveReason(req.body) : null));
12194
+ const assignment = await getAssignmentDetail(projectsDir2, projectSlug, assignmentSlug);
12195
+ res.json({ assignment });
12196
+ }
12197
+ router.post("/api/projects/:slug/assignments/:aslug/archive", async (req, res) => {
12198
+ try {
12199
+ await handleAssignmentArchive(req, res, true);
12200
+ } catch (error) {
12201
+ console.error("Error archiving assignment:", error);
12202
+ res.status(500).json({ error: `Failed to archive assignment: ${error.message}` });
12203
+ }
12204
+ });
12205
+ router.post("/api/projects/:slug/assignments/:aslug/unarchive", async (req, res) => {
12206
+ try {
12207
+ await handleAssignmentArchive(req, res, false);
12208
+ } catch (error) {
12209
+ console.error("Error restoring assignment:", error);
12210
+ res.status(500).json({ error: `Failed to restore assignment: ${error.message}` });
12211
+ }
12212
+ });
12213
+ async function handleStandaloneArchive(req, res, archived) {
12214
+ if (!assignmentsDir2) {
12215
+ res.status(501).json({ error: "Standalone assignments not configured on this server" });
12216
+ return;
12217
+ }
12218
+ const id = getParam(req.params.id);
12219
+ const resolved = await resolveAssignmentById(projectsDir2, assignmentsDir2, id);
12220
+ if (!resolved) {
12221
+ res.status(404).json({ error: `Assignment "${id}" not found` });
12222
+ return;
12223
+ }
12224
+ const assignmentPath = resolve21(resolved.assignmentDir, "assignment.md");
12225
+ const content = await readFile15(assignmentPath, "utf-8");
12226
+ await writeFileForce(assignmentPath, applyArchiveFields(content, archived, archived ? archiveReason(req.body) : null));
12227
+ const assignment = await getAssignmentDetailById(projectsDir2, assignmentsDir2, id);
12228
+ res.json({ assignment });
12229
+ }
12230
+ router.post("/api/assignments/:id/archive", async (req, res) => {
12231
+ try {
12232
+ await handleStandaloneArchive(req, res, true);
12233
+ } catch (error) {
12234
+ console.error("Error archiving assignment:", error);
12235
+ res.status(500).json({ error: `Failed to archive assignment: ${error.message}` });
12236
+ }
12237
+ });
12238
+ router.post("/api/assignments/:id/unarchive", async (req, res) => {
12239
+ try {
12240
+ await handleStandaloneArchive(req, res, false);
12241
+ } catch (error) {
12242
+ console.error("Error restoring assignment:", error);
12243
+ res.status(500).json({ error: `Failed to restore assignment: ${error.message}` });
12244
+ }
12245
+ });
11962
12246
  router.patch("/api/projects/:slug/assignments/:aslug/assignee", async (req, res) => {
11963
12247
  try {
11964
12248
  const projectSlug = getParam(req.params.slug);
@@ -12608,84 +12892,6 @@ ${entry}`;
12608
12892
  res.status(500).json({ error: `Failed to update title: ${error.message}` });
12609
12893
  }
12610
12894
  });
12611
- router.post("/api/assignments/bulk-status-override", async (req, res) => {
12612
- try {
12613
- const body = req.body;
12614
- if (!body || typeof body !== "object" || !Array.isArray(body.items)) {
12615
- res.status(400).json({ error: "Request body must include `items` (array)." });
12616
- return;
12617
- }
12618
- const items = body.items;
12619
- if (items.length === 0) {
12620
- res.status(400).json({ error: "`items` must contain at least one entry." });
12621
- return;
12622
- }
12623
- if (items.length > 200) {
12624
- res.status(400).json({ error: "`items` is capped at 200 entries per call." });
12625
- return;
12626
- }
12627
- const config = await getStatusConfig();
12628
- const validStatuses = new Set(config.statuses.map((s) => s.id));
12629
- const timestamp = nowTimestamp();
12630
- const results = [];
12631
- let succeeded = 0;
12632
- let failed = 0;
12633
- for (let index = 0; index < items.length; index += 1) {
12634
- const raw = items[index];
12635
- const itemKey = buildBulkItemKey(raw, index);
12636
- try {
12637
- if (!raw || typeof raw !== "object") {
12638
- throw new Error("item must be an object");
12639
- }
12640
- const item = raw;
12641
- const status = typeof item.status === "string" ? item.status : null;
12642
- if (!status || !validStatuses.has(status)) {
12643
- throw new Error(`invalid status "${status ?? ""}"`);
12644
- }
12645
- let assignmentPath = null;
12646
- if (typeof item.id === "string" && item.id.trim()) {
12647
- if (!assignmentsDir2) {
12648
- throw new Error("standalone assignments are not configured on this server");
12649
- }
12650
- const resolved = await resolveAssignmentById(projectsDir2, assignmentsDir2, item.id);
12651
- if (!resolved) {
12652
- throw new Error(`assignment "${item.id}" not found`);
12653
- }
12654
- assignmentPath = resolve21(resolved.assignmentDir, "assignment.md");
12655
- } else if (typeof item.projectSlug === "string" && typeof item.assignmentSlug === "string" && item.projectSlug && item.assignmentSlug) {
12656
- assignmentPath = resolve21(
12657
- projectsDir2,
12658
- item.projectSlug,
12659
- "assignments",
12660
- item.assignmentSlug,
12661
- "assignment.md"
12662
- );
12663
- } else {
12664
- throw new Error("must supply either `id` or both `projectSlug` and `assignmentSlug`");
12665
- }
12666
- if (!await fileExists(assignmentPath)) {
12667
- throw new Error("assignment file not found");
12668
- }
12669
- let content = await readFile15(assignmentPath, "utf-8");
12670
- content = setTopLevelField(content, "status", status);
12671
- content = setTopLevelField(content, "updated", timestamp);
12672
- if (status !== "blocked") {
12673
- content = setTopLevelField(content, "blockedReason", null);
12674
- }
12675
- await writeFileForce(assignmentPath, content);
12676
- results.push({ key: itemKey, ok: true });
12677
- succeeded += 1;
12678
- } catch (error) {
12679
- results.push({ key: itemKey, ok: false, error: error.message });
12680
- failed += 1;
12681
- }
12682
- }
12683
- res.json({ results, succeeded, failed });
12684
- } catch (error) {
12685
- console.error("Error in bulk-status-override:", error);
12686
- res.status(500).json({ error: `Bulk status override failed: ${error.message}` });
12687
- }
12688
- });
12689
12895
  router.patch("/api/assignments/:id/acceptance-criteria/:index", async (req, res) => {
12690
12896
  try {
12691
12897
  if (!assignmentsDir2) {
@@ -12799,16 +13005,6 @@ function validateTitleBody(body) {
12799
13005
  }
12800
13006
  return { ok: true, value: trimmed };
12801
13007
  }
12802
- function buildBulkItemKey(raw, index) {
12803
- if (raw && typeof raw === "object") {
12804
- const item = raw;
12805
- if (typeof item.id === "string" && item.id.trim()) return item.id;
12806
- if (typeof item.projectSlug === "string" && typeof item.assignmentSlug === "string") {
12807
- return `${item.projectSlug}/${item.assignmentSlug}`;
12808
- }
12809
- }
12810
- return `#${index}`;
12811
- }
12812
13008
  async function appendCommentTo(assignmentDir, assignmentRef, req, res, reloadDetail) {
12813
13009
  const commentsPath = resolve21(assignmentDir, "comments.md");
12814
13010
  const { body, author, type, replyTo } = req.body || {};
@@ -15693,8 +15889,8 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
15693
15889
  router.post("/:workspace/archive", async (req, res) => {
15694
15890
  try {
15695
15891
  const { archivePath: archivePath2 } = await Promise.resolve().then(() => (init_parser2(), parser_exports));
15696
- const { resolve: resolve78 } = await import("path");
15697
- const { readFile: readFile53 } = await import("fs/promises");
15892
+ const { resolve: resolve79 } = await import("path");
15893
+ const { readFile: readFile54 } = await import("fs/promises");
15698
15894
  const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
15699
15895
  const workspace = getWorkspaceParam(req.params.workspace);
15700
15896
  const checklist = await readChecklist(todosDir2, workspace);
@@ -15710,10 +15906,10 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
15710
15906
  (e) => e.itemIds.every((id) => completedIds.has(id))
15711
15907
  );
15712
15908
  const archFile = archivePath2(todosDir2, workspace, checklist.archiveInterval);
15713
- await ensureDir(resolve78(todosDir2, "archive"));
15909
+ await ensureDir(resolve79(todosDir2, "archive"));
15714
15910
  let archContent = "";
15715
15911
  if (await fileExists(archFile)) {
15716
- archContent = await readFile53(archFile, "utf-8");
15912
+ archContent = await readFile54(archFile, "utf-8");
15717
15913
  archContent = archContent.trimEnd() + "\n\n";
15718
15914
  } else {
15719
15915
  archContent = `---
@@ -15995,7 +16191,7 @@ workspace: ${workspace}
15995
16191
  const { readConfig: readConfig3 } = await Promise.resolve().then(() => (init_config2(), config_exports));
15996
16192
  const { assignmentsDir: assignmentsDirFn } = await Promise.resolve().then(() => (init_paths(), paths_exports));
15997
16193
  const { fileExists: fileExists2, writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
15998
- const { readFile: readFile53 } = await import("fs/promises");
16194
+ const { readFile: readFile54 } = await import("fs/promises");
15999
16195
  const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
16000
16196
  const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
16001
16197
  let assignmentRef;
@@ -16016,7 +16212,7 @@ workspace: ${workspace}
16016
16212
  }
16017
16213
  const assignmentMdPath2 = resolvePath2(assignmentDir, "assignment.md");
16018
16214
  if (!await fileExists2(assignmentMdPath2)) return { error: `Target assignment not found: ${assignmentMdPath2}` };
16019
- let content = await readFile53(assignmentMdPath2, "utf-8");
16215
+ let content = await readFile54(assignmentMdPath2, "utf-8");
16020
16216
  content = appendTodosToAssignmentBody2(
16021
16217
  content,
16022
16218
  items.map((it) => ({
@@ -18181,7 +18377,7 @@ function createDashboardServer(options) {
18181
18377
  }
18182
18378
  });
18183
18379
  const VIEW_PREFS_LOCK = "vp:global";
18184
- const FILTER_KEYS = /* @__PURE__ */ new Set(["status", "type", "priority", "assignee", "project", "activity"]);
18380
+ const FILTER_KEYS = /* @__PURE__ */ new Set(["status", "type", "priority", "assignee", "project", "tags", "activity"]);
18185
18381
  const GLOBAL_KEYS = /* @__PURE__ */ new Set(["defaultView", "sortField", "sortDirection", "density", "grouping", "filters"]);
18186
18382
  const SCOPE_KEYS = /* @__PURE__ */ new Set(["defaultView", "sortField", "sortDirection", "grouping", "filters"]);
18187
18383
  const ROOT_KEYS = /* @__PURE__ */ new Set(["global", "projects"]);
@@ -18200,7 +18396,7 @@ function createDashboardServer(options) {
18200
18396
  const unknown = unknownKey(obj, FILTER_KEYS, "filters");
18201
18397
  if (unknown) return { ok: false, error: unknown };
18202
18398
  const out = {};
18203
- for (const key of ["status", "type", "priority", "assignee", "project"]) {
18399
+ for (const key of ["status", "type", "priority", "assignee", "project", "tags"]) {
18204
18400
  if (obj[key] !== void 0) {
18205
18401
  if (!isFilterValue(obj[key])) {
18206
18402
  return { ok: false, error: `filters.${key} must be a non-empty string or array of non-empty strings` };
@@ -18425,6 +18621,15 @@ function createDashboardServer(options) {
18425
18621
  res.status(500).json({ error: "Failed to list assignments" });
18426
18622
  }
18427
18623
  });
18624
+ app.get("/api/archived", async (_req, res) => {
18625
+ try {
18626
+ const result = await listArchived(projectsDir2, assignmentsDir2);
18627
+ res.json(result);
18628
+ } catch (error) {
18629
+ console.error("Error listing archived content:", error);
18630
+ res.status(500).json({ error: "Failed to list archived content" });
18631
+ }
18632
+ });
18428
18633
  app.get("/api/projects/:slug", async (req, res) => {
18429
18634
  try {
18430
18635
  const detail = await getProjectDetail(projectsDir2, req.params.slug);
@@ -18852,6 +19057,91 @@ async function startCommand(assignment, options) {
18852
19057
  reportResult(result);
18853
19058
  }
18854
19059
 
19060
+ // src/commands/_archive-helper.ts
19061
+ init_paths();
19062
+ init_fs();
19063
+ init_config2();
19064
+ init_slug();
19065
+ init_frontmatter();
19066
+ init_timestamp();
19067
+ init_assignment_resolver();
19068
+ import { resolve as resolve33 } from "path";
19069
+ import { readFile as readFile21, writeFile as writeFile7 } from "fs/promises";
19070
+ async function resolveTarget(target, options) {
19071
+ const config = await readConfig();
19072
+ const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
19073
+ if (options.project) {
19074
+ if (!isValidSlug(options.project)) {
19075
+ throw new Error(`Invalid project slug "${options.project}".`);
19076
+ }
19077
+ if (!isValidSlug(target)) {
19078
+ throw new Error(`Invalid assignment slug "${target}".`);
19079
+ }
19080
+ const assignmentMd = resolve33(baseDir, options.project, "assignments", target, "assignment.md");
19081
+ if (!await fileExists(assignmentMd)) {
19082
+ throw new Error(`Assignment "${target}" not found in project "${options.project}".`);
19083
+ }
19084
+ return { kind: "assignment", filePath: assignmentMd, label: `assignment "${options.project}/${target}"` };
19085
+ }
19086
+ const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), target);
19087
+ if (resolved) {
19088
+ return {
19089
+ kind: "assignment",
19090
+ filePath: resolve33(resolved.assignmentDir, "assignment.md"),
19091
+ label: resolved.projectSlug ? `assignment "${resolved.projectSlug}/${resolved.assignmentSlug}"` : `assignment "${target}"`
19092
+ };
19093
+ }
19094
+ const projectMd = resolve33(baseDir, target, "project.md");
19095
+ if (await fileExists(projectMd)) {
19096
+ return { kind: "project", filePath: projectMd, label: `project "${target}"` };
19097
+ }
19098
+ return null;
19099
+ }
19100
+ async function writeArchiveState(filePath, archived, reason) {
19101
+ const content = await readFile21(filePath, "utf-8");
19102
+ const updated = updateAssignmentFile(content, {
19103
+ archived,
19104
+ archivedAt: archived ? nowTimestamp() : null,
19105
+ archivedReason: archived ? reason : null,
19106
+ updated: nowTimestamp()
19107
+ });
19108
+ await writeFile7(filePath, updated, "utf-8");
19109
+ }
19110
+ async function runArchive(target, options = {}) {
19111
+ const resolved = await resolveTarget(target, options);
19112
+ if (!resolved) {
19113
+ return { success: false, message: `No assignment or project matched "${target}".` };
19114
+ }
19115
+ await writeArchiveState(resolved.filePath, true, options.reason ?? null);
19116
+ return { success: true, message: `Archived ${resolved.label}.` };
19117
+ }
19118
+ async function runRestore(target, options = {}) {
19119
+ const resolved = await resolveTarget(target, options);
19120
+ if (!resolved) {
19121
+ return { success: false, message: `No assignment or project matched "${target}".` };
19122
+ }
19123
+ await writeArchiveState(resolved.filePath, false, null);
19124
+ return { success: true, message: `Restored ${resolved.label}.` };
19125
+ }
19126
+ function reportArchiveResult(result) {
19127
+ if (!result.success) {
19128
+ throw new Error(result.message);
19129
+ }
19130
+ console.log(result.message);
19131
+ }
19132
+
19133
+ // src/commands/archive.ts
19134
+ async function archiveCommand(target, options) {
19135
+ const result = await runArchive(target, options);
19136
+ reportArchiveResult(result);
19137
+ }
19138
+
19139
+ // src/commands/restore.ts
19140
+ async function restoreCommand(target, options) {
19141
+ const result = await runRestore(target, options);
19142
+ reportArchiveResult(result);
19143
+ }
19144
+
18855
19145
  // src/commands/shape.ts
18856
19146
  async function shapeCommand(assignment, options) {
18857
19147
  const result = await runTransition(assignment, "shape", options);
@@ -18876,8 +19166,8 @@ init_fs();
18876
19166
  init_config2();
18877
19167
  init_frontmatter();
18878
19168
  init_timestamp();
18879
- import { resolve as resolve33 } from "path";
18880
- import { readdir as readdir13, readFile as readFile21 } from "fs/promises";
19169
+ import { resolve as resolve34 } from "path";
19170
+ import { readdir as readdir13, readFile as readFile22 } from "fs/promises";
18881
19171
  var PROMOTABLE_STATUSES = /* @__PURE__ */ new Set(["pending"]);
18882
19172
  function objectiveIsFleshedOut(content) {
18883
19173
  const match = content.match(/##\s+Objective\s*\n([\s\S]*?)(?=\n##\s+|$)/);
@@ -18899,11 +19189,11 @@ async function collectCandidates(baseDirs) {
18899
19189
  for (const m of projects) {
18900
19190
  if (!m.isDirectory()) continue;
18901
19191
  if (m.name.startsWith(".") || m.name.startsWith("_")) continue;
18902
- const directAssignmentMd = resolve33(baseDir, m.name, "assignment.md");
19192
+ const directAssignmentMd = resolve34(baseDir, m.name, "assignment.md");
18903
19193
  if (await fileExists(directAssignmentMd)) {
18904
19194
  const fm = await parseSafe(directAssignmentMd);
18905
19195
  if (fm && PROMOTABLE_STATUSES.has(fm.status)) {
18906
- const content = await readFile21(directAssignmentMd, "utf-8");
19196
+ const content = await readFile22(directAssignmentMd, "utf-8");
18907
19197
  if (objectiveIsFleshedOut(content) && hasAcceptanceCriteria(content)) {
18908
19198
  candidates.push({
18909
19199
  projectSlug: null,
@@ -18916,17 +19206,17 @@ async function collectCandidates(baseDirs) {
18916
19206
  }
18917
19207
  continue;
18918
19208
  }
18919
- const assignmentsDir2 = resolve33(baseDir, m.name, "assignments");
19209
+ const assignmentsDir2 = resolve34(baseDir, m.name, "assignments");
18920
19210
  if (!await fileExists(assignmentsDir2)) continue;
18921
19211
  const entries = await readdir13(assignmentsDir2, { withFileTypes: true });
18922
19212
  for (const a of entries) {
18923
19213
  if (!a.isDirectory()) continue;
18924
19214
  if (a.name.startsWith(".") || a.name.startsWith("_")) continue;
18925
- const assignmentMd = resolve33(assignmentsDir2, a.name, "assignment.md");
19215
+ const assignmentMd = resolve34(assignmentsDir2, a.name, "assignment.md");
18926
19216
  if (!await fileExists(assignmentMd)) continue;
18927
19217
  const fm = await parseSafe(assignmentMd);
18928
19218
  if (!fm || !PROMOTABLE_STATUSES.has(fm.status)) continue;
18929
- const content = await readFile21(assignmentMd, "utf-8");
19219
+ const content = await readFile22(assignmentMd, "utf-8");
18930
19220
  if (!objectiveIsFleshedOut(content)) continue;
18931
19221
  if (!hasAcceptanceCriteria(content)) continue;
18932
19222
  candidates.push({
@@ -18943,7 +19233,7 @@ async function collectCandidates(baseDirs) {
18943
19233
  }
18944
19234
  async function parseSafe(path) {
18945
19235
  try {
18946
- const content = await readFile21(path, "utf-8");
19236
+ const content = await readFile22(path, "utf-8");
18947
19237
  return parseAssignmentFrontmatter(content);
18948
19238
  } catch {
18949
19239
  return null;
@@ -18972,7 +19262,7 @@ async function migrateStatusesCommand(options) {
18972
19262
  const now = nowTimestamp();
18973
19263
  let migrated = 0;
18974
19264
  for (const c2 of candidates) {
18975
- const content = await readFile21(c2.assignmentMd, "utf-8");
19265
+ const content = await readFile22(c2.assignmentMd, "utf-8");
18976
19266
  const updated = updateAssignmentFile(content, {
18977
19267
  status: c2.toStatus,
18978
19268
  updated: now
@@ -19030,29 +19320,29 @@ import {
19030
19320
  readdir as readdir14,
19031
19321
  symlink,
19032
19322
  lstat,
19033
- readFile as readFile22,
19323
+ readFile as readFile23,
19034
19324
  readlink,
19035
19325
  rename as rename8,
19036
19326
  rm as rm4,
19037
19327
  unlink as unlink7,
19038
- writeFile as writeFile7
19328
+ writeFile as writeFile8
19039
19329
  } from "fs/promises";
19040
19330
  import { existsSync as existsSync3 } from "fs";
19041
19331
  import { homedir as homedir3 } from "os";
19042
- import { basename as basename4, dirname as dirname10, isAbsolute as isAbsolute4, relative as relative2, resolve as resolve35 } from "path";
19332
+ import { basename as basename4, dirname as dirname10, isAbsolute as isAbsolute4, relative as relative2, resolve as resolve36 } from "path";
19043
19333
 
19044
19334
  // src/utils/package-root.ts
19045
19335
  init_fs();
19046
- import { dirname as dirname9, resolve as resolve34 } from "path";
19336
+ import { dirname as dirname9, resolve as resolve35 } from "path";
19047
19337
  import { fileURLToPath as fileURLToPath3 } from "url";
19048
19338
  async function findPackageRoot(expectedRelativePath) {
19049
19339
  let currentDir = dirname9(fileURLToPath3(import.meta.url));
19050
19340
  while (true) {
19051
- const candidate = resolve34(currentDir, expectedRelativePath);
19341
+ const candidate = resolve35(currentDir, expectedRelativePath);
19052
19342
  if (await fileExists(candidate)) {
19053
19343
  return currentDir;
19054
19344
  }
19055
- const parentDir = resolve34(currentDir, "..");
19345
+ const parentDir = resolve35(currentDir, "..");
19056
19346
  if (parentDir === currentDir) {
19057
19347
  throw new Error(
19058
19348
  `Could not locate package root containing ${expectedRelativePath}.`
@@ -19073,25 +19363,25 @@ function getPluginManifestRelativePath(pluginKind) {
19073
19363
  }
19074
19364
  function getDefaultPluginTargetDir(pluginKind) {
19075
19365
  const home = homedir3();
19076
- return pluginKind === "claude" ? resolve35(home, ".claude", "plugins", "syntaur") : resolve35(home, "plugins", "syntaur");
19366
+ return pluginKind === "claude" ? resolve36(home, ".claude", "plugins", "syntaur") : resolve36(home, "plugins", "syntaur");
19077
19367
  }
19078
19368
  function getDefaultMarketplacePath() {
19079
- return resolve35(homedir3(), ".agents", "plugins", "marketplace.json");
19369
+ return resolve36(homedir3(), ".agents", "plugins", "marketplace.json");
19080
19370
  }
19081
19371
  function getClaudeMarketplacesRoot() {
19082
- return resolve35(homedir3(), ".claude", "plugins", "marketplaces");
19372
+ return resolve36(homedir3(), ".claude", "plugins", "marketplaces");
19083
19373
  }
19084
19374
  function getClaudeKnownMarketplacesPath() {
19085
- return resolve35(homedir3(), ".claude", "plugins", "known_marketplaces.json");
19375
+ return resolve36(homedir3(), ".claude", "plugins", "known_marketplaces.json");
19086
19376
  }
19087
19377
  function getClaudeInstalledPluginsPath() {
19088
- return resolve35(homedir3(), ".claude", "plugins", "installed_plugins.json");
19378
+ return resolve36(homedir3(), ".claude", "plugins", "installed_plugins.json");
19089
19379
  }
19090
19380
  function getInstallMarkerPath(targetDir) {
19091
- return resolve35(targetDir, INSTALL_MARKER_FILENAME);
19381
+ return resolve36(targetDir, INSTALL_MARKER_FILENAME);
19092
19382
  }
19093
19383
  async function readPackageManifest(packageRoot) {
19094
- const raw = await readFile22(resolve35(packageRoot, "package.json"), "utf-8");
19384
+ const raw = await readFile23(resolve36(packageRoot, "package.json"), "utf-8");
19095
19385
  return JSON.parse(raw);
19096
19386
  }
19097
19387
  async function readJsonFileIfExists(pathValue) {
@@ -19099,7 +19389,7 @@ async function readJsonFileIfExists(pathValue) {
19099
19389
  return null;
19100
19390
  }
19101
19391
  try {
19102
- const raw = await readFile22(pathValue, "utf-8");
19392
+ const raw = await readFile23(pathValue, "utf-8");
19103
19393
  return JSON.parse(raw);
19104
19394
  } catch {
19105
19395
  return null;
@@ -19107,15 +19397,15 @@ async function readJsonFileIfExists(pathValue) {
19107
19397
  }
19108
19398
  async function readClaudePluginManifest(pluginDir) {
19109
19399
  return await readJsonFileIfExists(
19110
- resolve35(pluginDir, ".claude-plugin", "plugin.json")
19400
+ resolve36(pluginDir, ".claude-plugin", "plugin.json")
19111
19401
  ) ?? {};
19112
19402
  }
19113
19403
  async function readPluginManifestName(targetDir, pluginKind) {
19114
- const manifestPath = resolve35(targetDir, getPluginManifestRelativePath(pluginKind));
19404
+ const manifestPath = resolve36(targetDir, getPluginManifestRelativePath(pluginKind));
19115
19405
  if (!await fileExists(manifestPath)) {
19116
19406
  return void 0;
19117
19407
  }
19118
- const raw = await readFile22(manifestPath, "utf-8");
19408
+ const raw = await readFile23(manifestPath, "utf-8");
19119
19409
  const parsed = JSON.parse(raw);
19120
19410
  return parsed.name;
19121
19411
  }
@@ -19125,7 +19415,7 @@ async function readInstallMetadata(targetDir) {
19125
19415
  return null;
19126
19416
  }
19127
19417
  try {
19128
- const raw = await readFile22(markerPath, "utf-8");
19418
+ const raw = await readFile23(markerPath, "utf-8");
19129
19419
  return JSON.parse(raw);
19130
19420
  } catch {
19131
19421
  return null;
@@ -19138,7 +19428,7 @@ async function getInstallStatus(targetDir, pluginKind) {
19138
19428
  const info = await lstat(targetDir);
19139
19429
  if (info.isSymbolicLink()) {
19140
19430
  const symlinkTarget = await readlink(targetDir);
19141
- const resolvedTarget = resolve35(dirname10(targetDir), symlinkTarget);
19431
+ const resolvedTarget = resolve36(dirname10(targetDir), symlinkTarget);
19142
19432
  const manifestName2 = await readPluginManifestName(resolvedTarget, pluginKind);
19143
19433
  return {
19144
19434
  exists: true,
@@ -19167,7 +19457,7 @@ async function writeInstallMetadata(targetDir, pluginKind, installMode, packageM
19167
19457
  installMode,
19168
19458
  installedAt: (/* @__PURE__ */ new Date()).toISOString()
19169
19459
  };
19170
- await writeFile7(
19460
+ await writeFile8(
19171
19461
  getInstallMarkerPath(targetDir),
19172
19462
  `${JSON.stringify(metadata, null, 2)}
19173
19463
  `,
@@ -19184,7 +19474,7 @@ async function installLink(paths) {
19184
19474
  await ensureDir(dirname10(paths.targetDir));
19185
19475
  await rm4(paths.targetDir, { recursive: true, force: true });
19186
19476
  await ensureDir(dirname10(paths.targetDir));
19187
- await symlink(resolve35(paths.sourceDir), paths.targetDir, "dir");
19477
+ await symlink(resolve36(paths.sourceDir), paths.targetDir, "dir");
19188
19478
  }
19189
19479
  async function removeInstallMarker(targetDir) {
19190
19480
  const markerPath = getInstallMarkerPath(targetDir);
@@ -19198,13 +19488,13 @@ function normalizeAbsoluteInstallPath(pathValue, label) {
19198
19488
  if (!isAbsolute4(expanded)) {
19199
19489
  throw new Error(`${label} must be an absolute path.`);
19200
19490
  }
19201
- return resolve35(expanded);
19491
+ return resolve36(expanded);
19202
19492
  }
19203
19493
  async function resolvePluginPaths(pluginKind, targetDir) {
19204
19494
  const packageRoot = await findPackageRoot(getPluginRelativePath(pluginKind));
19205
19495
  return {
19206
19496
  packageRoot,
19207
- sourceDir: resolve35(packageRoot, getPluginRelativePath(pluginKind)),
19497
+ sourceDir: resolve36(packageRoot, getPluginRelativePath(pluginKind)),
19208
19498
  targetDir: targetDir ?? getDefaultPluginTargetDir(pluginKind)
19209
19499
  };
19210
19500
  }
@@ -19248,10 +19538,10 @@ async function writeClaudeMarketplaceFile(manifestPath, marketplace) {
19248
19538
  }
19249
19539
  if (await fileExists(manifestPath)) {
19250
19540
  try {
19251
- const prev = await readFile22(manifestPath, "utf-8");
19541
+ const prev = await readFile23(manifestPath, "utf-8");
19252
19542
  JSON.parse(prev);
19253
19543
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
19254
- await writeFile7(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
19544
+ await writeFile8(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
19255
19545
  } catch {
19256
19546
  throw new Error(
19257
19547
  `Refusing to overwrite ${manifestPath}: existing file is not valid JSON. Inspect and remove or repair it manually before re-running.`
@@ -19259,7 +19549,7 @@ async function writeClaudeMarketplaceFile(manifestPath, marketplace) {
19259
19549
  }
19260
19550
  }
19261
19551
  const tmpPath = `${manifestPath}.tmp`;
19262
- await writeFile7(tmpPath, `${JSON.stringify(marketplace, null, 2)}
19552
+ await writeFile8(tmpPath, `${JSON.stringify(marketplace, null, 2)}
19263
19553
  `, "utf-8");
19264
19554
  await rename8(tmpPath, manifestPath);
19265
19555
  }
@@ -19329,8 +19619,8 @@ async function listClaudeMarketplaceCandidates() {
19329
19619
  if (!entry.isDirectory()) {
19330
19620
  continue;
19331
19621
  }
19332
- const candidateRoot = resolve35(rootDir, entry.name);
19333
- const manifestPath = resolve35(candidateRoot, ".claude-plugin", "marketplace.json");
19622
+ const candidateRoot = resolve36(rootDir, entry.name);
19623
+ const manifestPath = resolve36(candidateRoot, ".claude-plugin", "marketplace.json");
19334
19624
  if (!await fileExists(manifestPath)) {
19335
19625
  continue;
19336
19626
  }
@@ -19357,11 +19647,11 @@ async function listClaudeMarketplaceCandidates() {
19357
19647
  if (!installLocation) {
19358
19648
  continue;
19359
19649
  }
19360
- const candidateRoot = resolve35(expandHome(installLocation));
19650
+ const candidateRoot = resolve36(expandHome(installLocation));
19361
19651
  if (seen.has(candidateRoot)) {
19362
19652
  continue;
19363
19653
  }
19364
- const manifestPath = resolve35(candidateRoot, ".claude-plugin", "marketplace.json");
19654
+ const manifestPath = resolve36(candidateRoot, ".claude-plugin", "marketplace.json");
19365
19655
  if (!await fileExists(manifestPath)) {
19366
19656
  continue;
19367
19657
  }
@@ -19389,14 +19679,14 @@ async function getPreferredClaudeMarketplace() {
19389
19679
  name: candidate.name,
19390
19680
  rootDir: candidate.rootDir,
19391
19681
  manifestPath: candidate.manifestPath,
19392
- targetDir: resolve35(candidate.rootDir, "plugins", "syntaur")
19682
+ targetDir: resolve36(candidate.rootDir, "plugins", "syntaur")
19393
19683
  };
19394
19684
  }
19395
19685
  async function registerKnownClaudeMarketplace(name, rootDir) {
19396
19686
  const manifestPath = getClaudeKnownMarketplacesPath();
19397
19687
  let existing = {};
19398
19688
  if (await fileExists(manifestPath)) {
19399
- const raw = await readFile22(manifestPath, "utf-8");
19689
+ const raw = await readFile23(manifestPath, "utf-8");
19400
19690
  try {
19401
19691
  const parsed = JSON.parse(raw);
19402
19692
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
@@ -19423,12 +19713,12 @@ async function registerKnownClaudeMarketplace(name, rootDir) {
19423
19713
  existing[name].autoUpdate = true;
19424
19714
  await ensureDir(dirname10(manifestPath));
19425
19715
  if (await fileExists(manifestPath)) {
19426
- const prev = await readFile22(manifestPath, "utf-8");
19716
+ const prev = await readFile23(manifestPath, "utf-8");
19427
19717
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
19428
- await writeFile7(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
19718
+ await writeFile8(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
19429
19719
  }
19430
19720
  const tmpPath = `${manifestPath}.tmp`;
19431
- await writeFile7(tmpPath, `${JSON.stringify(existing, null, 2)}
19721
+ await writeFile8(tmpPath, `${JSON.stringify(existing, null, 2)}
19432
19722
  `, "utf-8");
19433
19723
  await rename8(tmpPath, manifestPath);
19434
19724
  return { added: !had, updated: had };
@@ -19437,11 +19727,11 @@ async function ensureKnownClaudeMarketplaceForRoot(options) {
19437
19727
  return registerKnownClaudeMarketplace(options.name, options.rootDir);
19438
19728
  }
19439
19729
  async function setSyntaurPluginEnabled(options) {
19440
- const settingsPath = resolve35(homedir3(), ".claude", "settings.json");
19730
+ const settingsPath = resolve36(homedir3(), ".claude", "settings.json");
19441
19731
  const key = `syntaur@${options.marketplaceName}`;
19442
19732
  let parsed = {};
19443
19733
  if (await fileExists(settingsPath)) {
19444
- const raw = await readFile22(settingsPath, "utf-8");
19734
+ const raw = await readFile23(settingsPath, "utf-8");
19445
19735
  try {
19446
19736
  parsed = JSON.parse(raw);
19447
19737
  } catch {
@@ -19460,11 +19750,11 @@ async function setSyntaurPluginEnabled(options) {
19460
19750
  await ensureDir(dirname10(settingsPath));
19461
19751
  if (await fileExists(settingsPath)) {
19462
19752
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
19463
- const prev = await readFile22(settingsPath, "utf-8");
19464
- await writeFile7(`${settingsPath}.bak-${stamp}`, prev, "utf-8");
19753
+ const prev = await readFile23(settingsPath, "utf-8");
19754
+ await writeFile8(`${settingsPath}.bak-${stamp}`, prev, "utf-8");
19465
19755
  }
19466
19756
  const tmpPath = `${settingsPath}.tmp`;
19467
- await writeFile7(tmpPath, `${JSON.stringify(parsed, null, 2)}
19757
+ await writeFile8(tmpPath, `${JSON.stringify(parsed, null, 2)}
19468
19758
  `, "utf-8");
19469
19759
  await rename8(tmpPath, settingsPath);
19470
19760
  return { key, previous, current: options.enabled, changed: true };
@@ -19474,9 +19764,9 @@ async function ensureClaudeUserMarketplace() {
19474
19764
  if (existing) {
19475
19765
  return existing;
19476
19766
  }
19477
- const rootDir = resolve35(getClaudeMarketplacesRoot(), "user-plugins");
19478
- const manifestPath = resolve35(rootDir, ".claude-plugin", "marketplace.json");
19479
- await ensureDir(resolve35(rootDir, "plugins"));
19767
+ const rootDir = resolve36(getClaudeMarketplacesRoot(), "user-plugins");
19768
+ const manifestPath = resolve36(rootDir, ".claude-plugin", "marketplace.json");
19769
+ await ensureDir(resolve36(rootDir, "plugins"));
19480
19770
  if (!await fileExists(manifestPath)) {
19481
19771
  const scaffold = {
19482
19772
  plugins: []
@@ -19495,7 +19785,7 @@ async function ensureClaudeUserMarketplace() {
19495
19785
  name: "user-plugins",
19496
19786
  rootDir,
19497
19787
  manifestPath,
19498
- targetDir: resolve35(rootDir, "plugins", "syntaur")
19788
+ targetDir: resolve36(rootDir, "plugins", "syntaur")
19499
19789
  };
19500
19790
  }
19501
19791
  async function detectClaudeMarketplaceForTarget(targetDir) {
@@ -19505,7 +19795,7 @@ async function detectClaudeMarketplaceForTarget(targetDir) {
19505
19795
  return null;
19506
19796
  }
19507
19797
  const rootDir = dirname10(pluginsDir);
19508
- const manifestPath = resolve35(rootDir, ".claude-plugin", "marketplace.json");
19798
+ const manifestPath = resolve36(rootDir, ".claude-plugin", "marketplace.json");
19509
19799
  if (!await fileExists(manifestPath)) {
19510
19800
  return null;
19511
19801
  }
@@ -19521,7 +19811,7 @@ async function detectClaudeMarketplaceForTarget(targetDir) {
19521
19811
  async function findManagedClaudeMarketplacePluginDir() {
19522
19812
  const marketplaces = await listClaudeMarketplaceCandidates();
19523
19813
  for (const marketplace of marketplaces) {
19524
- const targetDir = resolve35(marketplace.rootDir, "plugins", "syntaur");
19814
+ const targetDir = resolve36(marketplace.rootDir, "plugins", "syntaur");
19525
19815
  const status = await getInstallStatus(targetDir, "claude");
19526
19816
  if (status.exists && status.managed) {
19527
19817
  return targetDir;
@@ -19646,7 +19936,7 @@ async function installManagedPlugin(options) {
19646
19936
  `${paths.targetDir} already exists and is not a Syntaur-managed install. Remove it manually before installing Syntaur there.`
19647
19937
  );
19648
19938
  }
19649
- if (desiredMode === "link" && existing.exists && existing.installMode === "link" && existing.symlinkTarget === resolve35(paths.sourceDir) && !force) {
19939
+ if (desiredMode === "link" && existing.exists && existing.installMode === "link" && existing.symlinkTarget === resolve36(paths.sourceDir) && !force) {
19650
19940
  return {
19651
19941
  targetDir: paths.targetDir,
19652
19942
  sourceDir: paths.sourceDir,
@@ -19698,7 +19988,7 @@ async function readMarketplaceFile(marketplacePath) {
19698
19988
  plugins: []
19699
19989
  };
19700
19990
  }
19701
- const raw = await readFile22(marketplacePath, "utf-8");
19991
+ const raw = await readFile23(marketplacePath, "utf-8");
19702
19992
  const parsed = JSON.parse(raw);
19703
19993
  return {
19704
19994
  name: parsed.name ?? "local",
@@ -19708,7 +19998,7 @@ async function readMarketplaceFile(marketplacePath) {
19708
19998
  }
19709
19999
  async function writeMarketplaceFile(marketplacePath, marketplace) {
19710
20000
  await ensureDir(dirname10(marketplacePath));
19711
- await writeFile7(marketplacePath, `${JSON.stringify(marketplace, null, 2)}
20001
+ await writeFile8(marketplacePath, `${JSON.stringify(marketplace, null, 2)}
19712
20002
  `, "utf-8");
19713
20003
  }
19714
20004
  async function hasAnySyntaurMarketplaceEntry(marketplacePath) {
@@ -19859,13 +20149,13 @@ async function recommendMarketplacePath() {
19859
20149
  return configuredOrManaged ?? getDefaultMarketplacePath();
19860
20150
  }
19861
20151
  async function isSyntaurDataInstalled() {
19862
- return fileExists(resolve35(syntaurRoot(), "config.md"));
20152
+ return fileExists(resolve36(syntaurRoot(), "config.md"));
19863
20153
  }
19864
20154
  async function removeSyntaurData() {
19865
20155
  await rm4(syntaurRoot(), { recursive: true, force: true });
19866
20156
  }
19867
20157
  async function getConfiguredProjectDir() {
19868
- if (!await fileExists(resolve35(syntaurRoot(), "config.md"))) {
20158
+ if (!await fileExists(resolve36(syntaurRoot(), "config.md"))) {
19869
20159
  return null;
19870
20160
  }
19871
20161
  return (await readConfig()).defaultProjectDir;
@@ -19934,24 +20224,24 @@ async function textPrompt(question, defaultValue) {
19934
20224
 
19935
20225
  // src/utils/install-skills.ts
19936
20226
  init_fs();
19937
- import { readFile as readFile24, readdir as readdir15, mkdir as mkdir4, copyFile, rm as rm5, lstat as lstat2 } from "fs/promises";
19938
- import { resolve as resolve37, relative as relative3, join as join4 } from "path";
20227
+ import { readFile as readFile25, readdir as readdir15, mkdir as mkdir4, copyFile, rm as rm5, lstat as lstat2 } from "fs/promises";
20228
+ import { resolve as resolve38, relative as relative3, join as join4 } from "path";
19939
20229
  import { homedir as homedir5 } from "os";
19940
20230
 
19941
20231
  // src/utils/plugin-state.ts
19942
20232
  init_fs();
19943
- import { readFile as readFile23 } from "fs/promises";
19944
- import { resolve as resolve36 } from "path";
20233
+ import { readFile as readFile24 } from "fs/promises";
20234
+ import { resolve as resolve37 } from "path";
19945
20235
  import { homedir as homedir4 } from "os";
19946
20236
  function settingsPathFor(agent) {
19947
- if (agent === "claude") return resolve36(homedir4(), ".claude", "settings.json");
20237
+ if (agent === "claude") return resolve37(homedir4(), ".claude", "settings.json");
19948
20238
  return null;
19949
20239
  }
19950
20240
  async function readJsonOrNull(path) {
19951
20241
  if (!path) return null;
19952
20242
  if (!await fileExists(path)) return null;
19953
20243
  try {
19954
- const raw = await readFile23(path, "utf-8");
20244
+ const raw = await readFile24(path, "utf-8");
19955
20245
  return JSON.parse(raw);
19956
20246
  } catch {
19957
20247
  return null;
@@ -20000,11 +20290,11 @@ var KNOWN_SKILL_NAMES = [
20000
20290
  var KNOWN_SKILLS = KNOWN_SKILL_NAMES;
20001
20291
  async function getSkillsDir() {
20002
20292
  const packageRoot = await findPackageRoot("skills");
20003
- return resolve37(packageRoot, "skills");
20293
+ return resolve38(packageRoot, "skills");
20004
20294
  }
20005
20295
  function defaultSkillTargetDir(target) {
20006
- if (target === "claude") return resolve37(homedir5(), ".claude", "skills");
20007
- return resolve37(homedir5(), ".codex", "skills");
20296
+ if (target === "claude") return resolve38(homedir5(), ".claude", "skills");
20297
+ return resolve38(homedir5(), ".codex", "skills");
20008
20298
  }
20009
20299
  async function walkFiles(root) {
20010
20300
  const out = [];
@@ -20024,7 +20314,7 @@ async function walkFiles(root) {
20024
20314
  }
20025
20315
  async function filesEqual(a, b) {
20026
20316
  try {
20027
- const [ba, bb] = await Promise.all([readFile24(a), readFile24(b)]);
20317
+ const [ba, bb] = await Promise.all([readFile25(a), readFile25(b)]);
20028
20318
  if (ba.length !== bb.length) return false;
20029
20319
  return ba.equals(bb);
20030
20320
  } catch {
@@ -20146,7 +20436,7 @@ async function uninstallSkills(options) {
20146
20436
  if (await isSymlink(destDir)) continue;
20147
20437
  const skillMd = join4(destDir, "SKILL.md");
20148
20438
  if (!await fileExists(skillMd)) continue;
20149
- const content = await readFile24(skillMd, "utf-8").catch(() => "");
20439
+ const content = await readFile25(skillMd, "utf-8").catch(() => "");
20150
20440
  const match = content.match(/^name:\s*(\S+)\s*$/m);
20151
20441
  if (!match || match[1] !== skill) continue;
20152
20442
  await rm5(destDir, { recursive: true, force: true });
@@ -20335,16 +20625,16 @@ async function installPluginCommand(options) {
20335
20625
  // src/commands/install-statusline.ts
20336
20626
  init_paths();
20337
20627
  init_fs();
20338
- import { readFile as readFile26, writeFile as writeFile9, copyFile as copyFile2, rm as rm6, stat as stat2, symlink as symlink2, unlink as unlink8, lstat as lstat3 } from "fs/promises";
20339
- import { resolve as resolve39, dirname as dirname12 } from "path";
20628
+ import { readFile as readFile27, writeFile as writeFile10, copyFile as copyFile2, rm as rm6, stat as stat2, symlink as symlink2, unlink as unlink8, lstat as lstat3 } from "fs/promises";
20629
+ import { resolve as resolve40, dirname as dirname12 } from "path";
20340
20630
  import { homedir as homedir6 } from "os";
20341
20631
  import { fileURLToPath as fileURLToPath4 } from "url";
20342
20632
 
20343
20633
  // src/commands/configure-statusline.ts
20344
20634
  init_paths();
20345
20635
  init_fs();
20346
- import { readFile as readFile25, writeFile as writeFile8 } from "fs/promises";
20347
- import { resolve as resolve38, dirname as dirname11 } from "path";
20636
+ import { readFile as readFile26, writeFile as writeFile9 } from "fs/promises";
20637
+ import { resolve as resolve39, dirname as dirname11 } from "path";
20348
20638
  import { spawnSync as spawnSync5 } from "child_process";
20349
20639
  import { checkbox, input as input2, confirm } from "@inquirer/prompts";
20350
20640
  var AVAILABLE_SEGMENTS = [
@@ -20365,12 +20655,12 @@ var PRESETS = {
20365
20655
  tracker: { segments: ["git", "assignment", "external", "session"], separator: " \xB7 " }
20366
20656
  };
20367
20657
  function getConfigPath(installRoot) {
20368
- return resolve38(installRoot, "statusline.config.json");
20658
+ return resolve39(installRoot, "statusline.config.json");
20369
20659
  }
20370
20660
  async function readConfig2(path) {
20371
20661
  if (!await fileExists(path)) return null;
20372
20662
  try {
20373
- const raw = await readFile25(path, "utf-8");
20663
+ const raw = await readFile26(path, "utf-8");
20374
20664
  const parsed = JSON.parse(raw);
20375
20665
  if (!parsed || typeof parsed !== "object") return null;
20376
20666
  const segments = Array.isArray(parsed.segments) ? parsed.segments.filter(isSegmentName) : [];
@@ -20517,13 +20807,13 @@ async function configureStatuslineCommand(options = {}) {
20517
20807
  return;
20518
20808
  }
20519
20809
  await ensureDir(dirname11(configPath));
20520
- await writeFile8(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
20810
+ await writeFile9(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
20521
20811
  console.log("Wrote statusline config:");
20522
20812
  console.log(` path: ${configPath}`);
20523
20813
  console.log(` segments: ${config.segments.join(", ")}`);
20524
20814
  console.log(` separator: ${JSON.stringify(config.separator)}`);
20525
20815
  if (config.wrap) console.log(` wrap: ${config.wrap}`);
20526
- const script = options.statuslineScript ?? resolve38(installRoot, "statusline.sh");
20816
+ const script = options.statuslineScript ?? resolve39(installRoot, "statusline.sh");
20527
20817
  if (await fileExists(script)) {
20528
20818
  console.log("");
20529
20819
  console.log("Live preview:");
@@ -20548,17 +20838,17 @@ async function writeDefaultConfigIfMissing(installRoot) {
20548
20838
  segments: ["git", "assignment", "session"],
20549
20839
  separator: " \xB7 "
20550
20840
  };
20551
- await writeFile8(path, JSON.stringify(defaultConfig, null, 2) + "\n", "utf-8");
20841
+ await writeFile9(path, JSON.stringify(defaultConfig, null, 2) + "\n", "utf-8");
20552
20842
  }
20553
20843
 
20554
20844
  // src/commands/install-statusline.ts
20555
20845
  function getPackageStatuslineSource() {
20556
20846
  const here = dirname12(fileURLToPath4(import.meta.url));
20557
- return resolve39(here, "..", "statusline", "statusline.sh");
20847
+ return resolve40(here, "..", "statusline", "statusline.sh");
20558
20848
  }
20559
20849
  async function readSettingsJson(settingsPath) {
20560
20850
  if (!await fileExists(settingsPath)) return {};
20561
- const raw = await readFile26(settingsPath, "utf-8");
20851
+ const raw = await readFile27(settingsPath, "utf-8");
20562
20852
  if (raw.trim() === "") return {};
20563
20853
  try {
20564
20854
  const parsed = JSON.parse(raw);
@@ -20571,7 +20861,7 @@ async function readSettingsJson(settingsPath) {
20571
20861
  }
20572
20862
  async function writeSettingsJson(settingsPath, data) {
20573
20863
  await ensureDir(dirname12(settingsPath));
20574
- await writeFile9(settingsPath, JSON.stringify(data, null, 2) + "\n", "utf-8");
20864
+ await writeFile10(settingsPath, JSON.stringify(data, null, 2) + "\n", "utf-8");
20575
20865
  }
20576
20866
  async function resolveMode(mode, existingCommand, ourCommand) {
20577
20867
  if (mode !== "ask") return mode;
@@ -20606,7 +20896,7 @@ function extractExistingCommand(settings) {
20606
20896
  }
20607
20897
  async function backupSettings(settingsSnapshot, backupPath) {
20608
20898
  await ensureDir(dirname12(backupPath));
20609
- await writeFile9(
20899
+ await writeFile10(
20610
20900
  backupPath,
20611
20901
  JSON.stringify(
20612
20902
  {
@@ -20638,12 +20928,12 @@ async function installScript(sourceScript, destScript, link) {
20638
20928
  }
20639
20929
  async function installStatuslineCommand(options = {}) {
20640
20930
  const mode = options.mode ?? "ask";
20641
- const settingsPath = options.settingsPath ?? resolve39(homedir6(), ".claude", "settings.json");
20931
+ const settingsPath = options.settingsPath ?? resolve40(homedir6(), ".claude", "settings.json");
20642
20932
  const installRoot = options.installRoot ?? syntaurRoot();
20643
20933
  const sourceScript = options.sourceScript ?? getPackageStatuslineSource();
20644
- const destScript = resolve39(installRoot, "statusline.sh");
20645
- const confPath = resolve39(installRoot, "statusline.conf");
20646
- const backupPath = resolve39(installRoot, "statusline.backup.json");
20934
+ const destScript = resolve40(installRoot, "statusline.sh");
20935
+ const confPath = resolve40(installRoot, "statusline.conf");
20936
+ const backupPath = resolve40(installRoot, "statusline.backup.json");
20647
20937
  if (!await fileExists(sourceScript)) {
20648
20938
  throw new Error(
20649
20939
  `Statusline source script not found at ${sourceScript}. Try re-installing syntaur (npm install -g syntaur) or pass --source-script explicitly.`
@@ -20679,19 +20969,19 @@ async function installStatuslineCommand(options = {}) {
20679
20969
  if (parsed) {
20680
20970
  wrapTarget = parsed;
20681
20971
  } else {
20682
- const wrapperPath = resolve39(installRoot, "statusline-wrapped.sh");
20972
+ const wrapperPath = resolve40(installRoot, "statusline-wrapped.sh");
20683
20973
  const wrapperBody = `#!/usr/bin/env bash
20684
20974
  # Auto-generated by syntaur install-statusline.
20685
20975
  # Executes the previously configured statusLine command.
20686
20976
  exec ${existingCommand}
20687
20977
  `;
20688
- await writeFile9(wrapperPath, wrapperBody, "utf-8");
20978
+ await writeFile10(wrapperPath, wrapperBody, "utf-8");
20689
20979
  await chmodExec(wrapperPath);
20690
20980
  wrapTarget = wrapperPath;
20691
20981
  }
20692
20982
  }
20693
20983
  await ensureDir(dirname12(confPath));
20694
- await writeFile9(
20984
+ await writeFile10(
20695
20985
  confPath,
20696
20986
  wrapTarget ? `# Wrap target \u2014 the command below is invoked with the same stdin; its
20697
20987
  # stdout becomes the leading segment of the statusline. Remove this
@@ -20734,19 +21024,19 @@ async function chmodExec(path) {
20734
21024
  }
20735
21025
  }
20736
21026
  async function uninstallStatuslineCommand(options = {}) {
20737
- const settingsPath = options.settingsPath ?? resolve39(homedir6(), ".claude", "settings.json");
21027
+ const settingsPath = options.settingsPath ?? resolve40(homedir6(), ".claude", "settings.json");
20738
21028
  const installRoot = options.installRoot ?? syntaurRoot();
20739
- const destScript = resolve39(installRoot, "statusline.sh");
20740
- const confPath = resolve39(installRoot, "statusline.conf");
20741
- const backupPath = resolve39(installRoot, "statusline.backup.json");
20742
- const wrapperPath = resolve39(installRoot, "statusline-wrapped.sh");
21029
+ const destScript = resolve40(installRoot, "statusline.sh");
21030
+ const confPath = resolve40(installRoot, "statusline.conf");
21031
+ const backupPath = resolve40(installRoot, "statusline.backup.json");
21032
+ const wrapperPath = resolve40(installRoot, "statusline-wrapped.sh");
20743
21033
  const settings = await readSettingsJson(settingsPath);
20744
21034
  const existing = extractExistingCommand(settings);
20745
21035
  const ourCommand = `bash ${destScript}`;
20746
21036
  let restored = null;
20747
21037
  if (await fileExists(backupPath)) {
20748
21038
  try {
20749
- const raw = await readFile26(backupPath, "utf-8");
21039
+ const raw = await readFile27(backupPath, "utf-8");
20750
21040
  const parsed = JSON.parse(raw);
20751
21041
  const prev = parsed?.previousStatusLine;
20752
21042
  if (prev && typeof prev === "object" && typeof prev.command === "string") {
@@ -20767,7 +21057,7 @@ async function uninstallStatuslineCommand(options = {}) {
20767
21057
  await writeSettingsJson(settingsPath, settings);
20768
21058
  }
20769
21059
  if (!options.keepScript) {
20770
- const configPath = resolve39(installRoot, "statusline.config.json");
21060
+ const configPath = resolve40(installRoot, "statusline.config.json");
20771
21061
  for (const path of [destScript, confPath, backupPath, wrapperPath, configPath]) {
20772
21062
  try {
20773
21063
  await rm6(path, { force: true });
@@ -21024,7 +21314,7 @@ async function setupCommand(options) {
21024
21314
  }
21025
21315
 
21026
21316
  // src/commands/uninstall.ts
21027
- import { resolve as resolve40 } from "path";
21317
+ import { resolve as resolve41 } from "path";
21028
21318
  init_paths();
21029
21319
  function expandTargets(options) {
21030
21320
  if (options.all) {
@@ -21104,7 +21394,7 @@ async function uninstallCommand(options) {
21104
21394
  const configuredProjectDir = await getConfiguredProjectDir();
21105
21395
  await removeSyntaurData();
21106
21396
  console.log(`Removed ${syntaurRoot()}`);
21107
- if (configuredProjectDir && resolve40(configuredProjectDir) !== resolve40(syntaurRoot(), "projects")) {
21397
+ if (configuredProjectDir && resolve41(configuredProjectDir) !== resolve41(syntaurRoot(), "projects")) {
21108
21398
  console.warn(
21109
21399
  `Warning: config.md pointed to an external project directory (${configuredProjectDir}). That directory was not removed automatically.`
21110
21400
  );
@@ -21123,7 +21413,7 @@ init_slug();
21123
21413
  init_cursor_rules();
21124
21414
  init_codex_agents();
21125
21415
  init_opencode_config();
21126
- import { resolve as resolve41 } from "path";
21416
+ import { resolve as resolve42 } from "path";
21127
21417
  var SUPPORTED_FRAMEWORKS = ["cursor", "codex", "opencode"];
21128
21418
  async function setupAdapterCommand(framework, options) {
21129
21419
  if (!SUPPORTED_FRAMEWORKS.includes(framework)) {
@@ -21149,19 +21439,19 @@ async function setupAdapterCommand(framework, options) {
21149
21439
  }
21150
21440
  const config = await readConfig();
21151
21441
  const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
21152
- const projectDir = resolve41(baseDir, options.project);
21153
- const assignmentDir = resolve41(
21442
+ const projectDir = resolve42(baseDir, options.project);
21443
+ const assignmentDir = resolve42(
21154
21444
  projectDir,
21155
21445
  "assignments",
21156
21446
  options.assignment
21157
21447
  );
21158
- const projectMdPath = resolve41(projectDir, "project.md");
21448
+ const projectMdPath = resolve42(projectDir, "project.md");
21159
21449
  if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
21160
21450
  throw new Error(
21161
21451
  `Project "${options.project}" not found at ${projectDir}.`
21162
21452
  );
21163
21453
  }
21164
- const assignmentMdPath2 = resolve41(assignmentDir, "assignment.md");
21454
+ const assignmentMdPath2 = resolve42(assignmentDir, "assignment.md");
21165
21455
  if (!await fileExists(assignmentDir) || !await fileExists(assignmentMdPath2)) {
21166
21456
  throw new Error(
21167
21457
  `Assignment "${options.assignment}" not found at ${assignmentDir}.`
@@ -21189,15 +21479,15 @@ async function setupAdapterCommand(framework, options) {
21189
21479
  }
21190
21480
  }
21191
21481
  if (framework === "cursor") {
21192
- const protocolPath = resolve41(cwd, ".cursor", "rules", "syntaur-protocol.mdc");
21193
- const assignmentPath = resolve41(cwd, ".cursor", "rules", "syntaur-assignment.mdc");
21482
+ const protocolPath = resolve42(cwd, ".cursor", "rules", "syntaur-protocol.mdc");
21483
+ const assignmentPath = resolve42(cwd, ".cursor", "rules", "syntaur-assignment.mdc");
21194
21484
  await writeAdapterFile(protocolPath, renderCursorProtocol());
21195
21485
  await writeAdapterFile(assignmentPath, renderCursorAssignment(rendererParams));
21196
21486
  } else if (framework === "codex" || framework === "opencode") {
21197
- const agentsPath = resolve41(cwd, "AGENTS.md");
21487
+ const agentsPath = resolve42(cwd, "AGENTS.md");
21198
21488
  await writeAdapterFile(agentsPath, renderCodexAgents(rendererParams));
21199
21489
  if (framework === "opencode") {
21200
- const configPath = resolve41(cwd, "opencode.json");
21490
+ const configPath = resolve42(cwd, "opencode.json");
21201
21491
  await writeAdapterFile(configPath, renderOpenCodeConfig({ projectDir }));
21202
21492
  }
21203
21493
  }
@@ -21222,7 +21512,7 @@ async function setupAdapterCommand(framework, options) {
21222
21512
  init_paths();
21223
21513
  init_fs();
21224
21514
  init_config2();
21225
- import { resolve as resolve42 } from "path";
21515
+ import { resolve as resolve43 } from "path";
21226
21516
  init_session_db();
21227
21517
  init_agent_sessions();
21228
21518
  async function trackSessionCommand(options) {
@@ -21237,7 +21527,7 @@ async function trackSessionCommand(options) {
21237
21527
  if (options.project) {
21238
21528
  const config = await readConfig();
21239
21529
  const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
21240
- const projectDir = resolve42(baseDir, options.project);
21530
+ const projectDir = resolve43(baseDir, options.project);
21241
21531
  if (!await fileExists(projectDir)) {
21242
21532
  throw new Error(
21243
21533
  `Project "${options.project}" not found at ${projectDir}.`
@@ -21613,7 +21903,7 @@ async function executeLaunchPlan(plan, spawnFn = realSpawn) {
21613
21903
  `Spawn failed: ${msg}. Verify the terminal is installed and on PATH.`
21614
21904
  );
21615
21905
  }
21616
- await new Promise((resolve78, reject) => {
21906
+ await new Promise((resolve79, reject) => {
21617
21907
  let settled = false;
21618
21908
  let stderr = "";
21619
21909
  const finishOk = () => {
@@ -21623,7 +21913,7 @@ async function executeLaunchPlan(plan, spawnFn = realSpawn) {
21623
21913
  child.unref();
21624
21914
  } catch {
21625
21915
  }
21626
- resolve78();
21916
+ resolve79();
21627
21917
  };
21628
21918
  const finishErr = (remediation) => {
21629
21919
  if (settled) return;
@@ -21752,7 +22042,7 @@ function appleScriptString(value) {
21752
22042
  init_paths();
21753
22043
  init_fs();
21754
22044
  import { fileURLToPath as fileURLToPath5 } from "url";
21755
- import { dirname as dirname13, resolve as resolve44, join as join5 } from "path";
22045
+ import { dirname as dirname13, resolve as resolve45, join as join5 } from "path";
21756
22046
  import { realpathSync, readFileSync, mkdirSync } from "fs";
21757
22047
  var NPX_PATTERNS = [
21758
22048
  { kind: "npm", re: /\/_npx\/([^/]+)\/node_modules(?:\/|$)/ },
@@ -21778,7 +22068,7 @@ function normalizeSlashes(p) {
21778
22068
  }
21779
22069
  function detectInstallKind(scriptUrl, opts = {}) {
21780
22070
  const realpath3 = opts.realpath ?? realpathSync.native;
21781
- const readFile53 = opts.readFile ?? ((p) => readFileSync(p, "utf-8"));
22071
+ const readFile54 = opts.readFile ?? ((p) => readFileSync(p, "utf-8"));
21782
22072
  const ua = opts.envUserAgent !== void 0 ? opts.envUserAgent : process.env.npm_config_user_agent ?? "";
21783
22073
  const resolved = resolveScriptPath(scriptUrl, realpath3);
21784
22074
  if (resolved === null) {
@@ -21799,7 +22089,7 @@ function detectInstallKind(scriptUrl, opts = {}) {
21799
22089
  const pkgJsonPath = join5(dir, "package.json");
21800
22090
  let raw;
21801
22091
  try {
21802
- raw = readFile53(pkgJsonPath);
22092
+ raw = readFile54(pkgJsonPath);
21803
22093
  } catch {
21804
22094
  const parent2 = dirname13(dir);
21805
22095
  if (parent2 === dir) break;
@@ -21831,7 +22121,7 @@ function extractNpxHash(scriptUrl, opts = {}) {
21831
22121
  return null;
21832
22122
  }
21833
22123
  function nudgeStampDir() {
21834
- return resolve44(syntaurRoot(), "npx-handler-nudge");
22124
+ return resolve45(syntaurRoot(), "npx-handler-nudge");
21835
22125
  }
21836
22126
  function sanitizeHash(hash) {
21837
22127
  return hash.replace(/[^A-Za-z0-9_-]/g, "_") || "_";
@@ -21975,8 +22265,8 @@ function formatInstallUrlHandlerError(err2) {
21975
22265
  init_config2();
21976
22266
  init_paths();
21977
22267
  init_fs();
21978
- import { resolve as resolve46, isAbsolute as isAbsolute7 } from "path";
21979
- import { readFile as readFile27 } from "fs/promises";
22268
+ import { resolve as resolve47, isAbsolute as isAbsolute7 } from "path";
22269
+ import { readFile as readFile28 } from "fs/promises";
21980
22270
  import { select, confirm as confirm2, input as input3 } from "@inquirer/prompts";
21981
22271
  async function browseCommand(options) {
21982
22272
  const config = await readConfig();
@@ -22045,7 +22335,7 @@ async function pickAgent2(agents) {
22045
22335
  return picked;
22046
22336
  }
22047
22337
  async function ensureWorktree(opts) {
22048
- const assignmentPath = resolve46(
22338
+ const assignmentPath = resolve47(
22049
22339
  opts.projectsDir,
22050
22340
  opts.projectSlug,
22051
22341
  "assignments",
@@ -22055,7 +22345,7 @@ async function ensureWorktree(opts) {
22055
22345
  if (!await fileExists(assignmentPath)) {
22056
22346
  return void 0;
22057
22347
  }
22058
- const content = await readFile27(assignmentPath, "utf-8");
22348
+ const content = await readFile28(assignmentPath, "utf-8");
22059
22349
  const { parseAssignmentFrontmatter: parseAssignmentFrontmatter2 } = await Promise.resolve().then(() => (init_frontmatter(), frontmatter_exports));
22060
22350
  const fm = parseAssignmentFrontmatter2(content);
22061
22351
  const { workspace } = fm;
@@ -22125,7 +22415,7 @@ async function ensureWorktree(opts) {
22125
22415
  async function runCreate(opts) {
22126
22416
  const { createWorktreeAndRecord: createWorktreeAndRecord2, GitWorktreeError: GitWorktreeError2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
22127
22417
  const expandedWorktree = expandHome(opts.worktreePath);
22128
- const absWorktree = isAbsolute7(expandedWorktree) ? expandedWorktree : resolve46(expandedWorktree);
22418
+ const absWorktree = isAbsolute7(expandedWorktree) ? expandedWorktree : resolve47(expandedWorktree);
22129
22419
  try {
22130
22420
  await createWorktreeAndRecord2({
22131
22421
  assignmentPath: opts.assignmentPath,
@@ -22154,7 +22444,7 @@ init_paths();
22154
22444
  init_fs();
22155
22445
  init_playbook();
22156
22446
  init_playbooks();
22157
- import { resolve as resolve47 } from "path";
22447
+ import { resolve as resolve48 } from "path";
22158
22448
  async function createPlaybookCommand(name, options) {
22159
22449
  if (!name.trim()) {
22160
22450
  throw new Error("Playbook name cannot be empty.");
@@ -22167,7 +22457,7 @@ async function createPlaybookCommand(name, options) {
22167
22457
  }
22168
22458
  const dir = playbooksDir();
22169
22459
  await ensureDir(dir);
22170
- const filePath = resolve47(dir, `${slug}.md`);
22460
+ const filePath = resolve48(dir, `${slug}.md`);
22171
22461
  if (await fileExists(filePath)) {
22172
22462
  throw new Error(
22173
22463
  `Playbook "${slug}" already exists at ${filePath}
@@ -22189,8 +22479,8 @@ init_paths();
22189
22479
  init_fs();
22190
22480
  init_parser();
22191
22481
  init_config2();
22192
- import { readdir as readdir16, readFile as readFile28 } from "fs/promises";
22193
- import { resolve as resolve48 } from "path";
22482
+ import { readdir as readdir16, readFile as readFile29 } from "fs/promises";
22483
+ import { resolve as resolve49 } from "path";
22194
22484
  async function listPlaybooksCommand(options = {}) {
22195
22485
  const dir = playbooksDir();
22196
22486
  if (!await fileExists(dir)) {
@@ -22205,8 +22495,8 @@ async function listPlaybooksCommand(options = {}) {
22205
22495
  );
22206
22496
  const rows = [];
22207
22497
  for (const entry of mdFiles) {
22208
- const filePath = resolve48(dir, entry.name);
22209
- const raw = await readFile28(filePath, "utf-8");
22498
+ const filePath = resolve49(dir, entry.name);
22499
+ const raw = await readFile29(filePath, "utf-8");
22210
22500
  const parsed = parsePlaybook(raw);
22211
22501
  const slug = parsed.slug || entry.name.replace(/\.md$/, "");
22212
22502
  const disabled = disabledSet.has(slug);
@@ -22329,14 +22619,14 @@ init_fs();
22329
22619
  init_config2();
22330
22620
  init_slug();
22331
22621
  import { Command as Command2 } from "commander";
22332
- import { readFile as readFile30 } from "fs/promises";
22333
- import { resolve as resolve50 } from "path";
22622
+ import { readFile as readFile31 } from "fs/promises";
22623
+ import { resolve as resolve51 } from "path";
22334
22624
 
22335
22625
  // src/commands/bundle.ts
22336
22626
  init_paths();
22337
22627
  import { Command } from "commander";
22338
- import { mkdir as mkdir7, readFile as readFile29, readdir as readdir17, rm as rm7, writeFile as writeFile11 } from "fs/promises";
22339
- import { resolve as resolve49 } from "path";
22628
+ import { mkdir as mkdir7, readFile as readFile30, readdir as readdir17, rm as rm7, writeFile as writeFile12 } from "fs/promises";
22629
+ import { resolve as resolve50 } from "path";
22340
22630
  init_parser2();
22341
22631
  init_fs();
22342
22632
  init_config2();
@@ -22354,7 +22644,7 @@ async function resolveBundleScope(options) {
22354
22644
  throw new Error(`Invalid project slug: "${options.project}".`);
22355
22645
  }
22356
22646
  const config = await readConfig();
22357
- const projectMd = resolve49(config.defaultProjectDir, options.project, "project.md");
22647
+ const projectMd = resolve50(config.defaultProjectDir, options.project, "project.md");
22358
22648
  if (!await fileExists(projectMd)) {
22359
22649
  throw new Error(`Project "${options.project}" not found.`);
22360
22650
  }
@@ -22424,10 +22714,10 @@ function pickNextPlanFile(planDir, existingFiles) {
22424
22714
  const m = f.match(/^plan-v(\d+)\.md$/);
22425
22715
  if (m) versions.add(parseInt(m[1], 10));
22426
22716
  }
22427
- if (versions.size === 0) return { target: resolve49(planDir, "plan.md"), version: 1 };
22717
+ if (versions.size === 0) return { target: resolve50(planDir, "plan.md"), version: 1 };
22428
22718
  let n = 2;
22429
22719
  while (versions.has(n)) n++;
22430
- return { target: resolve49(planDir, `plan-v${n}.md`), version: n };
22720
+ return { target: resolve50(planDir, `plan-v${n}.md`), version: n };
22431
22721
  }
22432
22722
  function dedupePreserveOrder(ids) {
22433
22723
  const out = [];
@@ -22511,7 +22801,7 @@ bundleCommand.command("new").description("Create a new bundle from 2+ existing t
22511
22801
  if (options.plan) {
22512
22802
  const planDir = bundlePlanDir(sc.todosPath, sc.scopeId, id);
22513
22803
  await ensureDir(planDir);
22514
- const target = resolve49(planDir, "plan.md");
22804
+ const target = resolve50(planDir, "plan.md");
22515
22805
  const memberLines = items.map((it) => `- ${it.description} [t:${it.id}]`).join("\n");
22516
22806
  const stub = [
22517
22807
  "---",
@@ -22687,7 +22977,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
22687
22977
  }
22688
22978
  const repository = options.repository ?? process.cwd();
22689
22979
  const parentBranch = options.parentBranch ?? "main";
22690
- const worktreePath = options.worktreePath ?? resolve49(repository, ".worktrees", options.branch);
22980
+ const worktreePath = options.worktreePath ?? resolve50(repository, ".worktrees", options.branch);
22691
22981
  const checklist = await readChecklist(sc.todosPath, sc.checklistKey);
22692
22982
  for (const memberId of bundle.todoIds) {
22693
22983
  const item = checklist.items.find((i) => i.id === memberId);
@@ -22697,8 +22987,8 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
22697
22987
  }
22698
22988
  const bundlesFilePath = bundlesPath(sc.todosPath);
22699
22989
  const checklistFilePath = checklistPath(sc.todosPath, sc.checklistKey);
22700
- const bundlesSnapshot = await fileExists(bundlesFilePath) ? await readFile29(bundlesFilePath, "utf-8") : null;
22701
- const checklistSnapshot = await fileExists(checklistFilePath) ? await readFile29(checklistFilePath, "utf-8") : null;
22990
+ const bundlesSnapshot = await fileExists(bundlesFilePath) ? await readFile30(bundlesFilePath, "utf-8") : null;
22991
+ const checklistSnapshot = await fileExists(checklistFilePath) ? await readFile30(checklistFilePath, "utf-8") : null;
22702
22992
  const record = async () => {
22703
22993
  bundle.branch = options.branch;
22704
22994
  bundle.worktreePath = worktreePath;
@@ -22714,7 +23004,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
22714
23004
  try {
22715
23005
  await writeBundles(sc.todosPath, bundles);
22716
23006
  await writeChecklist(sc.todosPath, checklist);
22717
- const ctxDir = resolve49(worktreePath, ".syntaur");
23007
+ const ctxDir = resolve50(worktreePath, ".syntaur");
22718
23008
  await mkdir7(ctxDir, { recursive: true });
22719
23009
  const payload = {
22720
23010
  bundleId: bundle.id,
@@ -22728,7 +23018,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
22728
23018
  repository,
22729
23019
  boundAt: nowISO()
22730
23020
  };
22731
- await writeFile11(resolve49(ctxDir, "context.json"), JSON.stringify(payload, null, 2) + "\n");
23021
+ await writeFile12(resolve50(ctxDir, "context.json"), JSON.stringify(payload, null, 2) + "\n");
22732
23022
  } catch (err2) {
22733
23023
  try {
22734
23024
  if (bundlesSnapshot === null) {
@@ -22918,7 +23208,7 @@ async function resolveScope(options) {
22918
23208
  throw new Error(`Invalid project slug: "${options.project}".`);
22919
23209
  }
22920
23210
  const config = await readConfig();
22921
- const projectMd = resolve50(config.defaultProjectDir, options.project, "project.md");
23211
+ const projectMd = resolve51(config.defaultProjectDir, options.project, "project.md");
22922
23212
  if (!await fileExists(projectMd)) {
22923
23213
  throw new Error(`Project "${options.project}" not found.`);
22924
23214
  }
@@ -23241,10 +23531,10 @@ todoCommand.command("archive").description("Archive completed todos and their lo
23241
23531
  (e) => e.itemIds.every((id) => completedIds.has(id))
23242
23532
  );
23243
23533
  const archFile = archivePath(todosPath, workspace, checklist.archiveInterval);
23244
- await ensureDir(resolve50(todosPath, "archive"));
23534
+ await ensureDir(resolve51(todosPath, "archive"));
23245
23535
  let archContent = "";
23246
23536
  if (await fileExists(archFile)) {
23247
- archContent = await readFile30(archFile, "utf-8");
23537
+ archContent = await readFile31(archFile, "utf-8");
23248
23538
  archContent = archContent.trimEnd() + "\n\n";
23249
23539
  } else {
23250
23540
  archContent = `---
@@ -23421,12 +23711,12 @@ function describeScope(scope) {
23421
23711
  }
23422
23712
  async function injectPromotedTodos(assignmentDir, todos, scopeLabel) {
23423
23713
  const { resolve: resolvePath2 } = await import("path");
23424
- const { readFile: readFile53 } = await import("fs/promises");
23714
+ const { readFile: readFile54 } = await import("fs/promises");
23425
23715
  const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
23426
23716
  const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
23427
23717
  const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
23428
23718
  const assignmentMdPath2 = resolvePath2(assignmentDir, "assignment.md");
23429
- let content = await readFile53(assignmentMdPath2, "utf-8");
23719
+ let content = await readFile54(assignmentMdPath2, "utf-8");
23430
23720
  content = appendTodosToAssignmentBody2(
23431
23721
  content,
23432
23722
  todos.map((t) => ({
@@ -23477,7 +23767,7 @@ todoCommand.command("plan").description("Create or open a plan directory for a t
23477
23767
  );
23478
23768
  let target;
23479
23769
  if (existingFiles.length === 0) {
23480
- target = resolve50(planDir, "plan.md");
23770
+ target = resolve51(planDir, "plan.md");
23481
23771
  } else {
23482
23772
  const versions = /* @__PURE__ */ new Set();
23483
23773
  for (const f of existingFiles) {
@@ -23487,7 +23777,7 @@ todoCommand.command("plan").description("Create or open a plan directory for a t
23487
23777
  }
23488
23778
  let n = 2;
23489
23779
  while (versions.has(n)) n++;
23490
- target = resolve50(planDir, `plan-v${n}.md`);
23780
+ target = resolve51(planDir, `plan-v${n}.md`);
23491
23781
  }
23492
23782
  if (!await fileExists(target)) {
23493
23783
  const stub = `---
@@ -23676,12 +23966,12 @@ backupCommand.command("config").description("Show or update backup configuration
23676
23966
 
23677
23967
  // src/commands/doctor.ts
23678
23968
  import { Command as Command4 } from "commander";
23679
- import { readFile as readFile38 } from "fs/promises";
23680
- import { isAbsolute as isAbsolute10, resolve as resolve62 } from "path";
23969
+ import { readFile as readFile39 } from "fs/promises";
23970
+ import { isAbsolute as isAbsolute10, resolve as resolve63 } from "path";
23681
23971
 
23682
23972
  // src/utils/doctor/index.ts
23683
23973
  import { fileURLToPath as fileURLToPath8 } from "url";
23684
- import { readFile as readFile37 } from "fs/promises";
23974
+ import { readFile as readFile38 } from "fs/promises";
23685
23975
  import { dirname as dirname17, join as join9 } from "path";
23686
23976
 
23687
23977
  // src/utils/doctor/context.ts
@@ -23689,11 +23979,11 @@ init_config2();
23689
23979
  init_paths();
23690
23980
  init_fs();
23691
23981
  import Database4 from "better-sqlite3";
23692
- import { resolve as resolve51 } from "path";
23982
+ import { resolve as resolve52 } from "path";
23693
23983
  async function buildCheckContext(cwd = process.cwd()) {
23694
23984
  const config = await readConfig();
23695
23985
  const root = syntaurRoot();
23696
- const dbPath = resolve51(root, "syntaur.db");
23986
+ const dbPath = resolve52(root, "syntaur.db");
23697
23987
  let db5 = null;
23698
23988
  let dbError = null;
23699
23989
  if (await fileExists(dbPath)) {
@@ -23727,8 +24017,8 @@ function closeCheckContext(ctx) {
23727
24017
  // src/utils/doctor/checks/env.ts
23728
24018
  init_fs();
23729
24019
  init_paths();
23730
- import { resolve as resolve52, isAbsolute as isAbsolute8 } from "path";
23731
- import { readFile as readFile31, stat as stat3 } from "fs/promises";
24020
+ import { resolve as resolve53, isAbsolute as isAbsolute8 } from "path";
24021
+ import { readFile as readFile32, stat as stat3 } from "fs/promises";
23732
24022
  import { fileURLToPath as fileURLToPath7 } from "url";
23733
24023
  import { dirname as dirname15, join as join7 } from "path";
23734
24024
  var CATEGORY = "env";
@@ -23768,7 +24058,7 @@ var configValid = {
23768
24058
  category: CATEGORY,
23769
24059
  title: "~/.syntaur/config.md is valid",
23770
24060
  async run(ctx) {
23771
- const configPath = resolve52(ctx.syntaurRoot, "config.md");
24061
+ const configPath = resolve53(ctx.syntaurRoot, "config.md");
23772
24062
  if (!await fileExists(configPath)) {
23773
24063
  return {
23774
24064
  id: this.id,
@@ -23785,7 +24075,7 @@ var configValid = {
23785
24075
  autoFixable: false
23786
24076
  };
23787
24077
  }
23788
- const content = await readFile31(configPath, "utf-8");
24078
+ const content = await readFile32(configPath, "utf-8");
23789
24079
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
23790
24080
  if (!fmMatch || fmMatch[1].trim() === "") {
23791
24081
  return {
@@ -24065,7 +24355,7 @@ async function readLocalPkg() {
24065
24355
  for (let i = 0; i < 6; i++) {
24066
24356
  const candidate = join7(dir, "package.json");
24067
24357
  try {
24068
- const text = await readFile31(candidate, "utf-8");
24358
+ const text = await readFile32(candidate, "utf-8");
24069
24359
  return JSON.parse(text);
24070
24360
  } catch {
24071
24361
  dir = dirname15(dir);
@@ -24117,7 +24407,7 @@ function versionGte(a, b) {
24117
24407
 
24118
24408
  // src/utils/doctor/checks/structure.ts
24119
24409
  init_fs();
24120
- import { resolve as resolve53 } from "path";
24410
+ import { resolve as resolve54 } from "path";
24121
24411
  import { readdir as readdir18, stat as stat4 } from "fs/promises";
24122
24412
  var CATEGORY2 = "structure";
24123
24413
  var KNOWN_TOP_LEVEL = /* @__PURE__ */ new Set([
@@ -24137,7 +24427,7 @@ var projectsDir = {
24137
24427
  category: CATEGORY2,
24138
24428
  title: "projects/ directory exists",
24139
24429
  async run(ctx) {
24140
- const p = resolve53(ctx.syntaurRoot, "projects");
24430
+ const p = resolve54(ctx.syntaurRoot, "projects");
24141
24431
  if (!await fileExists(p)) {
24142
24432
  return {
24143
24433
  id: this.id,
@@ -24162,7 +24452,7 @@ var playbooksDir2 = {
24162
24452
  category: CATEGORY2,
24163
24453
  title: "playbooks/ directory exists",
24164
24454
  async run(ctx) {
24165
- const p = resolve53(ctx.syntaurRoot, "playbooks");
24455
+ const p = resolve54(ctx.syntaurRoot, "playbooks");
24166
24456
  if (!await fileExists(p)) {
24167
24457
  return {
24168
24458
  id: this.id,
@@ -24187,7 +24477,7 @@ var todosDirValid = {
24187
24477
  category: CATEGORY2,
24188
24478
  title: "todos/ directory is readable (if present)",
24189
24479
  async run(ctx) {
24190
- const p = resolve53(ctx.syntaurRoot, "todos");
24480
+ const p = resolve54(ctx.syntaurRoot, "todos");
24191
24481
  if (!await fileExists(p)) {
24192
24482
  return {
24193
24483
  id: this.id,
@@ -24218,7 +24508,7 @@ var serversDirValid = {
24218
24508
  category: CATEGORY2,
24219
24509
  title: "servers/ directory is readable (if present)",
24220
24510
  async run(ctx) {
24221
- const p = resolve53(ctx.syntaurRoot, "servers");
24511
+ const p = resolve54(ctx.syntaurRoot, "servers");
24222
24512
  if (!await fileExists(p)) {
24223
24513
  return {
24224
24514
  id: this.id,
@@ -24263,7 +24553,7 @@ var knownFilesRecognized = {
24263
24553
  title: this.title,
24264
24554
  status: "warn",
24265
24555
  detail: `unexpected top-level entries: ${unexpected.join(", ")}`,
24266
- affected: unexpected.map((n) => resolve53(ctx.syntaurRoot, n)),
24556
+ affected: unexpected.map((n) => resolve54(ctx.syntaurRoot, n)),
24267
24557
  remediation: {
24268
24558
  kind: "manual",
24269
24559
  suggestion: "Review these entries \u2014 they may be leftover state from older versions",
@@ -24292,7 +24582,7 @@ function pass2(check) {
24292
24582
 
24293
24583
  // src/utils/doctor/checks/project.ts
24294
24584
  init_fs();
24295
- import { resolve as resolve54 } from "path";
24585
+ import { resolve as resolve55 } from "path";
24296
24586
  import { readdir as readdir19, stat as stat5 } from "fs/promises";
24297
24587
  var CATEGORY3 = "project";
24298
24588
  var REQUIRED_PROJECT_FILES = [
@@ -24322,10 +24612,10 @@ async function listProjects2(ctx) {
24322
24612
  for (const e of entries) {
24323
24613
  if (!e.isDirectory()) continue;
24324
24614
  if (e.name.startsWith(".") || e.name.startsWith("_")) continue;
24325
- const projectDir = resolve54(dir, e.name);
24615
+ const projectDir = resolve55(dir, e.name);
24326
24616
  let looksLikeProject = false;
24327
24617
  for (const marker of PROJECT_MARKERS) {
24328
- if (await fileExists(resolve54(projectDir, marker))) {
24618
+ if (await fileExists(resolve55(projectDir, marker))) {
24329
24619
  looksLikeProject = true;
24330
24620
  break;
24331
24621
  }
@@ -24344,7 +24634,7 @@ var requiredFiles = {
24344
24634
  for (const projectDir of projects) {
24345
24635
  const missing = [];
24346
24636
  for (const rel of REQUIRED_PROJECT_FILES) {
24347
- const p = resolve54(projectDir, rel);
24637
+ const p = resolve55(projectDir, rel);
24348
24638
  if (!await fileExists(p)) missing.push(rel);
24349
24639
  }
24350
24640
  if (missing.length === 0) continue;
@@ -24354,7 +24644,7 @@ var requiredFiles = {
24354
24644
  title: this.title,
24355
24645
  status: "error",
24356
24646
  detail: `project at ${projectDir} is missing: ${missing.join(", ")}`,
24357
- affected: missing.map((m) => resolve54(projectDir, m)),
24647
+ affected: missing.map((m) => resolve55(projectDir, m)),
24358
24648
  remediation: {
24359
24649
  kind: "manual",
24360
24650
  suggestion: "Recreate the missing scaffold files from templates",
@@ -24377,7 +24667,7 @@ var manifestStale = {
24377
24667
  const projects = await listProjects2(ctx);
24378
24668
  const results = [];
24379
24669
  for (const projectDir of projects) {
24380
- const manifestPath = resolve54(projectDir, "manifest.md");
24670
+ const manifestPath = resolve55(projectDir, "manifest.md");
24381
24671
  if (!await fileExists(manifestPath)) continue;
24382
24672
  const manifestMtime = (await stat5(manifestPath)).mtimeMs;
24383
24673
  const newestAssignment = await newestAssignmentMtime(projectDir);
@@ -24426,7 +24716,7 @@ var orphanFiles = {
24426
24716
  title: this.title,
24427
24717
  status: "warn",
24428
24718
  detail: `project at ${projectDir} has unexpected entries: ${orphans.join(", ")}`,
24429
- affected: orphans.map((o) => resolve54(projectDir, o)),
24719
+ affected: orphans.map((o) => resolve55(projectDir, o)),
24430
24720
  autoFixable: false
24431
24721
  });
24432
24722
  }
@@ -24436,7 +24726,7 @@ var orphanFiles = {
24436
24726
  };
24437
24727
  var projectChecks = [requiredFiles, manifestStale, orphanFiles];
24438
24728
  async function newestAssignmentMtime(projectDir) {
24439
- const assignmentsRoot = resolve54(projectDir, "assignments");
24729
+ const assignmentsRoot = resolve55(projectDir, "assignments");
24440
24730
  if (!await fileExists(assignmentsRoot)) return 0;
24441
24731
  let newest = 0;
24442
24732
  let entries;
@@ -24447,7 +24737,7 @@ async function newestAssignmentMtime(projectDir) {
24447
24737
  }
24448
24738
  for (const e of entries) {
24449
24739
  if (!e.isDirectory()) continue;
24450
- const assignmentMd = resolve54(assignmentsRoot, e.name, "assignment.md");
24740
+ const assignmentMd = resolve55(assignmentsRoot, e.name, "assignment.md");
24451
24741
  try {
24452
24742
  const s = await stat5(assignmentMd);
24453
24743
  if (s.mtimeMs > newest) newest = s.mtimeMs;
@@ -24471,8 +24761,8 @@ init_fs();
24471
24761
  init_parser();
24472
24762
  init_types();
24473
24763
  init_paths();
24474
- import { resolve as resolve55 } from "path";
24475
- import { readFile as readFile32, readdir as readdir20 } from "fs/promises";
24764
+ import { resolve as resolve56 } from "path";
24765
+ import { readFile as readFile33, readdir as readdir20 } from "fs/promises";
24476
24766
  var CATEGORY4 = "assignment";
24477
24767
  var STATUSES_REQUIRING_HANDOFF = /* @__PURE__ */ new Set(["review", "completed"]);
24478
24768
  var PRE_WORKSPACE_STATUSES = /* @__PURE__ */ new Set([
@@ -24566,7 +24856,7 @@ var invalidStatus = {
24566
24856
  const allowed = configuredStatuses(ctx);
24567
24857
  const results = [];
24568
24858
  for (const a of withAssignmentMd) {
24569
- const path = resolve55(a.assignmentDir, "assignment.md");
24859
+ const path = resolve56(a.assignmentDir, "assignment.md");
24570
24860
  const parsed = await parseSafe2(path);
24571
24861
  if (!parsed) continue;
24572
24862
  if (!allowed.has(parsed.status)) {
@@ -24599,7 +24889,7 @@ var workspaceMissing = {
24599
24889
  const terminal = terminalStatuses(ctx);
24600
24890
  const results = [];
24601
24891
  for (const a of withAssignmentMd) {
24602
- const path = resolve55(a.assignmentDir, "assignment.md");
24892
+ const path = resolve56(a.assignmentDir, "assignment.md");
24603
24893
  const parsed = await parseSafe2(path);
24604
24894
  if (!parsed) continue;
24605
24895
  if (terminal.has(parsed.status)) continue;
@@ -24646,12 +24936,12 @@ var requiredFilesByStatus = {
24646
24936
  const { withAssignmentMd } = await listAssignments(ctx);
24647
24937
  const results = [];
24648
24938
  for (const a of withAssignmentMd) {
24649
- const assignmentPath = resolve55(a.assignmentDir, "assignment.md");
24939
+ const assignmentPath = resolve56(a.assignmentDir, "assignment.md");
24650
24940
  const parsed = await parseSafe2(assignmentPath);
24651
24941
  if (!parsed) continue;
24652
24942
  const missing = [];
24653
24943
  if (STATUSES_REQUIRING_HANDOFF.has(parsed.status)) {
24654
- const handoffPath = resolve55(a.assignmentDir, "handoff.md");
24944
+ const handoffPath = resolve56(a.assignmentDir, "handoff.md");
24655
24945
  if (!await fileExists(handoffPath)) missing.push("handoff.md");
24656
24946
  }
24657
24947
  if (missing.length === 0) continue;
@@ -24661,7 +24951,7 @@ var requiredFilesByStatus = {
24661
24951
  title: this.title,
24662
24952
  status: "warn",
24663
24953
  detail: `${a.projectSlug}/${a.assignmentSlug} (status: ${parsed.status}) is missing ${missing.join(", ")}`,
24664
- affected: missing.map((m) => resolve55(a.assignmentDir, m)),
24954
+ affected: missing.map((m) => resolve56(a.assignmentDir, m)),
24665
24955
  remediation: {
24666
24956
  kind: "manual",
24667
24957
  suggestion: `Create the missing ${missing.join(" and ")} files for this assignment`,
@@ -24684,7 +24974,7 @@ var companionFilesScaffolded = {
24684
24974
  for (const a of withAssignmentMd) {
24685
24975
  const missing = [];
24686
24976
  for (const filename of ["progress.md", "comments.md"]) {
24687
- if (!await fileExists(resolve55(a.assignmentDir, filename))) {
24977
+ if (!await fileExists(resolve56(a.assignmentDir, filename))) {
24688
24978
  missing.push(filename);
24689
24979
  }
24690
24980
  }
@@ -24696,7 +24986,7 @@ var companionFilesScaffolded = {
24696
24986
  title: this.title,
24697
24987
  status: "warn",
24698
24988
  detail: `${label} is missing ${missing.join(" and ")} (pre-v2.0 assignment \u2014 not required, but scaffolding them keeps the dashboard and CLIs consistent)`,
24699
- affected: missing.map((m) => resolve55(a.assignmentDir, m)),
24989
+ affected: missing.map((m) => resolve56(a.assignmentDir, m)),
24700
24990
  remediation: {
24701
24991
  kind: "manual",
24702
24992
  suggestion: `Create ${missing.join(" and ")} with the renderProgress/renderComments templates, or re-scaffold via the CLI`,
@@ -24729,7 +25019,7 @@ var typeDefinition = {
24729
25019
  const { withAssignmentMd } = await listAssignments(ctx);
24730
25020
  const results = [];
24731
25021
  for (const a of withAssignmentMd) {
24732
- const path = resolve55(a.assignmentDir, "assignment.md");
25022
+ const path = resolve56(a.assignmentDir, "assignment.md");
24733
25023
  const parsed = await parseSafe2(path);
24734
25024
  if (!parsed) continue;
24735
25025
  if (!parsed.type) continue;
@@ -24763,7 +25053,7 @@ var projectFrontmatterMatchesContainer = {
24763
25053
  const { withAssignmentMd } = await listAssignments(ctx);
24764
25054
  const results = [];
24765
25055
  for (const a of withAssignmentMd) {
24766
- const path = resolve55(a.assignmentDir, "assignment.md");
25056
+ const path = resolve56(a.assignmentDir, "assignment.md");
24767
25057
  const parsed = await parseSafe2(path);
24768
25058
  if (!parsed) continue;
24769
25059
  if (a.standalone) {
@@ -24814,13 +25104,13 @@ var draftMissingObjective = {
24814
25104
  const { withAssignmentMd } = await listAssignments(ctx);
24815
25105
  const results = [];
24816
25106
  for (const a of withAssignmentMd) {
24817
- const path = resolve55(a.assignmentDir, "assignment.md");
25107
+ const path = resolve56(a.assignmentDir, "assignment.md");
24818
25108
  const parsed = await parseSafe2(path);
24819
25109
  if (!parsed) continue;
24820
25110
  if (parsed.status !== "draft") continue;
24821
25111
  let raw;
24822
25112
  try {
24823
- raw = await readFile32(path, "utf-8");
25113
+ raw = await readFile33(path, "utf-8");
24824
25114
  } catch {
24825
25115
  continue;
24826
25116
  }
@@ -24853,7 +25143,7 @@ var readyToImplementMissingPlan = {
24853
25143
  const { withAssignmentMd } = await listAssignments(ctx);
24854
25144
  const results = [];
24855
25145
  for (const a of withAssignmentMd) {
24856
- const path = resolve55(a.assignmentDir, "assignment.md");
25146
+ const path = resolve56(a.assignmentDir, "assignment.md");
24857
25147
  const parsed = await parseSafe2(path);
24858
25148
  if (!parsed) continue;
24859
25149
  if (parsed.status !== "ready_to_implement") continue;
@@ -24862,7 +25152,7 @@ var readyToImplementMissingPlan = {
24862
25152
  let hasPlanContent = false;
24863
25153
  for (const f of planFiles) {
24864
25154
  try {
24865
- const c2 = await readFile32(resolve55(a.assignmentDir, f), "utf-8");
25155
+ const c2 = await readFile33(resolve56(a.assignmentDir, f), "utf-8");
24866
25156
  if (c2.trim().length > 0) {
24867
25157
  hasPlanContent = true;
24868
25158
  break;
@@ -24878,7 +25168,7 @@ var readyToImplementMissingPlan = {
24878
25168
  title: this.title,
24879
25169
  status: "warn",
24880
25170
  detail: `${label} (status: ready_to_implement) has no plan.md or plan-v<N>.md`,
24881
- affected: [resolve55(a.assignmentDir, "plan.md")],
25171
+ affected: [resolve56(a.assignmentDir, "plan.md")],
24882
25172
  remediation: {
24883
25173
  kind: "manual",
24884
25174
  suggestion: `Write a plan with '/plan-assignment' (or 'syntaur plan'), then re-mark ready_to_implement`,
@@ -24905,7 +25195,7 @@ var assignmentChecks = [
24905
25195
  ];
24906
25196
  async function parseSafe2(path) {
24907
25197
  try {
24908
- const content = await readFile32(path, "utf-8");
25198
+ const content = await readFile33(path, "utf-8");
24909
25199
  return parseAssignmentFull(content);
24910
25200
  } catch {
24911
25201
  return null;
@@ -24924,7 +25214,7 @@ function pass4(check, detail) {
24924
25214
 
24925
25215
  // src/utils/doctor/checks/dashboard.ts
24926
25216
  init_fs();
24927
- import { resolve as resolve56 } from "path";
25217
+ import { resolve as resolve57 } from "path";
24928
25218
  var CATEGORY5 = "dashboard";
24929
25219
  var dbReachable = {
24930
25220
  id: "dashboard.db-reachable",
@@ -24938,7 +25228,7 @@ var dbReachable = {
24938
25228
  title: this.title,
24939
25229
  status: "error",
24940
25230
  detail: `could not open syntaur.db: ${ctx.dbError ?? "unknown error"}`,
24941
- affected: [resolve56(ctx.syntaurRoot, "syntaur.db")],
25231
+ affected: [resolve57(ctx.syntaurRoot, "syntaur.db")],
24942
25232
  remediation: {
24943
25233
  kind: "manual",
24944
25234
  suggestion: "Start the dashboard once (`syntaur dashboard`) to initialize the DB, or restore it from backup",
@@ -24956,7 +25246,7 @@ var dbReachable = {
24956
25246
  title: this.title,
24957
25247
  status: "error",
24958
25248
  detail: 'syntaur.db is missing the expected "sessions" table',
24959
- affected: [resolve56(ctx.syntaurRoot, "syntaur.db")],
25249
+ affected: [resolve57(ctx.syntaurRoot, "syntaur.db")],
24960
25250
  autoFixable: false
24961
25251
  };
24962
25252
  }
@@ -24968,7 +25258,7 @@ var dbReachable = {
24968
25258
  title: this.title,
24969
25259
  status: "error",
24970
25260
  detail: `syntaur.db query failed: ${err2 instanceof Error ? err2.message : String(err2)}`,
24971
- affected: [resolve56(ctx.syntaurRoot, "syntaur.db")],
25261
+ affected: [resolve57(ctx.syntaurRoot, "syntaur.db")],
24972
25262
  autoFixable: false
24973
25263
  };
24974
25264
  }
@@ -24994,7 +25284,7 @@ var ghostSessions = {
24994
25284
  const results = [];
24995
25285
  for (const row of rows) {
24996
25286
  if (!row.project_slug) continue;
24997
- const projectPath = resolve56(projectsDir2, row.project_slug, "project.md");
25287
+ const projectPath = resolve57(projectsDir2, row.project_slug, "project.md");
24998
25288
  if (!await fileExists(projectPath)) {
24999
25289
  results.push({
25000
25290
  id: this.id,
@@ -25013,7 +25303,7 @@ var ghostSessions = {
25013
25303
  continue;
25014
25304
  }
25015
25305
  if (row.assignment_slug) {
25016
- const assignmentPath = resolve56(
25306
+ const assignmentPath = resolve57(
25017
25307
  projectsDir2,
25018
25308
  row.project_slug,
25019
25309
  "assignments",
@@ -25065,8 +25355,8 @@ function skipped(check, reason) {
25065
25355
 
25066
25356
  // src/utils/doctor/checks/integrations.ts
25067
25357
  init_fs();
25068
- import { resolve as resolve57, dirname as dirname16, basename as basename5 } from "path";
25069
- import { readdir as readdir21, readFile as readFile33 } from "fs/promises";
25358
+ import { resolve as resolve58, dirname as dirname16, basename as basename5 } from "path";
25359
+ import { readdir as readdir21, readFile as readFile34 } from "fs/promises";
25070
25360
  import { homedir as homedir8 } from "os";
25071
25361
  var CATEGORY6 = "integrations";
25072
25362
  var claudePluginLinked = {
@@ -25148,10 +25438,10 @@ var backupConfigured = {
25148
25438
  }
25149
25439
  };
25150
25440
  async function readKnownMarketplaces() {
25151
- const path = resolve57(homedir8(), ".claude", "plugins", "known_marketplaces.json");
25441
+ const path = resolve58(homedir8(), ".claude", "plugins", "known_marketplaces.json");
25152
25442
  if (!await fileExists(path)) return {};
25153
25443
  try {
25154
- const raw = await readFile33(path, "utf-8");
25444
+ const raw = await readFile34(path, "utf-8");
25155
25445
  return JSON.parse(raw);
25156
25446
  } catch {
25157
25447
  return {};
@@ -25185,7 +25475,7 @@ var claudeMarketplaceRegistered = {
25185
25475
  };
25186
25476
  }
25187
25477
  const marketplaceRoot = dirname16(pluginsParent);
25188
- const marketplaceManifest = resolve57(marketplaceRoot, ".claude-plugin", "marketplace.json");
25478
+ const marketplaceManifest = resolve58(marketplaceRoot, ".claude-plugin", "marketplace.json");
25189
25479
  if (!await fileExists(marketplaceManifest)) {
25190
25480
  return {
25191
25481
  id: this.id,
@@ -25204,7 +25494,7 @@ var claudeMarketplaceRegistered = {
25204
25494
  }
25205
25495
  let parsed = {};
25206
25496
  try {
25207
- parsed = JSON.parse(await readFile33(marketplaceManifest, "utf-8"));
25497
+ parsed = JSON.parse(await readFile34(marketplaceManifest, "utf-8"));
25208
25498
  } catch {
25209
25499
  return {
25210
25500
  id: this.id,
@@ -25236,7 +25526,7 @@ var claudeMarketplaceRegistered = {
25236
25526
  title: this.title,
25237
25527
  status: "error",
25238
25528
  detail: issues.join("; "),
25239
- affected: [marketplaceManifest, resolve57(homedir8(), ".claude", "plugins", "known_marketplaces.json")],
25529
+ affected: [marketplaceManifest, resolve58(homedir8(), ".claude", "plugins", "known_marketplaces.json")],
25240
25530
  remediation: {
25241
25531
  kind: "manual",
25242
25532
  suggestion: "Re-run install-plugin to ensure both files are in sync.",
@@ -25276,8 +25566,8 @@ function skipped2(check, reason) {
25276
25566
  init_fs();
25277
25567
  init_parser();
25278
25568
  init_types();
25279
- import { resolve as resolve58 } from "path";
25280
- import { readFile as readFile34 } from "fs/promises";
25569
+ import { resolve as resolve59 } from "path";
25570
+ import { readFile as readFile35 } from "fs/promises";
25281
25571
  var CATEGORY7 = "workspace";
25282
25572
  var ASSIGNMENT_FIELDS = ["projectSlug", "assignmentSlug", "projectDir", "assignmentDir"];
25283
25573
  var BUNDLE_FIELDS = ["bundleId", "bundleScope", "bundleScopeId"];
@@ -25298,12 +25588,12 @@ function isStandaloneSession(ctx) {
25298
25588
  return !hasAnyAssignmentField(ctx) && !hasAnyBundleField(ctx) && typeof ctx.sessionId === "string" && ctx.sessionId.length > 0;
25299
25589
  }
25300
25590
  async function loadContext(ctx) {
25301
- const path = resolve58(ctx.cwd, ".syntaur", "context.json");
25591
+ const path = resolve59(ctx.cwd, ".syntaur", "context.json");
25302
25592
  if (!await fileExists(path)) {
25303
25593
  return { data: null, path, exists: false, parseError: null };
25304
25594
  }
25305
25595
  try {
25306
- const raw = await readFile34(path, "utf-8");
25596
+ const raw = await readFile35(path, "utf-8");
25307
25597
  return { data: JSON.parse(raw), path, exists: true, parseError: null };
25308
25598
  } catch (err2) {
25309
25599
  return {
@@ -25397,7 +25687,7 @@ var contextAssignmentResolves = {
25397
25687
  if (isStandaloneSession(data)) return skipped3(this, "standalone session context \u2014 no assignment to resolve");
25398
25688
  if (isBundleContext(data)) return skipped3(this, "bundle context \u2014 no assignment to resolve");
25399
25689
  if (!data?.assignmentDir) return skipped3(this, "context has no assignmentDir");
25400
- const assignmentMd = resolve58(data.assignmentDir, "assignment.md");
25690
+ const assignmentMd = resolve59(data.assignmentDir, "assignment.md");
25401
25691
  if (!await fileExists(assignmentMd)) {
25402
25692
  return {
25403
25693
  id: this.id,
@@ -25427,10 +25717,10 @@ var contextTerminal = {
25427
25717
  if (isStandaloneSession(data)) return skipped3(this, "standalone session context \u2014 no assignment to check");
25428
25718
  if (isBundleContext(data)) return skipped3(this, "bundle context \u2014 no assignment to check");
25429
25719
  if (!data?.assignmentDir) return skipped3(this, "context has no assignmentDir");
25430
- const assignmentMd = resolve58(data.assignmentDir, "assignment.md");
25720
+ const assignmentMd = resolve59(data.assignmentDir, "assignment.md");
25431
25721
  if (!await fileExists(assignmentMd)) return skipped3(this, "assignment file missing");
25432
25722
  try {
25433
- const content = await readFile34(assignmentMd, "utf-8");
25723
+ const content = await readFile35(assignmentMd, "utf-8");
25434
25724
  const parsed = parseAssignmentFull(content);
25435
25725
  const terminal = terminalStatuses2(ctx);
25436
25726
  if (terminal.has(parsed.status)) {
@@ -25576,15 +25866,15 @@ var agentChecks = [agentsResolvable];
25576
25866
  // src/utils/doctor/checks/terminal.ts
25577
25867
  init_config2();
25578
25868
  import { spawnSync as spawnSync8 } from "child_process";
25579
- import { readFile as readFile35 } from "fs/promises";
25580
- import { resolve as resolve59 } from "path";
25869
+ import { readFile as readFile36 } from "fs/promises";
25870
+ import { resolve as resolve60 } from "path";
25581
25871
  init_paths();
25582
25872
  init_fs();
25583
25873
  var CATEGORY9 = "terminal";
25584
25874
  async function readRawTerminalKey() {
25585
- const configPath = resolve59(syntaurRoot(), "config.md");
25875
+ const configPath = resolve60(syntaurRoot(), "config.md");
25586
25876
  if (!await fileExists(configPath)) return null;
25587
- const content = await readFile35(configPath, "utf-8");
25877
+ const content = await readFile36(configPath, "utf-8");
25588
25878
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
25589
25879
  if (!fmMatch) return null;
25590
25880
  const line = fmMatch[1].split("\n").find((l) => /^terminal:\s*/.test(l));
@@ -25734,13 +26024,13 @@ var terminalChecks = [
25734
26024
 
25735
26025
  // src/utils/doctor/checks/skills.ts
25736
26026
  init_fs();
25737
- import { resolve as resolve60, join as join8 } from "path";
25738
- import { readdir as readdir22, readFile as readFile36, lstat as lstat4 } from "fs/promises";
26027
+ import { resolve as resolve61, join as join8 } from "path";
26028
+ import { readdir as readdir22, readFile as readFile37, lstat as lstat4 } from "fs/promises";
25739
26029
  import { homedir as homedir9 } from "os";
25740
26030
  var CATEGORY10 = "skills";
25741
26031
  var skillTargets = [
25742
- { agent: "claude", dir: resolve60(homedir9(), ".claude", "skills"), label: "~/.claude/skills" },
25743
- { agent: "codex", dir: resolve60(homedir9(), ".codex", "skills"), label: "~/.codex/skills" }
26032
+ { agent: "claude", dir: resolve61(homedir9(), ".claude", "skills"), label: "~/.claude/skills" },
26033
+ { agent: "codex", dir: resolve61(homedir9(), ".codex", "skills"), label: "~/.codex/skills" }
25744
26034
  ];
25745
26035
  var skillsDedupCheck = {
25746
26036
  id: "skills.dedup",
@@ -25764,7 +26054,7 @@ var skillsDedupCheck = {
25764
26054
  if (!KNOWN_SKILLS.includes(entry.name)) continue;
25765
26055
  const skillMd = join8(dir, entry.name, "SKILL.md");
25766
26056
  if (!await fileExists(skillMd)) continue;
25767
- const content = await readFile36(skillMd, "utf-8").catch(() => "");
26057
+ const content = await readFile37(skillMd, "utf-8").catch(() => "");
25768
26058
  const match = content.match(/^name:\s*(\S+)\s*$/m);
25769
26059
  if (!match || match[1] !== entry.name) continue;
25770
26060
  let isSymlink2 = false;
@@ -25815,7 +26105,7 @@ var skillsChecks = [skillsDedupCheck];
25815
26105
  // src/utils/doctor/checks/bundles.ts
25816
26106
  init_fs();
25817
26107
  init_paths();
25818
- import { resolve as resolve61 } from "path";
26108
+ import { resolve as resolve62 } from "path";
25819
26109
  import { readdir as readdir23 } from "fs/promises";
25820
26110
  import { spawnSync as spawnSync9 } from "child_process";
25821
26111
  init_parser2();
@@ -25845,7 +26135,7 @@ async function listScopes(ctx) {
25845
26135
  if (!e.isDirectory()) continue;
25846
26136
  const slug = e.name;
25847
26137
  if (typeof slug !== "string" || slug.startsWith(".")) continue;
25848
- const projectMd = resolve61(ctx.config.defaultProjectDir, slug, "project.md");
26138
+ const projectMd = resolve62(ctx.config.defaultProjectDir, slug, "project.md");
25849
26139
  if (!await fileExists(projectMd)) continue;
25850
26140
  out.push({
25851
26141
  scopeLabel: `project:${slug}`,
@@ -26136,7 +26426,7 @@ async function readVersion() {
26136
26426
  let dir = dirname17(here);
26137
26427
  for (let i = 0; i < 6; i++) {
26138
26428
  try {
26139
- const raw = await readFile37(join9(dir, "package.json"), "utf-8");
26429
+ const raw = await readFile38(join9(dir, "package.json"), "utf-8");
26140
26430
  const parsed = JSON.parse(raw);
26141
26431
  return typeof parsed.version === "string" ? parsed.version : null;
26142
26432
  } catch {
@@ -26233,7 +26523,7 @@ var REQUIRED_WORKSPACE_FIELDS = [
26233
26523
  ];
26234
26524
  var ISO_DATE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;
26235
26525
  async function validateAssignmentFile(inputPath, cwd = process.cwd()) {
26236
- const absolute = isAbsolute10(inputPath) ? inputPath : resolve62(cwd, inputPath);
26526
+ const absolute = isAbsolute10(inputPath) ? inputPath : resolve63(cwd, inputPath);
26237
26527
  const errors = [];
26238
26528
  const warnings = [];
26239
26529
  if (!await fileExists(absolute)) {
@@ -26246,7 +26536,7 @@ async function validateAssignmentFile(inputPath, cwd = process.cwd()) {
26246
26536
  }
26247
26537
  let content;
26248
26538
  try {
26249
- content = await readFile38(absolute, "utf-8");
26539
+ content = await readFile39(absolute, "utf-8");
26250
26540
  } catch (err2) {
26251
26541
  return {
26252
26542
  ok: false,
@@ -26570,8 +26860,8 @@ init_uuid();
26570
26860
  init_timestamp();
26571
26861
  init_assignment_resolver();
26572
26862
  init_templates();
26573
- import { resolve as resolve63 } from "path";
26574
- import { readFile as readFile39 } from "fs/promises";
26863
+ import { resolve as resolve64 } from "path";
26864
+ import { readFile as readFile40 } from "fs/promises";
26575
26865
  function shortId() {
26576
26866
  return generateId().split("-")[0];
26577
26867
  }
@@ -26601,7 +26891,7 @@ async function commentCommand(target, text, options = {}) {
26601
26891
  if (!isValidSlug(target)) {
26602
26892
  throw new Error(`Invalid assignment slug "${target}".`);
26603
26893
  }
26604
- assignmentDir = resolve63(baseDir, options.project, "assignments", target);
26894
+ assignmentDir = resolve64(baseDir, options.project, "assignments", target);
26605
26895
  assignmentRef = target;
26606
26896
  } else {
26607
26897
  const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), target);
@@ -26611,13 +26901,13 @@ async function commentCommand(target, text, options = {}) {
26611
26901
  assignmentDir = resolved.assignmentDir;
26612
26902
  assignmentRef = resolved.standalone ? resolved.id : resolved.assignmentSlug;
26613
26903
  }
26614
- const commentsPath = resolve63(assignmentDir, "comments.md");
26904
+ const commentsPath = resolve64(assignmentDir, "comments.md");
26615
26905
  const timestamp = nowTimestamp();
26616
26906
  const author = options.author ?? process.env.USER ?? "unknown";
26617
26907
  let currentContent;
26618
26908
  let currentCount = 0;
26619
26909
  if (await fileExists(commentsPath)) {
26620
- currentContent = await readFile39(commentsPath, "utf-8");
26910
+ currentContent = await readFile40(commentsPath, "utf-8");
26621
26911
  const countMatch = currentContent.match(/^entryCount:\s*(\d+)/m);
26622
26912
  if (countMatch) currentCount = parseInt(countMatch[1], 10);
26623
26913
  } else {
@@ -26651,8 +26941,8 @@ ${entry}`;
26651
26941
  }
26652
26942
 
26653
26943
  // src/commands/capture.ts
26654
- import { resolve as resolve67, relative as relative4, dirname as dirname18 } from "path";
26655
- import { copyFile as copyFile3, mkdir as mkdir9, realpath as realpath2, rm as rm12, stat as stat8, writeFile as writeFile13 } from "fs/promises";
26944
+ import { resolve as resolve68, relative as relative4, dirname as dirname18 } from "path";
26945
+ import { copyFile as copyFile3, mkdir as mkdir9, realpath as realpath2, rm as rm12, stat as stat8, writeFile as writeFile14 } from "fs/promises";
26656
26946
  import { existsSync as existsSync5 } from "fs";
26657
26947
 
26658
26948
  // src/utils/assignment-target.ts
@@ -26662,8 +26952,8 @@ init_config2();
26662
26952
  init_slug();
26663
26953
  init_assignment_resolver();
26664
26954
  init_parser();
26665
- import { resolve as resolve64 } from "path";
26666
- import { readFile as readFile40 } from "fs/promises";
26955
+ import { resolve as resolve65 } from "path";
26956
+ import { readFile as readFile41 } from "fs/promises";
26667
26957
  var AssignmentTargetError = class extends Error {
26668
26958
  };
26669
26959
  function classifyContext(ctx) {
@@ -26675,10 +26965,10 @@ function classifyContext(ctx) {
26675
26965
  return "empty";
26676
26966
  }
26677
26967
  async function readAssignmentFrontmatterId(assignmentDir) {
26678
- const path = resolve64(assignmentDir, "assignment.md");
26968
+ const path = resolve65(assignmentDir, "assignment.md");
26679
26969
  if (!await fileExists(path)) return null;
26680
26970
  try {
26681
- const content = await readFile40(path, "utf-8");
26971
+ const content = await readFile41(path, "utf-8");
26682
26972
  const [fm] = extractFrontmatter(content);
26683
26973
  return getField(fm, "id");
26684
26974
  } catch {
@@ -26686,10 +26976,10 @@ async function readAssignmentFrontmatterId(assignmentDir) {
26686
26976
  }
26687
26977
  }
26688
26978
  async function readContextJson(cwd) {
26689
- const path = resolve64(cwd, ".syntaur", "context.json");
26979
+ const path = resolve65(cwd, ".syntaur", "context.json");
26690
26980
  if (!await fileExists(path)) return null;
26691
26981
  try {
26692
- const raw = await readFile40(path, "utf-8");
26982
+ const raw = await readFile41(path, "utf-8");
26693
26983
  return JSON.parse(raw);
26694
26984
  } catch {
26695
26985
  return null;
@@ -26710,15 +27000,15 @@ async function resolveAssignmentTarget(input4, opts = {}) {
26710
27000
  if (!isValidSlug(input4)) {
26711
27001
  throw new AssignmentTargetError(`Invalid assignment slug "${input4}".`);
26712
27002
  }
26713
- const projectDir = resolve64(baseDir, opts.project);
26714
- const projectMdPath = resolve64(projectDir, "project.md");
27003
+ const projectDir = resolve65(baseDir, opts.project);
27004
+ const projectMdPath = resolve65(projectDir, "project.md");
26715
27005
  if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
26716
27006
  throw new AssignmentTargetError(
26717
27007
  `Project "${opts.project}" not found at ${projectDir}.`
26718
27008
  );
26719
27009
  }
26720
- const assignmentDir = resolve64(projectDir, "assignments", input4);
26721
- const assignmentMdPath2 = resolve64(assignmentDir, "assignment.md");
27010
+ const assignmentDir = resolve65(projectDir, "assignments", input4);
27011
+ const assignmentMdPath2 = resolve65(assignmentDir, "assignment.md");
26722
27012
  if (!await fileExists(assignmentMdPath2)) {
26723
27013
  throw new AssignmentTargetError(
26724
27014
  `Assignment "${input4}" not found in project "${opts.project}".`
@@ -26757,7 +27047,7 @@ async function resolveAssignmentTarget(input4, opts = {}) {
26757
27047
  }
26758
27048
  if (ctx.assignmentDir) {
26759
27049
  const dir = expandHome(ctx.assignmentDir);
26760
- const assignmentMdPath2 = resolve64(dir, "assignment.md");
27050
+ const assignmentMdPath2 = resolve65(dir, "assignment.md");
26761
27051
  if (!await fileExists(assignmentMdPath2)) {
26762
27052
  throw new AssignmentTargetError(
26763
27053
  `.syntaur/context.json points to a missing assignment dir: ${dir}.`
@@ -26786,8 +27076,8 @@ async function resolveAssignmentTarget(input4, opts = {}) {
26786
27076
  `.syntaur/context.json contains invalid slugs: project="${ctx.projectSlug}" assignment="${ctx.assignmentSlug}".`
26787
27077
  );
26788
27078
  }
26789
- const assignmentDir = resolve64(baseDir, ctx.projectSlug, "assignments", ctx.assignmentSlug);
26790
- const assignmentMdPath2 = resolve64(assignmentDir, "assignment.md");
27079
+ const assignmentDir = resolve65(baseDir, ctx.projectSlug, "assignments", ctx.assignmentSlug);
27080
+ const assignmentMdPath2 = resolve65(assignmentDir, "assignment.md");
26791
27081
  if (!await fileExists(assignmentMdPath2)) {
26792
27082
  throw new AssignmentTargetError(
26793
27083
  `.syntaur/context.json points to a missing assignment: ${assignmentDir}.`
@@ -26922,7 +27212,7 @@ async function captureScreenshot(mode) {
26922
27212
 
26923
27213
  // src/utils/asciinema.ts
26924
27214
  import { spawn as spawn6 } from "child_process";
26925
- import { mkdtemp as mkdtemp3, readFile as readFile41, rm as rm9 } from "fs/promises";
27215
+ import { mkdtemp as mkdtemp3, readFile as readFile42, rm as rm9 } from "fs/promises";
26926
27216
  import { tmpdir as tmpdir4 } from "os";
26927
27217
  import { join as join11 } from "path";
26928
27218
  var SAFE_RE = /^[A-Za-z0-9_@%+=:,./-]+$/;
@@ -26985,7 +27275,7 @@ async function captureAsciinema(opts) {
26985
27275
  }
26986
27276
  throw err2;
26987
27277
  }
26988
- const text = await readFile41(castPath, "utf8").catch(() => null);
27278
+ const text = await readFile42(castPath, "utf8").catch(() => null);
26989
27279
  if (text === null) {
26990
27280
  throw new Error(
26991
27281
  `asciinema produced no cast file at ${castPath} (exit ${exitCode}). Try running 'asciinema rec ${castPath}' directly to diagnose.`
@@ -27013,9 +27303,9 @@ async function captureAsciinema(opts) {
27013
27303
  // src/utils/recording.ts
27014
27304
  init_paths();
27015
27305
  import { spawn as spawn7 } from "child_process";
27016
- import { mkdir as mkdir8, mkdtemp as mkdtemp4, open as open3, readFile as readFile42, rm as rm10, stat as stat7, unlink as unlink9, writeFile as writeFile12 } from "fs/promises";
27306
+ import { mkdir as mkdir8, mkdtemp as mkdtemp4, open as open3, readFile as readFile43, rm as rm10, stat as stat7, unlink as unlink9, writeFile as writeFile13 } from "fs/promises";
27017
27307
  import { tmpdir as tmpdir5 } from "os";
27018
- import { join as join12, resolve as resolve65 } from "path";
27308
+ import { join as join12, resolve as resolve66 } from "path";
27019
27309
  import { setTimeout as sleep } from "timers/promises";
27020
27310
  function sigintPollIntervalMs() {
27021
27311
  const raw = process.env.SYNTAUR_RECORDING_POLL_INTERVAL_MS;
@@ -27036,13 +27326,13 @@ function sigtermWaitMs() {
27036
27326
  return Number.isFinite(parsed) && parsed >= 0 ? parsed : 1e3;
27037
27327
  }
27038
27328
  function pidfilePath() {
27039
- return resolve65(syntaurRoot(), "recording.pid");
27329
+ return resolve66(syntaurRoot(), "recording.pid");
27040
27330
  }
27041
27331
  function logPath2() {
27042
- return resolve65(syntaurRoot(), "recording.log");
27332
+ return resolve66(syntaurRoot(), "recording.log");
27043
27333
  }
27044
27334
  function sidecarPath() {
27045
- return resolve65(syntaurRoot(), "recording.json");
27335
+ return resolve66(syntaurRoot(), "recording.json");
27046
27336
  }
27047
27337
  function ffmpegArgs(device, fps, mp4Path) {
27048
27338
  return [
@@ -27087,7 +27377,7 @@ async function acquirePidfile(pidfile) {
27087
27377
  } catch (err2) {
27088
27378
  if (err2.code !== "EEXIST") throw err2;
27089
27379
  if (attempt === 1) throw err2;
27090
- const existing = (await readFile42(pidfile, "utf-8").catch(() => "")).trim();
27380
+ const existing = (await readFile43(pidfile, "utf-8").catch(() => "")).trim();
27091
27381
  if (existing.startsWith(STARTING_SENTINEL_PREFIX)) {
27092
27382
  const parentPidRaw = existing.slice(STARTING_SENTINEL_PREFIX.length);
27093
27383
  const parentPid = Number.parseInt(parentPidRaw, 10);
@@ -27184,12 +27474,12 @@ async function startRecording(input4) {
27184
27474
  const pid = await pidReady;
27185
27475
  acquiredPid = pid;
27186
27476
  child.unref();
27187
- await writeFile12(pidfile, String(pid));
27477
+ await writeFile13(pidfile, String(pid));
27188
27478
  await logHandle.close();
27189
27479
  logHandle = null;
27190
27480
  if (warmupMs > 0) await sleep(warmupMs);
27191
27481
  if (!await isProcessAlive(pid)) {
27192
- const tail = await readFile42(log, "utf-8").then((s) => s.split("\n").slice(-20).join("\n")).catch(() => "");
27482
+ const tail = await readFile43(log, "utf-8").then((s) => s.split("\n").slice(-20).join("\n")).catch(() => "");
27193
27483
  acquiredPid = null;
27194
27484
  throw new Error(
27195
27485
  `ffmpeg exited during startup \u2014 likely macOS Screen Recording permission missing. Grant access to your terminal in System Settings \u2192 Privacy & Security \u2192 Screen Recording, then retry. Log: ${log}
@@ -27212,7 +27502,7 @@ ${tail}`
27212
27502
  device: input4.device,
27213
27503
  fps: input4.fps
27214
27504
  };
27215
- await writeFile12(sidecar, JSON.stringify(sidecarData, null, 2));
27505
+ await writeFile13(sidecar, JSON.stringify(sidecarData, null, 2));
27216
27506
  return {
27217
27507
  pid,
27218
27508
  logPath: log,
@@ -27246,7 +27536,7 @@ ${tail}`
27246
27536
  async function stopRecording() {
27247
27537
  const pidfile = pidfilePath();
27248
27538
  const sidecar = sidecarPath();
27249
- const pidRaw = await readFile42(pidfile, "utf-8").catch(() => null);
27539
+ const pidRaw = await readFile43(pidfile, "utf-8").catch(() => null);
27250
27540
  if (pidRaw === null) {
27251
27541
  throw new Error(
27252
27542
  `No active recording found (no pidfile at ${pidfile}). Did you run --start?`
@@ -27256,7 +27546,7 @@ async function stopRecording() {
27256
27546
  if (!Number.isInteger(pid) || pid <= 0) {
27257
27547
  throw new Error(`Pidfile at ${pidfile} is corrupt (got "${pidRaw}").`);
27258
27548
  }
27259
- const sidecarRaw = await readFile42(sidecar, "utf-8").catch(() => null);
27549
+ const sidecarRaw = await readFile43(sidecar, "utf-8").catch(() => null);
27260
27550
  if (sidecarRaw === null) {
27261
27551
  throw new Error(
27262
27552
  `No recording sidecar at ${sidecar}. The recording state is inconsistent \u2014 delete ${pidfile} and re-run --start.`
@@ -27321,7 +27611,7 @@ async function stopRecording() {
27321
27611
  // src/db/proof-db.ts
27322
27612
  init_paths();
27323
27613
  import Database5 from "better-sqlite3";
27324
- import { resolve as resolve66 } from "path";
27614
+ import { resolve as resolve67 } from "path";
27325
27615
  var db4 = null;
27326
27616
  var PROOF_SCHEMA_VERSION = "1";
27327
27617
  var SCHEMA_SQL4 = `
@@ -27341,7 +27631,7 @@ CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT);
27341
27631
  `;
27342
27632
  function initProofDb(dbPath) {
27343
27633
  if (db4) return db4;
27344
- const finalPath = dbPath ?? resolve66(syntaurRoot(), "syntaur.db");
27634
+ const finalPath = dbPath ?? resolve67(syntaurRoot(), "syntaur.db");
27345
27635
  db4 = new Database5(finalPath);
27346
27636
  db4.pragma("journal_mode = WAL");
27347
27637
  db4.exec(SCHEMA_SQL4);
@@ -27389,7 +27679,7 @@ function listArtifactsByAssignment(assignmentId) {
27389
27679
 
27390
27680
  // src/utils/transcribers/elevenlabs.ts
27391
27681
  import { spawn as spawn8 } from "child_process";
27392
- import { mkdtemp as mkdtemp5, readFile as readFile43, rm as rm11 } from "fs/promises";
27682
+ import { mkdtemp as mkdtemp5, readFile as readFile44, rm as rm11 } from "fs/promises";
27393
27683
  import { tmpdir as tmpdir6 } from "os";
27394
27684
  import { join as join13 } from "path";
27395
27685
  var SCRIBE_URL = "https://api.elevenlabs.io/v1/speech-to-text";
@@ -27453,7 +27743,7 @@ async function extractAudio(videoAbsPath, wavOut) {
27453
27743
  throw new TranscribeFfmpegError(`ffmpeg failed (exit ${result.code}): ${tail}`);
27454
27744
  }
27455
27745
  async function callScribe(wavPath, apiKey, opts) {
27456
- const audio = await readFile43(wavPath);
27746
+ const audio = await readFile44(wavPath);
27457
27747
  const form = new FormData();
27458
27748
  form.set("file", new Blob([new Uint8Array(audio)], { type: "audio/wav" }), "audio.wav");
27459
27749
  form.set("model_id", "scribe_v1");
@@ -27769,7 +28059,7 @@ async function captureCommand(target, options = {}) {
27769
28059
  });
27770
28060
  }
27771
28061
  if (options.file) {
27772
- const expanded = options.file.startsWith("~/") ? resolve67(process.env.HOME ?? "", options.file.slice(2)) : resolve67(options.file);
28062
+ const expanded = options.file.startsWith("~/") ? resolve68(process.env.HOME ?? "", options.file.slice(2)) : resolve68(options.file);
27773
28063
  if (!await fileExists(expanded)) {
27774
28064
  throw new Error(`--file does not exist: ${options.file}`);
27775
28065
  }
@@ -27810,7 +28100,7 @@ async function captureCommand(target, options = {}) {
27810
28100
  }
27811
28101
  initProofDb();
27812
28102
  const subdir = criterionIndex === null ? "untagged" : String(criterionIndex);
27813
- const destDir = resolve67(proofDir(resolved.assignmentDir), subdir);
28103
+ const destDir = resolve68(proofDir(resolved.assignmentDir), subdir);
27814
28104
  if (resolvedSource) await mkdir9(destDir, { recursive: true });
27815
28105
  const ext = resolvedSource ? extensionForKind(kind) : null;
27816
28106
  let id = null;
@@ -27819,7 +28109,7 @@ async function captureCommand(target, options = {}) {
27819
28109
  let lastErr = null;
27820
28110
  for (let attempt = 0; attempt < MAX_ID_RETRIES; attempt += 1) {
27821
28111
  const candidate = generateArtifactId();
27822
- const candidateAbsPath = resolvedSource && ext ? resolve67(destDir, `${candidate}.${ext}`) : null;
28112
+ const candidateAbsPath = resolvedSource && ext ? resolve68(destDir, `${candidate}.${ext}`) : null;
27823
28113
  const candidateRel = candidateAbsPath ? relative4(resolved.assignmentDir, candidateAbsPath) : null;
27824
28114
  try {
27825
28115
  insertArtifact({
@@ -27863,7 +28153,7 @@ async function captureCommand(target, options = {}) {
27863
28153
  }
27864
28154
  }
27865
28155
  if (options.transcribe && kind === "video" && absPath && id) {
27866
- const sidecarPath2 = resolve67(destDir, `${id}.transcript.md`);
28156
+ const sidecarPath2 = resolve68(destDir, `${id}.transcript.md`);
27867
28157
  if (existsSync5(sidecarPath2)) {
27868
28158
  console.warn(
27869
28159
  `transcript: ${sidecarPath2} already exists, skipping (delete to re-transcribe)`
@@ -27872,7 +28162,7 @@ async function captureCommand(target, options = {}) {
27872
28162
  try {
27873
28163
  const json = await getTranscriber().transcribe(absPath);
27874
28164
  const md = renderMarkdown(groupIntoPhrases(json.words ?? []));
27875
- await writeFile13(sidecarPath2, md, "utf8");
28165
+ await writeFile14(sidecarPath2, md, "utf8");
27876
28166
  console.log(`transcript: ${sidecarPath2}`);
27877
28167
  } catch (err2) {
27878
28168
  if (err2 instanceof TranscribeFfmpegMissingError) {
@@ -27895,7 +28185,7 @@ async function captureCommand(target, options = {}) {
27895
28185
  const tagSuffix = criterionIndex === null ? "untagged" : `criterion ${criterionIndex}`;
27896
28186
  console.log(`Captured artifact ${id} (${kind}) for ${ref} \u2014 ${tagSuffix}.`);
27897
28187
  if (relativeFilePath) {
27898
- console.log(` file: ${resolve67(resolved.assignmentDir, relativeFilePath)}`);
28188
+ console.log(` file: ${resolve68(resolved.assignmentDir, relativeFilePath)}`);
27899
28189
  }
27900
28190
  } catch (err2) {
27901
28191
  if (options.stop && kind === "video" && shelloutCleanup && resolvedSource) {
@@ -27918,8 +28208,8 @@ async function captureCommand(target, options = {}) {
27918
28208
 
27919
28209
  // src/commands/proof.ts
27920
28210
  import { Command as Command6 } from "commander";
27921
- import { readFile as readFile44, writeFile as writeFile14, rename as rename9, stat as stat9 } from "fs/promises";
27922
- import { resolve as resolve68, relative as relative5, isAbsolute as isAbsolute11, dirname as dirname19 } from "path";
28211
+ import { readFile as readFile45, writeFile as writeFile15, rename as rename9, stat as stat9 } from "fs/promises";
28212
+ import { resolve as resolve69, relative as relative5, isAbsolute as isAbsolute11, dirname as dirname19 } from "path";
27923
28213
  import { randomBytes as randomBytes4 } from "crypto";
27924
28214
 
27925
28215
  // src/utils/acceptance-criteria-parse.ts
@@ -28159,11 +28449,11 @@ function renderProofHtml(params2, inlineFiles = /* @__PURE__ */ new Map(), trans
28159
28449
 
28160
28450
  // src/commands/proof.ts
28161
28451
  async function readAssignmentMeta(assignmentDir) {
28162
- const path = resolve68(assignmentDir, "assignment.md");
28452
+ const path = resolve69(assignmentDir, "assignment.md");
28163
28453
  if (!await fileExists(path)) {
28164
28454
  return { title: "", body: "" };
28165
28455
  }
28166
- const content = await readFile44(path, "utf-8");
28456
+ const content = await readFile45(path, "utf-8");
28167
28457
  const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
28168
28458
  let title = "";
28169
28459
  if (fmMatch) {
@@ -28177,7 +28467,7 @@ async function readAssignmentMeta(assignmentDir) {
28177
28467
  }
28178
28468
  async function atomicWrite(destPath, content) {
28179
28469
  const tmp = `${destPath}.${randomBytes4(4).toString("hex")}.tmp`;
28180
- await writeFile14(tmp, content, "utf-8");
28470
+ await writeFile15(tmp, content, "utf-8");
28181
28471
  await rename9(tmp, destPath);
28182
28472
  }
28183
28473
  function isWithin(root, target) {
@@ -28210,7 +28500,7 @@ async function loadInlineFiles(rows, assignmentDir) {
28210
28500
  for (const r of rows) {
28211
28501
  if (!r.file_path) continue;
28212
28502
  if (r.kind !== "http" && r.kind !== "text") continue;
28213
- const abs = resolve68(assignmentDir, r.file_path);
28503
+ const abs = resolve69(assignmentDir, r.file_path);
28214
28504
  if (!isWithin(proofRoot, abs)) {
28215
28505
  out.set(r.file_path, null);
28216
28506
  continue;
@@ -28225,7 +28515,7 @@ async function loadInlineFiles(rows, assignmentDir) {
28225
28515
  continue;
28226
28516
  }
28227
28517
  try {
28228
- out.set(r.file_path, await readFile44(abs, "utf-8"));
28518
+ out.set(r.file_path, await readFile45(abs, "utf-8"));
28229
28519
  } catch {
28230
28520
  out.set(r.file_path, null);
28231
28521
  }
@@ -28237,14 +28527,14 @@ async function loadTranscriptSidecars(rows, assignmentDir) {
28237
28527
  const proofRoot = proofDir(assignmentDir);
28238
28528
  for (const r of rows) {
28239
28529
  if (r.kind !== "video" || !r.file_path) continue;
28240
- const videoAbs = resolve68(assignmentDir, r.file_path);
28241
- const sidecar = resolve68(dirname19(videoAbs), `${r.id}.transcript.md`);
28530
+ const videoAbs = resolve69(assignmentDir, r.file_path);
28531
+ const sidecar = resolve69(dirname19(videoAbs), `${r.id}.transcript.md`);
28242
28532
  if (!isWithin(proofRoot, sidecar)) continue;
28243
28533
  if (!await fileExists(sidecar)) continue;
28244
28534
  const st = await stat9(sidecar);
28245
28535
  if (st.size > INLINE_TEXT_LIMIT_BYTES) continue;
28246
28536
  try {
28247
- out.set(r.id, await readFile44(sidecar, "utf-8"));
28537
+ out.set(r.id, await readFile45(sidecar, "utf-8"));
28248
28538
  } catch {
28249
28539
  }
28250
28540
  }
@@ -28278,8 +28568,8 @@ async function proofBuildCommand(target, options = {}) {
28278
28568
  };
28279
28569
  const md = renderProofMarkdown(renderParams);
28280
28570
  const html = renderProofHtml(renderParams, inlineFiles, transcriptSidecars);
28281
- const mdPath = resolve68(resolved.assignmentDir, "proof.md");
28282
- const htmlPath = resolve68(resolved.assignmentDir, "proof.html");
28571
+ const mdPath = resolve69(resolved.assignmentDir, "proof.md");
28572
+ const htmlPath = resolve69(resolved.assignmentDir, "proof.html");
28283
28573
  await atomicWrite(mdPath, md);
28284
28574
  await atomicWrite(htmlPath, html);
28285
28575
  console.log(`Wrote ${htmlPath}`);
@@ -28944,7 +29234,7 @@ async function runCcusage(opts = {}) {
28944
29234
  };
28945
29235
  }
28946
29236
  function runOnce(binary, args, env, timeoutMs, maxOutputBytes) {
28947
- return new Promise((resolve78) => {
29237
+ return new Promise((resolve79) => {
28948
29238
  const child = spawn9(binary, args, {
28949
29239
  env: env ?? process.env,
28950
29240
  stdio: ["ignore", "pipe", "pipe"]
@@ -28958,7 +29248,7 @@ function runOnce(binary, args, env, timeoutMs, maxOutputBytes) {
28958
29248
  if (settled) return;
28959
29249
  settled = true;
28960
29250
  clearTimeout(timer2);
28961
- resolve78(result);
29251
+ resolve79(result);
28962
29252
  };
28963
29253
  const timer2 = setTimeout(() => {
28964
29254
  timedOut = true;
@@ -29480,8 +29770,8 @@ init_slug();
29480
29770
  init_timestamp();
29481
29771
  init_assignment_resolver();
29482
29772
  init_assignment_todos();
29483
- import { resolve as resolve69 } from "path";
29484
- import { readFile as readFile45 } from "fs/promises";
29773
+ import { resolve as resolve70 } from "path";
29774
+ import { readFile as readFile46 } from "fs/promises";
29485
29775
  async function requestCommand(target, text, options = {}) {
29486
29776
  if (!text || !text.trim()) {
29487
29777
  throw new Error("Request text cannot be empty.");
@@ -29497,7 +29787,7 @@ async function requestCommand(target, text, options = {}) {
29497
29787
  if (!isValidSlug(target)) {
29498
29788
  throw new Error(`Invalid assignment slug "${target}".`);
29499
29789
  }
29500
- assignmentDir = resolve69(baseDir, options.project, "assignments", target);
29790
+ assignmentDir = resolve70(baseDir, options.project, "assignments", target);
29501
29791
  targetRef = target;
29502
29792
  } else {
29503
29793
  const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), target);
@@ -29507,12 +29797,12 @@ async function requestCommand(target, text, options = {}) {
29507
29797
  assignmentDir = resolved.assignmentDir;
29508
29798
  targetRef = resolved.standalone ? resolved.id : resolved.assignmentSlug;
29509
29799
  }
29510
- const assignmentMdPath2 = resolve69(assignmentDir, "assignment.md");
29800
+ const assignmentMdPath2 = resolve70(assignmentDir, "assignment.md");
29511
29801
  if (!await fileExists(assignmentMdPath2)) {
29512
29802
  throw new Error(`assignment.md not found at ${assignmentMdPath2}`);
29513
29803
  }
29514
29804
  const source = options.from ?? process.env.SYNTAUR_ASSIGNMENT ?? "unknown";
29515
- let content = await readFile45(assignmentMdPath2, "utf-8");
29805
+ let content = await readFile46(assignmentMdPath2, "utf-8");
29516
29806
  content = appendTodosToAssignmentBody(content, [
29517
29807
  { description: `${text.trim()} (from: ${source})` }
29518
29808
  ]);
@@ -29525,13 +29815,13 @@ async function requestCommand(target, text, options = {}) {
29525
29815
  init_fs();
29526
29816
  init_paths();
29527
29817
  import { Command as Command9 } from "commander";
29528
- import { readFile as readFile46, readdir as readdir25 } from "fs/promises";
29529
- import { resolve as resolve70 } from "path";
29818
+ import { readFile as readFile47, readdir as readdir25 } from "fs/promises";
29819
+ import { resolve as resolve71 } from "path";
29530
29820
  async function readContextAssignmentDir(cwd) {
29531
- const path = resolve70(cwd, ".syntaur", "context.json");
29821
+ const path = resolve71(cwd, ".syntaur", "context.json");
29532
29822
  if (!await fileExists(path)) return null;
29533
29823
  try {
29534
- const raw = await readFile46(path, "utf-8");
29824
+ const raw = await readFile47(path, "utf-8");
29535
29825
  const ctx = JSON.parse(raw);
29536
29826
  if (typeof ctx.assignmentDir === "string" && ctx.assignmentDir.length > 0) {
29537
29827
  return ctx.assignmentDir;
@@ -29545,9 +29835,9 @@ async function resolveAssignmentDir(opts) {
29545
29835
  const cwd = opts.cwd ?? process.cwd();
29546
29836
  if (opts.assignment) {
29547
29837
  if (opts.project) {
29548
- return resolve70(defaultProjectDir(), opts.project, "assignments", opts.assignment);
29838
+ return resolve71(defaultProjectDir(), opts.project, "assignments", opts.assignment);
29549
29839
  }
29550
- return resolve70(assignmentsDir(), opts.assignment);
29840
+ return resolve71(assignmentsDir(), opts.assignment);
29551
29841
  }
29552
29842
  const fromCtx = await readContextAssignmentDir(cwd);
29553
29843
  if (fromCtx) return fromCtx;
@@ -29690,7 +29980,7 @@ async function runPlanVersion(options) {
29690
29980
  if (!await fileExists(assignmentDir)) {
29691
29981
  throw new Error(`Assignment directory does not exist: ${assignmentDir}`);
29692
29982
  }
29693
- const assignmentMdPath2 = resolve70(assignmentDir, "assignment.md");
29983
+ const assignmentMdPath2 = resolve71(assignmentDir, "assignment.md");
29694
29984
  if (!await fileExists(assignmentMdPath2)) {
29695
29985
  throw new Error(`Missing assignment.md at: ${assignmentMdPath2}`);
29696
29986
  }
@@ -29702,15 +29992,15 @@ async function runPlanVersion(options) {
29702
29992
  }
29703
29993
  const current = planFiles[planFiles.length - 1];
29704
29994
  const next = nextPlanFileName(current.version);
29705
- const newPath = resolve70(assignmentDir, next.fileName);
29995
+ const newPath = resolve71(assignmentDir, next.fileName);
29706
29996
  if (await fileExists(newPath) && !options.force) {
29707
29997
  throw new Error(`${next.fileName} already exists. Use --force to overwrite.`);
29708
29998
  }
29709
- const assignmentMd = await readFile46(assignmentMdPath2, "utf-8");
29999
+ const assignmentMd = await readFile47(assignmentMdPath2, "utf-8");
29710
30000
  const slugMatch = assignmentMd.match(/^slug:\s*(.+?)\s*$/m);
29711
30001
  const slug = slugMatch ? slugMatch[1].trim() : assignmentDir.split("/").pop() ?? "";
29712
- const oldPlanPath = resolve70(assignmentDir, current.fileName);
29713
- const oldPlanContent = await readFile46(oldPlanPath, "utf-8");
30002
+ const oldPlanPath = resolve71(assignmentDir, current.fileName);
30003
+ const oldPlanContent = await readFile47(oldPlanPath, "utf-8");
29714
30004
  const oldBody = oldPlanContent.replace(/^---[\s\S]*?\n---\n?/, "");
29715
30005
  const carriedTodos = extractUncheckedTodos(oldBody);
29716
30006
  const stub = buildNewPlanStub({
@@ -29747,26 +30037,26 @@ planCommand.command("version").description(
29747
30037
  // src/commands/session.ts
29748
30038
  init_fs();
29749
30039
  import { Command as Command10 } from "commander";
29750
- import { readFile as readFile47, readdir as readdir26, stat as stat11 } from "fs/promises";
29751
- import { resolve as resolve71 } from "path";
30040
+ import { readFile as readFile48, readdir as readdir26, stat as stat11 } from "fs/promises";
30041
+ import { resolve as resolve72 } from "path";
29752
30042
  async function readContext(cwd) {
29753
- const path = resolve71(cwd, ".syntaur", "context.json");
30043
+ const path = resolve72(cwd, ".syntaur", "context.json");
29754
30044
  if (!await fileExists(path)) return null;
29755
30045
  try {
29756
- const raw = await readFile47(path, "utf-8");
30046
+ const raw = await readFile48(path, "utf-8");
29757
30047
  return JSON.parse(raw);
29758
30048
  } catch {
29759
30049
  return null;
29760
30050
  }
29761
30051
  }
29762
30052
  async function findLatestSessionSummary(assignmentDir) {
29763
- const sessionsRoot = resolve71(assignmentDir, "sessions");
30053
+ const sessionsRoot = resolve72(assignmentDir, "sessions");
29764
30054
  if (!await fileExists(sessionsRoot)) return null;
29765
30055
  const entries = await readdir26(sessionsRoot, { withFileTypes: true });
29766
30056
  let best = null;
29767
30057
  for (const entry of entries) {
29768
30058
  if (!entry.isDirectory()) continue;
29769
- const summaryPath = resolve71(sessionsRoot, entry.name, "summary.md");
30059
+ const summaryPath = resolve72(sessionsRoot, entry.name, "summary.md");
29770
30060
  if (!await fileExists(summaryPath)) continue;
29771
30061
  const st = await stat11(summaryPath);
29772
30062
  if (best === null || st.mtime.getTime() > best.mtime.getTime()) {
@@ -29776,9 +30066,9 @@ async function findLatestSessionSummary(assignmentDir) {
29776
30066
  return best;
29777
30067
  }
29778
30068
  async function findOpenHandoff(assignmentDir) {
29779
- const handoffPath = resolve71(assignmentDir, "handoff.md");
30069
+ const handoffPath = resolve72(assignmentDir, "handoff.md");
29780
30070
  if (!await fileExists(handoffPath)) return null;
29781
- const content = await readFile47(handoffPath, "utf-8");
30071
+ const content = await readFile48(handoffPath, "utf-8");
29782
30072
  const body = content.replace(/^---[\s\S]*?\n---\n?/, "").trim();
29783
30073
  if (body.length === 0) return null;
29784
30074
  if (/^<!--[\s\S]*-->$/.test(body)) return null;
@@ -29886,13 +30176,13 @@ init_git_worktree();
29886
30176
  init_fs();
29887
30177
  init_paths();
29888
30178
  import { Command as Command11 } from "commander";
29889
- import { readFile as readFile48 } from "fs/promises";
29890
- import { resolve as resolve72 } from "path";
30179
+ import { readFile as readFile49 } from "fs/promises";
30180
+ import { resolve as resolve73 } from "path";
29891
30181
  async function readContext2(cwd) {
29892
- const path = resolve72(cwd, ".syntaur", "context.json");
30182
+ const path = resolve73(cwd, ".syntaur", "context.json");
29893
30183
  if (!await fileExists(path)) return null;
29894
30184
  try {
29895
- return JSON.parse(await readFile48(path, "utf-8"));
30185
+ return JSON.parse(await readFile49(path, "utf-8"));
29896
30186
  } catch {
29897
30187
  return null;
29898
30188
  }
@@ -29900,7 +30190,7 @@ async function readContext2(cwd) {
29900
30190
  async function resolveAssignmentPath2(opts) {
29901
30191
  if (opts.assignment) {
29902
30192
  if (opts.project) {
29903
- return resolve72(
30193
+ return resolve73(
29904
30194
  defaultProjectDir(),
29905
30195
  opts.project,
29906
30196
  "assignments",
@@ -29908,10 +30198,10 @@ async function resolveAssignmentPath2(opts) {
29908
30198
  "assignment.md"
29909
30199
  );
29910
30200
  }
29911
- return resolve72(assignmentsDir(), opts.assignment, "assignment.md");
30201
+ return resolve73(assignmentsDir(), opts.assignment, "assignment.md");
29912
30202
  }
29913
30203
  const ctx = await readContext2(opts.cwd);
29914
- if (ctx?.assignmentDir) return resolve72(ctx.assignmentDir, "assignment.md");
30204
+ if (ctx?.assignmentDir) return resolve73(ctx.assignmentDir, "assignment.md");
29915
30205
  throw new Error(
29916
30206
  "No active assignment. Pass --assignment <slug> [--project <slug>] or run from a workspace with .syntaur/context.json."
29917
30207
  );
@@ -29922,7 +30212,7 @@ async function runWorktreeCreate(options, cwd = process.cwd()) {
29922
30212
  }
29923
30213
  const repository = options.repository ?? cwd;
29924
30214
  const parentBranch = options.parentBranch ?? "main";
29925
- const worktreePath = options.worktreePath ?? resolve72(repository, ".worktrees", options.branch);
30215
+ const worktreePath = options.worktreePath ?? resolve73(repository, ".worktrees", options.branch);
29926
30216
  const assignmentPath = await resolveAssignmentPath2({
29927
30217
  assignment: options.assignment,
29928
30218
  project: options.project,
@@ -29959,13 +30249,13 @@ init_paths();
29959
30249
  init_fs();
29960
30250
  init_slug();
29961
30251
  import { Command as Command12 } from "commander";
29962
- import { resolve as resolve74 } from "path";
30252
+ import { resolve as resolve75 } from "path";
29963
30253
 
29964
30254
  // src/utils/project-indexes.ts
29965
30255
  init_parser();
29966
30256
  init_fs();
29967
- import { readdir as readdir27, readFile as readFile49 } from "fs/promises";
29968
- import { resolve as resolve73 } from "path";
30257
+ import { readdir as readdir27, readFile as readFile50 } from "fs/promises";
30258
+ import { resolve as resolve74 } from "path";
29969
30259
  function nowIso3() {
29970
30260
  return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
29971
30261
  }
@@ -29984,7 +30274,7 @@ function joinList(items) {
29984
30274
  return items.length === 0 ? "\u2014" : items.map(escapeCell).join(", ");
29985
30275
  }
29986
30276
  async function rebuildResourcesIndex(projectDir) {
29987
- const dir = resolve73(projectDir, "resources");
30277
+ const dir = resolve74(projectDir, "resources");
29988
30278
  await ensureDir(dir);
29989
30279
  const files = await listSlugFiles(dir);
29990
30280
  const slug = readProjectSlug(projectDir);
@@ -30000,7 +30290,7 @@ async function rebuildResourcesIndex(projectDir) {
30000
30290
  lines.push("| Name | Category | Source | Related Assignments | Updated |");
30001
30291
  lines.push("|------|----------|--------|---------------------|---------|");
30002
30292
  for (const fileName of files) {
30003
- const content = await readFile49(resolve73(dir, fileName), "utf-8");
30293
+ const content = await readFile50(resolve74(dir, fileName), "utf-8");
30004
30294
  const parsed = parseResource(content);
30005
30295
  const slugBase = fileName.replace(/\.md$/, "");
30006
30296
  const name = parsed.name || slugBase;
@@ -30010,12 +30300,12 @@ async function rebuildResourcesIndex(projectDir) {
30010
30300
  );
30011
30301
  }
30012
30302
  lines.push("");
30013
- const indexPath = resolve73(dir, "_index.md");
30303
+ const indexPath = resolve74(dir, "_index.md");
30014
30304
  await writeFileForce(indexPath, lines.join("\n"));
30015
30305
  return { total: files.length, path: indexPath };
30016
30306
  }
30017
30307
  async function rebuildMemoriesIndex(projectDir) {
30018
- const dir = resolve73(projectDir, "memories");
30308
+ const dir = resolve74(projectDir, "memories");
30019
30309
  await ensureDir(dir);
30020
30310
  const files = await listSlugFiles(dir);
30021
30311
  const slug = readProjectSlug(projectDir);
@@ -30031,7 +30321,7 @@ async function rebuildMemoriesIndex(projectDir) {
30031
30321
  lines.push("| Name | Source | Scope | Source Assignment | Updated |");
30032
30322
  lines.push("|------|--------|-------|-------------------|---------|");
30033
30323
  for (const fileName of files) {
30034
- const content = await readFile49(resolve73(dir, fileName), "utf-8");
30324
+ const content = await readFile50(resolve74(dir, fileName), "utf-8");
30035
30325
  const parsed = parseMemory(content);
30036
30326
  const slugBase = fileName.replace(/\.md$/, "");
30037
30327
  const name = parsed.name || slugBase;
@@ -30041,7 +30331,7 @@ async function rebuildMemoriesIndex(projectDir) {
30041
30331
  );
30042
30332
  }
30043
30333
  lines.push("");
30044
- const indexPath = resolve73(dir, "_index.md");
30334
+ const indexPath = resolve74(dir, "_index.md");
30045
30335
  await writeFileForce(indexPath, lines.join("\n"));
30046
30336
  return { total: files.length, path: indexPath };
30047
30337
  }
@@ -30079,8 +30369,8 @@ async function runResourceAdd(options) {
30079
30369
  if (!isValidSlug(options.project)) {
30080
30370
  throw new Error(`Invalid project slug: "${options.project}".`);
30081
30371
  }
30082
- const projectDir = resolve74(defaultProjectDir(), options.project);
30083
- if (!await fileExists(resolve74(projectDir, "project.md"))) {
30372
+ const projectDir = resolve75(defaultProjectDir(), options.project);
30373
+ if (!await fileExists(resolve75(projectDir, "project.md"))) {
30084
30374
  throw new Error(`Project "${options.project}" not found at ${projectDir}.`);
30085
30375
  }
30086
30376
  if (!options.name) throw new Error("--name is required.");
@@ -30089,7 +30379,7 @@ async function runResourceAdd(options) {
30089
30379
  if (!isValidSlug(slug)) {
30090
30380
  throw new Error(`Invalid resource slug: "${slug}".`);
30091
30381
  }
30092
- const filePath = resolve74(projectDir, "resources", `${slug}.md`);
30382
+ const filePath = resolve75(projectDir, "resources", `${slug}.md`);
30093
30383
  if (await fileExists(filePath) && !options.force) {
30094
30384
  throw new Error(
30095
30385
  `Resource "${slug}" already exists at ${filePath}. Use --force to overwrite.`
@@ -30124,7 +30414,7 @@ init_paths();
30124
30414
  init_fs();
30125
30415
  init_slug();
30126
30416
  import { Command as Command13 } from "commander";
30127
- import { resolve as resolve75 } from "path";
30417
+ import { resolve as resolve76 } from "path";
30128
30418
  function nowIso5() {
30129
30419
  return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
30130
30420
  }
@@ -30159,8 +30449,8 @@ async function runMemoryAdd(options) {
30159
30449
  if (!isValidSlug(options.project)) {
30160
30450
  throw new Error(`Invalid project slug: "${options.project}".`);
30161
30451
  }
30162
- const projectDir = resolve75(defaultProjectDir(), options.project);
30163
- if (!await fileExists(resolve75(projectDir, "project.md"))) {
30452
+ const projectDir = resolve76(defaultProjectDir(), options.project);
30453
+ if (!await fileExists(resolve76(projectDir, "project.md"))) {
30164
30454
  throw new Error(`Project "${options.project}" not found at ${projectDir}.`);
30165
30455
  }
30166
30456
  if (!options.name) throw new Error("--name is required.");
@@ -30169,7 +30459,7 @@ async function runMemoryAdd(options) {
30169
30459
  if (!isValidSlug(slug)) {
30170
30460
  throw new Error(`Invalid memory slug: "${slug}".`);
30171
30461
  }
30172
- const filePath = resolve75(projectDir, "memories", `${slug}.md`);
30462
+ const filePath = resolve76(projectDir, "memories", `${slug}.md`);
30173
30463
  if (await fileExists(filePath) && !options.force) {
30174
30464
  throw new Error(
30175
30465
  `Memory "${slug}" already exists at ${filePath}. Use --force to overwrite.`
@@ -30206,8 +30496,8 @@ init_paths();
30206
30496
  init_fs();
30207
30497
  init_frontmatter();
30208
30498
  import { Command as Command14 } from "commander";
30209
- import { readFile as readFile50 } from "fs/promises";
30210
- import { resolve as resolve76 } from "path";
30499
+ import { readFile as readFile51 } from "fs/promises";
30500
+ import { resolve as resolve77 } from "path";
30211
30501
  var AGE_PATTERN = /^(\d+)([dhwm])$/i;
30212
30502
  function parseAgeToCutoff(age) {
30213
30503
  const match = age.match(AGE_PATTERN);
@@ -30226,7 +30516,7 @@ function parseAgeToCutoff(age) {
30226
30516
  }
30227
30517
  function assignmentMdPath(item) {
30228
30518
  if (item.projectSlug) {
30229
- return resolve76(
30519
+ return resolve77(
30230
30520
  defaultProjectDir(),
30231
30521
  item.projectSlug,
30232
30522
  "assignments",
@@ -30234,13 +30524,13 @@ function assignmentMdPath(item) {
30234
30524
  "assignment.md"
30235
30525
  );
30236
30526
  }
30237
- return resolve76(assignmentsDir(), item.id, "assignment.md");
30527
+ return resolve77(assignmentsDir(), item.id, "assignment.md");
30238
30528
  }
30239
30529
  async function loadTags(item) {
30240
30530
  const path = assignmentMdPath(item);
30241
30531
  if (!await fileExists(path)) return [];
30242
30532
  try {
30243
- const content = await readFile50(path, "utf-8");
30533
+ const content = await readFile51(path, "utf-8");
30244
30534
  return parseAssignmentFrontmatter(content).tags;
30245
30535
  } catch {
30246
30536
  return [];
@@ -30249,7 +30539,8 @@ async function loadTags(item) {
30249
30539
  async function runLs(options) {
30250
30540
  const board = await listAssignmentsBoard(
30251
30541
  defaultProjectDir(),
30252
- assignmentsDir()
30542
+ assignmentsDir(),
30543
+ { archived: options.archived ? "only" : "exclude" }
30253
30544
  );
30254
30545
  let items = board.assignments;
30255
30546
  if (options.status) {
@@ -30302,7 +30593,7 @@ function renderTable2(items) {
30302
30593
  }
30303
30594
  var lsCommand = new Command14("ls").description(
30304
30595
  "List assignments across all projects with optional filters by status, project, tag, or age."
30305
- ).option("--status <list>", "Comma-separated status filter (e.g. pending,in_progress)").option("--project <slug>", "Filter to one project").option("--tag <list>", "Comma-separated tag filter (assignment must have ALL tags)").option("--age <duration>", "Only include assignments updated within duration (e.g. 7d, 24h, 2w, 1m)").option("--json", "Emit JSON instead of a table").action(async (options) => {
30596
+ ).option("--status <list>", "Comma-separated status filter (e.g. pending,in_progress)").option("--project <slug>", "Filter to one project").option("--tag <list>", "Comma-separated tag filter (assignment must have ALL tags)").option("--age <duration>", "Only include assignments updated within duration (e.g. 7d, 24h, 2w, 1m)").option("--archived", "List only archived assignments (hidden from the default view)").option("--json", "Emit JSON instead of a table").action(async (options) => {
30306
30597
  try {
30307
30598
  const { items } = await runLs(options);
30308
30599
  if (options.json) {
@@ -30358,20 +30649,20 @@ async function getDefaultCommandName() {
30358
30649
  init_paths();
30359
30650
  init_fs();
30360
30651
  import { fileURLToPath as fileURLToPath10 } from "url";
30361
- import { readFile as readFile52 } from "fs/promises";
30362
- import { dirname as dirname21, join as join16, resolve as resolve77 } from "path";
30652
+ import { readFile as readFile53 } from "fs/promises";
30653
+ import { dirname as dirname21, join as join16, resolve as resolve78 } from "path";
30363
30654
  import { spawn as spawn10 } from "child_process";
30364
30655
  import { createInterface as createInterface2 } from "readline/promises";
30365
30656
 
30366
30657
  // src/utils/version.ts
30367
30658
  import { fileURLToPath as fileURLToPath9 } from "url";
30368
- import { readFile as readFile51 } from "fs/promises";
30659
+ import { readFile as readFile52 } from "fs/promises";
30369
30660
  import { dirname as dirname20, join as join15 } from "path";
30370
30661
  async function readPackageVersion(scriptUrl) {
30371
30662
  try {
30372
30663
  const scriptPath = fileURLToPath9(scriptUrl);
30373
30664
  const pkgRoot = dirname20(dirname20(scriptPath));
30374
- const raw = await readFile51(join15(pkgRoot, "package.json"), "utf-8");
30665
+ const raw = await readFile52(join15(pkgRoot, "package.json"), "utf-8");
30375
30666
  const parsed = JSON.parse(raw);
30376
30667
  return typeof parsed.version === "string" ? parsed.version : null;
30377
30668
  } catch {
@@ -30380,7 +30671,7 @@ async function readPackageVersion(scriptUrl) {
30380
30671
  }
30381
30672
 
30382
30673
  // src/utils/npx-prompt.ts
30383
- var STATE_FILE = resolve77(syntaurRoot(), "npx-install.json");
30674
+ var STATE_FILE = resolve78(syntaurRoot(), "npx-install.json");
30384
30675
  var META_ARGS2 = /* @__PURE__ */ new Set(["-h", "--help", "-V", "--version", "help"]);
30385
30676
  var GLOBAL_VERSION_TIMEOUT_MS = 2e3;
30386
30677
  function isRunningViaNpx(scriptUrl) {
@@ -30401,7 +30692,7 @@ function isRunningViaNpx(scriptUrl) {
30401
30692
  async function readState() {
30402
30693
  if (!await fileExists(STATE_FILE)) return null;
30403
30694
  try {
30404
- const raw = await readFile52(STATE_FILE, "utf-8");
30695
+ const raw = await readFile53(STATE_FILE, "utf-8");
30405
30696
  return JSON.parse(raw);
30406
30697
  } catch {
30407
30698
  return null;
@@ -30460,7 +30751,7 @@ async function readGlobalVersion() {
30460
30751
  try {
30461
30752
  const manifestPath = join16(rootPath, "syntaur", "package.json");
30462
30753
  if (!await fileExists(manifestPath)) return null;
30463
- const raw = await readFile52(manifestPath, "utf-8");
30754
+ const raw = await readFile53(manifestPath, "utf-8");
30464
30755
  const parsed = JSON.parse(raw);
30465
30756
  return typeof parsed.version === "string" ? parsed.version : null;
30466
30757
  } catch {
@@ -30703,6 +30994,22 @@ program.command("start").description("Transition an assignment to in_progress").
30703
30994
  process.exit(1);
30704
30995
  }
30705
30996
  });
30997
+ program.command("archive").description("Archive an assignment or a project (hidden from normal views; restorable)").argument("<target>", "Assignment slug/UUID, or a project slug").option("--project <slug>", "Resolve <target> as an assignment within this project").option("--reason <text>", "Optional reason recorded with the archive").option("--dir <path>", "Override default project directory").action(async (target, options) => {
30998
+ try {
30999
+ await archiveCommand(target, options);
31000
+ } catch (error) {
31001
+ console.error("Error:", error instanceof Error ? error.message : String(error));
31002
+ process.exit(1);
31003
+ }
31004
+ });
31005
+ program.command("restore").description("Restore an archived assignment or project (preserves prior status)").argument("<target>", "Assignment slug/UUID, or a project slug").option("--project <slug>", "Resolve <target> as an assignment within this project").option("--dir <path>", "Override default project directory").action(async (target, options) => {
31006
+ try {
31007
+ await restoreCommand(target, options);
31008
+ } catch (error) {
31009
+ console.error("Error:", error instanceof Error ? error.message : String(error));
31010
+ process.exit(1);
31011
+ }
31012
+ });
30706
31013
  program.command("shape").description("Transition an assignment from draft to ready_for_planning").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--agent <name>", "Agent name (sets assignee if not already set)").option("--dir <path>", "Override default project directory").action(async (assignment, options) => {
30707
31014
  try {
30708
31015
  await shapeCommand(assignment, options);