syntaur 0.26.0 → 0.27.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 (62) hide show
  1. package/dashboard/dist/assets/{_basePickBy-jPItyrQO.js → _basePickBy-DPBuiT9A.js} +1 -1
  2. package/dashboard/dist/assets/{_baseUniq-pEwUwurC.js → _baseUniq-B5Q4dkW3.js} +1 -1
  3. package/dashboard/dist/assets/{arc-ZZtp507S.js → arc-Bp71QC_v.js} +1 -1
  4. package/dashboard/dist/assets/{architectureDiagram-2XIMDMQ5-BNUerPqd.js → architectureDiagram-2XIMDMQ5-CWHBISZ5.js} +1 -1
  5. package/dashboard/dist/assets/{blockDiagram-WCTKOSBZ-CQyovXFv.js → blockDiagram-WCTKOSBZ-D0txIHgi.js} +1 -1
  6. package/dashboard/dist/assets/{c4Diagram-IC4MRINW-wNQ6EHeF.js → c4Diagram-IC4MRINW-D_Hpnc38.js} +1 -1
  7. package/dashboard/dist/assets/channel-D41AslDq.js +1 -0
  8. package/dashboard/dist/assets/{chunk-4BX2VUAB-ZaueC30R.js → chunk-4BX2VUAB-D0A_A8qn.js} +1 -1
  9. package/dashboard/dist/assets/{chunk-55IACEB6-BjsRB0t8.js → chunk-55IACEB6-DuK8QvrD.js} +1 -1
  10. package/dashboard/dist/assets/{chunk-FMBD7UC4-BHuSr-Tl.js → chunk-FMBD7UC4-B5WfIDS6.js} +1 -1
  11. package/dashboard/dist/assets/{chunk-JSJVCQXG-SHNJA0es.js → chunk-JSJVCQXG-D3jB_ZJP.js} +1 -1
  12. package/dashboard/dist/assets/{chunk-KX2RTZJC-JXFPjeo4.js → chunk-KX2RTZJC-DtxN1mOD.js} +1 -1
  13. package/dashboard/dist/assets/{chunk-NQ4KR5QH-BiJqWT0B.js → chunk-NQ4KR5QH-4fQpgivN.js} +1 -1
  14. package/dashboard/dist/assets/{chunk-QZHKN3VN-DoXWBqP2.js → chunk-QZHKN3VN-BOf9TZCT.js} +1 -1
  15. package/dashboard/dist/assets/{chunk-WL4C6EOR-Dqtf_5it.js → chunk-WL4C6EOR-D9HeEPWL.js} +1 -1
  16. package/dashboard/dist/assets/classDiagram-VBA2DB6C-BnKy62Yt.js +1 -0
  17. package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-BnKy62Yt.js +1 -0
  18. package/dashboard/dist/assets/clone-Cz7h9axV.js +1 -0
  19. package/dashboard/dist/assets/{cose-bilkent-S5V4N54A-Cr6bkSKq.js → cose-bilkent-S5V4N54A-CpzWcyB7.js} +1 -1
  20. package/dashboard/dist/assets/{dagre-KLK3FWXG-oXpXFuJQ.js → dagre-KLK3FWXG-CC9-omFF.js} +1 -1
  21. package/dashboard/dist/assets/{diagram-E7M64L7V-Bq_xdDbg.js → diagram-E7M64L7V-q_F9KKPz.js} +1 -1
  22. package/dashboard/dist/assets/{diagram-IFDJBPK2-N7Er4Dui.js → diagram-IFDJBPK2-CbYvNpQB.js} +1 -1
  23. package/dashboard/dist/assets/{diagram-P4PSJMXO-BU0Zm2Fn.js → diagram-P4PSJMXO-q8XUUKRC.js} +1 -1
  24. package/dashboard/dist/assets/{erDiagram-INFDFZHY-BSgZb5me.js → erDiagram-INFDFZHY-Q-oL35fO.js} +1 -1
  25. package/dashboard/dist/assets/{flowDiagram-PKNHOUZH-Bn7pEu0U.js → flowDiagram-PKNHOUZH-Cptj-2yF.js} +1 -1
  26. package/dashboard/dist/assets/{ganttDiagram-A5KZAMGK-B8Xq9tyM.js → ganttDiagram-A5KZAMGK-BYmgXBad.js} +1 -1
  27. package/dashboard/dist/assets/{gitGraphDiagram-K3NZZRJ6-BoLUjYDa.js → gitGraphDiagram-K3NZZRJ6-DHF3w-Cn.js} +1 -1
  28. package/dashboard/dist/assets/{graph-Pde_ni_y.js → graph-Br4uG9xg.js} +1 -1
  29. package/dashboard/dist/assets/index-Ds1-e_jv.css +1 -0
  30. package/dashboard/dist/assets/index-dyJ_mu3x.js +555 -0
  31. package/dashboard/dist/assets/{infoDiagram-LFFYTUFH-Brv2khjP.js → infoDiagram-LFFYTUFH-Ckb3YLUI.js} +1 -1
  32. package/dashboard/dist/assets/{ishikawaDiagram-PHBUUO56-D5hxQ0Ke.js → ishikawaDiagram-PHBUUO56-DSXXm4hL.js} +1 -1
  33. package/dashboard/dist/assets/{journeyDiagram-4ABVD52K-CUevv5jA.js → journeyDiagram-4ABVD52K-D4JJ4wn_.js} +1 -1
  34. package/dashboard/dist/assets/{kanban-definition-K7BYSVSG-Cf6XyrAC.js → kanban-definition-K7BYSVSG-DZeWPcIi.js} +1 -1
  35. package/dashboard/dist/assets/{layout-Bc8RP2w3.js → layout-DU5mcBKh.js} +1 -1
  36. package/dashboard/dist/assets/{linear-Cd_XUbl7.js → linear-h7AvdT63.js} +1 -1
  37. package/dashboard/dist/assets/{mermaid.core-Bx8MuMEM.js → mermaid.core-DIOnVuDB.js} +4 -4
  38. package/dashboard/dist/assets/{mindmap-definition-YRQLILUH-D_4Pl3Mu.js → mindmap-definition-YRQLILUH-BVSORv6W.js} +1 -1
  39. package/dashboard/dist/assets/{pieDiagram-SKSYHLDU-DRVbjwxO.js → pieDiagram-SKSYHLDU-BEdO084J.js} +1 -1
  40. package/dashboard/dist/assets/{quadrantDiagram-337W2JSQ-BciLlBMH.js → quadrantDiagram-337W2JSQ-3Dc5mQ7q.js} +1 -1
  41. package/dashboard/dist/assets/{requirementDiagram-Z7DCOOCP-Bprwe8Z2.js → requirementDiagram-Z7DCOOCP-eu-8doSY.js} +1 -1
  42. package/dashboard/dist/assets/{sankeyDiagram-WA2Y5GQK-DI0t8Uiu.js → sankeyDiagram-WA2Y5GQK-jA292hzv.js} +1 -1
  43. package/dashboard/dist/assets/{sequenceDiagram-2WXFIKYE-CpCLCs5J.js → sequenceDiagram-2WXFIKYE-et31a6Tg.js} +1 -1
  44. package/dashboard/dist/assets/{stateDiagram-RAJIS63D-V-1VCApT.js → stateDiagram-RAJIS63D-D6MtTWaR.js} +1 -1
  45. package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-sYL-A3ib.js +1 -0
  46. package/dashboard/dist/assets/{timeline-definition-YZTLITO2-DCAo6tA7.js → timeline-definition-YZTLITO2-Oa_SYaCP.js} +1 -1
  47. package/dashboard/dist/assets/{treemap-KZPCXAKY-CKlbZ6Y_.js → treemap-KZPCXAKY-vrIbKmuv.js} +1 -1
  48. package/dashboard/dist/assets/{vennDiagram-LZ73GAT5-CJSijre_.js → vennDiagram-LZ73GAT5-B3UlkEHW.js} +1 -1
  49. package/dashboard/dist/assets/{xychartDiagram-JWTSCODW-DXd1BBmK.js → xychartDiagram-JWTSCODW-BLiVVy6A.js} +1 -1
  50. package/dashboard/dist/index.html +2 -2
  51. package/dist/dashboard/server.js +612 -225
  52. package/dist/dashboard/server.js.map +1 -1
  53. package/dist/index.js +1204 -827
  54. package/dist/index.js.map +1 -1
  55. package/package.json +1 -1
  56. package/dashboard/dist/assets/channel-BYnzdl2x.js +0 -1
  57. package/dashboard/dist/assets/classDiagram-VBA2DB6C-BnPZbM4g.js +0 -1
  58. package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-BnPZbM4g.js +0 -1
  59. package/dashboard/dist/assets/clone-DYNFxLr3.js +0 -1
  60. package/dashboard/dist/assets/index-7rNWNKq7.css +0 -1
  61. package/dashboard/dist/assets/index-Nc9kfSW-.js +0 -550
  62. package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-B6S2ctrX.js +0 -1
package/dist/index.js CHANGED
@@ -187,8 +187,8 @@ function extractFrontmatter(fileContent) {
187
187
  const body = fileContent.slice(match[0].length).trim();
188
188
  return [frontmatterBlock, body];
189
189
  }
190
- function parseSimpleValue(raw) {
191
- const trimmed = raw.trim();
190
+ function parseSimpleValue(raw2) {
191
+ const trimmed = raw2.trim();
192
192
  if (trimmed === "null" || trimmed === "~" || trimmed === "") return null;
193
193
  if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
194
194
  return trimmed.slice(1, -1);
@@ -540,8 +540,8 @@ ${key}: ${formatted}${content.slice(closingIdx)}`;
540
540
  function readFrontmatterField(content, key) {
541
541
  const match = content.match(new RegExp(`^${key}:\\s*(.*)$`, "m"));
542
542
  if (!match) return null;
543
- const raw = match[1].trim().replace(/^['"]|['"]$/g, "");
544
- return raw === "" || raw === "null" ? null : raw;
543
+ const raw2 = match[1].trim().replace(/^['"]|['"]$/g, "");
544
+ return raw2 === "" || raw2 === "null" ? null : raw2;
545
545
  }
546
546
  async function migrateLegacyArchivedProjects(projectsDir2) {
547
547
  const result = { reconciled: [] };
@@ -811,9 +811,9 @@ function normalizeHiddenList(input4) {
811
811
  if (!Array.isArray(input4)) return [];
812
812
  const seen = /* @__PURE__ */ new Set();
813
813
  const out = [];
814
- for (const raw of input4) {
815
- if (typeof raw !== "string") continue;
816
- const name = raw.trim();
814
+ for (const raw2 of input4) {
815
+ if (typeof raw2 !== "string") continue;
816
+ const name = raw2.trim();
817
817
  if (name.length === 0) continue;
818
818
  if (name.length > MAX_WORKSPACE_NAME_LENGTH) continue;
819
819
  if (/[\r\n]/.test(name)) continue;
@@ -1192,13 +1192,13 @@ function parsePlaybooksConfig(fmBlock) {
1192
1192
  continue;
1193
1193
  }
1194
1194
  if (currentSection === "disabled" && indent >= 4 && trimmed.startsWith("- ")) {
1195
- const raw = trimmed.slice(2).trim().replace(/^["']|["']$/g, "");
1196
- if (raw.length === 0) continue;
1197
- if (/\s/.test(raw)) {
1198
- console.warn(`Warning: config.md playbooks.disabled entry "${raw}" contains whitespace, ignoring`);
1195
+ const raw2 = trimmed.slice(2).trim().replace(/^["']|["']$/g, "");
1196
+ if (raw2.length === 0) continue;
1197
+ if (/\s/.test(raw2)) {
1198
+ console.warn(`Warning: config.md playbooks.disabled entry "${raw2}" contains whitespace, ignoring`);
1199
1199
  continue;
1200
1200
  }
1201
- disabled.push(raw);
1201
+ disabled.push(raw2);
1202
1202
  continue;
1203
1203
  }
1204
1204
  }
@@ -1478,9 +1478,9 @@ function serializeHotkeyBindingsConfig(cfg) {
1478
1478
  async function writeHotkeyBindingsConfig(cfg) {
1479
1479
  const cleaned = {};
1480
1480
  for (const kind of BINDABLE_ACTION_KINDS) {
1481
- const raw = cfg.bindings[kind];
1482
- if (typeof raw !== "string" || raw.trim() === "") continue;
1483
- const canonical = canonicalizeCombo(raw);
1481
+ const raw2 = cfg.bindings[kind];
1482
+ if (typeof raw2 !== "string" || raw2.trim() === "") continue;
1483
+ const canonical = canonicalizeCombo(raw2);
1484
1484
  if (!canonical) continue;
1485
1485
  if (isReservedCombo(canonical)) continue;
1486
1486
  cleaned[kind] = canonical;
@@ -2277,8 +2277,8 @@ async function resolvePlaybookSlug(playbooksDir3, slug) {
2277
2277
  for (const entry of entries) {
2278
2278
  if (!isVisiblePlaybookFile(entry.name, entry.isFile())) continue;
2279
2279
  const filePath = resolve4(playbooksDir3, entry.name);
2280
- const raw = await readFile4(filePath, "utf-8");
2281
- const parsed = parsePlaybook(raw);
2280
+ const raw2 = await readFile4(filePath, "utf-8");
2281
+ const parsed = parsePlaybook(raw2);
2282
2282
  const canonical = parsed.slug || entry.name.replace(/\.md$/, "");
2283
2283
  if (canonical === slug) {
2284
2284
  return { filename: entry.name, slug: canonical, parsed };
@@ -2325,8 +2325,8 @@ async function rebuildPlaybookManifest(playbooksDir3) {
2325
2325
  const rows = [];
2326
2326
  for (const entry of entries) {
2327
2327
  if (!isVisiblePlaybookFile(entry.name, entry.isFile())) continue;
2328
- const raw = await readFile4(resolve4(playbooksDir3, entry.name), "utf-8");
2329
- const parsed = parsePlaybook(raw);
2328
+ const raw2 = await readFile4(resolve4(playbooksDir3, entry.name), "utf-8");
2329
+ const parsed = parsePlaybook(raw2);
2330
2330
  const slug = parsed.slug || entry.name.replace(/\.md$/, "");
2331
2331
  if (disabledSet.has(slug)) continue;
2332
2332
  rows.push({
@@ -2403,8 +2403,8 @@ async function renamePlaybook(playbooksDir3, oldSlug, newSlug) {
2403
2403
  );
2404
2404
  }
2405
2405
  }
2406
- const raw = await readFile4(oldPath, "utf-8");
2407
- let next = setFrontmatterField2(raw, "slug", newSlug);
2406
+ const raw2 = await readFile4(oldPath, "utf-8");
2407
+ let next = setFrontmatterField2(raw2, "slug", newSlug);
2408
2408
  next = setFrontmatterField2(next, "updated", `"${nowTimestamp()}"`);
2409
2409
  await writeFileForce(newPath, next);
2410
2410
  if (!renamedInPlace) {
@@ -3683,8 +3683,8 @@ function extractFrontmatter2(fileContent) {
3683
3683
  const body = fileContent.slice(match[0].length);
3684
3684
  return [frontmatterBlock, body];
3685
3685
  }
3686
- function parseSimpleValue2(raw) {
3687
- const trimmed = raw.trim();
3686
+ function parseSimpleValue2(raw2) {
3687
+ const trimmed = raw2.trim();
3688
3688
  if (trimmed === "null" || trimmed === "~" || trimmed === "") return null;
3689
3689
  if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
3690
3690
  return trimmed.slice(1, -1);
@@ -5283,9 +5283,9 @@ async function migrateFromMarkdown(projectsDir2) {
5283
5283
  }
5284
5284
  async function parseMarkdownSessionsIndex(filePath, projectSlug) {
5285
5285
  const { readFile: readFile56 } = await import("fs/promises");
5286
- const raw = await readFile56(filePath, "utf-8");
5286
+ const raw2 = await readFile56(filePath, "utf-8");
5287
5287
  const sessions = [];
5288
- const lines = raw.split("\n");
5288
+ const lines = raw2.split("\n");
5289
5289
  let inTable = false;
5290
5290
  let headerSeen = false;
5291
5291
  for (const line of lines) {
@@ -5441,8 +5441,8 @@ async function deleteSessions(sessionIds) {
5441
5441
  }
5442
5442
  async function readAssignmentStatusFromPath(assignmentMdPath2) {
5443
5443
  if (!await fileExists(assignmentMdPath2)) return null;
5444
- const raw = await readFile9(assignmentMdPath2, "utf-8");
5445
- const match = raw.match(/^status:\s*(.+)$/m);
5444
+ const raw2 = await readFile9(assignmentMdPath2, "utf-8");
5445
+ const match = raw2.match(/^status:\s*(.+)$/m);
5446
5446
  return match ? match[1].trim() : null;
5447
5447
  }
5448
5448
  async function readAssignmentStatus(projectDir, assignmentSlug) {
@@ -5586,8 +5586,8 @@ async function listSessionFiles(dir) {
5586
5586
  async function readSessionFile(dir, name) {
5587
5587
  const filePath = resolve14(dir, `${sanitizeSessionName(name)}.md`);
5588
5588
  if (!await fileExists(filePath)) return null;
5589
- const raw = await readFile10(filePath, "utf-8");
5590
- const [frontmatter] = extractFrontmatter(raw);
5589
+ const raw2 = await readFile10(filePath, "utf-8");
5590
+ const [frontmatter] = extractFrontmatter(raw2);
5591
5591
  if (!frontmatter) return null;
5592
5592
  const session = getField(frontmatter, "session") ?? name;
5593
5593
  const registered = getField(frontmatter, "registered") ?? "";
@@ -5715,8 +5715,8 @@ function scanKey(serversDir2, projectsDir2, assignmentsDir2) {
5715
5715
  return `${serversDir2}\0${projectsDir2}\0${assignmentsDir2 ?? ""}`;
5716
5716
  }
5717
5717
  function delay(ms) {
5718
- return new Promise((resolve82) => {
5719
- const timer2 = setTimeout(resolve82, ms);
5718
+ return new Promise((resolve83) => {
5719
+ const timer2 = setTimeout(resolve83, ms);
5720
5720
  if (typeof timer2.unref === "function") {
5721
5721
  timer2.unref();
5722
5722
  }
@@ -6323,8 +6323,8 @@ async function listProjects(projectsDir2) {
6323
6323
  async function readWorkspaceRegistry(projectsDir2) {
6324
6324
  const registryPath = resolve16(dirname3(projectsDir2), "workspaces.json");
6325
6325
  try {
6326
- const raw = await readFile11(registryPath, "utf-8");
6327
- const parsed = JSON.parse(raw);
6326
+ const raw2 = await readFile11(registryPath, "utf-8");
6327
+ const parsed = JSON.parse(raw2);
6328
6328
  return Array.isArray(parsed) ? parsed.filter((w) => typeof w === "string") : [];
6329
6329
  } catch {
6330
6330
  return [];
@@ -6412,8 +6412,8 @@ async function deleteWorkspace(projectsDir2, name, opts = {}) {
6412
6412
  const timestamp = nowTimestamp();
6413
6413
  for (const slug of projectsReferencing) {
6414
6414
  const path = resolve16(projectsDir2, slug, "project.md");
6415
- const raw = await readFile11(path, "utf-8");
6416
- let next = clearFrontmatterField(raw, "workspace");
6415
+ const raw2 = await readFile11(path, "utf-8");
6416
+ let next = clearFrontmatterField(raw2, "workspace");
6417
6417
  next = setUpdatedField(next, timestamp);
6418
6418
  await writeFileForce(path, next);
6419
6419
  rewroteFiles = true;
@@ -6421,8 +6421,8 @@ async function deleteWorkspace(projectsDir2, name, opts = {}) {
6421
6421
  for (const id of standalonesReferencing) {
6422
6422
  if (!opts.assignmentsDir) break;
6423
6423
  const path = resolve16(opts.assignmentsDir, id, "assignment.md");
6424
- const raw = await readFile11(path, "utf-8");
6425
- let next = clearFrontmatterField(raw, "workspaceGroup");
6424
+ const raw2 = await readFile11(path, "utf-8");
6425
+ let next = clearFrontmatterField(raw2, "workspaceGroup");
6426
6426
  next = setUpdatedField(next, timestamp);
6427
6427
  await writeFileForce(path, next);
6428
6428
  rewroteFiles = true;
@@ -7872,8 +7872,8 @@ async function listPlaybooks(playbooksDir3) {
7872
7872
  for (const entry of entries) {
7873
7873
  if (!entry.isFile() || !entry.name.endsWith(".md") || entry.name.startsWith("_") || entry.name === "manifest.md") continue;
7874
7874
  const filePath = resolve16(playbooksDir3, entry.name);
7875
- const raw = await readFile11(filePath, "utf-8");
7876
- const parsed = parsePlaybook(raw);
7875
+ const raw2 = await readFile11(filePath, "utf-8");
7876
+ const parsed = parsePlaybook(raw2);
7877
7877
  const slug = parsed.slug || entry.name.replace(/\.md$/, "");
7878
7878
  playbooks.push({
7879
7879
  slug,
@@ -8446,8 +8446,8 @@ __export(launch_exports, {
8446
8446
  shellQuote: () => shellQuote
8447
8447
  });
8448
8448
  import { spawn as spawn3 } from "child_process";
8449
- import { mkdir as mkdir5, writeFile as writeFile9 } from "fs/promises";
8450
- import { isAbsolute as isAbsolute5, resolve as resolve39 } from "path";
8449
+ import { mkdir as mkdir6, writeFile as writeFile10 } from "fs/promises";
8450
+ import { isAbsolute as isAbsolute5, resolve as resolve40 } from "path";
8451
8451
  function shellQuote(arg) {
8452
8452
  if (arg === "") return "''";
8453
8453
  return `'${arg.replace(/'/g, `'\\''`)}'`;
@@ -8483,8 +8483,8 @@ async function launchAgent(options) {
8483
8483
  console.error(`Assignment not found: ${projectSlug}/${assignmentSlug}`);
8484
8484
  process.exit(1);
8485
8485
  }
8486
- const projectDir = resolve39(projectsDir2, projectSlug);
8487
- const assignmentDir = resolve39(projectDir, "assignments", assignmentSlug);
8486
+ const projectDir = resolve40(projectsDir2, projectSlug);
8487
+ const assignmentDir = resolve40(projectDir, "assignments", assignmentSlug);
8488
8488
  let workspaceDir;
8489
8489
  if (cwdOverride) {
8490
8490
  if (!isExistingDir(cwdOverride)) {
@@ -8516,8 +8516,8 @@ async function launchAgent(options) {
8516
8516
  });
8517
8517
  if (warning) console.warn(warning);
8518
8518
  }
8519
- const contextDir = resolve39(workspaceDir, ".syntaur");
8520
- await mkdir5(contextDir, { recursive: true });
8519
+ const contextDir = resolve40(workspaceDir, ".syntaur");
8520
+ await mkdir6(contextDir, { recursive: true });
8521
8521
  const context = {
8522
8522
  projectSlug,
8523
8523
  assignmentSlug,
@@ -8528,8 +8528,8 @@ async function launchAgent(options) {
8528
8528
  branch: detail.workspace.branch ?? null,
8529
8529
  grabbedAt: (/* @__PURE__ */ new Date()).toISOString()
8530
8530
  };
8531
- await writeFile9(
8532
- resolve39(contextDir, "context.json"),
8531
+ await writeFile10(
8532
+ resolve40(contextDir, "context.json"),
8533
8533
  JSON.stringify(context, null, 2) + "\n"
8534
8534
  );
8535
8535
  const { argv, shellFallbackWarning } = buildAgentArgv(
@@ -8604,7 +8604,7 @@ import {
8604
8604
  unlinkSync
8605
8605
  } from "fs";
8606
8606
  import { fileURLToPath as fileURLToPath9, pathToFileURL } from "url";
8607
- import { dirname as dirname16, resolve as resolve49, join as join9 } from "path";
8607
+ import { dirname as dirname17, resolve as resolve50, join as join9 } from "path";
8608
8608
  import { homedir as homedir9, tmpdir as tmpdir2 } from "os";
8609
8609
  import { spawnSync as spawnSync7 } from "child_process";
8610
8610
  function syntaurRootMjs() {
@@ -8626,7 +8626,7 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
8626
8626
  }
8627
8627
  const stateRoot = syntaurRootMjs();
8628
8628
  mkdirSync2(stateRoot, { recursive: true });
8629
- const lockPath = resolve49(stateRoot, "install-url-handler.lock");
8629
+ const lockPath = resolve50(stateRoot, "install-url-handler.lock");
8630
8630
  let lockFd;
8631
8631
  try {
8632
8632
  lockFd = openSync(lockPath, "wx");
@@ -8642,8 +8642,8 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
8642
8642
  throw err2;
8643
8643
  }
8644
8644
  try {
8645
- const pkgRoot = resolve49(dirname16(fileURLToPath9(import.meta.url)), "..");
8646
- const cliBin = realpathSync3(resolve49(pkgRoot, "bin/syntaur.js"));
8645
+ const pkgRoot = resolve50(dirname17(fileURLToPath9(import.meta.url)), "..");
8646
+ const cliBin = realpathSync3(resolve50(pkgRoot, "bin/syntaur.js"));
8647
8647
  const nodeBin = process.execPath;
8648
8648
  const bundleParent = join9(
8649
8649
  homedir9(),
@@ -9651,7 +9651,7 @@ init_create_assignment();
9651
9651
  init_config2();
9652
9652
  import { spawn as spawn2 } from "child_process";
9653
9653
  import { createServer as createNetServer } from "net";
9654
- import { resolve as resolve31, dirname as dirname8 } from "path";
9654
+ import { resolve as resolve32, dirname as dirname9 } from "path";
9655
9655
  import { fileURLToPath as fileURLToPath2 } from "url";
9656
9656
 
9657
9657
  // src/dashboard/server.ts
@@ -9661,8 +9661,8 @@ init_assignment_resolver();
9661
9661
  init_agent_sessions();
9662
9662
  import express from "express";
9663
9663
  import { createServer } from "http";
9664
- import { resolve as resolve30 } from "path";
9665
- import { writeFile as writeFile6, unlink as unlink6 } from "fs/promises";
9664
+ import { resolve as resolve31 } from "path";
9665
+ import { writeFile as writeFile7, unlink as unlink7 } from "fs/promises";
9666
9666
  import { WebSocketServer, WebSocket } from "ws";
9667
9667
 
9668
9668
  // src/dashboard/session-liveness.ts
@@ -10136,15 +10136,15 @@ async function readViewPrefsFile() {
10136
10136
  if (!await fileExists(path)) {
10137
10137
  return { ...DEFAULT_VIEW_PREFS_FILE };
10138
10138
  }
10139
- let raw;
10139
+ let raw2;
10140
10140
  try {
10141
- raw = await readFile12(path, "utf-8");
10141
+ raw2 = await readFile12(path, "utf-8");
10142
10142
  } catch {
10143
10143
  return { ...DEFAULT_VIEW_PREFS_FILE };
10144
10144
  }
10145
10145
  let parsed;
10146
10146
  try {
10147
- parsed = JSON.parse(raw);
10147
+ parsed = JSON.parse(raw2);
10148
10148
  } catch {
10149
10149
  await backupCorrupt(path);
10150
10150
  return { ...DEFAULT_VIEW_PREFS_FILE };
@@ -10349,15 +10349,15 @@ async function readSavedViewsFile() {
10349
10349
  if (!await fileExists(path)) {
10350
10350
  return cloneDefault();
10351
10351
  }
10352
- let raw;
10352
+ let raw2;
10353
10353
  try {
10354
- raw = await readFile13(path, "utf-8");
10354
+ raw2 = await readFile13(path, "utf-8");
10355
10355
  } catch {
10356
10356
  return cloneDefault();
10357
10357
  }
10358
10358
  let parsed;
10359
10359
  try {
10360
- parsed = JSON.parse(raw);
10360
+ parsed = JSON.parse(raw2);
10361
10361
  } catch {
10362
10362
  await backupCorrupt2(path);
10363
10363
  return cloneDefault();
@@ -10768,8 +10768,8 @@ async function getProjectRepositoryCandidates(projectsDir2, projectSlug) {
10768
10768
  const projectPath = resolve20(projectsDir2, projectSlug, "project.md");
10769
10769
  if (await fileExists(projectPath)) {
10770
10770
  const project = parseProject(await readFile15(projectPath, "utf-8"));
10771
- for (const raw of project.repositories) {
10772
- const path = raw.trim();
10771
+ for (const raw2 of project.repositories) {
10772
+ const path = raw2.trim();
10773
10773
  if (!path) continue;
10774
10774
  const abs = resolve20(path);
10775
10775
  if (seen.has(abs)) continue;
@@ -13678,8 +13678,8 @@ function mapAgentErrorToFieldErrors(err2) {
13678
13678
  }
13679
13679
  return { error: message };
13680
13680
  }
13681
- function coerceAgentRow(raw, index) {
13682
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
13681
+ function coerceAgentRow(raw2, index) {
13682
+ if (!raw2 || typeof raw2 !== "object" || Array.isArray(raw2)) {
13683
13683
  return {
13684
13684
  ok: false,
13685
13685
  status: 400,
@@ -13689,7 +13689,7 @@ function coerceAgentRow(raw, index) {
13689
13689
  }
13690
13690
  };
13691
13691
  }
13692
- const entry = raw;
13692
+ const entry = raw2;
13693
13693
  if (typeof entry.id !== "string" || entry.id.length === 0) {
13694
13694
  return {
13695
13695
  ok: false,
@@ -13798,14 +13798,14 @@ function createAgentsRouter() {
13798
13798
  });
13799
13799
  router.put("/", async (req, res) => {
13800
13800
  try {
13801
- const raw = req.body && typeof req.body === "object" ? req.body : {};
13802
- if (!Array.isArray(raw.agents)) {
13801
+ const raw2 = req.body && typeof req.body === "object" ? req.body : {};
13802
+ if (!Array.isArray(raw2.agents)) {
13803
13803
  res.status(400).json({ error: "agents must be an array" });
13804
13804
  return;
13805
13805
  }
13806
13806
  const cleaned = [];
13807
- for (let i = 0; i < raw.agents.length; i++) {
13808
- const result = coerceAgentRow(raw.agents[i], i);
13807
+ for (let i = 0; i < raw2.agents.length; i++) {
13808
+ const result = coerceAgentRow(raw2.agents[i], i);
13809
13809
  if (!result.ok) {
13810
13810
  res.status(result.status).json(result.body);
13811
13811
  return;
@@ -14363,18 +14363,18 @@ function buildAffectedResponse(id, list) {
14363
14363
  function isString(x) {
14364
14364
  return typeof x === "string" && x.length > 0;
14365
14365
  }
14366
- function parseResolutions(raw) {
14367
- if (raw === void 0) {
14366
+ function parseResolutions(raw2) {
14367
+ if (raw2 === void 0) {
14368
14368
  return { resolutions: [], malformed: null, duplicateIds: null };
14369
14369
  }
14370
- if (!Array.isArray(raw)) {
14370
+ if (!Array.isArray(raw2)) {
14371
14371
  return { resolutions: [], malformed: "resolutions must be an array", duplicateIds: null };
14372
14372
  }
14373
14373
  const out = [];
14374
14374
  const seen = /* @__PURE__ */ new Set();
14375
14375
  const dups = /* @__PURE__ */ new Set();
14376
- for (let i = 0; i < raw.length; i++) {
14377
- const r = raw[i];
14376
+ for (let i = 0; i < raw2.length; i++) {
14377
+ const r = raw2[i];
14378
14378
  if (!r || typeof r !== "object") {
14379
14379
  return { resolutions: [], malformed: `resolutions[${i}] must be an object`, duplicateIds: null };
14380
14380
  }
@@ -15863,13 +15863,362 @@ init_fs_migration();
15863
15863
  init_parser2();
15864
15864
  init_fs();
15865
15865
  init_paths();
15866
- import { Router as Router13 } from "express";
15867
- import { readdir as readdir11 } from "fs/promises";
15868
- import { resolve as resolvePath, dirname as dirname6 } from "path";
15869
- import { rename as rename5, mkdir as mkdir2 } from "fs/promises";
15866
+ import { Router as Router14 } from "express";
15867
+ import { readdir as readdir12 } from "fs/promises";
15868
+ import { resolve as resolvePath, dirname as dirname7 } from "path";
15869
+ import { rename as rename6, mkdir as mkdir3 } from "fs/promises";
15870
15870
  init_slug();
15871
15871
  init_promote_todos();
15872
15872
  init_api();
15873
+
15874
+ // src/dashboard/todo-attachments-routes.ts
15875
+ import { raw } from "express";
15876
+
15877
+ // src/todos/attachments.ts
15878
+ import { mkdir as mkdir2, readdir as readdir11, stat, rename as rename5, rm as rm3, unlink as unlink5, writeFile as writeFile5, cp } from "fs/promises";
15879
+ import { resolve as resolve27, basename as basename4, dirname as dirname6, extname } from "path";
15880
+
15881
+ // src/utils/proof-artifact-id.ts
15882
+ import { randomBytes as randomBytes2 } from "crypto";
15883
+ function generateArtifactId() {
15884
+ const ts = Date.now().toString(36);
15885
+ const rand = randomBytes2(2).toString("hex");
15886
+ return `${ts}-${rand}`;
15887
+ }
15888
+ var EXTENSIONS = {
15889
+ screenshot: "png",
15890
+ video: "mp4",
15891
+ asciinema: "cast",
15892
+ http: "txt",
15893
+ text: "txt"
15894
+ };
15895
+ function extensionForKind(kind) {
15896
+ const ext = EXTENSIONS[kind];
15897
+ if (!ext) {
15898
+ throw new Error(`Unknown artifact kind: ${kind}`);
15899
+ }
15900
+ return ext;
15901
+ }
15902
+ var ARTIFACT_KINDS = [
15903
+ "screenshot",
15904
+ "video",
15905
+ "asciinema",
15906
+ "http",
15907
+ "text"
15908
+ ];
15909
+ function isArtifactKind(value) {
15910
+ return typeof value === "string" && ARTIFACT_KINDS.includes(value);
15911
+ }
15912
+
15913
+ // src/todos/attachments.ts
15914
+ var SCOPE_RE = /^[a-z0-9_][a-z0-9-]*$/;
15915
+ var TODO_ID_RE = /^[a-f0-9]{4}$/;
15916
+ var ATTACHMENT_ID_RE = /^[a-z0-9]+-[0-9a-f]{4}$/;
15917
+ var AttachmentValidationError = class extends Error {
15918
+ constructor(message) {
15919
+ super(message);
15920
+ this.name = "AttachmentValidationError";
15921
+ }
15922
+ };
15923
+ function assertScope(scopeId) {
15924
+ if (!SCOPE_RE.test(scopeId)) throw new AttachmentValidationError(`Invalid scope id: "${scopeId}"`);
15925
+ }
15926
+ function assertTodoId(todoId) {
15927
+ if (!TODO_ID_RE.test(todoId)) throw new AttachmentValidationError(`Invalid todo id: "${todoId}"`);
15928
+ }
15929
+ function assertAttachmentId(attachmentId) {
15930
+ if (!ATTACHMENT_ID_RE.test(attachmentId)) {
15931
+ throw new AttachmentValidationError(`Invalid attachment id: "${attachmentId}"`);
15932
+ }
15933
+ }
15934
+ var EXT_MIME = {
15935
+ png: "image/png",
15936
+ jpg: "image/jpeg",
15937
+ jpeg: "image/jpeg",
15938
+ gif: "image/gif",
15939
+ webp: "image/webp",
15940
+ bmp: "image/bmp",
15941
+ ico: "image/x-icon",
15942
+ svg: "image/svg+xml",
15943
+ pdf: "application/pdf",
15944
+ txt: "text/plain",
15945
+ log: "text/plain",
15946
+ md: "text/markdown",
15947
+ json: "application/json",
15948
+ csv: "text/csv",
15949
+ html: "text/html",
15950
+ htm: "text/html",
15951
+ xml: "application/xml",
15952
+ mp4: "video/mp4",
15953
+ mov: "video/quicktime",
15954
+ webm: "video/webm",
15955
+ mp3: "audio/mpeg",
15956
+ wav: "audio/wav",
15957
+ m4a: "audio/mp4",
15958
+ zip: "application/zip"
15959
+ };
15960
+ function mimeForName(name) {
15961
+ const ext = extname(name).slice(1).toLowerCase();
15962
+ return EXT_MIME[ext] ?? "application/octet-stream";
15963
+ }
15964
+ var SAFE_INLINE_MIME = /* @__PURE__ */ new Set([
15965
+ "image/png",
15966
+ "image/jpeg",
15967
+ "image/gif",
15968
+ "image/webp",
15969
+ "application/pdf",
15970
+ "text/plain"
15971
+ ]);
15972
+ function isSafeInlineMime(mime) {
15973
+ return SAFE_INLINE_MIME.has(mime);
15974
+ }
15975
+ function sanitizeAttachmentName(name) {
15976
+ let n = basename4(name || "").replace(/["'\\/]/g, "_");
15977
+ n = Array.from(n, (ch) => {
15978
+ const code = ch.charCodeAt(0);
15979
+ return code < 32 || code === 127 ? "_" : ch;
15980
+ }).join("");
15981
+ n = n.trim();
15982
+ if (!n || n === "." || n === "..") n = "file";
15983
+ if (n.length > 120) {
15984
+ const ext = extname(n);
15985
+ n = n.slice(0, Math.max(1, 120 - ext.length)) + ext;
15986
+ }
15987
+ return n;
15988
+ }
15989
+ function attachmentsRootDir(todosDir2) {
15990
+ return resolve27(todosDir2, "attachments");
15991
+ }
15992
+ function attachmentDirFor(todosDir2, scopeId, todoId) {
15993
+ assertScope(scopeId);
15994
+ assertTodoId(todoId);
15995
+ return resolve27(attachmentsRootDir(todosDir2), scopeId, todoId);
15996
+ }
15997
+ async function dirExists(p) {
15998
+ try {
15999
+ return (await stat(p)).isDirectory();
16000
+ } catch {
16001
+ return false;
16002
+ }
16003
+ }
16004
+ async function writeAttachment(todosDir2, scopeId, todoId, originalName, bytes) {
16005
+ const dir = attachmentDirFor(todosDir2, scopeId, todoId);
16006
+ await mkdir2(dir, { recursive: true });
16007
+ const id = generateArtifactId();
16008
+ const filename = sanitizeAttachmentName(originalName);
16009
+ await writeFile5(resolve27(dir, `${id}__${filename}`), bytes);
16010
+ return {
16011
+ id,
16012
+ filename,
16013
+ mime: mimeForName(filename),
16014
+ size: bytes.length,
16015
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
16016
+ };
16017
+ }
16018
+ async function listAttachments(todosDir2, scopeId, todoId) {
16019
+ const dir = attachmentDirFor(todosDir2, scopeId, todoId);
16020
+ let names;
16021
+ try {
16022
+ names = await readdir11(dir);
16023
+ } catch {
16024
+ return [];
16025
+ }
16026
+ const out = [];
16027
+ for (const stored of names) {
16028
+ const sep2 = stored.indexOf("__");
16029
+ if (sep2 <= 0) continue;
16030
+ const id = stored.slice(0, sep2);
16031
+ if (!ATTACHMENT_ID_RE.test(id)) continue;
16032
+ const filename = stored.slice(sep2 + 2);
16033
+ try {
16034
+ const st = await stat(resolve27(dir, stored));
16035
+ if (!st.isFile()) continue;
16036
+ out.push({ id, filename, mime: mimeForName(filename), size: st.size, createdAt: st.mtime.toISOString() });
16037
+ } catch {
16038
+ }
16039
+ }
16040
+ out.sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
16041
+ return out;
16042
+ }
16043
+ async function readScopeAttachments(todosDir2, scopeId) {
16044
+ assertScope(scopeId);
16045
+ const scopeDir = resolve27(attachmentsRootDir(todosDir2), scopeId);
16046
+ let todoIds;
16047
+ try {
16048
+ todoIds = await readdir11(scopeDir);
16049
+ } catch {
16050
+ return {};
16051
+ }
16052
+ const result = {};
16053
+ for (const todoId of todoIds) {
16054
+ if (!TODO_ID_RE.test(todoId)) continue;
16055
+ const list = await listAttachments(todosDir2, scopeId, todoId);
16056
+ if (list.length) result[todoId] = list;
16057
+ }
16058
+ return result;
16059
+ }
16060
+ async function resolveAttachmentFile(todosDir2, scopeId, todoId, attachmentId) {
16061
+ assertAttachmentId(attachmentId);
16062
+ const dir = attachmentDirFor(todosDir2, scopeId, todoId);
16063
+ let names;
16064
+ try {
16065
+ names = await readdir11(dir);
16066
+ } catch {
16067
+ return null;
16068
+ }
16069
+ const prefix = `${attachmentId}__`;
16070
+ const stored = names.find((n) => n.startsWith(prefix));
16071
+ if (!stored) return null;
16072
+ const filename = stored.slice(prefix.length);
16073
+ return { path: resolve27(dir, stored), filename, mime: mimeForName(filename) };
16074
+ }
16075
+ async function deleteAttachment(todosDir2, scopeId, todoId, attachmentId) {
16076
+ const resolved = await resolveAttachmentFile(todosDir2, scopeId, todoId, attachmentId);
16077
+ if (!resolved) return false;
16078
+ await unlink5(resolved.path);
16079
+ return true;
16080
+ }
16081
+ async function deleteAllAttachments(todosDir2, scopeId, todoId) {
16082
+ await rm3(attachmentDirFor(todosDir2, scopeId, todoId), { recursive: true, force: true });
16083
+ }
16084
+ async function attachmentMoveConflict(srcTodosDir, srcScopeId, dstTodosDir, dstScopeId, todoId) {
16085
+ const src = attachmentDirFor(srcTodosDir, srcScopeId, todoId);
16086
+ const dst = attachmentDirFor(dstTodosDir, dstScopeId, todoId);
16087
+ return await dirExists(src) && await dirExists(dst);
16088
+ }
16089
+ async function moveAttachments(srcTodosDir, srcScopeId, dstTodosDir, dstScopeId, todoId) {
16090
+ const src = attachmentDirFor(srcTodosDir, srcScopeId, todoId);
16091
+ if (!await dirExists(src)) return;
16092
+ const dst = attachmentDirFor(dstTodosDir, dstScopeId, todoId);
16093
+ await mkdir2(dirname6(dst), { recursive: true });
16094
+ try {
16095
+ await rename5(src, dst);
16096
+ } catch (err2) {
16097
+ if (err2?.code === "EXDEV") {
16098
+ await cp(src, dst, { recursive: true });
16099
+ await rm3(src, { recursive: true, force: true });
16100
+ } else {
16101
+ throw err2;
16102
+ }
16103
+ }
16104
+ }
16105
+
16106
+ // src/dashboard/todo-attachments-routes.ts
16107
+ var MAX_UPLOAD_BYTES = 25 * 1024 * 1024;
16108
+ function headerValue(req, name) {
16109
+ const v = req.headers[name];
16110
+ return Array.isArray(v) ? v[0] : v;
16111
+ }
16112
+ function paramStr(v) {
16113
+ return Array.isArray(v) ? v[0] ?? "" : v ?? "";
16114
+ }
16115
+ function sendError(res, err2) {
16116
+ if (err2 instanceof AttachmentValidationError) {
16117
+ res.status(400).json({ error: err2.message });
16118
+ return;
16119
+ }
16120
+ res.status(500).json({ error: err2 instanceof Error ? err2.message : "Attachment operation failed" });
16121
+ }
16122
+ function contentDisposition(filename, inline) {
16123
+ const disp = inline ? "inline" : "attachment";
16124
+ const asciiFallback = Array.from(filename, (ch) => {
16125
+ const code = ch.charCodeAt(0);
16126
+ return code >= 32 && code <= 126 && ch !== '"' && ch !== "\\" ? ch : "_";
16127
+ }).join("");
16128
+ return `${disp}; filename="${asciiFallback}"; filename*=UTF-8''${encodeURIComponent(filename)}`;
16129
+ }
16130
+ function installTodoAttachmentRoutes(router, prefix, opts) {
16131
+ router.post(
16132
+ `${prefix}/attachments`,
16133
+ raw({ type: () => true, limit: MAX_UPLOAD_BYTES }),
16134
+ async (req, res) => {
16135
+ try {
16136
+ const rawName = headerValue(req, "x-attachment-filename");
16137
+ let filename = "file";
16138
+ if (rawName) {
16139
+ try {
16140
+ filename = decodeURIComponent(rawName);
16141
+ } catch {
16142
+ res.status(400).json({ error: "Invalid x-attachment-filename header" });
16143
+ return;
16144
+ }
16145
+ }
16146
+ const body = req.body;
16147
+ if (!Buffer.isBuffer(body) || body.length === 0) {
16148
+ res.status(400).json({ error: "Empty upload body" });
16149
+ return;
16150
+ }
16151
+ const scope = opts.resolveScope(req);
16152
+ const result = await opts.withScopeLock(req, async () => {
16153
+ if (!await opts.todoExists(scope)) return null;
16154
+ return writeAttachment(scope.todosDir, scope.scopeId, scope.todoId, filename, body);
16155
+ });
16156
+ if (!result) {
16157
+ res.status(404).json({ error: `Todo "${scope.todoId}" not found` });
16158
+ return;
16159
+ }
16160
+ opts.onChange(req);
16161
+ res.status(201).json(result);
16162
+ } catch (err2) {
16163
+ sendError(res, err2);
16164
+ }
16165
+ }
16166
+ );
16167
+ router.get(`${prefix}/attachments/:attachmentId`, async (req, res) => {
16168
+ try {
16169
+ const scope = opts.resolveScope(req);
16170
+ const attachmentId = paramStr(req.params.attachmentId);
16171
+ const resolved = await opts.withScopeLock(req, async () => {
16172
+ if (!await opts.todoExists(scope)) return { notFound: true };
16173
+ return {
16174
+ file: await resolveAttachmentFile(scope.todosDir, scope.scopeId, scope.todoId, attachmentId)
16175
+ };
16176
+ });
16177
+ if ("notFound" in resolved) {
16178
+ res.status(404).json({ error: `Todo "${scope.todoId}" not found` });
16179
+ return;
16180
+ }
16181
+ if (!resolved.file) {
16182
+ res.status(404).json({ error: `Attachment "${attachmentId}" not found` });
16183
+ return;
16184
+ }
16185
+ const { path, filename, mime } = resolved.file;
16186
+ const inline = isSafeInlineMime(mime);
16187
+ res.setHeader("X-Content-Type-Options", "nosniff");
16188
+ res.setHeader("Content-Type", inline ? mime : "application/octet-stream");
16189
+ res.setHeader("Content-Disposition", contentDisposition(filename, inline));
16190
+ res.sendFile(path, (err2) => {
16191
+ if (err2 && !res.headersSent) res.status(500).end();
16192
+ });
16193
+ } catch (err2) {
16194
+ sendError(res, err2);
16195
+ }
16196
+ });
16197
+ router.delete(`${prefix}/attachments/:attachmentId`, async (req, res) => {
16198
+ try {
16199
+ const scope = opts.resolveScope(req);
16200
+ const attachmentId = paramStr(req.params.attachmentId);
16201
+ const result = await opts.withScopeLock(req, async () => {
16202
+ if (!await opts.todoExists(scope)) return { notFound: true };
16203
+ return { deleted: await deleteAttachment(scope.todosDir, scope.scopeId, scope.todoId, attachmentId) };
16204
+ });
16205
+ if ("notFound" in result) {
16206
+ res.status(404).json({ error: `Todo "${scope.todoId}" not found` });
16207
+ return;
16208
+ }
16209
+ if (!result.deleted) {
16210
+ res.status(404).json({ error: `Attachment "${attachmentId}" not found` });
16211
+ return;
16212
+ }
16213
+ opts.onChange(req);
16214
+ res.json({ deleted: attachmentId });
16215
+ } catch (err2) {
16216
+ sendError(res, err2);
16217
+ }
16218
+ });
16219
+ }
16220
+
16221
+ // src/dashboard/api-todos.ts
15873
16222
  var WORKSPACE_REGEX = /^[a-z0-9_][a-z0-9-]*$/;
15874
16223
  function getWorkspaceParam(value) {
15875
16224
  if (Array.isArray(value)) {
@@ -15883,7 +16232,7 @@ function touchItem3(item) {
15883
16232
  item.updatedAt = now;
15884
16233
  }
15885
16234
  function createTodosRouter(todosDir2, broadcast, projectsDir2) {
15886
- const router = Router13();
16235
+ const router = Router14();
15887
16236
  installRecordsInvalidation(router);
15888
16237
  function broadcastUpdate() {
15889
16238
  broadcast({ type: "todos-updated", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
@@ -15900,6 +16249,19 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
15900
16249
  next();
15901
16250
  }
15902
16251
  router.param("workspace", validateWorkspace);
16252
+ installTodoAttachmentRoutes(router, "/:workspace/:id", {
16253
+ resolveScope: (req) => ({
16254
+ todosDir: todosDir2,
16255
+ scopeId: getWorkspaceParam(req.params.workspace),
16256
+ todoId: getWorkspaceParam(req.params.id)
16257
+ }),
16258
+ withScopeLock: (req, fn) => wsLock(getWorkspaceParam(req.params.workspace), fn),
16259
+ todoExists: async (scope) => {
16260
+ const checklist = await readChecklist(scope.todosDir, scope.scopeId);
16261
+ return checklist.items.some((i) => i.id === scope.todoId);
16262
+ },
16263
+ onChange: () => broadcastUpdate()
16264
+ });
15903
16265
  router.post("/promote-bulk", async (req, res) => {
15904
16266
  try {
15905
16267
  const { groups, mode, target, title, type, priority, keepSource } = req.body ?? {};
@@ -16004,17 +16366,18 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
16004
16366
  router.get("/", async (_req, res) => {
16005
16367
  try {
16006
16368
  await ensureDir(todosDir2);
16007
- const files = await readdir11(todosDir2).catch(() => []);
16369
+ const files = await readdir12(todosDir2).catch(() => []);
16008
16370
  const workspaces = [];
16009
16371
  for (const file of files) {
16010
16372
  if (typeof file !== "string") continue;
16011
16373
  if (!file.endsWith(".md") || file.endsWith("-log.md")) continue;
16012
16374
  const workspace = file.replace(".md", "");
16013
16375
  const checklist = await readChecklist(todosDir2, workspace);
16376
+ const attachmentsByTodo = await readScopeAttachments(todosDir2, checklist.workspace);
16014
16377
  workspaces.push({
16015
16378
  workspace: checklist.workspace,
16016
16379
  archiveInterval: checklist.archiveInterval,
16017
- items: checklist.items,
16380
+ items: checklist.items.map((i) => ({ ...i, attachments: attachmentsByTodo[i.id] ?? [] })),
16018
16381
  counts: computeCounts(checklist.items)
16019
16382
  });
16020
16383
  }
@@ -16027,10 +16390,11 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
16027
16390
  try {
16028
16391
  const workspace = getWorkspaceParam(req.params.workspace);
16029
16392
  const checklist = await readChecklist(todosDir2, workspace);
16393
+ const attachmentsByTodo = await readScopeAttachments(todosDir2, workspace);
16030
16394
  res.json({
16031
16395
  workspace: checklist.workspace,
16032
16396
  archiveInterval: checklist.archiveInterval,
16033
- items: checklist.items,
16397
+ items: checklist.items.map((i) => ({ ...i, attachments: attachmentsByTodo[i.id] ?? [] })),
16034
16398
  counts: computeCounts(checklist.items)
16035
16399
  });
16036
16400
  } catch (error) {
@@ -16118,63 +16482,68 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
16118
16482
  router.post("/:workspace/archive", async (req, res) => {
16119
16483
  try {
16120
16484
  const { archivePath: archivePath2 } = await Promise.resolve().then(() => (init_parser2(), parser_exports));
16121
- const { resolve: resolve82 } = await import("path");
16485
+ const { resolve: resolve83 } = await import("path");
16122
16486
  const { readFile: readFile56 } = await import("fs/promises");
16123
16487
  const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
16124
16488
  const workspace = getWorkspaceParam(req.params.workspace);
16125
- const checklist = await readChecklist(todosDir2, workspace);
16126
- const log = await readLog(todosDir2, workspace);
16127
- const completedIds = new Set(
16128
- checklist.items.filter((i) => i.status === "completed").map((i) => i.id)
16129
- );
16130
- if (completedIds.size === 0) {
16131
- res.json({ archived: 0, message: "No completed items to archive" });
16132
- return;
16133
- }
16134
- const toArchive = log.entries.filter(
16135
- (e) => e.itemIds.every((id) => completedIds.has(id))
16136
- );
16137
- const archFile = archivePath2(todosDir2, workspace, checklist.archiveInterval);
16138
- await ensureDir(resolve82(todosDir2, "archive"));
16139
- let archContent = "";
16140
- if (await fileExists(archFile)) {
16141
- archContent = await readFile56(archFile, "utf-8");
16142
- archContent = archContent.trimEnd() + "\n\n";
16143
- } else {
16144
- archContent = `---
16489
+ const outcome = await wsLock(workspace, async () => {
16490
+ const checklist = await readChecklist(todosDir2, workspace);
16491
+ const log = await readLog(todosDir2, workspace);
16492
+ const completedIds = new Set(
16493
+ checklist.items.filter((i) => i.status === "completed").map((i) => i.id)
16494
+ );
16495
+ if (completedIds.size === 0) {
16496
+ return { archived: 0, message: "No completed items to archive" };
16497
+ }
16498
+ const toArchive = log.entries.filter(
16499
+ (e) => e.itemIds.every((id) => completedIds.has(id))
16500
+ );
16501
+ const archFile = archivePath2(todosDir2, workspace, checklist.archiveInterval);
16502
+ await ensureDir(resolve83(todosDir2, "archive"));
16503
+ let archContent = "";
16504
+ if (await fileExists(archFile)) {
16505
+ archContent = await readFile56(archFile, "utf-8");
16506
+ archContent = archContent.trimEnd() + "\n\n";
16507
+ } else {
16508
+ archContent = `---
16145
16509
  workspace: ${workspace}
16146
16510
  ---
16147
16511
 
16148
16512
  # Archive
16149
16513
 
16150
16514
  `;
16151
- }
16152
- const completedItems = checklist.items.filter((i) => completedIds.has(i.id));
16153
- for (const item of completedItems) {
16154
- archContent += `- [x] ${item.description} ${item.tags.map((t) => `#${t}`).join(" ")} [t:${item.id}]
16515
+ }
16516
+ const completedItems = checklist.items.filter((i) => completedIds.has(i.id));
16517
+ for (const item of completedItems) {
16518
+ archContent += `- [x] ${item.description} ${item.tags.map((t) => `#${t}`).join(" ")} [t:${item.id}]
16155
16519
  `;
16156
- }
16157
- archContent += "\n";
16158
- for (const entry of toArchive) {
16159
- archContent += `### ${entry.timestamp} \u2014 ${entry.itemIds.map((i) => `t:${i}`).join(", ")}
16520
+ }
16521
+ archContent += "\n";
16522
+ for (const entry of toArchive) {
16523
+ archContent += `### ${entry.timestamp} \u2014 ${entry.itemIds.map((i) => `t:${i}`).join(", ")}
16160
16524
  `;
16161
- if (entry.items) archContent += `**Items:** ${entry.items}
16525
+ if (entry.items) archContent += `**Items:** ${entry.items}
16162
16526
  `;
16163
- if (entry.session) archContent += `**Session:** ${entry.session}
16527
+ if (entry.session) archContent += `**Session:** ${entry.session}
16164
16528
  `;
16165
- if (entry.branch) archContent += `**Branch:** ${entry.branch}
16529
+ if (entry.branch) archContent += `**Branch:** ${entry.branch}
16166
16530
  `;
16167
- if (entry.summary) archContent += `**Summary:** ${entry.summary}
16531
+ if (entry.summary) archContent += `**Summary:** ${entry.summary}
16168
16532
  `;
16169
- if (entry.blockers) archContent += `**Blockers:** ${entry.blockers}
16533
+ if (entry.blockers) archContent += `**Blockers:** ${entry.blockers}
16170
16534
  `;
16171
- archContent += "\n";
16172
- }
16173
- await writeFileForce2(archFile, archContent);
16174
- checklist.items = checklist.items.filter((i) => !completedIds.has(i.id));
16175
- await writeChecklist(todosDir2, checklist);
16176
- broadcastUpdate();
16177
- res.json({ archived: completedIds.size, logEntries: toArchive.length });
16535
+ archContent += "\n";
16536
+ }
16537
+ await writeFileForce2(archFile, archContent);
16538
+ checklist.items = checklist.items.filter((i) => !completedIds.has(i.id));
16539
+ await writeChecklist(todosDir2, checklist);
16540
+ for (const id of completedIds) {
16541
+ await deleteAllAttachments(todosDir2, workspace, id);
16542
+ }
16543
+ return { archived: completedIds.size, logEntries: toArchive.length };
16544
+ });
16545
+ if (outcome.archived > 0) broadcastUpdate();
16546
+ res.json(outcome);
16178
16547
  } catch (error) {
16179
16548
  res.status(500).json({ error: error instanceof Error ? error.message : "Failed to archive" });
16180
16549
  }
@@ -16199,7 +16568,8 @@ workspace: ${workspace}
16199
16568
  }
16200
16569
  const log = await readLog(todosDir2, workspace);
16201
16570
  const logEntries = log.entries.filter((e) => e.itemIds.includes(req.params.id));
16202
- res.json({ ...item, log: logEntries });
16571
+ const attachments = await listAttachments(todosDir2, workspace, item.id);
16572
+ res.json({ ...item, attachments, log: logEntries });
16203
16573
  } catch (error) {
16204
16574
  res.status(500).json({ error: error instanceof Error ? error.message : "Failed to get todo" });
16205
16575
  }
@@ -16236,6 +16606,7 @@ workspace: ${workspace}
16236
16606
  if (idx === -1) return false;
16237
16607
  checklist.items.splice(idx, 1);
16238
16608
  await writeChecklist(todosDir2, checklist);
16609
+ await deleteAllAttachments(todosDir2, workspace, req.params.id);
16239
16610
  return true;
16240
16611
  });
16241
16612
  if (!deleted) {
@@ -16547,15 +16918,22 @@ workspace: ${workspace}
16547
16918
  return { status: 409, error: "id already exists in target" };
16548
16919
  }
16549
16920
  const item = sourceChecklist.items[idx];
16921
+ let newPlanDir = null;
16550
16922
  if (item.planDir) {
16551
- const newPlanDir = todoPlanDir(target.todosPath, target.id, id);
16923
+ newPlanDir = todoPlanDir(target.todosPath, target.id, id);
16552
16924
  if (await fileExists(newPlanDir)) {
16553
16925
  return { status: 409, error: "plan dir already exists in target" };
16554
16926
  }
16555
- await mkdir2(dirname6(newPlanDir), { recursive: true });
16556
- await rename5(item.planDir, newPlanDir);
16927
+ }
16928
+ if (await attachmentMoveConflict(todosDir2, sourceWs, target.todosPath, target.id, id)) {
16929
+ return { status: 409, error: "attachments already exist in target" };
16930
+ }
16931
+ if (item.planDir && newPlanDir) {
16932
+ await mkdir3(dirname7(newPlanDir), { recursive: true });
16933
+ await rename6(item.planDir, newPlanDir);
16557
16934
  item.planDir = newPlanDir;
16558
16935
  }
16936
+ await moveAttachments(todosDir2, sourceWs, target.todosPath, target.id, id);
16559
16937
  sourceChecklist.items.splice(idx, 1);
16560
16938
  targetChecklist.items.push(item);
16561
16939
  await writeChecklist(todosDir2, sourceChecklist);
@@ -16628,9 +17006,9 @@ init_parser2();
16628
17006
  init_fs();
16629
17007
  init_paths();
16630
17008
  init_slug();
16631
- import { Router as Router14 } from "express";
16632
- import { mkdir as mkdir3, readFile as readFile19, rename as rename6 } from "fs/promises";
16633
- import { resolve as resolve27, dirname as dirname7 } from "path";
17009
+ import { Router as Router15 } from "express";
17010
+ import { mkdir as mkdir4, readFile as readFile19, rename as rename7 } from "fs/promises";
17011
+ import { resolve as resolve28, dirname as dirname8 } from "path";
16634
17012
  init_promote_todos();
16635
17013
  init_api();
16636
17014
  var WORKSPACE_REGEX2 = /^[a-z0-9_][a-z0-9-]*$/;
@@ -16647,12 +17025,12 @@ function params(req) {
16647
17025
  return req.params;
16648
17026
  }
16649
17027
  async function projectExists(projectsDir2, slug) {
16650
- return fileExists(resolve27(projectsDir2, slug, "project.md"));
17028
+ return fileExists(resolve28(projectsDir2, slug, "project.md"));
16651
17029
  }
16652
17030
  async function ensureProjectTodosDir(projectsDir2, slug) {
16653
17031
  const todosDir2 = projectTodosDir(projectsDir2, slug);
16654
17032
  try {
16655
- await mkdir3(todosDir2, { recursive: false });
17033
+ await mkdir4(todosDir2, { recursive: false });
16656
17034
  } catch (err2) {
16657
17035
  const code = err2.code;
16658
17036
  if (code === "EEXIST") return;
@@ -16664,7 +17042,7 @@ async function ensureProjectTodosDir(projectsDir2, slug) {
16664
17042
  throw err2;
16665
17043
  }
16666
17044
  try {
16667
- await mkdir3(resolve27(todosDir2, "archive"), { recursive: false });
17045
+ await mkdir4(resolve28(todosDir2, "archive"), { recursive: false });
16668
17046
  } catch (err2) {
16669
17047
  const code = err2.code;
16670
17048
  if (code === "EEXIST") return;
@@ -16680,7 +17058,7 @@ function notFound(res, slug) {
16680
17058
  res.status(404).json({ error: `Project "${slug}" not found` });
16681
17059
  }
16682
17060
  function createProjectTodosRouter(projectsDir2, broadcast, workspaceTodosDir) {
16683
- const router = Router14({ mergeParams: true });
17061
+ const router = Router15({ mergeParams: true });
16684
17062
  installRecordsInvalidation(router);
16685
17063
  function broadcastUpdate(projectSlug) {
16686
17064
  broadcast({ type: "todos-updated", projectSlug, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
@@ -16697,6 +17075,18 @@ function createProjectTodosRouter(projectsDir2, broadcast, workspaceTodosDir) {
16697
17075
  next();
16698
17076
  }
16699
17077
  router.use(validateProjectId);
17078
+ installTodoAttachmentRoutes(router, "/:id", {
17079
+ resolveScope: (req) => {
17080
+ const slug = getProjectIdParam(params(req).projectId);
17081
+ return { todosDir: projectTodosDir(projectsDir2, slug), scopeId: slug, todoId: params(req).id ?? "" };
17082
+ },
17083
+ withScopeLock: (req, fn) => projLock(getProjectIdParam(params(req).projectId), fn),
17084
+ todoExists: async (scope) => {
17085
+ const checklist = await readChecklist(scope.todosDir, scope.scopeId);
17086
+ return checklist.items.some((i) => i.id === scope.todoId);
17087
+ },
17088
+ onChange: (req) => broadcastUpdate(getProjectIdParam(params(req).projectId))
17089
+ });
16700
17090
  router.get("/", async (req, res) => {
16701
17091
  try {
16702
17092
  const slug = getProjectIdParam(params(req).projectId);
@@ -16706,10 +17096,11 @@ function createProjectTodosRouter(projectsDir2, broadcast, workspaceTodosDir) {
16706
17096
  }
16707
17097
  const todosDir2 = projectTodosDir(projectsDir2, slug);
16708
17098
  const checklist = await readChecklist(todosDir2, slug);
17099
+ const attachmentsByTodo = await readScopeAttachments(todosDir2, slug);
16709
17100
  res.json({
16710
17101
  workspace: checklist.workspace,
16711
17102
  archiveInterval: checklist.archiveInterval,
16712
- items: checklist.items,
17103
+ items: checklist.items.map((i) => ({ ...i, attachments: attachmentsByTodo[i.id] ?? [] })),
16713
17104
  counts: computeCounts(checklist.items)
16714
17105
  });
16715
17106
  } catch (error) {
@@ -16837,61 +17228,71 @@ function createProjectTodosRouter(projectsDir2, broadcast, workspaceTodosDir) {
16837
17228
  notFound(res, slug);
16838
17229
  return;
16839
17230
  }
16840
- const todosDir2 = projectTodosDir(projectsDir2, slug);
16841
- await ensureProjectTodosDir(projectsDir2, slug);
16842
- const checklist = await readChecklist(todosDir2, slug);
16843
- const log = await readLog(todosDir2, slug);
16844
- const completedIds = new Set(
16845
- checklist.items.filter((i) => i.status === "completed").map((i) => i.id)
16846
- );
16847
- if (completedIds.size === 0) {
16848
- res.json({ archived: 0, message: "No completed items to archive" });
16849
- return;
16850
- }
16851
- const toArchive = log.entries.filter(
16852
- (e) => e.itemIds.every((id) => completedIds.has(id))
16853
- );
16854
- const archFile = archivePath(todosDir2, slug, checklist.archiveInterval);
16855
- let archContent = "";
16856
- if (await fileExists(archFile)) {
16857
- archContent = await readFile19(archFile, "utf-8");
16858
- archContent = archContent.trimEnd() + "\n\n";
16859
- } else {
16860
- archContent = `---
17231
+ const outcome = await projLock(slug, async () => {
17232
+ if (!await projectExists(projectsDir2, slug)) return "gone";
17233
+ await ensureProjectTodosDir(projectsDir2, slug);
17234
+ const todosDir2 = projectTodosDir(projectsDir2, slug);
17235
+ const checklist = await readChecklist(todosDir2, slug);
17236
+ const log = await readLog(todosDir2, slug);
17237
+ const completedIds = new Set(
17238
+ checklist.items.filter((i) => i.status === "completed").map((i) => i.id)
17239
+ );
17240
+ if (completedIds.size === 0) {
17241
+ return { archived: 0, message: "No completed items to archive" };
17242
+ }
17243
+ const toArchive = log.entries.filter(
17244
+ (e) => e.itemIds.every((id) => completedIds.has(id))
17245
+ );
17246
+ const archFile = archivePath(todosDir2, slug, checklist.archiveInterval);
17247
+ let archContent = "";
17248
+ if (await fileExists(archFile)) {
17249
+ archContent = await readFile19(archFile, "utf-8");
17250
+ archContent = archContent.trimEnd() + "\n\n";
17251
+ } else {
17252
+ archContent = `---
16861
17253
  workspace: ${slug}
16862
17254
  ---
16863
17255
 
16864
17256
  # Archive
16865
17257
 
16866
17258
  `;
16867
- }
16868
- const completedItems = checklist.items.filter((i) => completedIds.has(i.id));
16869
- for (const item of completedItems) {
16870
- archContent += `- [x] ${item.description} ${item.tags.map((t) => `#${t}`).join(" ")} [t:${item.id}]
17259
+ }
17260
+ const completedItems = checklist.items.filter((i) => completedIds.has(i.id));
17261
+ for (const item of completedItems) {
17262
+ archContent += `- [x] ${item.description} ${item.tags.map((t) => `#${t}`).join(" ")} [t:${item.id}]
16871
17263
  `;
16872
- }
16873
- archContent += "\n";
16874
- for (const entry of toArchive) {
16875
- archContent += `### ${entry.timestamp} \u2014 ${entry.itemIds.map((i) => `t:${i}`).join(", ")}
17264
+ }
17265
+ archContent += "\n";
17266
+ for (const entry of toArchive) {
17267
+ archContent += `### ${entry.timestamp} \u2014 ${entry.itemIds.map((i) => `t:${i}`).join(", ")}
16876
17268
  `;
16877
- if (entry.items) archContent += `**Items:** ${entry.items}
17269
+ if (entry.items) archContent += `**Items:** ${entry.items}
16878
17270
  `;
16879
- if (entry.session) archContent += `**Session:** ${entry.session}
17271
+ if (entry.session) archContent += `**Session:** ${entry.session}
16880
17272
  `;
16881
- if (entry.branch) archContent += `**Branch:** ${entry.branch}
17273
+ if (entry.branch) archContent += `**Branch:** ${entry.branch}
16882
17274
  `;
16883
- if (entry.summary) archContent += `**Summary:** ${entry.summary}
17275
+ if (entry.summary) archContent += `**Summary:** ${entry.summary}
16884
17276
  `;
16885
- if (entry.blockers) archContent += `**Blockers:** ${entry.blockers}
17277
+ if (entry.blockers) archContent += `**Blockers:** ${entry.blockers}
16886
17278
  `;
16887
- archContent += "\n";
17279
+ archContent += "\n";
17280
+ }
17281
+ await writeFileForce(archFile, archContent);
17282
+ checklist.workspace = slug;
17283
+ checklist.items = checklist.items.filter((i) => !completedIds.has(i.id));
17284
+ await writeChecklist(todosDir2, checklist);
17285
+ for (const id of completedIds) {
17286
+ await deleteAllAttachments(todosDir2, slug, id);
17287
+ }
17288
+ return { archived: completedIds.size, logEntries: toArchive.length };
17289
+ });
17290
+ if (outcome === "gone") {
17291
+ notFound(res, slug);
17292
+ return;
16888
17293
  }
16889
- await writeFileForce(archFile, archContent);
16890
- checklist.workspace = slug;
16891
- checklist.items = checklist.items.filter((i) => !completedIds.has(i.id));
16892
- await writeChecklist(todosDir2, checklist);
16893
- broadcastUpdate(slug);
16894
- res.json({ archived: completedIds.size, logEntries: toArchive.length });
17294
+ if (outcome.archived > 0) broadcastUpdate(slug);
17295
+ res.json(outcome);
16895
17296
  } catch (error) {
16896
17297
  if (error.code === "PROJECT_GONE") {
16897
17298
  notFound(res, getProjectIdParam(params(req).projectId));
@@ -16931,7 +17332,8 @@ workspace: ${slug}
16931
17332
  }
16932
17333
  const log = await readLog(todosDir2, slug);
16933
17334
  const logEntries = log.entries.filter((e) => e.itemIds.includes(params(req).id ?? ""));
16934
- res.json({ ...item, log: logEntries });
17335
+ const attachments = await listAttachments(todosDir2, slug, item.id);
17336
+ res.json({ ...item, attachments, log: logEntries });
16935
17337
  } catch (error) {
16936
17338
  res.status(500).json({ error: error instanceof Error ? error.message : "Failed to get todo" });
16937
17339
  }
@@ -16987,11 +17389,13 @@ workspace: ${slug}
16987
17389
  await ensureProjectTodosDir(projectsDir2, slug);
16988
17390
  const todosDir2 = projectTodosDir(projectsDir2, slug);
16989
17391
  const checklist = await readChecklist(todosDir2, slug);
16990
- const idx = checklist.items.findIndex((i) => i.id === (params(req).id ?? ""));
17392
+ const targetId = params(req).id ?? "";
17393
+ const idx = checklist.items.findIndex((i) => i.id === targetId);
16991
17394
  if (idx === -1) return false;
16992
17395
  checklist.items.splice(idx, 1);
16993
17396
  checklist.workspace = slug;
16994
17397
  await writeChecklist(todosDir2, checklist);
17398
+ await deleteAllAttachments(todosDir2, slug, targetId);
16995
17399
  return true;
16996
17400
  });
16997
17401
  if (deleted === "gone") {
@@ -17301,15 +17705,15 @@ workspace: ${slug}
17301
17705
  if (tg.includes("/")) {
17302
17706
  const parts = tg.split("/");
17303
17707
  if (parts.length !== 2) return { error: `Invalid target.assignment "${tg}"` };
17304
- assignmentDir = resolve27(projectsDir2, parts[0], "assignments", parts[1]);
17708
+ assignmentDir = resolve28(projectsDir2, parts[0], "assignments", parts[1]);
17305
17709
  assignmentRef = `${parts[0]}/${parts[1]}`;
17306
17710
  } else if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(tg)) {
17307
- assignmentDir = resolve27(assignmentsDirFn(), tg);
17711
+ assignmentDir = resolve28(assignmentsDirFn(), tg);
17308
17712
  assignmentRef = tg;
17309
17713
  } else {
17310
17714
  return { error: `Invalid target.assignment "${tg}"` };
17311
17715
  }
17312
- const assignmentMdPath2 = resolve27(assignmentDir, "assignment.md");
17716
+ const assignmentMdPath2 = resolve28(assignmentDir, "assignment.md");
17313
17717
  if (!await fileExists(assignmentMdPath2)) return { error: `Target assignment not found: ${assignmentMdPath2}` };
17314
17718
  let content = await readFile19(assignmentMdPath2, "utf-8");
17315
17719
  content = appendTodosToAssignmentBody2(
@@ -17439,15 +17843,22 @@ workspace: ${slug}
17439
17843
  return { status: 409, error: "id already exists in target" };
17440
17844
  }
17441
17845
  const item = sourceChecklist.items[idx];
17846
+ let newPlanDir = null;
17442
17847
  if (item.planDir) {
17443
- const newPlanDir = todoPlanDir(target.todosPath, target.id, id);
17848
+ newPlanDir = todoPlanDir(target.todosPath, target.id, id);
17444
17849
  if (await fileExists(newPlanDir)) {
17445
17850
  return { status: 409, error: "plan dir already exists in target" };
17446
17851
  }
17447
- await mkdir3(dirname7(newPlanDir), { recursive: true });
17448
- await rename6(item.planDir, newPlanDir);
17852
+ }
17853
+ if (await attachmentMoveConflict(sourceTodosDir, sourceSlug, target.todosPath, target.id, id)) {
17854
+ return { status: 409, error: "attachments already exist in target" };
17855
+ }
17856
+ if (item.planDir && newPlanDir) {
17857
+ await mkdir4(dirname8(newPlanDir), { recursive: true });
17858
+ await rename7(item.planDir, newPlanDir);
17449
17859
  item.planDir = newPlanDir;
17450
17860
  }
17861
+ await moveAttachments(sourceTodosDir, sourceSlug, target.todosPath, target.id, id);
17451
17862
  sourceChecklist.items.splice(idx, 1);
17452
17863
  targetChecklist.items.push(item);
17453
17864
  sourceChecklist.workspace = sourceSlug;
@@ -17506,22 +17917,22 @@ workspace: ${slug}
17506
17917
  }
17507
17918
 
17508
17919
  // src/dashboard/api-bundles.ts
17509
- import { Router as Router15 } from "express";
17510
- import { readdir as readdir12 } from "fs/promises";
17920
+ import { Router as Router16 } from "express";
17921
+ import { readdir as readdir13 } from "fs/promises";
17511
17922
 
17512
17923
  // src/todos/bundle-parser.ts
17513
17924
  init_parser();
17514
17925
  init_fs();
17515
17926
  init_paths();
17516
17927
  init_parser2();
17517
- import { randomBytes as randomBytes2 } from "crypto";
17928
+ import { randomBytes as randomBytes3 } from "crypto";
17518
17929
  import { readFile as readFile20 } from "fs/promises";
17519
17930
  var BUNDLE_ID_REGEX = /^[a-f0-9]{4}$/;
17520
17931
  var SCOPE_VALUES = /* @__PURE__ */ new Set(["workspace", "project", "global"]);
17521
17932
  var SCOPE_ID_REGEX = /^[a-z0-9_][a-z0-9_-]*$/;
17522
17933
  var BUNDLE_LINE_REGEX = /^- b:([a-f0-9]{4})\s+<([^>]*)>\s*$/;
17523
17934
  function generateShortBundleId() {
17524
- return randomBytes2(2).toString("hex");
17935
+ return randomBytes3(2).toString("hex");
17525
17936
  }
17526
17937
  function generateUniqueBundleId(existing) {
17527
17938
  let id = generateShortBundleId();
@@ -17532,19 +17943,19 @@ function generateUniqueBundleId(existing) {
17532
17943
  }
17533
17944
  return id;
17534
17945
  }
17535
- function parseScopeToken(raw) {
17536
- const idx = raw.indexOf(":");
17946
+ function parseScopeToken(raw2) {
17947
+ const idx = raw2.indexOf(":");
17537
17948
  if (idx < 0) return null;
17538
- const scopeRaw = raw.slice(0, idx);
17539
- const scopeId = raw.slice(idx + 1);
17949
+ const scopeRaw = raw2.slice(0, idx);
17950
+ const scopeId = raw2.slice(idx + 1);
17540
17951
  if (!SCOPE_VALUES.has(scopeRaw)) return null;
17541
17952
  if (!scopeId) return null;
17542
17953
  if (!SCOPE_ID_REGEX.test(scopeId)) return null;
17543
17954
  return { scope: scopeRaw, scopeId };
17544
17955
  }
17545
- function parseTodosToken(raw) {
17546
- if (!raw) return [];
17547
- return raw.split(",").map((s) => s.trim()).filter((s) => BUNDLE_ID_REGEX.test(s));
17956
+ function parseTodosToken(raw2) {
17957
+ if (!raw2) return [];
17958
+ return raw2.split(",").map((s) => s.trim()).filter((s) => BUNDLE_ID_REGEX.test(s));
17548
17959
  }
17549
17960
  function parseBundleLine(line) {
17550
17961
  const match = line.match(BUNDLE_LINE_REGEX);
@@ -17657,7 +18068,7 @@ function annotate(bundle, items) {
17657
18068
  }
17658
18069
  function createBundlesRouter(todosDir2, broadcast) {
17659
18070
  void broadcast;
17660
- const router = Router15();
18071
+ const router = Router16();
17661
18072
  function validateWorkspace(req, res, next) {
17662
18073
  const workspace = getWorkspaceParam2(req.params.workspace);
17663
18074
  if (workspace && !WORKSPACE_REGEX3.test(workspace)) {
@@ -17671,7 +18082,7 @@ function createBundlesRouter(todosDir2, broadcast) {
17671
18082
  try {
17672
18083
  await ensureDir(todosDir2);
17673
18084
  const bundles = await readBundles(todosDir2);
17674
- const workspaceFiles = await readdir12(todosDir2).catch(() => []);
18085
+ const workspaceFiles = await readdir13(todosDir2).catch(() => []);
17675
18086
  const itemsByKey = /* @__PURE__ */ new Map();
17676
18087
  for (const f of workspaceFiles) {
17677
18088
  if (typeof f !== "string") continue;
@@ -17723,8 +18134,8 @@ function createBundlesRouter(todosDir2, broadcast) {
17723
18134
  init_fs();
17724
18135
  init_paths();
17725
18136
  init_slug();
17726
- import { Router as Router16 } from "express";
17727
- import { resolve as resolve28 } from "path";
18137
+ import { Router as Router17 } from "express";
18138
+ import { resolve as resolve29 } from "path";
17728
18139
  init_parser2();
17729
18140
  function deriveStatus2(bundle, items) {
17730
18141
  const members = bundle.todoIds.map((id) => items.find((i) => i.id === id)).filter((i) => i !== void 0);
@@ -17753,7 +18164,7 @@ function notFound2(res, slug) {
17753
18164
  }
17754
18165
  function createProjectBundlesRouter(projectsDir2, broadcast) {
17755
18166
  void broadcast;
17756
- const router = Router16({ mergeParams: true });
18167
+ const router = Router17({ mergeParams: true });
17757
18168
  function validateProjectId(req, res, next) {
17758
18169
  const slug = getProjectIdParam2(req.params.projectId);
17759
18170
  if (!slug || !isValidSlug(slug)) {
@@ -17766,7 +18177,7 @@ function createProjectBundlesRouter(projectsDir2, broadcast) {
17766
18177
  router.get("/", async (req, res) => {
17767
18178
  try {
17768
18179
  const slug = getProjectIdParam2(req.params.projectId);
17769
- const projectMd = resolve28(projectsDir2, slug, "project.md");
18180
+ const projectMd = resolve29(projectsDir2, slug, "project.md");
17770
18181
  if (!await fileExists(projectMd)) {
17771
18182
  notFound2(res, slug);
17772
18183
  return;
@@ -17787,7 +18198,7 @@ function createProjectBundlesRouter(projectsDir2, broadcast) {
17787
18198
  init_config2();
17788
18199
  init_api();
17789
18200
  init_scanner();
17790
- import { Router as Router17 } from "express";
18201
+ import { Router as Router18 } from "express";
17791
18202
 
17792
18203
  // src/utils/github-backup.ts
17793
18204
  init_paths();
@@ -17795,8 +18206,8 @@ init_fs();
17795
18206
  init_config2();
17796
18207
  import { execFile as execFile2 } from "child_process";
17797
18208
  import { promisify as promisify2 } from "util";
17798
- import { cp, mkdtemp, rm as rm3, readFile as readFile21, writeFile as writeFile5, unlink as unlink5, stat, open as open2, rename as rename7 } from "fs/promises";
17799
- import { resolve as resolve29, join as join3 } from "path";
18209
+ import { cp as cp2, mkdtemp, rm as rm4, readFile as readFile21, writeFile as writeFile6, unlink as unlink6, stat as stat2, open as open2, rename as rename8 } from "fs/promises";
18210
+ import { resolve as resolve30, join as join3 } from "path";
17800
18211
  import { tmpdir } from "os";
17801
18212
  var exec2 = promisify2(execFile2);
17802
18213
  var VALID_CATEGORIES = ["projects", "playbooks", "todos", "servers", "config"];
@@ -17836,7 +18247,7 @@ async function resolveCategoryPath(category) {
17836
18247
  case "servers":
17837
18248
  return { sourcePath: serversDir(), repoPath: "servers", isFile: false };
17838
18249
  case "config":
17839
- return { sourcePath: resolve29(syntaurRoot(), "config.md"), repoPath: "config.md", isFile: true };
18250
+ return { sourcePath: resolve30(syntaurRoot(), "config.md"), repoPath: "config.md", isFile: true };
17840
18251
  }
17841
18252
  }
17842
18253
  async function checkGitInstalled() {
@@ -17847,7 +18258,7 @@ async function checkGitInstalled() {
17847
18258
  }
17848
18259
  }
17849
18260
  async function acquireLock() {
17850
- const lockPath = resolve29(syntaurRoot(), LOCK_FILE_NAME);
18261
+ const lockPath = resolve30(syntaurRoot(), LOCK_FILE_NAME);
17851
18262
  await ensureDir(syntaurRoot());
17852
18263
  try {
17853
18264
  const handle = await open2(lockPath, "wx");
@@ -17866,7 +18277,7 @@ async function acquireLock() {
17866
18277
  }
17867
18278
  async function releaseLock(lockPath) {
17868
18279
  try {
17869
- await unlink5(lockPath);
18280
+ await unlink6(lockPath);
17870
18281
  } catch {
17871
18282
  }
17872
18283
  }
@@ -17889,13 +18300,13 @@ async function cloneOrInit(repoUrl, destDir) {
17889
18300
  }
17890
18301
  async function copyRecursive(src, dest) {
17891
18302
  if (!await fileExists(src)) return;
17892
- const s = await stat(src);
18303
+ const s = await stat2(src);
17893
18304
  if (s.isDirectory()) {
17894
18305
  await ensureDir(dest);
17895
- await cp(src, dest, { recursive: true, force: true });
18306
+ await cp2(src, dest, { recursive: true, force: true });
17896
18307
  } else {
17897
- await ensureDir(resolve29(dest, ".."));
17898
- await cp(src, dest, { force: true });
18308
+ await ensureDir(resolve30(dest, ".."));
18309
+ await cp2(src, dest, { force: true });
17899
18310
  }
17900
18311
  }
17901
18312
  function resolveCategoriesStrict(csv) {
@@ -17932,9 +18343,9 @@ async function backupToGithub(overrides) {
17932
18343
  const { sourcePath, repoPath, isFile } = await resolveCategoryPath(category);
17933
18344
  const destPath = join3(tmpDir, repoPath);
17934
18345
  if (isFile) {
17935
- await rm3(destPath, { force: true });
18346
+ await rm4(destPath, { force: true });
17936
18347
  } else {
17937
- await rm3(destPath, { recursive: true, force: true });
18348
+ await rm4(destPath, { recursive: true, force: true });
17938
18349
  }
17939
18350
  if (!await fileExists(sourcePath)) {
17940
18351
  console.warn(`Category "${category}": no local data at ${sourcePath}; backup will reflect deletion.`);
@@ -17942,8 +18353,8 @@ async function backupToGithub(overrides) {
17942
18353
  }
17943
18354
  if (category === "config") {
17944
18355
  const sanitized = await readSanitizedConfig(sourcePath);
17945
- await ensureDir(resolve29(destPath, ".."));
17946
- await writeFile5(destPath, sanitized, "utf-8");
18356
+ await ensureDir(resolve30(destPath, ".."));
18357
+ await writeFile6(destPath, sanitized, "utf-8");
17947
18358
  } else {
17948
18359
  await copyRecursive(sourcePath, destPath);
17949
18360
  }
@@ -17988,7 +18399,7 @@ async function backupToGithub(overrides) {
17988
18399
  };
17989
18400
  } finally {
17990
18401
  if (tmpDir) {
17991
- await rm3(tmpDir, { recursive: true, force: true }).catch(() => {
18402
+ await rm4(tmpDir, { recursive: true, force: true }).catch(() => {
17992
18403
  });
17993
18404
  }
17994
18405
  await releaseLock(lockPath);
@@ -17996,18 +18407,18 @@ async function backupToGithub(overrides) {
17996
18407
  }
17997
18408
  async function safeRestoreCategory(localPath, repoSrcPath, isFile) {
17998
18409
  if (isFile) {
17999
- await ensureDir(resolve29(localPath, ".."));
18000
- await cp(repoSrcPath, localPath, { force: true });
18410
+ await ensureDir(resolve30(localPath, ".."));
18411
+ await cp2(repoSrcPath, localPath, { force: true });
18001
18412
  return;
18002
18413
  }
18003
18414
  const stagingPath = `${localPath}.syntaur-restore-staging`;
18004
18415
  const backupPath = `${localPath}.syntaur-restore-backup`;
18005
- await rm3(stagingPath, { recursive: true, force: true });
18416
+ await rm4(stagingPath, { recursive: true, force: true });
18006
18417
  const backupExistsBefore = await fileExists(backupPath);
18007
18418
  const localExistsBefore = await fileExists(localPath);
18008
18419
  if (backupExistsBefore) {
18009
18420
  if (!localExistsBefore) {
18010
- await rename7(backupPath, localPath);
18421
+ await rename8(backupPath, localPath);
18011
18422
  } else {
18012
18423
  throw new Error(
18013
18424
  `Cannot restore "${localPath}": a stale crash-recovery backup exists at ${backupPath} while the current path also exists. Inspect both and remove the one you don't need, then retry.`
@@ -18016,21 +18427,21 @@ async function safeRestoreCategory(localPath, repoSrcPath, isFile) {
18016
18427
  }
18017
18428
  let localMovedAside = false;
18018
18429
  try {
18019
- await cp(repoSrcPath, stagingPath, { recursive: true, force: true });
18430
+ await cp2(repoSrcPath, stagingPath, { recursive: true, force: true });
18020
18431
  const localExists = await fileExists(localPath);
18021
18432
  if (localExists) {
18022
- await rename7(localPath, backupPath);
18433
+ await rename8(localPath, backupPath);
18023
18434
  localMovedAside = true;
18024
18435
  }
18025
- await rename7(stagingPath, localPath);
18026
- await rm3(backupPath, { recursive: true, force: true }).catch(() => {
18436
+ await rename8(stagingPath, localPath);
18437
+ await rm4(backupPath, { recursive: true, force: true }).catch(() => {
18027
18438
  });
18028
18439
  } catch (err2) {
18029
18440
  if (localMovedAside && await fileExists(backupPath)) {
18030
- await rename7(backupPath, localPath).catch(() => {
18441
+ await rename8(backupPath, localPath).catch(() => {
18031
18442
  });
18032
18443
  }
18033
- await rm3(stagingPath, { recursive: true, force: true }).catch(() => {
18444
+ await rm4(stagingPath, { recursive: true, force: true }).catch(() => {
18034
18445
  });
18035
18446
  throw err2;
18036
18447
  }
@@ -18089,7 +18500,7 @@ async function restoreFromGithub(overrides) {
18089
18500
  };
18090
18501
  } finally {
18091
18502
  if (tmpDir) {
18092
- await rm3(tmpDir, { recursive: true, force: true }).catch(() => {
18503
+ await rm4(tmpDir, { recursive: true, force: true }).catch(() => {
18093
18504
  });
18094
18505
  }
18095
18506
  await releaseLock(lockPath);
@@ -18097,7 +18508,7 @@ async function restoreFromGithub(overrides) {
18097
18508
  }
18098
18509
  async function getBackupStatus() {
18099
18510
  const config = await readConfig();
18100
- const lockPath = resolve29(syntaurRoot(), LOCK_FILE_NAME);
18511
+ const lockPath = resolve30(syntaurRoot(), LOCK_FILE_NAME);
18101
18512
  const locked = await fileExists(lockPath);
18102
18513
  return {
18103
18514
  repo: config.backup?.repo ?? null,
@@ -18110,7 +18521,7 @@ async function getBackupStatus() {
18110
18521
 
18111
18522
  // src/dashboard/api-backup.ts
18112
18523
  function createBackupRouter() {
18113
- const router = Router17();
18524
+ const router = Router18();
18114
18525
  router.get("/", async (_req, res) => {
18115
18526
  try {
18116
18527
  const status = await getBackupStatus();
@@ -18445,7 +18856,7 @@ function createDashboardServer(options) {
18445
18856
  (async () => {
18446
18857
  try {
18447
18858
  const configResult = await migrateLegacyConfig(
18448
- resolve30(syntaurRoot(), "config.md")
18859
+ resolve31(syntaurRoot(), "config.md")
18449
18860
  );
18450
18861
  const projectResult = await migrateLegacyProjectFiles(projectsDir2);
18451
18862
  const summary = summarizeMigration(projectResult, configResult);
@@ -18546,8 +18957,8 @@ function createDashboardServer(options) {
18546
18957
  });
18547
18958
  app.put("/api/config/hotkeys", async (req, res) => {
18548
18959
  try {
18549
- const raw = req.body && typeof req.body === "object" ? req.body : {};
18550
- const incoming = raw.bindings;
18960
+ const raw2 = req.body && typeof req.body === "object" ? req.body : {};
18961
+ const incoming = raw2.bindings;
18551
18962
  if (!incoming || typeof incoming !== "object" || Array.isArray(incoming)) {
18552
18963
  res.status(400).json({ error: "bindings must be an object keyed by action kind" });
18553
18964
  return;
@@ -18963,14 +19374,14 @@ function createDashboardServer(options) {
18963
19374
  app.use("/api/backup", createBackupRouter());
18964
19375
  if (serveStaticUi && dashboardDistPath) {
18965
19376
  const sendOpts = { dotfiles: "allow" };
18966
- app.use("/assets", express.static(resolve30(dashboardDistPath, "assets"), sendOpts));
19377
+ app.use("/assets", express.static(resolve31(dashboardDistPath, "assets"), sendOpts));
18967
19378
  app.use(express.static(dashboardDistPath, { ...sendOpts, index: false, fallthrough: true }));
18968
19379
  app.get("{*path}", async (req, res) => {
18969
19380
  if (req.path.startsWith("/api") || req.path === "/ws" || req.path.startsWith("/assets")) {
18970
19381
  res.status(404).json({ error: "Not Found" });
18971
19382
  return;
18972
19383
  }
18973
- const indexPath = resolve30(dashboardDistPath, "index.html");
19384
+ const indexPath = resolve31(dashboardDistPath, "index.html");
18974
19385
  if (!await fileExists(indexPath)) {
18975
19386
  res.status(503).send(
18976
19387
  'Dashboard not built. Run "npm run build:dashboard" first.'
@@ -18994,7 +19405,7 @@ function createDashboardServer(options) {
18994
19405
  serversDir: serversDir2,
18995
19406
  playbooksDir: playbooksDir3,
18996
19407
  todosDir: todosDir2,
18997
- dbPath: resolve30(syntaurRoot(), "syntaur.db"),
19408
+ dbPath: resolve31(syntaurRoot(), "syntaur.db"),
18998
19409
  onMessage: broadcast
18999
19410
  });
19000
19411
  startAutodiscovery({ serversDir: serversDir2, projectsDir: projectsDir2, assignmentsDir: assignmentsDir2, excludePids: /* @__PURE__ */ new Set([process.pid]) });
@@ -19009,8 +19420,8 @@ function createDashboardServer(options) {
19009
19420
  }
19010
19421
  });
19011
19422
  server.listen(port, () => {
19012
- const portFile = resolve30(syntaurRoot(), "dashboard-port");
19013
- writeFile6(portFile, String(port), "utf-8").catch(() => {
19423
+ const portFile = resolve31(syntaurRoot(), "dashboard-port");
19424
+ writeFile7(portFile, String(port), "utf-8").catch(() => {
19014
19425
  });
19015
19426
  resolvePromise();
19016
19427
  });
@@ -19028,8 +19439,8 @@ function createDashboardServer(options) {
19028
19439
  client.terminate();
19029
19440
  }
19030
19441
  clients.clear();
19031
- const portFile = resolve30(syntaurRoot(), "dashboard-port");
19032
- await unlink6(portFile).catch(() => {
19442
+ const portFile = resolve31(syntaurRoot(), "dashboard-port");
19443
+ await unlink7(portFile).catch(() => {
19033
19444
  });
19034
19445
  server.closeAllConnections?.();
19035
19446
  return new Promise((resolvePromise) => {
@@ -19108,8 +19519,8 @@ async function dashboardCommand(options) {
19108
19519
  port = availablePort;
19109
19520
  }
19110
19521
  const thisFile = fileURLToPath2(import.meta.url);
19111
- const packageRoot = resolve31(dirname8(thisFile), "..");
19112
- const dashboardDist = resolve31(packageRoot, "dashboard", "dist");
19522
+ const packageRoot = resolve32(dirname9(thisFile), "..");
19523
+ const dashboardDist = resolve32(packageRoot, "dashboard", "dist");
19113
19524
  const server = createDashboardServer({
19114
19525
  port,
19115
19526
  projectsDir: projectsDir2,
@@ -19123,8 +19534,8 @@ async function dashboardCommand(options) {
19123
19534
  await server.start();
19124
19535
  let viteProcess = null;
19125
19536
  if (mode === "dev") {
19126
- const dashboardDir = resolve31(packageRoot, "dashboard");
19127
- const viteBin = resolve31(dashboardDir, "node_modules", ".bin", "vite");
19537
+ const dashboardDir = resolve32(packageRoot, "dashboard");
19538
+ const viteBin = resolve32(dashboardDir, "node_modules", ".bin", "vite");
19128
19539
  if (!await fileExists(viteBin)) {
19129
19540
  console.error(
19130
19541
  'Vite not found. Run "npm ci --prefix dashboard" first, or use the default bundled dashboard mode.'
@@ -19199,7 +19610,7 @@ init_config2();
19199
19610
  init_slug();
19200
19611
  init_lifecycle();
19201
19612
  init_assignment_resolver();
19202
- import { resolve as resolve32 } from "path";
19613
+ import { resolve as resolve33 } from "path";
19203
19614
  function resolveLinkedTodosLookup(projectsDir2) {
19204
19615
  return { todosDir: todosDir(), projectsDir: projectsDir2 };
19205
19616
  }
@@ -19213,8 +19624,8 @@ async function runTransition(assignment, command, options = {}) {
19213
19624
  if (!isValidSlug(assignment)) {
19214
19625
  throw new Error(`Invalid assignment slug "${assignment}".`);
19215
19626
  }
19216
- const projectDir = resolve32(baseDir, options.project);
19217
- const projectMdPath = resolve32(projectDir, "project.md");
19627
+ const projectDir = resolve33(baseDir, options.project);
19628
+ const projectMdPath = resolve33(projectDir, "project.md");
19218
19629
  if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
19219
19630
  throw new Error(`Project "${options.project}" not found at ${projectDir}.`);
19220
19631
  }
@@ -19247,8 +19658,8 @@ async function runAssign(assignment, agent, options = {}) {
19247
19658
  if (!isValidSlug(assignment)) {
19248
19659
  throw new Error(`Invalid assignment slug "${assignment}".`);
19249
19660
  }
19250
- const projectDir = resolve32(baseDir, options.project);
19251
- const projectMdPath = resolve32(projectDir, "project.md");
19661
+ const projectDir = resolve33(baseDir, options.project);
19662
+ const projectMdPath = resolve33(projectDir, "project.md");
19252
19663
  if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
19253
19664
  throw new Error(`Project "${options.project}" not found at ${projectDir}.`);
19254
19665
  }
@@ -19295,8 +19706,8 @@ init_slug();
19295
19706
  init_frontmatter();
19296
19707
  init_timestamp();
19297
19708
  init_assignment_resolver();
19298
- import { resolve as resolve33 } from "path";
19299
- import { readFile as readFile22, writeFile as writeFile7 } from "fs/promises";
19709
+ import { resolve as resolve34 } from "path";
19710
+ import { readFile as readFile22, writeFile as writeFile8 } from "fs/promises";
19300
19711
  async function resolveTarget(target, options) {
19301
19712
  const config = await readConfig();
19302
19713
  const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
@@ -19307,7 +19718,7 @@ async function resolveTarget(target, options) {
19307
19718
  if (!isValidSlug(target)) {
19308
19719
  throw new Error(`Invalid assignment slug "${target}".`);
19309
19720
  }
19310
- const assignmentMd = resolve33(baseDir, options.project, "assignments", target, "assignment.md");
19721
+ const assignmentMd = resolve34(baseDir, options.project, "assignments", target, "assignment.md");
19311
19722
  if (!await fileExists(assignmentMd)) {
19312
19723
  throw new Error(`Assignment "${target}" not found in project "${options.project}".`);
19313
19724
  }
@@ -19317,11 +19728,11 @@ async function resolveTarget(target, options) {
19317
19728
  if (resolved) {
19318
19729
  return {
19319
19730
  kind: "assignment",
19320
- filePath: resolve33(resolved.assignmentDir, "assignment.md"),
19731
+ filePath: resolve34(resolved.assignmentDir, "assignment.md"),
19321
19732
  label: resolved.projectSlug ? `assignment "${resolved.projectSlug}/${resolved.assignmentSlug}"` : `assignment "${target}"`
19322
19733
  };
19323
19734
  }
19324
- const projectMd = resolve33(baseDir, target, "project.md");
19735
+ const projectMd = resolve34(baseDir, target, "project.md");
19325
19736
  if (await fileExists(projectMd)) {
19326
19737
  return { kind: "project", filePath: projectMd, label: `project "${target}"` };
19327
19738
  }
@@ -19335,7 +19746,7 @@ async function writeArchiveState(filePath, archived, reason) {
19335
19746
  archivedReason: archived ? reason : null,
19336
19747
  updated: nowTimestamp()
19337
19748
  });
19338
- await writeFile7(filePath, updated, "utf-8");
19749
+ await writeFile8(filePath, updated, "utf-8");
19339
19750
  }
19340
19751
  async function runArchive(target, options = {}) {
19341
19752
  const resolved = await resolveTarget(target, options);
@@ -19396,8 +19807,8 @@ init_fs();
19396
19807
  init_config2();
19397
19808
  init_frontmatter();
19398
19809
  init_timestamp();
19399
- import { resolve as resolve34 } from "path";
19400
- import { readdir as readdir13, readFile as readFile23 } from "fs/promises";
19810
+ import { resolve as resolve35 } from "path";
19811
+ import { readdir as readdir14, readFile as readFile23 } from "fs/promises";
19401
19812
  var PROMOTABLE_STATUSES = /* @__PURE__ */ new Set(["pending"]);
19402
19813
  function objectiveIsFleshedOut(content) {
19403
19814
  const match = content.match(/##\s+Objective\s*\n([\s\S]*?)(?=\n##\s+|$)/);
@@ -19415,11 +19826,11 @@ async function collectCandidates(baseDirs) {
19415
19826
  const candidates = [];
19416
19827
  for (const baseDir of baseDirs) {
19417
19828
  if (!await fileExists(baseDir)) continue;
19418
- const projects = await readdir13(baseDir, { withFileTypes: true });
19829
+ const projects = await readdir14(baseDir, { withFileTypes: true });
19419
19830
  for (const m of projects) {
19420
19831
  if (!m.isDirectory()) continue;
19421
19832
  if (m.name.startsWith(".") || m.name.startsWith("_")) continue;
19422
- const directAssignmentMd = resolve34(baseDir, m.name, "assignment.md");
19833
+ const directAssignmentMd = resolve35(baseDir, m.name, "assignment.md");
19423
19834
  if (await fileExists(directAssignmentMd)) {
19424
19835
  const fm = await parseSafe(directAssignmentMd);
19425
19836
  if (fm && PROMOTABLE_STATUSES.has(fm.status)) {
@@ -19436,13 +19847,13 @@ async function collectCandidates(baseDirs) {
19436
19847
  }
19437
19848
  continue;
19438
19849
  }
19439
- const assignmentsDir2 = resolve34(baseDir, m.name, "assignments");
19850
+ const assignmentsDir2 = resolve35(baseDir, m.name, "assignments");
19440
19851
  if (!await fileExists(assignmentsDir2)) continue;
19441
- const entries = await readdir13(assignmentsDir2, { withFileTypes: true });
19852
+ const entries = await readdir14(assignmentsDir2, { withFileTypes: true });
19442
19853
  for (const a of entries) {
19443
19854
  if (!a.isDirectory()) continue;
19444
19855
  if (a.name.startsWith(".") || a.name.startsWith("_")) continue;
19445
- const assignmentMd = resolve34(assignmentsDir2, a.name, "assignment.md");
19856
+ const assignmentMd = resolve35(assignmentsDir2, a.name, "assignment.md");
19446
19857
  if (!await fileExists(assignmentMd)) continue;
19447
19858
  const fm = await parseSafe(assignmentMd);
19448
19859
  if (!fm || !PROMOTABLE_STATUSES.has(fm.status)) continue;
@@ -19546,33 +19957,33 @@ init_config2();
19546
19957
  init_config2();
19547
19958
  init_fs();
19548
19959
  import {
19549
- cp as cp2,
19550
- readdir as readdir14,
19960
+ cp as cp3,
19961
+ readdir as readdir15,
19551
19962
  symlink,
19552
19963
  lstat,
19553
19964
  readFile as readFile24,
19554
19965
  readlink,
19555
- rename as rename8,
19556
- rm as rm4,
19557
- unlink as unlink7,
19558
- writeFile as writeFile8
19966
+ rename as rename9,
19967
+ rm as rm5,
19968
+ unlink as unlink8,
19969
+ writeFile as writeFile9
19559
19970
  } from "fs/promises";
19560
19971
  import { existsSync as existsSync3 } from "fs";
19561
19972
  import { homedir as homedir3 } from "os";
19562
- import { basename as basename4, dirname as dirname10, isAbsolute as isAbsolute4, relative as relative2, resolve as resolve36 } from "path";
19973
+ import { basename as basename5, dirname as dirname11, isAbsolute as isAbsolute4, relative as relative2, resolve as resolve37 } from "path";
19563
19974
 
19564
19975
  // src/utils/package-root.ts
19565
19976
  init_fs();
19566
- import { dirname as dirname9, resolve as resolve35 } from "path";
19977
+ import { dirname as dirname10, resolve as resolve36 } from "path";
19567
19978
  import { fileURLToPath as fileURLToPath3 } from "url";
19568
19979
  async function findPackageRoot(expectedRelativePath) {
19569
- let currentDir = dirname9(fileURLToPath3(import.meta.url));
19980
+ let currentDir = dirname10(fileURLToPath3(import.meta.url));
19570
19981
  while (true) {
19571
- const candidate = resolve35(currentDir, expectedRelativePath);
19982
+ const candidate = resolve36(currentDir, expectedRelativePath);
19572
19983
  if (await fileExists(candidate)) {
19573
19984
  return currentDir;
19574
19985
  }
19575
- const parentDir = resolve35(currentDir, "..");
19986
+ const parentDir = resolve36(currentDir, "..");
19576
19987
  if (parentDir === currentDir) {
19577
19988
  throw new Error(
19578
19989
  `Could not locate package root containing ${expectedRelativePath}.`
@@ -19593,50 +20004,50 @@ function getPluginManifestRelativePath(pluginKind) {
19593
20004
  }
19594
20005
  function getDefaultPluginTargetDir(pluginKind) {
19595
20006
  const home2 = homedir3();
19596
- return pluginKind === "claude" ? resolve36(home2, ".claude", "plugins", "syntaur") : resolve36(home2, "plugins", "syntaur");
20007
+ return pluginKind === "claude" ? resolve37(home2, ".claude", "plugins", "syntaur") : resolve37(home2, "plugins", "syntaur");
19597
20008
  }
19598
20009
  function getDefaultMarketplacePath() {
19599
- return resolve36(homedir3(), ".agents", "plugins", "marketplace.json");
20010
+ return resolve37(homedir3(), ".agents", "plugins", "marketplace.json");
19600
20011
  }
19601
20012
  function getClaudeMarketplacesRoot() {
19602
- return resolve36(homedir3(), ".claude", "plugins", "marketplaces");
20013
+ return resolve37(homedir3(), ".claude", "plugins", "marketplaces");
19603
20014
  }
19604
20015
  function getClaudeKnownMarketplacesPath() {
19605
- return resolve36(homedir3(), ".claude", "plugins", "known_marketplaces.json");
20016
+ return resolve37(homedir3(), ".claude", "plugins", "known_marketplaces.json");
19606
20017
  }
19607
20018
  function getClaudeInstalledPluginsPath() {
19608
- return resolve36(homedir3(), ".claude", "plugins", "installed_plugins.json");
20019
+ return resolve37(homedir3(), ".claude", "plugins", "installed_plugins.json");
19609
20020
  }
19610
20021
  function getInstallMarkerPath(targetDir) {
19611
- return resolve36(targetDir, INSTALL_MARKER_FILENAME);
20022
+ return resolve37(targetDir, INSTALL_MARKER_FILENAME);
19612
20023
  }
19613
20024
  async function readPackageManifest(packageRoot) {
19614
- const raw = await readFile24(resolve36(packageRoot, "package.json"), "utf-8");
19615
- return JSON.parse(raw);
20025
+ const raw2 = await readFile24(resolve37(packageRoot, "package.json"), "utf-8");
20026
+ return JSON.parse(raw2);
19616
20027
  }
19617
20028
  async function readJsonFileIfExists(pathValue) {
19618
20029
  if (!await fileExists(pathValue)) {
19619
20030
  return null;
19620
20031
  }
19621
20032
  try {
19622
- const raw = await readFile24(pathValue, "utf-8");
19623
- return JSON.parse(raw);
20033
+ const raw2 = await readFile24(pathValue, "utf-8");
20034
+ return JSON.parse(raw2);
19624
20035
  } catch {
19625
20036
  return null;
19626
20037
  }
19627
20038
  }
19628
20039
  async function readClaudePluginManifest(pluginDir) {
19629
20040
  return await readJsonFileIfExists(
19630
- resolve36(pluginDir, ".claude-plugin", "plugin.json")
20041
+ resolve37(pluginDir, ".claude-plugin", "plugin.json")
19631
20042
  ) ?? {};
19632
20043
  }
19633
20044
  async function readPluginManifestName(targetDir, pluginKind) {
19634
- const manifestPath = resolve36(targetDir, getPluginManifestRelativePath(pluginKind));
20045
+ const manifestPath = resolve37(targetDir, getPluginManifestRelativePath(pluginKind));
19635
20046
  if (!await fileExists(manifestPath)) {
19636
20047
  return void 0;
19637
20048
  }
19638
- const raw = await readFile24(manifestPath, "utf-8");
19639
- const parsed = JSON.parse(raw);
20049
+ const raw2 = await readFile24(manifestPath, "utf-8");
20050
+ const parsed = JSON.parse(raw2);
19640
20051
  return parsed.name;
19641
20052
  }
19642
20053
  async function readInstallMetadata(targetDir) {
@@ -19645,8 +20056,8 @@ async function readInstallMetadata(targetDir) {
19645
20056
  return null;
19646
20057
  }
19647
20058
  try {
19648
- const raw = await readFile24(markerPath, "utf-8");
19649
- return JSON.parse(raw);
20059
+ const raw2 = await readFile24(markerPath, "utf-8");
20060
+ return JSON.parse(raw2);
19650
20061
  } catch {
19651
20062
  return null;
19652
20063
  }
@@ -19658,7 +20069,7 @@ async function getInstallStatus(targetDir, pluginKind) {
19658
20069
  const info = await lstat(targetDir);
19659
20070
  if (info.isSymbolicLink()) {
19660
20071
  const symlinkTarget = await readlink(targetDir);
19661
- const resolvedTarget = resolve36(dirname10(targetDir), symlinkTarget);
20072
+ const resolvedTarget = resolve37(dirname11(targetDir), symlinkTarget);
19662
20073
  const manifestName2 = await readPluginManifestName(resolvedTarget, pluginKind);
19663
20074
  return {
19664
20075
  exists: true,
@@ -19687,7 +20098,7 @@ async function writeInstallMetadata(targetDir, pluginKind, installMode, packageM
19687
20098
  installMode,
19688
20099
  installedAt: (/* @__PURE__ */ new Date()).toISOString()
19689
20100
  };
19690
- await writeFile8(
20101
+ await writeFile9(
19691
20102
  getInstallMarkerPath(targetDir),
19692
20103
  `${JSON.stringify(metadata, null, 2)}
19693
20104
  `,
@@ -19695,21 +20106,21 @@ async function writeInstallMetadata(targetDir, pluginKind, installMode, packageM
19695
20106
  );
19696
20107
  }
19697
20108
  async function installCopy(paths, pluginKind) {
19698
- await ensureDir(dirname10(paths.targetDir));
19699
- await cp2(paths.sourceDir, paths.targetDir, { recursive: true });
20109
+ await ensureDir(dirname11(paths.targetDir));
20110
+ await cp3(paths.sourceDir, paths.targetDir, { recursive: true });
19700
20111
  const packageManifest = await readPackageManifest(paths.packageRoot);
19701
20112
  await writeInstallMetadata(paths.targetDir, pluginKind, "copy", packageManifest);
19702
20113
  }
19703
20114
  async function installLink(paths) {
19704
- await ensureDir(dirname10(paths.targetDir));
19705
- await rm4(paths.targetDir, { recursive: true, force: true });
19706
- await ensureDir(dirname10(paths.targetDir));
19707
- await symlink(resolve36(paths.sourceDir), paths.targetDir, "dir");
20115
+ await ensureDir(dirname11(paths.targetDir));
20116
+ await rm5(paths.targetDir, { recursive: true, force: true });
20117
+ await ensureDir(dirname11(paths.targetDir));
20118
+ await symlink(resolve37(paths.sourceDir), paths.targetDir, "dir");
19708
20119
  }
19709
20120
  async function removeInstallMarker(targetDir) {
19710
20121
  const markerPath = getInstallMarkerPath(targetDir);
19711
20122
  if (await fileExists(markerPath)) {
19712
- await unlink7(markerPath).catch(() => {
20123
+ await unlink8(markerPath).catch(() => {
19713
20124
  });
19714
20125
  }
19715
20126
  }
@@ -19718,13 +20129,13 @@ function normalizeAbsoluteInstallPath(pathValue, label) {
19718
20129
  if (!isAbsolute4(expanded)) {
19719
20130
  throw new Error(`${label} must be an absolute path.`);
19720
20131
  }
19721
- return resolve36(expanded);
20132
+ return resolve37(expanded);
19722
20133
  }
19723
20134
  async function resolvePluginPaths(pluginKind, targetDir) {
19724
20135
  const packageRoot = await findPackageRoot(getPluginRelativePath(pluginKind));
19725
20136
  return {
19726
20137
  packageRoot,
19727
- sourceDir: resolve36(packageRoot, getPluginRelativePath(pluginKind)),
20138
+ sourceDir: resolve37(packageRoot, getPluginRelativePath(pluginKind)),
19728
20139
  targetDir: targetDir ?? getDefaultPluginTargetDir(pluginKind)
19729
20140
  };
19730
20141
  }
@@ -19758,7 +20169,7 @@ async function readClaudeMarketplaceFile(manifestPath) {
19758
20169
  };
19759
20170
  }
19760
20171
  async function writeClaudeMarketplaceFile(manifestPath, marketplace) {
19761
- await ensureDir(dirname10(manifestPath));
20172
+ await ensureDir(dirname11(manifestPath));
19762
20173
  if (Array.isArray(marketplace.plugins)) {
19763
20174
  marketplace.plugins = [...marketplace.plugins].sort((a, b) => {
19764
20175
  const an = a?.name ?? "";
@@ -19771,7 +20182,7 @@ async function writeClaudeMarketplaceFile(manifestPath, marketplace) {
19771
20182
  const prev = await readFile24(manifestPath, "utf-8");
19772
20183
  JSON.parse(prev);
19773
20184
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
19774
- await writeFile8(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
20185
+ await writeFile9(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
19775
20186
  } catch {
19776
20187
  throw new Error(
19777
20188
  `Refusing to overwrite ${manifestPath}: existing file is not valid JSON. Inspect and remove or repair it manually before re-running.`
@@ -19779,9 +20190,9 @@ async function writeClaudeMarketplaceFile(manifestPath, marketplace) {
19779
20190
  }
19780
20191
  }
19781
20192
  const tmpPath = `${manifestPath}.tmp`;
19782
- await writeFile8(tmpPath, `${JSON.stringify(marketplace, null, 2)}
20193
+ await writeFile9(tmpPath, `${JSON.stringify(marketplace, null, 2)}
19783
20194
  `, "utf-8");
19784
- await rename8(tmpPath, manifestPath);
20195
+ await rename9(tmpPath, manifestPath);
19785
20196
  }
19786
20197
  function buildClaudeMarketplaceSourcePath(pluginTargetDir, marketplaceRootDir) {
19787
20198
  const relPath = relative2(marketplaceRootDir, pluginTargetDir).replaceAll("\\", "/");
@@ -19841,7 +20252,7 @@ async function listClaudeMarketplaceCandidates() {
19841
20252
  const [knownMarketplaces, activeMarketplaceNames, entries] = await Promise.all([
19842
20253
  readKnownClaudeMarketplaceRecords(),
19843
20254
  readInstalledClaudeMarketplaceNames(),
19844
- readdir14(rootDir, { withFileTypes: true })
20255
+ readdir15(rootDir, { withFileTypes: true })
19845
20256
  ]);
19846
20257
  const candidates = [];
19847
20258
  const seen = /* @__PURE__ */ new Set();
@@ -19849,8 +20260,8 @@ async function listClaudeMarketplaceCandidates() {
19849
20260
  if (!entry.isDirectory()) {
19850
20261
  continue;
19851
20262
  }
19852
- const candidateRoot = resolve36(rootDir, entry.name);
19853
- const manifestPath = resolve36(candidateRoot, ".claude-plugin", "marketplace.json");
20263
+ const candidateRoot = resolve37(rootDir, entry.name);
20264
+ const manifestPath = resolve37(candidateRoot, ".claude-plugin", "marketplace.json");
19854
20265
  if (!await fileExists(manifestPath)) {
19855
20266
  continue;
19856
20267
  }
@@ -19877,11 +20288,11 @@ async function listClaudeMarketplaceCandidates() {
19877
20288
  if (!installLocation) {
19878
20289
  continue;
19879
20290
  }
19880
- const candidateRoot = resolve36(expandHome(installLocation));
20291
+ const candidateRoot = resolve37(expandHome(installLocation));
19881
20292
  if (seen.has(candidateRoot)) {
19882
20293
  continue;
19883
20294
  }
19884
- const manifestPath = resolve36(candidateRoot, ".claude-plugin", "marketplace.json");
20295
+ const manifestPath = resolve37(candidateRoot, ".claude-plugin", "marketplace.json");
19885
20296
  if (!await fileExists(manifestPath)) {
19886
20297
  continue;
19887
20298
  }
@@ -19909,16 +20320,16 @@ async function getPreferredClaudeMarketplace() {
19909
20320
  name: candidate.name,
19910
20321
  rootDir: candidate.rootDir,
19911
20322
  manifestPath: candidate.manifestPath,
19912
- targetDir: resolve36(candidate.rootDir, "plugins", "syntaur")
20323
+ targetDir: resolve37(candidate.rootDir, "plugins", "syntaur")
19913
20324
  };
19914
20325
  }
19915
20326
  async function registerKnownClaudeMarketplace(name, rootDir) {
19916
20327
  const manifestPath = getClaudeKnownMarketplacesPath();
19917
20328
  let existing = {};
19918
20329
  if (await fileExists(manifestPath)) {
19919
- const raw = await readFile24(manifestPath, "utf-8");
20330
+ const raw2 = await readFile24(manifestPath, "utf-8");
19920
20331
  try {
19921
- const parsed = JSON.parse(raw);
20332
+ const parsed = JSON.parse(raw2);
19922
20333
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
19923
20334
  existing = parsed;
19924
20335
  } else {
@@ -19941,29 +20352,29 @@ async function registerKnownClaudeMarketplace(name, rootDir) {
19941
20352
  };
19942
20353
  existing[name].lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
19943
20354
  existing[name].autoUpdate = true;
19944
- await ensureDir(dirname10(manifestPath));
20355
+ await ensureDir(dirname11(manifestPath));
19945
20356
  if (await fileExists(manifestPath)) {
19946
20357
  const prev = await readFile24(manifestPath, "utf-8");
19947
20358
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
19948
- await writeFile8(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
20359
+ await writeFile9(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
19949
20360
  }
19950
20361
  const tmpPath = `${manifestPath}.tmp`;
19951
- await writeFile8(tmpPath, `${JSON.stringify(existing, null, 2)}
20362
+ await writeFile9(tmpPath, `${JSON.stringify(existing, null, 2)}
19952
20363
  `, "utf-8");
19953
- await rename8(tmpPath, manifestPath);
20364
+ await rename9(tmpPath, manifestPath);
19954
20365
  return { added: !had, updated: had };
19955
20366
  }
19956
20367
  async function ensureKnownClaudeMarketplaceForRoot(options) {
19957
20368
  return registerKnownClaudeMarketplace(options.name, options.rootDir);
19958
20369
  }
19959
20370
  async function setSyntaurPluginEnabled(options) {
19960
- const settingsPath = resolve36(homedir3(), ".claude", "settings.json");
20371
+ const settingsPath = resolve37(homedir3(), ".claude", "settings.json");
19961
20372
  const key = `syntaur@${options.marketplaceName}`;
19962
20373
  let parsed = {};
19963
20374
  if (await fileExists(settingsPath)) {
19964
- const raw = await readFile24(settingsPath, "utf-8");
20375
+ const raw2 = await readFile24(settingsPath, "utf-8");
19965
20376
  try {
19966
- parsed = JSON.parse(raw);
20377
+ parsed = JSON.parse(raw2);
19967
20378
  } catch {
19968
20379
  throw new Error(
19969
20380
  `Cannot toggle plugin: ${settingsPath} is not valid JSON. Inspect and repair it before retrying.`
@@ -19977,16 +20388,16 @@ async function setSyntaurPluginEnabled(options) {
19977
20388
  }
19978
20389
  enabledPlugins[key] = options.enabled;
19979
20390
  parsed.enabledPlugins = enabledPlugins;
19980
- await ensureDir(dirname10(settingsPath));
20391
+ await ensureDir(dirname11(settingsPath));
19981
20392
  if (await fileExists(settingsPath)) {
19982
20393
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
19983
20394
  const prev = await readFile24(settingsPath, "utf-8");
19984
- await writeFile8(`${settingsPath}.bak-${stamp}`, prev, "utf-8");
20395
+ await writeFile9(`${settingsPath}.bak-${stamp}`, prev, "utf-8");
19985
20396
  }
19986
20397
  const tmpPath = `${settingsPath}.tmp`;
19987
- await writeFile8(tmpPath, `${JSON.stringify(parsed, null, 2)}
20398
+ await writeFile9(tmpPath, `${JSON.stringify(parsed, null, 2)}
19988
20399
  `, "utf-8");
19989
- await rename8(tmpPath, settingsPath);
20400
+ await rename9(tmpPath, settingsPath);
19990
20401
  return { key, previous, current: options.enabled, changed: true };
19991
20402
  }
19992
20403
  async function ensureClaudeUserMarketplace() {
@@ -19994,9 +20405,9 @@ async function ensureClaudeUserMarketplace() {
19994
20405
  if (existing) {
19995
20406
  return existing;
19996
20407
  }
19997
- const rootDir = resolve36(getClaudeMarketplacesRoot(), "user-plugins");
19998
- const manifestPath = resolve36(rootDir, ".claude-plugin", "marketplace.json");
19999
- await ensureDir(resolve36(rootDir, "plugins"));
20408
+ const rootDir = resolve37(getClaudeMarketplacesRoot(), "user-plugins");
20409
+ const manifestPath = resolve37(rootDir, ".claude-plugin", "marketplace.json");
20410
+ await ensureDir(resolve37(rootDir, "plugins"));
20000
20411
  if (!await fileExists(manifestPath)) {
20001
20412
  const scaffold = {
20002
20413
  plugins: []
@@ -20015,22 +20426,22 @@ async function ensureClaudeUserMarketplace() {
20015
20426
  name: "user-plugins",
20016
20427
  rootDir,
20017
20428
  manifestPath,
20018
- targetDir: resolve36(rootDir, "plugins", "syntaur")
20429
+ targetDir: resolve37(rootDir, "plugins", "syntaur")
20019
20430
  };
20020
20431
  }
20021
20432
  async function detectClaudeMarketplaceForTarget(targetDir) {
20022
20433
  const normalizedTargetDir = normalizeAbsoluteInstallPath(targetDir, "Claude plugin target");
20023
- const pluginsDir = dirname10(normalizedTargetDir);
20024
- if (basename4(pluginsDir) !== "plugins") {
20434
+ const pluginsDir = dirname11(normalizedTargetDir);
20435
+ if (basename5(pluginsDir) !== "plugins") {
20025
20436
  return null;
20026
20437
  }
20027
- const rootDir = dirname10(pluginsDir);
20028
- const manifestPath = resolve36(rootDir, ".claude-plugin", "marketplace.json");
20438
+ const rootDir = dirname11(pluginsDir);
20439
+ const manifestPath = resolve37(rootDir, ".claude-plugin", "marketplace.json");
20029
20440
  if (!await fileExists(manifestPath)) {
20030
20441
  return null;
20031
20442
  }
20032
20443
  const marketplace = await readClaudeMarketplaceFile(manifestPath);
20033
- const name = typeof marketplace.name === "string" && marketplace.name.trim() !== "" ? marketplace.name : basename4(rootDir);
20444
+ const name = typeof marketplace.name === "string" && marketplace.name.trim() !== "" ? marketplace.name : basename5(rootDir);
20034
20445
  return {
20035
20446
  name,
20036
20447
  rootDir,
@@ -20041,7 +20452,7 @@ async function detectClaudeMarketplaceForTarget(targetDir) {
20041
20452
  async function findManagedClaudeMarketplacePluginDir() {
20042
20453
  const marketplaces = await listClaudeMarketplaceCandidates();
20043
20454
  for (const marketplace of marketplaces) {
20044
- const targetDir = resolve36(marketplace.rootDir, "plugins", "syntaur");
20455
+ const targetDir = resolve37(marketplace.rootDir, "plugins", "syntaur");
20045
20456
  const status = await getInstallStatus(targetDir, "claude");
20046
20457
  if (status.exists && status.managed) {
20047
20458
  return targetDir;
@@ -20166,7 +20577,7 @@ async function installManagedPlugin(options) {
20166
20577
  `${paths.targetDir} already exists and is not a Syntaur-managed install. Remove it manually before installing Syntaur there.`
20167
20578
  );
20168
20579
  }
20169
- if (desiredMode === "link" && existing.exists && existing.installMode === "link" && existing.symlinkTarget === resolve36(paths.sourceDir) && !force) {
20580
+ if (desiredMode === "link" && existing.exists && existing.installMode === "link" && existing.symlinkTarget === resolve37(paths.sourceDir) && !force) {
20170
20581
  return {
20171
20582
  targetDir: paths.targetDir,
20172
20583
  sourceDir: paths.sourceDir,
@@ -20175,7 +20586,7 @@ async function installManagedPlugin(options) {
20175
20586
  };
20176
20587
  }
20177
20588
  if (existing.exists) {
20178
- await rm4(paths.targetDir, { recursive: true, force: true });
20589
+ await rm5(paths.targetDir, { recursive: true, force: true });
20179
20590
  }
20180
20591
  if (desiredMode === "link") {
20181
20592
  await installLink(paths);
@@ -20190,7 +20601,7 @@ async function installManagedPlugin(options) {
20190
20601
  };
20191
20602
  }
20192
20603
  function buildMarketplaceSourcePath(pluginTargetDir, marketplacePath) {
20193
- const relPath = relative2(dirname10(marketplacePath), pluginTargetDir).replaceAll("\\", "/");
20604
+ const relPath = relative2(dirname11(marketplacePath), pluginTargetDir).replaceAll("\\", "/");
20194
20605
  if (relPath === "") {
20195
20606
  return ".";
20196
20607
  }
@@ -20218,8 +20629,8 @@ async function readMarketplaceFile(marketplacePath) {
20218
20629
  plugins: []
20219
20630
  };
20220
20631
  }
20221
- const raw = await readFile24(marketplacePath, "utf-8");
20222
- const parsed = JSON.parse(raw);
20632
+ const raw2 = await readFile24(marketplacePath, "utf-8");
20633
+ const parsed = JSON.parse(raw2);
20223
20634
  return {
20224
20635
  name: parsed.name ?? "local",
20225
20636
  interface: parsed.interface ?? { displayName: "Local Plugins" },
@@ -20227,8 +20638,8 @@ async function readMarketplaceFile(marketplacePath) {
20227
20638
  };
20228
20639
  }
20229
20640
  async function writeMarketplaceFile(marketplacePath, marketplace) {
20230
- await ensureDir(dirname10(marketplacePath));
20231
- await writeFile8(marketplacePath, `${JSON.stringify(marketplace, null, 2)}
20641
+ await ensureDir(dirname11(marketplacePath));
20642
+ await writeFile9(marketplacePath, `${JSON.stringify(marketplace, null, 2)}
20232
20643
  `, "utf-8");
20233
20644
  }
20234
20645
  async function hasAnySyntaurMarketplaceEntry(marketplacePath) {
@@ -20314,7 +20725,7 @@ async function removeMarketplaceEntry(options) {
20314
20725
  return { marketplacePath, removed: false };
20315
20726
  }
20316
20727
  if (marketplace.plugins.length === 0 && isDefaultMarketplaceShell(marketplace)) {
20317
- await rm4(marketplacePath, { force: true });
20728
+ await rm5(marketplacePath, { force: true });
20318
20729
  return { marketplacePath, removed: true };
20319
20730
  }
20320
20731
  await writeMarketplaceFile(marketplacePath, marketplace);
@@ -20335,7 +20746,7 @@ async function uninstallManagedPlugin(pluginKind, targetDir = getDefaultPluginTa
20335
20746
  );
20336
20747
  }
20337
20748
  await removeInstallMarker(normalizedTarget);
20338
- await rm4(normalizedTarget, { recursive: true, force: true });
20749
+ await rm5(normalizedTarget, { recursive: true, force: true });
20339
20750
  return { removed: true, targetDir: normalizedTarget };
20340
20751
  }
20341
20752
  async function getConfiguredOrLegacyManagedPluginDir(pluginKind) {
@@ -20379,13 +20790,13 @@ async function recommendMarketplacePath() {
20379
20790
  return configuredOrManaged ?? getDefaultMarketplacePath();
20380
20791
  }
20381
20792
  async function isSyntaurDataInstalled() {
20382
- return fileExists(resolve36(syntaurRoot(), "config.md"));
20793
+ return fileExists(resolve37(syntaurRoot(), "config.md"));
20383
20794
  }
20384
20795
  async function removeSyntaurData() {
20385
- await rm4(syntaurRoot(), { recursive: true, force: true });
20796
+ await rm5(syntaurRoot(), { recursive: true, force: true });
20386
20797
  }
20387
20798
  async function getConfiguredProjectDir() {
20388
- if (!await fileExists(resolve36(syntaurRoot(), "config.md"))) {
20799
+ if (!await fileExists(resolve37(syntaurRoot(), "config.md"))) {
20389
20800
  return null;
20390
20801
  }
20391
20802
  return (await readConfig()).defaultProjectDir;
@@ -20454,25 +20865,25 @@ async function textPrompt(question, defaultValue) {
20454
20865
 
20455
20866
  // src/utils/install-skills.ts
20456
20867
  init_fs();
20457
- import { readFile as readFile26, readdir as readdir15, mkdir as mkdir4, copyFile, rm as rm5, lstat as lstat2 } from "fs/promises";
20458
- import { resolve as resolve38, relative as relative3, join as join4 } from "path";
20868
+ import { readFile as readFile26, readdir as readdir16, mkdir as mkdir5, copyFile, rm as rm6, lstat as lstat2 } from "fs/promises";
20869
+ import { resolve as resolve39, relative as relative3, join as join4 } from "path";
20459
20870
  import { homedir as homedir5 } from "os";
20460
20871
 
20461
20872
  // src/utils/plugin-state.ts
20462
20873
  init_fs();
20463
20874
  import { readFile as readFile25 } from "fs/promises";
20464
- import { resolve as resolve37 } from "path";
20875
+ import { resolve as resolve38 } from "path";
20465
20876
  import { homedir as homedir4 } from "os";
20466
20877
  function settingsPathFor(agent) {
20467
- if (agent === "claude") return resolve37(homedir4(), ".claude", "settings.json");
20878
+ if (agent === "claude") return resolve38(homedir4(), ".claude", "settings.json");
20468
20879
  return null;
20469
20880
  }
20470
20881
  async function readJsonOrNull(path) {
20471
20882
  if (!path) return null;
20472
20883
  if (!await fileExists(path)) return null;
20473
20884
  try {
20474
- const raw = await readFile25(path, "utf-8");
20475
- return JSON.parse(raw);
20885
+ const raw2 = await readFile25(path, "utf-8");
20886
+ return JSON.parse(raw2);
20476
20887
  } catch {
20477
20888
  return null;
20478
20889
  }
@@ -20521,16 +20932,16 @@ var KNOWN_SKILL_NAMES = [
20521
20932
  var KNOWN_SKILLS = KNOWN_SKILL_NAMES;
20522
20933
  async function getSkillsDir() {
20523
20934
  const packageRoot = await findPackageRoot("skills");
20524
- return resolve38(packageRoot, "skills");
20935
+ return resolve39(packageRoot, "skills");
20525
20936
  }
20526
20937
  function defaultSkillTargetDir(target) {
20527
- if (target === "claude") return resolve38(homedir5(), ".claude", "skills");
20528
- return resolve38(homedir5(), ".codex", "skills");
20938
+ if (target === "claude") return resolve39(homedir5(), ".claude", "skills");
20939
+ return resolve39(homedir5(), ".codex", "skills");
20529
20940
  }
20530
20941
  async function walkFiles(root) {
20531
20942
  const out = [];
20532
20943
  async function walk(dir) {
20533
- const entries = await readdir15(dir, { withFileTypes: true });
20944
+ const entries = await readdir16(dir, { withFileTypes: true });
20534
20945
  for (const entry of entries) {
20535
20946
  const full = join4(dir, entry.name);
20536
20947
  if (entry.isDirectory()) {
@@ -20553,8 +20964,8 @@ async function filesEqual(a, b) {
20553
20964
  }
20554
20965
  }
20555
20966
  async function copyDir(srcDir, destDir) {
20556
- await mkdir4(destDir, { recursive: true });
20557
- const entries = await readdir15(srcDir, { withFileTypes: true });
20967
+ await mkdir5(destDir, { recursive: true });
20968
+ const entries = await readdir16(srcDir, { withFileTypes: true });
20558
20969
  for (const entry of entries) {
20559
20970
  const src = join4(srcDir, entry.name);
20560
20971
  const dest = join4(destDir, entry.name);
@@ -20579,8 +20990,8 @@ async function skillMatches(srcDir, destDir) {
20579
20990
  }
20580
20991
  async function isSymlink(path) {
20581
20992
  try {
20582
- const stat12 = await lstat2(path);
20583
- return stat12.isSymbolicLink();
20993
+ const stat13 = await lstat2(path);
20994
+ return stat13.isSymbolicLink();
20584
20995
  } catch {
20585
20996
  return false;
20586
20997
  }
@@ -20601,14 +21012,14 @@ async function installSkillDir(srcDir, destDir, skillName, force) {
20601
21012
  return { skill: skillName, status: "already-current", targetPath: destDir };
20602
21013
  }
20603
21014
  if (force) {
20604
- await rm5(destDir, { recursive: true, force: true });
21015
+ await rm6(destDir, { recursive: true, force: true });
20605
21016
  await copyDir(srcDir, destDir);
20606
21017
  return { skill: skillName, status: "overwritten", targetPath: destDir };
20607
21018
  }
20608
21019
  return { skill: skillName, status: "differs-preserved", targetPath: destDir };
20609
21020
  }
20610
21021
  async function discoverSkillNames(sourceDir) {
20611
- const entries = await readdir15(sourceDir, { withFileTypes: true });
21022
+ const entries = await readdir16(sourceDir, { withFileTypes: true });
20612
21023
  const names = [];
20613
21024
  for (const entry of entries) {
20614
21025
  if (!entry.isDirectory()) continue;
@@ -20638,7 +21049,7 @@ async function installSkillsWithReport(options) {
20638
21049
  }
20639
21050
  const skillNames = await discoverSkillNames(source);
20640
21051
  const results = [];
20641
- await mkdir4(targetRoot, { recursive: true });
21052
+ await mkdir5(targetRoot, { recursive: true });
20642
21053
  for (const skill of skillNames) {
20643
21054
  const srcDir = join4(source, skill);
20644
21055
  const destDir = join4(targetRoot, skill);
@@ -20655,7 +21066,7 @@ async function installSkillsToDir(options) {
20655
21066
  }
20656
21067
  const force = options.force ?? false;
20657
21068
  const skillNames = await discoverSkillNames(source);
20658
- await mkdir4(options.targetDir, { recursive: true });
21069
+ await mkdir5(options.targetDir, { recursive: true });
20659
21070
  const results = [];
20660
21071
  for (const skill of skillNames) {
20661
21072
  const srcDir = join4(source, skill);
@@ -20688,7 +21099,7 @@ async function uninstallSkills(options) {
20688
21099
  const content = await readFile26(skillMd, "utf-8").catch(() => "");
20689
21100
  const match = content.match(/^name:\s*(\S+)\s*$/m);
20690
21101
  if (!match || match[1] !== skill) continue;
20691
- await rm5(destDir, { recursive: true, force: true });
21102
+ await rm6(destDir, { recursive: true, force: true });
20692
21103
  removed.push(destDir);
20693
21104
  }
20694
21105
  return removed;
@@ -20971,14 +21382,14 @@ function parseOpenUrl(input4) {
20971
21382
  }
20972
21383
  let mode = "resume";
20973
21384
  if (modeVals.length === 1) {
20974
- const raw = modeVals[0];
20975
- if (!SESSION_MODES.includes(raw)) {
21385
+ const raw2 = modeVals[0];
21386
+ if (!SESSION_MODES.includes(raw2)) {
20976
21387
  throw new OpenUrlError(
20977
21388
  "bad-mode",
20978
- `\`mode\` must be one of ${SESSION_MODES.join("|")} (got "${raw}")`
21389
+ `\`mode\` must be one of ${SESSION_MODES.join("|")} (got "${raw2}")`
20979
21390
  );
20980
21391
  }
20981
- mode = raw;
21392
+ mode = raw2;
20982
21393
  }
20983
21394
  return { kind: "session", id, mode, ...terminal ? { terminal } : {} };
20984
21395
  }
@@ -21213,7 +21624,7 @@ async function executeLaunchPlan(plan, spawnFn = realSpawn) {
21213
21624
  `Spawn failed: ${msg}. Verify the terminal is installed and on PATH.`
21214
21625
  );
21215
21626
  }
21216
- await new Promise((resolve82, reject) => {
21627
+ await new Promise((resolve83, reject) => {
21217
21628
  let settled = false;
21218
21629
  let stderr = "";
21219
21630
  const finishOk = () => {
@@ -21223,7 +21634,7 @@ async function executeLaunchPlan(plan, spawnFn = realSpawn) {
21223
21634
  child.unref();
21224
21635
  } catch {
21225
21636
  }
21226
- resolve82();
21637
+ resolve83();
21227
21638
  };
21228
21639
  const finishErr = (remediation) => {
21229
21640
  if (settled) return;
@@ -21368,7 +21779,7 @@ function appleScriptString(value) {
21368
21779
  init_paths();
21369
21780
  init_fs();
21370
21781
  import { fileURLToPath as fileURLToPath4 } from "url";
21371
- import { dirname as dirname11, resolve as resolve40, join as join5 } from "path";
21782
+ import { dirname as dirname12, resolve as resolve41, join as join5 } from "path";
21372
21783
  import { realpathSync, readFileSync, mkdirSync } from "fs";
21373
21784
  var NPX_PATTERNS = [
21374
21785
  { kind: "npm", re: /\/_npx\/([^/]+)\/node_modules(?:\/|$)/ },
@@ -21410,26 +21821,26 @@ function detectInstallKind(scriptUrl, opts = {}) {
21410
21821
  if (GLOBAL_PATTERN.test(norm)) {
21411
21822
  return "global";
21412
21823
  }
21413
- let dir = dirname11(resolved);
21824
+ let dir = dirname12(resolved);
21414
21825
  for (let depth = 0; depth < 8; depth++) {
21415
21826
  const pkgJsonPath = join5(dir, "package.json");
21416
- let raw;
21827
+ let raw2;
21417
21828
  try {
21418
- raw = readFile56(pkgJsonPath);
21829
+ raw2 = readFile56(pkgJsonPath);
21419
21830
  } catch {
21420
- const parent2 = dirname11(dir);
21831
+ const parent2 = dirname12(dir);
21421
21832
  if (parent2 === dir) break;
21422
21833
  dir = parent2;
21423
21834
  continue;
21424
21835
  }
21425
21836
  try {
21426
- const pkg = JSON.parse(raw);
21837
+ const pkg = JSON.parse(raw2);
21427
21838
  if (typeof pkg.name === "string" && pkg.name === "syntaur" && !normalizeSlashes(dir).includes("/node_modules/")) {
21428
21839
  return "local";
21429
21840
  }
21430
21841
  } catch {
21431
21842
  }
21432
- const parent = dirname11(dir);
21843
+ const parent = dirname12(dir);
21433
21844
  if (parent === dir) break;
21434
21845
  dir = parent;
21435
21846
  }
@@ -21447,7 +21858,7 @@ function extractNpxHash(scriptUrl, opts = {}) {
21447
21858
  return null;
21448
21859
  }
21449
21860
  function nudgeStampDir() {
21450
- return resolve40(syntaurRoot(), "npx-handler-nudge");
21861
+ return resolve41(syntaurRoot(), "npx-handler-nudge");
21451
21862
  }
21452
21863
  function sanitizeHash(hash) {
21453
21864
  return hash.replace(/[^A-Za-z0-9_-]/g, "_") || "_";
@@ -21469,9 +21880,9 @@ async function recordNudge(hash) {
21469
21880
  }
21470
21881
  }
21471
21882
  function isHandlerNudgeDisabled() {
21472
- const raw = process.env.SYNTAUR_SKIP_HANDLER_NUDGE;
21473
- if (raw === void 0) return false;
21474
- const trimmed = raw.trim();
21883
+ const raw2 = process.env.SYNTAUR_SKIP_HANDLER_NUDGE;
21884
+ if (raw2 === void 0) return false;
21885
+ const trimmed = raw2.trim();
21475
21886
  return /^(1|true|yes)$/i.test(trimmed);
21476
21887
  }
21477
21888
  function nudgeMessage() {
@@ -21501,20 +21912,20 @@ init_paths();
21501
21912
  init_fs();
21502
21913
  import { fileURLToPath as fileURLToPath6 } from "url";
21503
21914
  import { readFile as readFile28 } from "fs/promises";
21504
- import { dirname as dirname13, join as join7, resolve as resolve41 } from "path";
21915
+ import { dirname as dirname14, join as join7, resolve as resolve42 } from "path";
21505
21916
  import { spawn as spawn5 } from "child_process";
21506
21917
  import { createInterface as createInterface2 } from "readline/promises";
21507
21918
 
21508
21919
  // src/utils/version.ts
21509
21920
  import { fileURLToPath as fileURLToPath5 } from "url";
21510
21921
  import { readFile as readFile27 } from "fs/promises";
21511
- import { dirname as dirname12, join as join6 } from "path";
21922
+ import { dirname as dirname13, join as join6 } from "path";
21512
21923
  async function readPackageVersion(scriptUrl) {
21513
21924
  try {
21514
21925
  const scriptPath = fileURLToPath5(scriptUrl);
21515
- const pkgRoot = dirname12(dirname12(scriptPath));
21516
- const raw = await readFile27(join6(pkgRoot, "package.json"), "utf-8");
21517
- const parsed = JSON.parse(raw);
21926
+ const pkgRoot = dirname13(dirname13(scriptPath));
21927
+ const raw2 = await readFile27(join6(pkgRoot, "package.json"), "utf-8");
21928
+ const parsed = JSON.parse(raw2);
21518
21929
  return typeof parsed.version === "string" ? parsed.version : null;
21519
21930
  } catch {
21520
21931
  return null;
@@ -21522,7 +21933,7 @@ async function readPackageVersion(scriptUrl) {
21522
21933
  }
21523
21934
 
21524
21935
  // src/utils/npx-prompt.ts
21525
- var STATE_FILE = resolve41(syntaurRoot(), "npx-install.json");
21936
+ var STATE_FILE = resolve42(syntaurRoot(), "npx-install.json");
21526
21937
  var META_ARGS2 = /* @__PURE__ */ new Set(["-h", "--help", "-V", "--version", "help"]);
21527
21938
  var GLOBAL_VERSION_TIMEOUT_MS = 2e3;
21528
21939
  function isRunningViaNpx(scriptUrl) {
@@ -21543,8 +21954,8 @@ function isRunningViaNpx(scriptUrl) {
21543
21954
  async function readState() {
21544
21955
  if (!await fileExists(STATE_FILE)) return null;
21545
21956
  try {
21546
- const raw = await readFile28(STATE_FILE, "utf-8");
21547
- return JSON.parse(raw);
21957
+ const raw2 = await readFile28(STATE_FILE, "utf-8");
21958
+ return JSON.parse(raw2);
21548
21959
  } catch {
21549
21960
  return null;
21550
21961
  }
@@ -21554,7 +21965,7 @@ async function writeState(state) {
21554
21965
  `);
21555
21966
  }
21556
21967
  async function resolveNpmBin() {
21557
- const nodeDir = dirname13(process.execPath);
21968
+ const nodeDir = dirname14(process.execPath);
21558
21969
  const isWin = process.platform === "win32";
21559
21970
  const npmName = isWin ? "npm.cmd" : "npm";
21560
21971
  const nearNode = join7(nodeDir, npmName);
@@ -21602,8 +22013,8 @@ async function readGlobalVersion() {
21602
22013
  try {
21603
22014
  const manifestPath = join7(rootPath, "syntaur", "package.json");
21604
22015
  if (!await fileExists(manifestPath)) return null;
21605
- const raw = await readFile28(manifestPath, "utf-8");
21606
- const parsed = JSON.parse(raw);
22016
+ const raw2 = await readFile28(manifestPath, "utf-8");
22017
+ const parsed = JSON.parse(raw2);
21607
22018
  return typeof parsed.version === "string" ? parsed.version : null;
21608
22019
  } catch {
21609
22020
  return null;
@@ -21632,10 +22043,10 @@ async function askChoice(promptLabel) {
21632
22043
  const onSigint = () => controller.abort();
21633
22044
  process.once("SIGINT", onSigint);
21634
22045
  try {
21635
- const raw = await rl.question(promptLabel, {
22046
+ const raw2 = await rl.question(promptLabel, {
21636
22047
  signal: controller.signal
21637
22048
  });
21638
- return raw.trim();
22049
+ return raw2.trim();
21639
22050
  } catch {
21640
22051
  return "";
21641
22052
  } finally {
@@ -21960,16 +22371,16 @@ async function refreshPluginSkills(options, pm, runner, getManagedDir, resolveFr
21960
22371
  // src/commands/install-statusline.ts
21961
22372
  init_paths();
21962
22373
  init_fs();
21963
- import { readFile as readFile30, writeFile as writeFile11, copyFile as copyFile2, rm as rm6, stat as stat2, symlink as symlink2, unlink as unlink8, lstat as lstat3 } from "fs/promises";
21964
- import { resolve as resolve43, dirname as dirname15 } from "path";
22374
+ import { readFile as readFile30, writeFile as writeFile12, copyFile as copyFile2, rm as rm7, stat as stat3, symlink as symlink2, unlink as unlink9, lstat as lstat3 } from "fs/promises";
22375
+ import { resolve as resolve44, dirname as dirname16 } from "path";
21965
22376
  import { homedir as homedir7 } from "os";
21966
22377
  import { fileURLToPath as fileURLToPath8 } from "url";
21967
22378
 
21968
22379
  // src/commands/configure-statusline.ts
21969
22380
  init_paths();
21970
22381
  init_fs();
21971
- import { readFile as readFile29, writeFile as writeFile10 } from "fs/promises";
21972
- import { resolve as resolve42, dirname as dirname14 } from "path";
22382
+ import { readFile as readFile29, writeFile as writeFile11 } from "fs/promises";
22383
+ import { resolve as resolve43, dirname as dirname15 } from "path";
21973
22384
  import { spawnSync as spawnSync5 } from "child_process";
21974
22385
  import { checkbox, input as input2, confirm } from "@inquirer/prompts";
21975
22386
  var AVAILABLE_SEGMENTS = [
@@ -21990,13 +22401,13 @@ var PRESETS = {
21990
22401
  tracker: { segments: ["git", "assignment", "external", "session"], separator: " \xB7 " }
21991
22402
  };
21992
22403
  function getConfigPath(installRoot) {
21993
- return resolve42(installRoot, "statusline.config.json");
22404
+ return resolve43(installRoot, "statusline.config.json");
21994
22405
  }
21995
22406
  async function readConfig2(path) {
21996
22407
  if (!await fileExists(path)) return null;
21997
22408
  try {
21998
- const raw = await readFile29(path, "utf-8");
21999
- const parsed = JSON.parse(raw);
22409
+ const raw2 = await readFile29(path, "utf-8");
22410
+ const parsed = JSON.parse(raw2);
22000
22411
  if (!parsed || typeof parsed !== "object") return null;
22001
22412
  const segments = Array.isArray(parsed.segments) ? parsed.segments.filter(isSegmentName) : [];
22002
22413
  const separator = typeof parsed.separator === "string" ? parsed.separator : " \xB7 ";
@@ -22045,7 +22456,7 @@ async function promptSegmentsInteractive(current) {
22045
22456
  default: false
22046
22457
  });
22047
22458
  if (wantReorder) {
22048
- const raw = await input2({
22459
+ const raw2 = await input2({
22049
22460
  message: `Enter the segments in the order you want, comma-separated:`,
22050
22461
  default: defaultReorderHint,
22051
22462
  validate: (value) => {
@@ -22061,7 +22472,7 @@ async function promptSegmentsInteractive(current) {
22061
22472
  return true;
22062
22473
  }
22063
22474
  });
22064
- orderedSegments = raw.split(",").map((s) => s.trim()).filter(Boolean);
22475
+ orderedSegments = raw2.split(",").map((s) => s.trim()).filter(Boolean);
22065
22476
  }
22066
22477
  const separator = await input2({
22067
22478
  message: "Separator between segments:",
@@ -22090,7 +22501,7 @@ function renderPreview(config, statuslineScript, cwd) {
22090
22501
  env: {
22091
22502
  ...process.env,
22092
22503
  // Force the child to pick up the freshly-written config from install root.
22093
- HOME: dirname14(dirname14(statuslineScript))
22504
+ HOME: dirname15(dirname15(statuslineScript))
22094
22505
  }
22095
22506
  });
22096
22507
  if (res.status !== 0) return null;
@@ -22141,14 +22552,14 @@ async function configureStatuslineCommand(options = {}) {
22141
22552
  console.log("(preview mode \u2014 config NOT written)");
22142
22553
  return;
22143
22554
  }
22144
- await ensureDir(dirname14(configPath));
22145
- await writeFile10(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
22555
+ await ensureDir(dirname15(configPath));
22556
+ await writeFile11(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
22146
22557
  console.log("Wrote statusline config:");
22147
22558
  console.log(` path: ${configPath}`);
22148
22559
  console.log(` segments: ${config.segments.join(", ")}`);
22149
22560
  console.log(` separator: ${JSON.stringify(config.separator)}`);
22150
22561
  if (config.wrap) console.log(` wrap: ${config.wrap}`);
22151
- const script = options.statuslineScript ?? resolve42(installRoot, "statusline.sh");
22562
+ const script = options.statuslineScript ?? resolve43(installRoot, "statusline.sh");
22152
22563
  if (await fileExists(script)) {
22153
22564
  console.log("");
22154
22565
  console.log("Live preview:");
@@ -22168,25 +22579,25 @@ async function configureStatuslineCommand(options = {}) {
22168
22579
  async function writeDefaultConfigIfMissing(installRoot) {
22169
22580
  const path = getConfigPath(installRoot);
22170
22581
  if (await fileExists(path)) return;
22171
- await ensureDir(dirname14(path));
22582
+ await ensureDir(dirname15(path));
22172
22583
  const defaultConfig = {
22173
22584
  segments: ["git", "assignment", "session"],
22174
22585
  separator: " \xB7 "
22175
22586
  };
22176
- await writeFile10(path, JSON.stringify(defaultConfig, null, 2) + "\n", "utf-8");
22587
+ await writeFile11(path, JSON.stringify(defaultConfig, null, 2) + "\n", "utf-8");
22177
22588
  }
22178
22589
 
22179
22590
  // src/commands/install-statusline.ts
22180
22591
  function getPackageStatuslineSource() {
22181
- const here = dirname15(fileURLToPath8(import.meta.url));
22182
- return resolve43(here, "..", "statusline", "statusline.sh");
22592
+ const here = dirname16(fileURLToPath8(import.meta.url));
22593
+ return resolve44(here, "..", "statusline", "statusline.sh");
22183
22594
  }
22184
22595
  async function readSettingsJson(settingsPath) {
22185
22596
  if (!await fileExists(settingsPath)) return {};
22186
- const raw = await readFile30(settingsPath, "utf-8");
22187
- if (raw.trim() === "") return {};
22597
+ const raw2 = await readFile30(settingsPath, "utf-8");
22598
+ if (raw2.trim() === "") return {};
22188
22599
  try {
22189
- const parsed = JSON.parse(raw);
22600
+ const parsed = JSON.parse(raw2);
22190
22601
  return parsed && typeof parsed === "object" ? parsed : {};
22191
22602
  } catch (error) {
22192
22603
  throw new Error(
@@ -22195,8 +22606,8 @@ async function readSettingsJson(settingsPath) {
22195
22606
  }
22196
22607
  }
22197
22608
  async function writeSettingsJson(settingsPath, data) {
22198
- await ensureDir(dirname15(settingsPath));
22199
- await writeFile11(settingsPath, JSON.stringify(data, null, 2) + "\n", "utf-8");
22609
+ await ensureDir(dirname16(settingsPath));
22610
+ await writeFile12(settingsPath, JSON.stringify(data, null, 2) + "\n", "utf-8");
22200
22611
  }
22201
22612
  async function resolveMode(mode, existingCommand, ourCommand) {
22202
22613
  if (mode !== "ask") return mode;
@@ -22230,8 +22641,8 @@ function extractExistingCommand(settings) {
22230
22641
  };
22231
22642
  }
22232
22643
  async function backupSettings(settingsSnapshot, backupPath) {
22233
- await ensureDir(dirname15(backupPath));
22234
- await writeFile11(
22644
+ await ensureDir(dirname16(backupPath));
22645
+ await writeFile12(
22235
22646
  backupPath,
22236
22647
  JSON.stringify(
22237
22648
  {
@@ -22247,11 +22658,11 @@ async function backupSettings(settingsSnapshot, backupPath) {
22247
22658
  );
22248
22659
  }
22249
22660
  async function installScript(sourceScript, destScript, link) {
22250
- await ensureDir(dirname15(destScript));
22661
+ await ensureDir(dirname16(destScript));
22251
22662
  try {
22252
22663
  const s = await lstat3(destScript);
22253
22664
  if (s.isSymbolicLink() || s.isFile()) {
22254
- await unlink8(destScript);
22665
+ await unlink9(destScript);
22255
22666
  }
22256
22667
  } catch {
22257
22668
  }
@@ -22263,12 +22674,12 @@ async function installScript(sourceScript, destScript, link) {
22263
22674
  }
22264
22675
  async function installStatuslineCommand(options = {}) {
22265
22676
  const mode = options.mode ?? "ask";
22266
- const settingsPath = options.settingsPath ?? resolve43(homedir7(), ".claude", "settings.json");
22677
+ const settingsPath = options.settingsPath ?? resolve44(homedir7(), ".claude", "settings.json");
22267
22678
  const installRoot = options.installRoot ?? syntaurRoot();
22268
22679
  const sourceScript = options.sourceScript ?? getPackageStatuslineSource();
22269
- const destScript = resolve43(installRoot, "statusline.sh");
22270
- const confPath = resolve43(installRoot, "statusline.conf");
22271
- const backupPath = resolve43(installRoot, "statusline.backup.json");
22680
+ const destScript = resolve44(installRoot, "statusline.sh");
22681
+ const confPath = resolve44(installRoot, "statusline.conf");
22682
+ const backupPath = resolve44(installRoot, "statusline.backup.json");
22272
22683
  if (!await fileExists(sourceScript)) {
22273
22684
  throw new Error(
22274
22685
  `Statusline source script not found at ${sourceScript}. Try re-installing syntaur (npm install -g syntaur) or pass --source-script explicitly.`
@@ -22304,19 +22715,19 @@ async function installStatuslineCommand(options = {}) {
22304
22715
  if (parsed) {
22305
22716
  wrapTarget = parsed;
22306
22717
  } else {
22307
- const wrapperPath = resolve43(installRoot, "statusline-wrapped.sh");
22718
+ const wrapperPath = resolve44(installRoot, "statusline-wrapped.sh");
22308
22719
  const wrapperBody = `#!/usr/bin/env bash
22309
22720
  # Auto-generated by syntaur install-statusline.
22310
22721
  # Executes the previously configured statusLine command.
22311
22722
  exec ${existingCommand}
22312
22723
  `;
22313
- await writeFile11(wrapperPath, wrapperBody, "utf-8");
22724
+ await writeFile12(wrapperPath, wrapperBody, "utf-8");
22314
22725
  await chmodExec(wrapperPath);
22315
22726
  wrapTarget = wrapperPath;
22316
22727
  }
22317
22728
  }
22318
- await ensureDir(dirname15(confPath));
22319
- await writeFile11(
22729
+ await ensureDir(dirname16(confPath));
22730
+ await writeFile12(
22320
22731
  confPath,
22321
22732
  wrapTarget ? `# Wrap target \u2014 the command below is invoked with the same stdin; its
22322
22733
  # stdout becomes the leading segment of the statusline. Remove this
@@ -22353,26 +22764,26 @@ function parseWrapCommand(command) {
22353
22764
  async function chmodExec(path) {
22354
22765
  const fs = await import("fs/promises");
22355
22766
  try {
22356
- const s = await stat2(path);
22767
+ const s = await stat3(path);
22357
22768
  await fs.chmod(path, s.mode | 73);
22358
22769
  } catch {
22359
22770
  }
22360
22771
  }
22361
22772
  async function uninstallStatuslineCommand(options = {}) {
22362
- const settingsPath = options.settingsPath ?? resolve43(homedir7(), ".claude", "settings.json");
22773
+ const settingsPath = options.settingsPath ?? resolve44(homedir7(), ".claude", "settings.json");
22363
22774
  const installRoot = options.installRoot ?? syntaurRoot();
22364
- const destScript = resolve43(installRoot, "statusline.sh");
22365
- const confPath = resolve43(installRoot, "statusline.conf");
22366
- const backupPath = resolve43(installRoot, "statusline.backup.json");
22367
- const wrapperPath = resolve43(installRoot, "statusline-wrapped.sh");
22775
+ const destScript = resolve44(installRoot, "statusline.sh");
22776
+ const confPath = resolve44(installRoot, "statusline.conf");
22777
+ const backupPath = resolve44(installRoot, "statusline.backup.json");
22778
+ const wrapperPath = resolve44(installRoot, "statusline-wrapped.sh");
22368
22779
  const settings = await readSettingsJson(settingsPath);
22369
22780
  const existing = extractExistingCommand(settings);
22370
22781
  const ourCommand = `bash ${destScript}`;
22371
22782
  let restored = null;
22372
22783
  if (await fileExists(backupPath)) {
22373
22784
  try {
22374
- const raw = await readFile30(backupPath, "utf-8");
22375
- const parsed = JSON.parse(raw);
22785
+ const raw2 = await readFile30(backupPath, "utf-8");
22786
+ const parsed = JSON.parse(raw2);
22376
22787
  const prev = parsed?.previousStatusLine;
22377
22788
  if (prev && typeof prev === "object" && typeof prev.command === "string") {
22378
22789
  restored = { command: prev.command };
@@ -22392,10 +22803,10 @@ async function uninstallStatuslineCommand(options = {}) {
22392
22803
  await writeSettingsJson(settingsPath, settings);
22393
22804
  }
22394
22805
  if (!options.keepScript) {
22395
- const configPath = resolve43(installRoot, "statusline.config.json");
22806
+ const configPath = resolve44(installRoot, "statusline.config.json");
22396
22807
  for (const path of [destScript, confPath, backupPath, wrapperPath, configPath]) {
22397
22808
  try {
22398
- await rm6(path, { force: true });
22809
+ await rm7(path, { force: true });
22399
22810
  } catch {
22400
22811
  }
22401
22812
  }
@@ -22552,7 +22963,7 @@ init_config2();
22552
22963
  // src/commands/cross-agent-install.ts
22553
22964
  init_fs();
22554
22965
  import { spawnSync as spawnSync6 } from "child_process";
22555
- import { resolve as resolve46 } from "path";
22966
+ import { resolve as resolve47 } from "path";
22556
22967
  import { readFile as readFile31 } from "fs/promises";
22557
22968
 
22558
22969
  // src/commands/setup-adapter.ts
@@ -22560,28 +22971,28 @@ init_paths();
22560
22971
  init_fs();
22561
22972
  init_config2();
22562
22973
  init_slug();
22563
- import { resolve as resolve45 } from "path";
22974
+ import { resolve as resolve46 } from "path";
22564
22975
 
22565
22976
  // src/targets/registry.ts
22566
22977
  init_fs();
22567
22978
  import { homedir as homedir8 } from "os";
22568
- import { resolve as resolve44 } from "path";
22979
+ import { resolve as resolve45 } from "path";
22569
22980
  function home(...segments) {
22570
- return resolve44(homedir8(), ...segments);
22981
+ return resolve45(homedir8(), ...segments);
22571
22982
  }
22572
22983
  function hermesHome() {
22573
22984
  const env = process.env.HERMES_HOME;
22574
- return env && env.length > 0 ? resolve44(env) : home(".hermes");
22985
+ return env && env.length > 0 ? resolve45(env) : home(".hermes");
22575
22986
  }
22576
22987
  function hermesSkillsDir() {
22577
- return resolve44(hermesHome(), "skills");
22988
+ return resolve45(hermesHome(), "skills");
22578
22989
  }
22579
22990
  function isHermesHomeCustom() {
22580
22991
  return hermesHome() !== home(".hermes");
22581
22992
  }
22582
22993
  function codexHome() {
22583
22994
  const env = process.env.CODEX_HOME;
22584
- return env && env.length > 0 ? resolve44(env) : home(".codex");
22995
+ return env && env.length > 0 ? resolve45(env) : home(".codex");
22585
22996
  }
22586
22997
  var detectDir = (dir) => () => fileExists(dir);
22587
22998
  var AGENT_TARGETS = [
@@ -22605,7 +23016,7 @@ var AGENT_TARGETS = [
22605
23016
  skillsShAgentId: "codex",
22606
23017
  nativePlugin: "codex",
22607
23018
  detect: detectDir(codexHome()),
22608
- skillsDir: { global: resolve44(codexHome(), "skills") },
23019
+ skillsDir: { global: resolve45(codexHome(), "skills") },
22609
23020
  instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] }
22610
23021
  },
22611
23022
  {
@@ -22709,13 +23120,13 @@ async function setupAdapterCommand(framework, options) {
22709
23120
  }
22710
23121
  const config = await readConfig();
22711
23122
  const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
22712
- const projectDir = resolve45(baseDir, options.project);
22713
- const assignmentDir = resolve45(projectDir, "assignments", options.assignment);
22714
- const projectMdPath = resolve45(projectDir, "project.md");
23123
+ const projectDir = resolve46(baseDir, options.project);
23124
+ const assignmentDir = resolve46(projectDir, "assignments", options.assignment);
23125
+ const projectMdPath = resolve46(projectDir, "project.md");
22715
23126
  if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
22716
23127
  throw new Error(`Project "${options.project}" not found at ${projectDir}.`);
22717
23128
  }
22718
- const assignmentMdPath2 = resolve45(assignmentDir, "assignment.md");
23129
+ const assignmentMdPath2 = resolve46(assignmentDir, "assignment.md");
22719
23130
  if (!await fileExists(assignmentDir) || !await fileExists(assignmentMdPath2)) {
22720
23131
  throw new Error(
22721
23132
  `Assignment "${options.assignment}" not found at ${assignmentDir}.`
@@ -22732,7 +23143,7 @@ async function setupAdapterCommand(framework, options) {
22732
23143
  const upToDateFiles = [];
22733
23144
  const skippedFiles = [];
22734
23145
  for (const file of target.instructions.files) {
22735
- const filePath = resolve45(cwd, file.path);
23146
+ const filePath = resolve46(cwd, file.path);
22736
23147
  const content = RENDERERS[file.renderer](rendererParams);
22737
23148
  const status = await writeFileReport(filePath, content, {
22738
23149
  force: options.force
@@ -22772,8 +23183,8 @@ async function setupAdapterCommand(framework, options) {
22772
23183
  init_config2();
22773
23184
  var DEFAULT_SKILLS_SOURCE = "prong-horn/syntaur";
22774
23185
  function parseTargetIds(options) {
22775
- const raw = [options.target, options.agent].filter(Boolean).join(",");
22776
- const ids = raw.split(",").map((s) => s.trim()).filter(Boolean);
23186
+ const raw2 = [options.target, options.agent].filter(Boolean).join(",");
23187
+ const ids = raw2.split(",").map((s) => s.trim()).filter(Boolean);
22777
23188
  return [...new Set(ids)];
22778
23189
  }
22779
23190
  function isNpxAvailable() {
@@ -22785,7 +23196,7 @@ function isNpxAvailable() {
22785
23196
  }
22786
23197
  }
22787
23198
  async function readAssignmentContext() {
22788
- const p = resolve46(process.cwd(), ".syntaur", "context.json");
23199
+ const p = resolve47(process.cwd(), ".syntaur", "context.json");
22789
23200
  if (!await fileExists(p)) return null;
22790
23201
  try {
22791
23202
  return JSON.parse(await readFile31(p, "utf-8"));
@@ -22858,7 +23269,7 @@ async function crossAgentInstallCommand(options) {
22858
23269
  if (dryRun) {
22859
23270
  for (const f of t.instructions.files) {
22860
23271
  console.log(
22861
- `${prefix}Tier 2 (${t.id}): ${resolve46(process.cwd(), f.path)}`
23272
+ `${prefix}Tier 2 (${t.id}): ${resolve47(process.cwd(), f.path)}`
22862
23273
  );
22863
23274
  }
22864
23275
  continue;
@@ -23005,7 +23416,7 @@ async function setupCommand(options) {
23005
23416
  }
23006
23417
 
23007
23418
  // src/commands/uninstall.ts
23008
- import { resolve as resolve47 } from "path";
23419
+ import { resolve as resolve48 } from "path";
23009
23420
  init_paths();
23010
23421
  function expandTargets(options) {
23011
23422
  if (options.all) {
@@ -23085,7 +23496,7 @@ async function uninstallCommand(options) {
23085
23496
  const configuredProjectDir = await getConfiguredProjectDir();
23086
23497
  await removeSyntaurData();
23087
23498
  console.log(`Removed ${syntaurRoot()}`);
23088
- if (configuredProjectDir && resolve47(configuredProjectDir) !== resolve47(syntaurRoot(), "projects")) {
23499
+ if (configuredProjectDir && resolve48(configuredProjectDir) !== resolve48(syntaurRoot(), "projects")) {
23089
23500
  console.warn(
23090
23501
  `Warning: config.md pointed to an external project directory (${configuredProjectDir}). That directory was not removed automatically.`
23091
23502
  );
@@ -23100,7 +23511,7 @@ async function uninstallCommand(options) {
23100
23511
  init_paths();
23101
23512
  init_fs();
23102
23513
  init_config2();
23103
- import { resolve as resolve48 } from "path";
23514
+ import { resolve as resolve49 } from "path";
23104
23515
  init_session_db();
23105
23516
  init_agent_sessions();
23106
23517
  async function trackSessionCommand(options) {
@@ -23115,7 +23526,7 @@ async function trackSessionCommand(options) {
23115
23526
  if (options.project) {
23116
23527
  const config = await readConfig();
23117
23528
  const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
23118
- const projectDir = resolve48(baseDir, options.project);
23529
+ const projectDir = resolve49(baseDir, options.project);
23119
23530
  if (!await fileExists(projectDir)) {
23120
23531
  throw new Error(
23121
23532
  `Project "${options.project}" not found at ${projectDir}.`
@@ -23247,7 +23658,7 @@ function formatInstallUrlHandlerError(err2) {
23247
23658
  init_config2();
23248
23659
  init_paths();
23249
23660
  init_fs();
23250
- import { resolve as resolve50, isAbsolute as isAbsolute7 } from "path";
23661
+ import { resolve as resolve51, isAbsolute as isAbsolute7 } from "path";
23251
23662
  import { readFile as readFile32 } from "fs/promises";
23252
23663
  import { select, confirm as confirm2, input as input3 } from "@inquirer/prompts";
23253
23664
  async function browseCommand(options) {
@@ -23317,7 +23728,7 @@ async function pickAgent2(agents) {
23317
23728
  return picked;
23318
23729
  }
23319
23730
  async function ensureWorktree(opts) {
23320
- const assignmentPath = resolve50(
23731
+ const assignmentPath = resolve51(
23321
23732
  opts.projectsDir,
23322
23733
  opts.projectSlug,
23323
23734
  "assignments",
@@ -23397,7 +23808,7 @@ async function ensureWorktree(opts) {
23397
23808
  async function runCreate(opts) {
23398
23809
  const { createWorktreeAndRecord: createWorktreeAndRecord2, GitWorktreeError: GitWorktreeError2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
23399
23810
  const expandedWorktree = expandHome(opts.worktreePath);
23400
- const absWorktree = isAbsolute7(expandedWorktree) ? expandedWorktree : resolve50(expandedWorktree);
23811
+ const absWorktree = isAbsolute7(expandedWorktree) ? expandedWorktree : resolve51(expandedWorktree);
23401
23812
  try {
23402
23813
  await createWorktreeAndRecord2({
23403
23814
  assignmentPath: opts.assignmentPath,
@@ -23426,7 +23837,7 @@ init_paths();
23426
23837
  init_fs();
23427
23838
  init_playbook();
23428
23839
  init_playbooks();
23429
- import { resolve as resolve51 } from "path";
23840
+ import { resolve as resolve52 } from "path";
23430
23841
  async function createPlaybookCommand(name, options) {
23431
23842
  if (!name.trim()) {
23432
23843
  throw new Error("Playbook name cannot be empty.");
@@ -23439,7 +23850,7 @@ async function createPlaybookCommand(name, options) {
23439
23850
  }
23440
23851
  const dir = playbooksDir();
23441
23852
  await ensureDir(dir);
23442
- const filePath = resolve51(dir, `${slug}.md`);
23853
+ const filePath = resolve52(dir, `${slug}.md`);
23443
23854
  if (await fileExists(filePath)) {
23444
23855
  throw new Error(
23445
23856
  `Playbook "${slug}" already exists at ${filePath}
@@ -23461,8 +23872,8 @@ init_paths();
23461
23872
  init_fs();
23462
23873
  init_parser();
23463
23874
  init_config2();
23464
- import { readdir as readdir16, readFile as readFile33 } from "fs/promises";
23465
- import { resolve as resolve52 } from "path";
23875
+ import { readdir as readdir17, readFile as readFile33 } from "fs/promises";
23876
+ import { resolve as resolve53 } from "path";
23466
23877
  async function listPlaybooksCommand(options = {}) {
23467
23878
  const dir = playbooksDir();
23468
23879
  if (!await fileExists(dir)) {
@@ -23471,15 +23882,15 @@ async function listPlaybooksCommand(options = {}) {
23471
23882
  }
23472
23883
  const config = await readConfig();
23473
23884
  const disabledSet = new Set(config.playbooks.disabled);
23474
- const entries = await readdir16(dir, { withFileTypes: true });
23885
+ const entries = await readdir17(dir, { withFileTypes: true });
23475
23886
  const mdFiles = entries.filter(
23476
23887
  (e) => e.isFile() && e.name.endsWith(".md") && !e.name.startsWith("_") && e.name !== "manifest.md"
23477
23888
  );
23478
23889
  const rows = [];
23479
23890
  for (const entry of mdFiles) {
23480
- const filePath = resolve52(dir, entry.name);
23481
- const raw = await readFile33(filePath, "utf-8");
23482
- const parsed = parsePlaybook(raw);
23891
+ const filePath = resolve53(dir, entry.name);
23892
+ const raw2 = await readFile33(filePath, "utf-8");
23893
+ const parsed = parsePlaybook(raw2);
23483
23894
  const slug = parsed.slug || entry.name.replace(/\.md$/, "");
23484
23895
  const disabled = disabledSet.has(slug);
23485
23896
  if (disabled && !options.all) continue;
@@ -23602,13 +24013,13 @@ init_config2();
23602
24013
  init_slug();
23603
24014
  import { Command as Command2 } from "commander";
23604
24015
  import { readFile as readFile35 } from "fs/promises";
23605
- import { resolve as resolve54 } from "path";
24016
+ import { resolve as resolve55 } from "path";
23606
24017
 
23607
24018
  // src/commands/bundle.ts
23608
24019
  init_paths();
23609
24020
  import { Command } from "commander";
23610
- import { mkdir as mkdir7, readFile as readFile34, readdir as readdir17, rm as rm7, writeFile as writeFile12 } from "fs/promises";
23611
- import { resolve as resolve53 } from "path";
24021
+ import { mkdir as mkdir8, readFile as readFile34, readdir as readdir18, rm as rm8, writeFile as writeFile13 } from "fs/promises";
24022
+ import { resolve as resolve54 } from "path";
23612
24023
  init_parser2();
23613
24024
  init_fs();
23614
24025
  init_config2();
@@ -23626,7 +24037,7 @@ async function resolveBundleScope(options) {
23626
24037
  throw new Error(`Invalid project slug: "${options.project}".`);
23627
24038
  }
23628
24039
  const config = await readConfig();
23629
- const projectMd = resolve53(config.defaultProjectDir, options.project, "project.md");
24040
+ const projectMd = resolve54(config.defaultProjectDir, options.project, "project.md");
23630
24041
  if (!await fileExists(projectMd)) {
23631
24042
  throw new Error(`Project "${options.project}" not found.`);
23632
24043
  }
@@ -23696,10 +24107,10 @@ function pickNextPlanFile(planDir, existingFiles) {
23696
24107
  const m = f.match(/^plan-v(\d+)\.md$/);
23697
24108
  if (m) versions.add(parseInt(m[1], 10));
23698
24109
  }
23699
- if (versions.size === 0) return { target: resolve53(planDir, "plan.md"), version: 1 };
24110
+ if (versions.size === 0) return { target: resolve54(planDir, "plan.md"), version: 1 };
23700
24111
  let n = 2;
23701
24112
  while (versions.has(n)) n++;
23702
- return { target: resolve53(planDir, `plan-v${n}.md`), version: n };
24113
+ return { target: resolve54(planDir, `plan-v${n}.md`), version: n };
23703
24114
  }
23704
24115
  function dedupePreserveOrder(ids) {
23705
24116
  const out = [];
@@ -23783,7 +24194,7 @@ bundleCommand.command("new").description("Create a new bundle from 2+ existing t
23783
24194
  if (options.plan) {
23784
24195
  const planDir = bundlePlanDir(sc.todosPath, sc.scopeId, id);
23785
24196
  await ensureDir(planDir);
23786
- const target = resolve53(planDir, "plan.md");
24197
+ const target = resolve54(planDir, "plan.md");
23787
24198
  const memberLines = items.map((it) => `- ${it.description} [t:${it.id}]`).join("\n");
23788
24199
  const stub = [
23789
24200
  "---",
@@ -23900,7 +24311,7 @@ bundleCommand.command("plan").description("Create or open the bundle's shared pl
23900
24311
  }
23901
24312
  const planDir = bundlePlanDir(sc.todosPath, sc.scopeId, id);
23902
24313
  await ensureDir(planDir);
23903
- const existing = (await readdir17(planDir).catch(() => [])).filter((f) => /^plan(?:-v\d+)?\.md$/.test(f));
24314
+ const existing = (await readdir18(planDir).catch(() => [])).filter((f) => /^plan(?:-v\d+)?\.md$/.test(f));
23904
24315
  const { target } = pickNextPlanFile(planDir, existing);
23905
24316
  const checklist = await readChecklist(sc.todosPath, sc.checklistKey);
23906
24317
  if (!await fileExists(target)) {
@@ -23959,7 +24370,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
23959
24370
  }
23960
24371
  const repository = options.repository ?? process.cwd();
23961
24372
  const parentBranch = options.parentBranch ?? "main";
23962
- const worktreePath = options.worktreePath ?? resolve53(repository, ".worktrees", options.branch);
24373
+ const worktreePath = options.worktreePath ?? resolve54(repository, ".worktrees", options.branch);
23963
24374
  const checklist = await readChecklist(sc.todosPath, sc.checklistKey);
23964
24375
  for (const memberId of bundle.todoIds) {
23965
24376
  const item = checklist.items.find((i) => i.id === memberId);
@@ -23986,8 +24397,8 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
23986
24397
  try {
23987
24398
  await writeBundles(sc.todosPath, bundles);
23988
24399
  await writeChecklist(sc.todosPath, checklist);
23989
- const ctxDir = resolve53(worktreePath, ".syntaur");
23990
- await mkdir7(ctxDir, { recursive: true });
24400
+ const ctxDir = resolve54(worktreePath, ".syntaur");
24401
+ await mkdir8(ctxDir, { recursive: true });
23991
24402
  const payload = {
23992
24403
  bundleId: bundle.id,
23993
24404
  bundleSlug: bundle.slug,
@@ -24000,16 +24411,16 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
24000
24411
  repository,
24001
24412
  boundAt: nowISO()
24002
24413
  };
24003
- await writeFile12(resolve53(ctxDir, "context.json"), JSON.stringify(payload, null, 2) + "\n");
24414
+ await writeFile13(resolve54(ctxDir, "context.json"), JSON.stringify(payload, null, 2) + "\n");
24004
24415
  } catch (err2) {
24005
24416
  try {
24006
24417
  if (bundlesSnapshot === null) {
24007
- await rm7(bundlesFilePath, { force: true });
24418
+ await rm8(bundlesFilePath, { force: true });
24008
24419
  } else {
24009
24420
  await writeFileForce(bundlesFilePath, bundlesSnapshot);
24010
24421
  }
24011
24422
  if (checklistSnapshot === null) {
24012
- await rm7(checklistFilePath, { force: true });
24423
+ await rm8(checklistFilePath, { force: true });
24013
24424
  } else {
24014
24425
  await writeFileForce(checklistFilePath, checklistSnapshot);
24015
24426
  }
@@ -24190,7 +24601,7 @@ async function resolveScope(options) {
24190
24601
  throw new Error(`Invalid project slug: "${options.project}".`);
24191
24602
  }
24192
24603
  const config = await readConfig();
24193
- const projectMd = resolve54(config.defaultProjectDir, options.project, "project.md");
24604
+ const projectMd = resolve55(config.defaultProjectDir, options.project, "project.md");
24194
24605
  if (!await fileExists(projectMd)) {
24195
24606
  throw new Error(`Project "${options.project}" not found.`);
24196
24607
  }
@@ -24513,7 +24924,7 @@ todoCommand.command("archive").description("Archive completed todos and their lo
24513
24924
  (e) => e.itemIds.every((id) => completedIds.has(id))
24514
24925
  );
24515
24926
  const archFile = archivePath(todosPath, workspace, checklist.archiveInterval);
24516
- await ensureDir(resolve54(todosPath, "archive"));
24927
+ await ensureDir(resolve55(todosPath, "archive"));
24517
24928
  let archContent = "";
24518
24929
  if (await fileExists(archFile)) {
24519
24930
  archContent = await readFile35(archFile, "utf-8");
@@ -24743,13 +25154,13 @@ todoCommand.command("plan").description("Create or open a plan directory for a t
24743
25154
  }
24744
25155
  const planDir = todoPlanDir(todosPath, workspace, id);
24745
25156
  await ensureDir(planDir);
24746
- const { readdir: readdir29 } = await import("fs/promises");
24747
- const existingFiles = (await readdir29(planDir).catch(() => [])).filter(
25157
+ const { readdir: readdir30 } = await import("fs/promises");
25158
+ const existingFiles = (await readdir30(planDir).catch(() => [])).filter(
24748
25159
  (f) => /^plan(?:-v\d+)?\.md$/.test(f)
24749
25160
  );
24750
25161
  let target;
24751
25162
  if (existingFiles.length === 0) {
24752
- target = resolve54(planDir, "plan.md");
25163
+ target = resolve55(planDir, "plan.md");
24753
25164
  } else {
24754
25165
  const versions = /* @__PURE__ */ new Set();
24755
25166
  for (const f of existingFiles) {
@@ -24759,7 +25170,7 @@ todoCommand.command("plan").description("Create or open a plan directory for a t
24759
25170
  }
24760
25171
  let n = 2;
24761
25172
  while (versions.has(n)) n++;
24762
- target = resolve54(planDir, `plan-v${n}.md`);
25173
+ target = resolve55(planDir, `plan-v${n}.md`);
24763
25174
  }
24764
25175
  if (!await fileExists(target)) {
24765
25176
  const stub = `---
@@ -24829,10 +25240,10 @@ async function moveTodo(id, options) {
24829
25240
  if (await fileExists(newPlanDir)) {
24830
25241
  throw new Error(`Plan directory already exists at target: ${newPlanDir}; refusing to move.`);
24831
25242
  }
24832
- const { rename: rename10, mkdir: mkdir10 } = await import("fs/promises");
24833
- const { dirname: dirname22 } = await import("path");
24834
- await mkdir10(dirname22(newPlanDir), { recursive: true });
24835
- await rename10(item.planDir, newPlanDir);
25243
+ const { rename: rename11, mkdir: mkdir11 } = await import("fs/promises");
25244
+ const { dirname: dirname23 } = await import("path");
25245
+ await mkdir11(dirname23(newPlanDir), { recursive: true });
25246
+ await rename11(item.planDir, newPlanDir);
24836
25247
  item.planDir = newPlanDir;
24837
25248
  }
24838
25249
  sourceChecklist.items.splice(idx, 1);
@@ -24949,23 +25360,23 @@ backupCommand.command("config").description("Show or update backup configuration
24949
25360
  // src/commands/doctor.ts
24950
25361
  import { Command as Command4 } from "commander";
24951
25362
  import { readFile as readFile43 } from "fs/promises";
24952
- import { isAbsolute as isAbsolute10, resolve as resolve67 } from "path";
25363
+ import { isAbsolute as isAbsolute10, resolve as resolve68 } from "path";
24953
25364
 
24954
25365
  // src/utils/doctor/index.ts
24955
25366
  import { fileURLToPath as fileURLToPath11 } from "url";
24956
25367
  import { readFile as readFile42 } from "fs/promises";
24957
- import { dirname as dirname19, join as join13 } from "path";
25368
+ import { dirname as dirname20, join as join13 } from "path";
24958
25369
 
24959
25370
  // src/utils/doctor/context.ts
24960
25371
  init_config2();
24961
25372
  init_paths();
24962
25373
  init_fs();
24963
25374
  import Database4 from "better-sqlite3";
24964
- import { resolve as resolve55 } from "path";
25375
+ import { resolve as resolve56 } from "path";
24965
25376
  async function buildCheckContext(cwd = process.cwd()) {
24966
25377
  const config = await readConfig();
24967
25378
  const root = syntaurRoot();
24968
- const dbPath = resolve55(root, "syntaur.db");
25379
+ const dbPath = resolve56(root, "syntaur.db");
24969
25380
  let db5 = null;
24970
25381
  let dbError = null;
24971
25382
  if (await fileExists(dbPath)) {
@@ -24999,10 +25410,10 @@ function closeCheckContext(ctx) {
24999
25410
  // src/utils/doctor/checks/env.ts
25000
25411
  init_fs();
25001
25412
  init_paths();
25002
- import { resolve as resolve56, isAbsolute as isAbsolute8 } from "path";
25003
- import { readFile as readFile36, stat as stat3 } from "fs/promises";
25413
+ import { resolve as resolve57, isAbsolute as isAbsolute8 } from "path";
25414
+ import { readFile as readFile36, stat as stat4 } from "fs/promises";
25004
25415
  import { fileURLToPath as fileURLToPath10 } from "url";
25005
- import { dirname as dirname17, join as join10 } from "path";
25416
+ import { dirname as dirname18, join as join10 } from "path";
25006
25417
  var CATEGORY = "env";
25007
25418
  var syntaurRootExists = {
25008
25419
  id: "env.syntaur-root-exists",
@@ -25010,7 +25421,7 @@ var syntaurRootExists = {
25010
25421
  title: "~/.syntaur/ directory exists",
25011
25422
  async run(ctx) {
25012
25423
  try {
25013
- const s = await stat3(ctx.syntaurRoot);
25424
+ const s = await stat4(ctx.syntaurRoot);
25014
25425
  if (!s.isDirectory()) {
25015
25426
  return err(this, `${ctx.syntaurRoot} exists but is not a directory`, [
25016
25427
  ctx.syntaurRoot
@@ -25040,7 +25451,7 @@ var configValid = {
25040
25451
  category: CATEGORY,
25041
25452
  title: "~/.syntaur/config.md is valid",
25042
25453
  async run(ctx) {
25043
- const configPath = resolve56(ctx.syntaurRoot, "config.md");
25454
+ const configPath = resolve57(ctx.syntaurRoot, "config.md");
25044
25455
  if (!await fileExists(configPath)) {
25045
25456
  return {
25046
25457
  id: this.id,
@@ -25153,8 +25564,8 @@ function detectNestedParseMismatch(fmBlock, config) {
25153
25564
  ["integrations.codexMarketplacePath", config.integrations.codexMarketplacePath]
25154
25565
  ];
25155
25566
  for (const [dotted, parsedValue] of integrationChecks2) {
25156
- const raw = readNestedField(fmBlock, dotted);
25157
- if (raw !== null && raw !== "null" && raw !== "" && parsedValue === null) {
25567
+ const raw2 = readNestedField(fmBlock, dotted);
25568
+ if (raw2 !== null && raw2 !== "null" && raw2 !== "" && parsedValue === null) {
25158
25569
  return { field: dotted, parent: "integrations" };
25159
25570
  }
25160
25571
  }
@@ -25164,8 +25575,8 @@ function detectNestedParseMismatch(fmBlock, config) {
25164
25575
  ["backup.lastRestore", config.backup?.lastRestore ?? null]
25165
25576
  ];
25166
25577
  for (const [dotted, parsedValue] of backupFields) {
25167
- const raw = readNestedField(fmBlock, dotted);
25168
- if (raw !== null && raw !== "null" && raw !== "" && parsedValue === null) {
25578
+ const raw2 = readNestedField(fmBlock, dotted);
25579
+ if (raw2 !== null && raw2 !== "null" && raw2 !== "" && parsedValue === null) {
25169
25580
  return { field: dotted, parent: "backup" };
25170
25581
  }
25171
25582
  }
@@ -25203,11 +25614,11 @@ function readNestedField(fmBlock, dotted) {
25203
25614
  if (colonIdx < 0) continue;
25204
25615
  const lineKey = stripped.slice(0, colonIdx).trim();
25205
25616
  if (lineKey !== key) continue;
25206
- const raw = stripped.slice(colonIdx + 1).trim();
25207
- if (raw.startsWith('"') && raw.endsWith('"') || raw.startsWith("'") && raw.endsWith("'")) {
25208
- return raw.slice(1, -1);
25617
+ const raw2 = stripped.slice(colonIdx + 1).trim();
25618
+ if (raw2.startsWith('"') && raw2.endsWith('"') || raw2.startsWith("'") && raw2.endsWith("'")) {
25619
+ return raw2.slice(1, -1);
25209
25620
  }
25210
- return raw;
25621
+ return raw2;
25211
25622
  }
25212
25623
  return null;
25213
25624
  }
@@ -25319,28 +25730,28 @@ function err(check, detail, affected) {
25319
25730
  };
25320
25731
  }
25321
25732
  async function readEngineMin() {
25322
- const raw = await readLocalPkg();
25323
- if (!raw) return null;
25324
- const engine = raw.engines?.node;
25733
+ const raw2 = await readLocalPkg();
25734
+ if (!raw2) return null;
25735
+ const engine = raw2.engines?.node;
25325
25736
  if (typeof engine !== "string") return null;
25326
25737
  const match = engine.match(/(\d+(?:\.\d+){0,2})/);
25327
25738
  return match ? match[1] : null;
25328
25739
  }
25329
25740
  async function readLocalVersion() {
25330
- const raw = await readLocalPkg();
25331
- return typeof raw?.version === "string" ? raw.version : null;
25741
+ const raw2 = await readLocalPkg();
25742
+ return typeof raw2?.version === "string" ? raw2.version : null;
25332
25743
  }
25333
25744
  async function readLocalPkg() {
25334
25745
  try {
25335
25746
  const here = fileURLToPath10(import.meta.url);
25336
- let dir = dirname17(here);
25747
+ let dir = dirname18(here);
25337
25748
  for (let i = 0; i < 6; i++) {
25338
25749
  const candidate = join10(dir, "package.json");
25339
25750
  try {
25340
25751
  const text = await readFile36(candidate, "utf-8");
25341
25752
  return JSON.parse(text);
25342
25753
  } catch {
25343
- dir = dirname17(dir);
25754
+ dir = dirname18(dir);
25344
25755
  }
25345
25756
  }
25346
25757
  return null;
@@ -25367,12 +25778,12 @@ async function fetchLatestNpmVersion2(pkg, timeoutMs) {
25367
25778
  function readTopLevelField(fmBlock, key) {
25368
25779
  const match = fmBlock.match(new RegExp(`^${key}:\\s*(.*)$`, "m"));
25369
25780
  if (!match) return null;
25370
- const raw = match[1].trim();
25371
- if (raw === "") return null;
25372
- if (raw.startsWith('"') && raw.endsWith('"') || raw.startsWith("'") && raw.endsWith("'")) {
25373
- return raw.slice(1, -1);
25781
+ const raw2 = match[1].trim();
25782
+ if (raw2 === "") return null;
25783
+ if (raw2.startsWith('"') && raw2.endsWith('"') || raw2.startsWith("'") && raw2.endsWith("'")) {
25784
+ return raw2.slice(1, -1);
25374
25785
  }
25375
- return raw;
25786
+ return raw2;
25376
25787
  }
25377
25788
  function versionGte(a, b) {
25378
25789
  const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
@@ -25389,8 +25800,8 @@ function versionGte(a, b) {
25389
25800
 
25390
25801
  // src/utils/doctor/checks/structure.ts
25391
25802
  init_fs();
25392
- import { resolve as resolve57 } from "path";
25393
- import { readdir as readdir18, stat as stat4 } from "fs/promises";
25803
+ import { resolve as resolve58 } from "path";
25804
+ import { readdir as readdir19, stat as stat5 } from "fs/promises";
25394
25805
  var CATEGORY2 = "structure";
25395
25806
  var KNOWN_TOP_LEVEL = /* @__PURE__ */ new Set([
25396
25807
  "projects",
@@ -25409,7 +25820,7 @@ var projectsDir = {
25409
25820
  category: CATEGORY2,
25410
25821
  title: "projects/ directory exists",
25411
25822
  async run(ctx) {
25412
- const p = resolve57(ctx.syntaurRoot, "projects");
25823
+ const p = resolve58(ctx.syntaurRoot, "projects");
25413
25824
  if (!await fileExists(p)) {
25414
25825
  return {
25415
25826
  id: this.id,
@@ -25434,7 +25845,7 @@ var playbooksDir2 = {
25434
25845
  category: CATEGORY2,
25435
25846
  title: "playbooks/ directory exists",
25436
25847
  async run(ctx) {
25437
- const p = resolve57(ctx.syntaurRoot, "playbooks");
25848
+ const p = resolve58(ctx.syntaurRoot, "playbooks");
25438
25849
  if (!await fileExists(p)) {
25439
25850
  return {
25440
25851
  id: this.id,
@@ -25459,7 +25870,7 @@ var todosDirValid = {
25459
25870
  category: CATEGORY2,
25460
25871
  title: "todos/ directory is readable (if present)",
25461
25872
  async run(ctx) {
25462
- const p = resolve57(ctx.syntaurRoot, "todos");
25873
+ const p = resolve58(ctx.syntaurRoot, "todos");
25463
25874
  if (!await fileExists(p)) {
25464
25875
  return {
25465
25876
  id: this.id,
@@ -25470,7 +25881,7 @@ var todosDirValid = {
25470
25881
  autoFixable: false
25471
25882
  };
25472
25883
  }
25473
- const s = await stat4(p);
25884
+ const s = await stat5(p);
25474
25885
  if (!s.isDirectory()) {
25475
25886
  return {
25476
25887
  id: this.id,
@@ -25490,7 +25901,7 @@ var serversDirValid = {
25490
25901
  category: CATEGORY2,
25491
25902
  title: "servers/ directory is readable (if present)",
25492
25903
  async run(ctx) {
25493
- const p = resolve57(ctx.syntaurRoot, "servers");
25904
+ const p = resolve58(ctx.syntaurRoot, "servers");
25494
25905
  if (!await fileExists(p)) {
25495
25906
  return {
25496
25907
  id: this.id,
@@ -25501,7 +25912,7 @@ var serversDirValid = {
25501
25912
  autoFixable: false
25502
25913
  };
25503
25914
  }
25504
- const s = await stat4(p);
25915
+ const s = await stat5(p);
25505
25916
  if (!s.isDirectory()) {
25506
25917
  return {
25507
25918
  id: this.id,
@@ -25521,7 +25932,7 @@ var knownFilesRecognized = {
25521
25932
  category: CATEGORY2,
25522
25933
  title: "No unexpected top-level entries under ~/.syntaur/",
25523
25934
  async run(ctx) {
25524
- const entries = await readdir18(ctx.syntaurRoot, { withFileTypes: true });
25935
+ const entries = await readdir19(ctx.syntaurRoot, { withFileTypes: true });
25525
25936
  const unexpected = [];
25526
25937
  for (const e of entries) {
25527
25938
  if (e.name.startsWith(".")) continue;
@@ -25535,7 +25946,7 @@ var knownFilesRecognized = {
25535
25946
  title: this.title,
25536
25947
  status: "warn",
25537
25948
  detail: `unexpected top-level entries: ${unexpected.join(", ")}`,
25538
- affected: unexpected.map((n) => resolve57(ctx.syntaurRoot, n)),
25949
+ affected: unexpected.map((n) => resolve58(ctx.syntaurRoot, n)),
25539
25950
  remediation: {
25540
25951
  kind: "manual",
25541
25952
  suggestion: "Review these entries \u2014 they may be leftover state from older versions",
@@ -25564,8 +25975,8 @@ function pass2(check) {
25564
25975
 
25565
25976
  // src/utils/doctor/checks/project.ts
25566
25977
  init_fs();
25567
- import { resolve as resolve58 } from "path";
25568
- import { readdir as readdir19, stat as stat5 } from "fs/promises";
25978
+ import { resolve as resolve59 } from "path";
25979
+ import { readdir as readdir20, stat as stat6 } from "fs/promises";
25569
25980
  var CATEGORY3 = "project";
25570
25981
  var REQUIRED_PROJECT_FILES = [
25571
25982
  "project.md",
@@ -25589,15 +26000,15 @@ var PROJECT_MARKERS = ["project.md", "manifest.md", "assignments"];
25589
26000
  async function listProjects2(ctx) {
25590
26001
  const dir = ctx.config.defaultProjectDir;
25591
26002
  if (!await fileExists(dir)) return [];
25592
- const entries = await readdir19(dir, { withFileTypes: true });
26003
+ const entries = await readdir20(dir, { withFileTypes: true });
25593
26004
  const result = [];
25594
26005
  for (const e of entries) {
25595
26006
  if (!e.isDirectory()) continue;
25596
26007
  if (e.name.startsWith(".") || e.name.startsWith("_")) continue;
25597
- const projectDir = resolve58(dir, e.name);
26008
+ const projectDir = resolve59(dir, e.name);
25598
26009
  let looksLikeProject = false;
25599
26010
  for (const marker of PROJECT_MARKERS) {
25600
- if (await fileExists(resolve58(projectDir, marker))) {
26011
+ if (await fileExists(resolve59(projectDir, marker))) {
25601
26012
  looksLikeProject = true;
25602
26013
  break;
25603
26014
  }
@@ -25616,7 +26027,7 @@ var requiredFiles = {
25616
26027
  for (const projectDir of projects) {
25617
26028
  const missing = [];
25618
26029
  for (const rel of REQUIRED_PROJECT_FILES) {
25619
- const p = resolve58(projectDir, rel);
26030
+ const p = resolve59(projectDir, rel);
25620
26031
  if (!await fileExists(p)) missing.push(rel);
25621
26032
  }
25622
26033
  if (missing.length === 0) continue;
@@ -25626,7 +26037,7 @@ var requiredFiles = {
25626
26037
  title: this.title,
25627
26038
  status: "error",
25628
26039
  detail: `project at ${projectDir} is missing: ${missing.join(", ")}`,
25629
- affected: missing.map((m) => resolve58(projectDir, m)),
26040
+ affected: missing.map((m) => resolve59(projectDir, m)),
25630
26041
  remediation: {
25631
26042
  kind: "manual",
25632
26043
  suggestion: "Recreate the missing scaffold files from templates",
@@ -25649,9 +26060,9 @@ var manifestStale = {
25649
26060
  const projects = await listProjects2(ctx);
25650
26061
  const results = [];
25651
26062
  for (const projectDir of projects) {
25652
- const manifestPath = resolve58(projectDir, "manifest.md");
26063
+ const manifestPath = resolve59(projectDir, "manifest.md");
25653
26064
  if (!await fileExists(manifestPath)) continue;
25654
- const manifestMtime = (await stat5(manifestPath)).mtimeMs;
26065
+ const manifestMtime = (await stat6(manifestPath)).mtimeMs;
25655
26066
  const newestAssignment = await newestAssignmentMtime(projectDir);
25656
26067
  if (newestAssignment === 0) continue;
25657
26068
  if (newestAssignment > manifestMtime) {
@@ -25683,7 +26094,7 @@ var orphanFiles = {
25683
26094
  const projects = await listProjects2(ctx);
25684
26095
  const results = [];
25685
26096
  for (const projectDir of projects) {
25686
- const entries = await readdir19(projectDir, { withFileTypes: true });
26097
+ const entries = await readdir20(projectDir, { withFileTypes: true });
25687
26098
  const orphans = [];
25688
26099
  for (const e of entries) {
25689
26100
  if (e.name.startsWith(".")) continue;
@@ -25698,7 +26109,7 @@ var orphanFiles = {
25698
26109
  title: this.title,
25699
26110
  status: "warn",
25700
26111
  detail: `project at ${projectDir} has unexpected entries: ${orphans.join(", ")}`,
25701
- affected: orphans.map((o) => resolve58(projectDir, o)),
26112
+ affected: orphans.map((o) => resolve59(projectDir, o)),
25702
26113
  autoFixable: false
25703
26114
  });
25704
26115
  }
@@ -25708,20 +26119,20 @@ var orphanFiles = {
25708
26119
  };
25709
26120
  var projectChecks = [requiredFiles, manifestStale, orphanFiles];
25710
26121
  async function newestAssignmentMtime(projectDir) {
25711
- const assignmentsRoot = resolve58(projectDir, "assignments");
26122
+ const assignmentsRoot = resolve59(projectDir, "assignments");
25712
26123
  if (!await fileExists(assignmentsRoot)) return 0;
25713
26124
  let newest = 0;
25714
26125
  let entries;
25715
26126
  try {
25716
- entries = await readdir19(assignmentsRoot, { withFileTypes: true });
26127
+ entries = await readdir20(assignmentsRoot, { withFileTypes: true });
25717
26128
  } catch {
25718
26129
  return 0;
25719
26130
  }
25720
26131
  for (const e of entries) {
25721
26132
  if (!e.isDirectory()) continue;
25722
- const assignmentMd = resolve58(assignmentsRoot, e.name, "assignment.md");
26133
+ const assignmentMd = resolve59(assignmentsRoot, e.name, "assignment.md");
25723
26134
  try {
25724
- const s = await stat5(assignmentMd);
26135
+ const s = await stat6(assignmentMd);
25725
26136
  if (s.mtimeMs > newest) newest = s.mtimeMs;
25726
26137
  } catch {
25727
26138
  }
@@ -25743,8 +26154,8 @@ init_fs();
25743
26154
  init_parser();
25744
26155
  init_types();
25745
26156
  init_paths();
25746
- import { resolve as resolve59 } from "path";
25747
- import { readFile as readFile37, readdir as readdir20 } from "fs/promises";
26157
+ import { resolve as resolve60 } from "path";
26158
+ import { readFile as readFile37, readdir as readdir21 } from "fs/promises";
25748
26159
  var CATEGORY4 = "assignment";
25749
26160
  var STATUSES_REQUIRING_HANDOFF = /* @__PURE__ */ new Set(["review", "completed"]);
25750
26161
  var PRE_WORKSPACE_STATUSES = /* @__PURE__ */ new Set([
@@ -25838,7 +26249,7 @@ var invalidStatus = {
25838
26249
  const allowed = configuredStatuses(ctx);
25839
26250
  const results = [];
25840
26251
  for (const a of withAssignmentMd) {
25841
- const path = resolve59(a.assignmentDir, "assignment.md");
26252
+ const path = resolve60(a.assignmentDir, "assignment.md");
25842
26253
  const parsed = await parseSafe2(path);
25843
26254
  if (!parsed) continue;
25844
26255
  if (!allowed.has(parsed.status)) {
@@ -25871,7 +26282,7 @@ var workspaceMissing = {
25871
26282
  const terminal = terminalStatuses(ctx);
25872
26283
  const results = [];
25873
26284
  for (const a of withAssignmentMd) {
25874
- const path = resolve59(a.assignmentDir, "assignment.md");
26285
+ const path = resolve60(a.assignmentDir, "assignment.md");
25875
26286
  const parsed = await parseSafe2(path);
25876
26287
  if (!parsed) continue;
25877
26288
  if (terminal.has(parsed.status)) continue;
@@ -25918,12 +26329,12 @@ var requiredFilesByStatus = {
25918
26329
  const { withAssignmentMd } = await listAssignments(ctx);
25919
26330
  const results = [];
25920
26331
  for (const a of withAssignmentMd) {
25921
- const assignmentPath = resolve59(a.assignmentDir, "assignment.md");
26332
+ const assignmentPath = resolve60(a.assignmentDir, "assignment.md");
25922
26333
  const parsed = await parseSafe2(assignmentPath);
25923
26334
  if (!parsed) continue;
25924
26335
  const missing = [];
25925
26336
  if (STATUSES_REQUIRING_HANDOFF.has(parsed.status)) {
25926
- const handoffPath = resolve59(a.assignmentDir, "handoff.md");
26337
+ const handoffPath = resolve60(a.assignmentDir, "handoff.md");
25927
26338
  if (!await fileExists(handoffPath)) missing.push("handoff.md");
25928
26339
  }
25929
26340
  if (missing.length === 0) continue;
@@ -25933,7 +26344,7 @@ var requiredFilesByStatus = {
25933
26344
  title: this.title,
25934
26345
  status: "warn",
25935
26346
  detail: `${a.projectSlug}/${a.assignmentSlug} (status: ${parsed.status}) is missing ${missing.join(", ")}`,
25936
- affected: missing.map((m) => resolve59(a.assignmentDir, m)),
26347
+ affected: missing.map((m) => resolve60(a.assignmentDir, m)),
25937
26348
  remediation: {
25938
26349
  kind: "manual",
25939
26350
  suggestion: `Create the missing ${missing.join(" and ")} files for this assignment`,
@@ -25956,7 +26367,7 @@ var companionFilesScaffolded = {
25956
26367
  for (const a of withAssignmentMd) {
25957
26368
  const missing = [];
25958
26369
  for (const filename of ["progress.md", "comments.md"]) {
25959
- if (!await fileExists(resolve59(a.assignmentDir, filename))) {
26370
+ if (!await fileExists(resolve60(a.assignmentDir, filename))) {
25960
26371
  missing.push(filename);
25961
26372
  }
25962
26373
  }
@@ -25968,7 +26379,7 @@ var companionFilesScaffolded = {
25968
26379
  title: this.title,
25969
26380
  status: "warn",
25970
26381
  detail: `${label} is missing ${missing.join(" and ")} (pre-v2.0 assignment \u2014 not required, but scaffolding them keeps the dashboard and CLIs consistent)`,
25971
- affected: missing.map((m) => resolve59(a.assignmentDir, m)),
26382
+ affected: missing.map((m) => resolve60(a.assignmentDir, m)),
25972
26383
  remediation: {
25973
26384
  kind: "manual",
25974
26385
  suggestion: `Create ${missing.join(" and ")} with the renderProgress/renderComments templates, or re-scaffold via the CLI`,
@@ -26001,7 +26412,7 @@ var typeDefinition = {
26001
26412
  const { withAssignmentMd } = await listAssignments(ctx);
26002
26413
  const results = [];
26003
26414
  for (const a of withAssignmentMd) {
26004
- const path = resolve59(a.assignmentDir, "assignment.md");
26415
+ const path = resolve60(a.assignmentDir, "assignment.md");
26005
26416
  const parsed = await parseSafe2(path);
26006
26417
  if (!parsed) continue;
26007
26418
  if (!parsed.type) continue;
@@ -26035,7 +26446,7 @@ var projectFrontmatterMatchesContainer = {
26035
26446
  const { withAssignmentMd } = await listAssignments(ctx);
26036
26447
  const results = [];
26037
26448
  for (const a of withAssignmentMd) {
26038
- const path = resolve59(a.assignmentDir, "assignment.md");
26449
+ const path = resolve60(a.assignmentDir, "assignment.md");
26039
26450
  const parsed = await parseSafe2(path);
26040
26451
  if (!parsed) continue;
26041
26452
  if (a.standalone) {
@@ -26086,17 +26497,17 @@ var draftMissingObjective = {
26086
26497
  const { withAssignmentMd } = await listAssignments(ctx);
26087
26498
  const results = [];
26088
26499
  for (const a of withAssignmentMd) {
26089
- const path = resolve59(a.assignmentDir, "assignment.md");
26500
+ const path = resolve60(a.assignmentDir, "assignment.md");
26090
26501
  const parsed = await parseSafe2(path);
26091
26502
  if (!parsed) continue;
26092
26503
  if (parsed.status !== "draft") continue;
26093
- let raw;
26504
+ let raw2;
26094
26505
  try {
26095
- raw = await readFile37(path, "utf-8");
26506
+ raw2 = await readFile37(path, "utf-8");
26096
26507
  } catch {
26097
26508
  continue;
26098
26509
  }
26099
- if (!objectiveBodyIsEmpty(raw)) continue;
26510
+ if (!objectiveBodyIsEmpty(raw2)) continue;
26100
26511
  const label = a.standalone ? `standalone/${a.assignmentSlug}` : `${a.projectSlug}/${a.assignmentSlug}`;
26101
26512
  results.push({
26102
26513
  id: this.id,
@@ -26125,16 +26536,16 @@ var readyToImplementMissingPlan = {
26125
26536
  const { withAssignmentMd } = await listAssignments(ctx);
26126
26537
  const results = [];
26127
26538
  for (const a of withAssignmentMd) {
26128
- const path = resolve59(a.assignmentDir, "assignment.md");
26539
+ const path = resolve60(a.assignmentDir, "assignment.md");
26129
26540
  const parsed = await parseSafe2(path);
26130
26541
  if (!parsed) continue;
26131
26542
  if (parsed.status !== "ready_to_implement") continue;
26132
- const entries = await readdir20(a.assignmentDir).catch(() => []);
26543
+ const entries = await readdir21(a.assignmentDir).catch(() => []);
26133
26544
  const planFiles = entries.filter((f) => /^plan(?:-v\d+)?\.md$/i.test(f));
26134
26545
  let hasPlanContent = false;
26135
26546
  for (const f of planFiles) {
26136
26547
  try {
26137
- const c2 = await readFile37(resolve59(a.assignmentDir, f), "utf-8");
26548
+ const c2 = await readFile37(resolve60(a.assignmentDir, f), "utf-8");
26138
26549
  if (c2.trim().length > 0) {
26139
26550
  hasPlanContent = true;
26140
26551
  break;
@@ -26150,7 +26561,7 @@ var readyToImplementMissingPlan = {
26150
26561
  title: this.title,
26151
26562
  status: "warn",
26152
26563
  detail: `${label} (status: ready_to_implement) has no plan.md or plan-v<N>.md`,
26153
- affected: [resolve59(a.assignmentDir, "plan.md")],
26564
+ affected: [resolve60(a.assignmentDir, "plan.md")],
26154
26565
  remediation: {
26155
26566
  kind: "manual",
26156
26567
  suggestion: `Write a plan with '/plan-assignment' (or 'syntaur plan'), then re-mark ready_to_implement`,
@@ -26196,7 +26607,7 @@ function pass4(check, detail) {
26196
26607
 
26197
26608
  // src/utils/doctor/checks/dashboard.ts
26198
26609
  init_fs();
26199
- import { resolve as resolve60 } from "path";
26610
+ import { resolve as resolve61 } from "path";
26200
26611
  var CATEGORY5 = "dashboard";
26201
26612
  var dbReachable = {
26202
26613
  id: "dashboard.db-reachable",
@@ -26210,7 +26621,7 @@ var dbReachable = {
26210
26621
  title: this.title,
26211
26622
  status: "error",
26212
26623
  detail: `could not open syntaur.db: ${ctx.dbError ?? "unknown error"}`,
26213
- affected: [resolve60(ctx.syntaurRoot, "syntaur.db")],
26624
+ affected: [resolve61(ctx.syntaurRoot, "syntaur.db")],
26214
26625
  remediation: {
26215
26626
  kind: "manual",
26216
26627
  suggestion: "Start the dashboard once (`syntaur dashboard`) to initialize the DB, or restore it from backup",
@@ -26228,7 +26639,7 @@ var dbReachable = {
26228
26639
  title: this.title,
26229
26640
  status: "error",
26230
26641
  detail: 'syntaur.db is missing the expected "sessions" table',
26231
- affected: [resolve60(ctx.syntaurRoot, "syntaur.db")],
26642
+ affected: [resolve61(ctx.syntaurRoot, "syntaur.db")],
26232
26643
  autoFixable: false
26233
26644
  };
26234
26645
  }
@@ -26240,7 +26651,7 @@ var dbReachable = {
26240
26651
  title: this.title,
26241
26652
  status: "error",
26242
26653
  detail: `syntaur.db query failed: ${err2 instanceof Error ? err2.message : String(err2)}`,
26243
- affected: [resolve60(ctx.syntaurRoot, "syntaur.db")],
26654
+ affected: [resolve61(ctx.syntaurRoot, "syntaur.db")],
26244
26655
  autoFixable: false
26245
26656
  };
26246
26657
  }
@@ -26266,7 +26677,7 @@ var ghostSessions = {
26266
26677
  const results = [];
26267
26678
  for (const row of rows) {
26268
26679
  if (!row.project_slug) continue;
26269
- const projectPath = resolve60(projectsDir2, row.project_slug, "project.md");
26680
+ const projectPath = resolve61(projectsDir2, row.project_slug, "project.md");
26270
26681
  if (!await fileExists(projectPath)) {
26271
26682
  results.push({
26272
26683
  id: this.id,
@@ -26285,7 +26696,7 @@ var ghostSessions = {
26285
26696
  continue;
26286
26697
  }
26287
26698
  if (row.assignment_slug) {
26288
- const assignmentPath = resolve60(
26699
+ const assignmentPath = resolve61(
26289
26700
  projectsDir2,
26290
26701
  row.project_slug,
26291
26702
  "assignments",
@@ -26337,8 +26748,8 @@ function skipped(check, reason) {
26337
26748
 
26338
26749
  // src/utils/doctor/checks/integrations.ts
26339
26750
  init_fs();
26340
- import { resolve as resolve61, dirname as dirname18, basename as basename5 } from "path";
26341
- import { readdir as readdir21, readFile as readFile38 } from "fs/promises";
26751
+ import { resolve as resolve62, dirname as dirname19, basename as basename6 } from "path";
26752
+ import { readdir as readdir22, readFile as readFile38 } from "fs/promises";
26342
26753
  import { homedir as homedir10 } from "os";
26343
26754
  var CATEGORY6 = "integrations";
26344
26755
  var claudePluginLinked = {
@@ -26401,7 +26812,7 @@ var backupConfigured = {
26401
26812
  if (ctx.config.backup?.repo) return pass6(this);
26402
26813
  const projectsDir2 = ctx.config.defaultProjectDir;
26403
26814
  if (!await fileExists(projectsDir2)) return skipped2(this, "no projects dir");
26404
- const entries = await readdir21(projectsDir2, { withFileTypes: true });
26815
+ const entries = await readdir22(projectsDir2, { withFileTypes: true });
26405
26816
  const hasProjects = entries.some((e) => e.isDirectory() && !e.name.startsWith(".") && !e.name.startsWith("_"));
26406
26817
  if (!hasProjects) return skipped2(this, "no projects yet");
26407
26818
  return {
@@ -26420,11 +26831,11 @@ var backupConfigured = {
26420
26831
  }
26421
26832
  };
26422
26833
  async function readKnownMarketplaces() {
26423
- const path = resolve61(homedir10(), ".claude", "plugins", "known_marketplaces.json");
26834
+ const path = resolve62(homedir10(), ".claude", "plugins", "known_marketplaces.json");
26424
26835
  if (!await fileExists(path)) return {};
26425
26836
  try {
26426
- const raw = await readFile38(path, "utf-8");
26427
- return JSON.parse(raw);
26837
+ const raw2 = await readFile38(path, "utf-8");
26838
+ return JSON.parse(raw2);
26428
26839
  } catch {
26429
26840
  return {};
26430
26841
  }
@@ -26439,8 +26850,8 @@ var claudeMarketplaceRegistered = {
26439
26850
  if (!await fileExists(dir)) {
26440
26851
  return skipped2(this, "claudePluginDir does not exist (run install-plugin)");
26441
26852
  }
26442
- const pluginsParent = dirname18(dir);
26443
- if (basename5(pluginsParent) !== "plugins") {
26853
+ const pluginsParent = dirname19(dir);
26854
+ if (basename6(pluginsParent) !== "plugins") {
26444
26855
  return {
26445
26856
  id: this.id,
26446
26857
  category: this.category,
@@ -26456,8 +26867,8 @@ var claudeMarketplaceRegistered = {
26456
26867
  autoFixable: false
26457
26868
  };
26458
26869
  }
26459
- const marketplaceRoot = dirname18(pluginsParent);
26460
- const marketplaceManifest = resolve61(marketplaceRoot, ".claude-plugin", "marketplace.json");
26870
+ const marketplaceRoot = dirname19(pluginsParent);
26871
+ const marketplaceManifest = resolve62(marketplaceRoot, ".claude-plugin", "marketplace.json");
26461
26872
  if (!await fileExists(marketplaceManifest)) {
26462
26873
  return {
26463
26874
  id: this.id,
@@ -26488,7 +26899,7 @@ var claudeMarketplaceRegistered = {
26488
26899
  autoFixable: false
26489
26900
  };
26490
26901
  }
26491
- const marketplaceName = parsed.name ?? basename5(marketplaceRoot);
26902
+ const marketplaceName = parsed.name ?? basename6(marketplaceRoot);
26492
26903
  const hasSyntaurEntry = (parsed.plugins ?? []).some((p) => p?.name === "syntaur");
26493
26904
  const known = await readKnownMarketplaces();
26494
26905
  const registered = known[marketplaceName]?.installLocation === marketplaceRoot || Object.values(known).some((v) => v.installLocation === marketplaceRoot);
@@ -26508,7 +26919,7 @@ var claudeMarketplaceRegistered = {
26508
26919
  title: this.title,
26509
26920
  status: "error",
26510
26921
  detail: issues.join("; "),
26511
- affected: [marketplaceManifest, resolve61(homedir10(), ".claude", "plugins", "known_marketplaces.json")],
26922
+ affected: [marketplaceManifest, resolve62(homedir10(), ".claude", "plugins", "known_marketplaces.json")],
26512
26923
  remediation: {
26513
26924
  kind: "manual",
26514
26925
  suggestion: "Re-run install-plugin to ensure both files are in sync.",
@@ -26548,7 +26959,7 @@ function skipped2(check, reason) {
26548
26959
  init_fs();
26549
26960
  init_parser();
26550
26961
  init_types();
26551
- import { resolve as resolve62 } from "path";
26962
+ import { resolve as resolve63 } from "path";
26552
26963
  import { readFile as readFile39 } from "fs/promises";
26553
26964
  var CATEGORY7 = "workspace";
26554
26965
  var ASSIGNMENT_FIELDS = ["projectSlug", "assignmentSlug", "projectDir", "assignmentDir"];
@@ -26570,13 +26981,13 @@ function isStandaloneSession(ctx) {
26570
26981
  return !hasAnyAssignmentField(ctx) && !hasAnyBundleField(ctx) && typeof ctx.sessionId === "string" && ctx.sessionId.length > 0;
26571
26982
  }
26572
26983
  async function loadContext(ctx) {
26573
- const path = resolve62(ctx.cwd, ".syntaur", "context.json");
26984
+ const path = resolve63(ctx.cwd, ".syntaur", "context.json");
26574
26985
  if (!await fileExists(path)) {
26575
26986
  return { data: null, path, exists: false, parseError: null };
26576
26987
  }
26577
26988
  try {
26578
- const raw = await readFile39(path, "utf-8");
26579
- return { data: JSON.parse(raw), path, exists: true, parseError: null };
26989
+ const raw2 = await readFile39(path, "utf-8");
26990
+ return { data: JSON.parse(raw2), path, exists: true, parseError: null };
26580
26991
  } catch (err2) {
26581
26992
  return {
26582
26993
  data: null,
@@ -26669,7 +27080,7 @@ var contextAssignmentResolves = {
26669
27080
  if (isStandaloneSession(data)) return skipped3(this, "standalone session context \u2014 no assignment to resolve");
26670
27081
  if (isBundleContext(data)) return skipped3(this, "bundle context \u2014 no assignment to resolve");
26671
27082
  if (!data?.assignmentDir) return skipped3(this, "context has no assignmentDir");
26672
- const assignmentMd = resolve62(data.assignmentDir, "assignment.md");
27083
+ const assignmentMd = resolve63(data.assignmentDir, "assignment.md");
26673
27084
  if (!await fileExists(assignmentMd)) {
26674
27085
  return {
26675
27086
  id: this.id,
@@ -26699,7 +27110,7 @@ var contextTerminal = {
26699
27110
  if (isStandaloneSession(data)) return skipped3(this, "standalone session context \u2014 no assignment to check");
26700
27111
  if (isBundleContext(data)) return skipped3(this, "bundle context \u2014 no assignment to check");
26701
27112
  if (!data?.assignmentDir) return skipped3(this, "context has no assignmentDir");
26702
- const assignmentMd = resolve62(data.assignmentDir, "assignment.md");
27113
+ const assignmentMd = resolve63(data.assignmentDir, "assignment.md");
26703
27114
  if (!await fileExists(assignmentMd)) return skipped3(this, "assignment file missing");
26704
27115
  try {
26705
27116
  const content = await readFile39(assignmentMd, "utf-8");
@@ -26849,30 +27260,30 @@ var agentChecks = [agentsResolvable];
26849
27260
  init_config2();
26850
27261
  import { spawnSync as spawnSync9 } from "child_process";
26851
27262
  import { readFile as readFile40 } from "fs/promises";
26852
- import { resolve as resolve63 } from "path";
27263
+ import { resolve as resolve64 } from "path";
26853
27264
  init_paths();
26854
27265
  init_fs();
26855
27266
  var CATEGORY9 = "terminal";
26856
27267
  async function readRawTerminalKey() {
26857
- const configPath = resolve63(syntaurRoot(), "config.md");
27268
+ const configPath = resolve64(syntaurRoot(), "config.md");
26858
27269
  if (!await fileExists(configPath)) return null;
26859
27270
  const content = await readFile40(configPath, "utf-8");
26860
27271
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
26861
27272
  if (!fmMatch) return null;
26862
27273
  const line = fmMatch[1].split("\n").find((l) => /^terminal:\s*/.test(l));
26863
27274
  if (!line) return null;
26864
- const raw = line.replace(/^terminal:\s*/, "").trim();
26865
- if (raw.length === 0) return null;
26866
- const unquoted = /^"(.*)"$|^'(.*)'$/.exec(raw);
26867
- return unquoted ? unquoted[1] ?? unquoted[2] : raw;
27275
+ const raw2 = line.replace(/^terminal:\s*/, "").trim();
27276
+ if (raw2.length === 0) return null;
27277
+ const unquoted = /^"(.*)"$|^'(.*)'$/.exec(raw2);
27278
+ return unquoted ? unquoted[1] ?? unquoted[2] : raw2;
26868
27279
  }
26869
27280
  var terminalValueValid = {
26870
27281
  id: "terminal.value-valid",
26871
27282
  category: CATEGORY9,
26872
27283
  title: "Configured terminal value is recognized",
26873
27284
  async run(ctx) {
26874
- const raw = await readRawTerminalKey();
26875
- if (raw === null) {
27285
+ const raw2 = await readRawTerminalKey();
27286
+ if (raw2 === null) {
26876
27287
  return {
26877
27288
  id: this.id,
26878
27289
  category: this.category,
@@ -26882,13 +27293,13 @@ var terminalValueValid = {
26882
27293
  autoFixable: false
26883
27294
  };
26884
27295
  }
26885
- if (!TERMINAL_CHOICES.includes(raw)) {
27296
+ if (!TERMINAL_CHOICES.includes(raw2)) {
26886
27297
  return {
26887
27298
  id: this.id,
26888
27299
  category: this.category,
26889
27300
  title: this.title,
26890
27301
  status: "warn",
26891
- detail: `unknown terminal "${raw}" in ~/.syntaur/config.md`,
27302
+ detail: `unknown terminal "${raw2}" in ~/.syntaur/config.md`,
26892
27303
  remediation: {
26893
27304
  kind: "manual",
26894
27305
  suggestion: `Set \`terminal:\` in ~/.syntaur/config.md to one of: ${TERMINAL_CHOICES.join(", ")}`,
@@ -26902,7 +27313,7 @@ var terminalValueValid = {
26902
27313
  category: this.category,
26903
27314
  title: this.title,
26904
27315
  status: "pass",
26905
- detail: `terminal: ${raw}`,
27316
+ detail: `terminal: ${raw2}`,
26906
27317
  autoFixable: false
26907
27318
  };
26908
27319
  }
@@ -27006,13 +27417,13 @@ var terminalChecks = [
27006
27417
 
27007
27418
  // src/utils/doctor/checks/skills.ts
27008
27419
  init_fs();
27009
- import { resolve as resolve64, join as join11 } from "path";
27010
- import { readdir as readdir22, readFile as readFile41, lstat as lstat4 } from "fs/promises";
27420
+ import { resolve as resolve65, join as join11 } from "path";
27421
+ import { readdir as readdir23, readFile as readFile41, lstat as lstat4 } from "fs/promises";
27011
27422
  import { homedir as homedir11 } from "os";
27012
27423
  var CATEGORY10 = "skills";
27013
27424
  var skillTargets = [
27014
- { agent: "claude", dir: resolve64(homedir11(), ".claude", "skills"), label: "~/.claude/skills" },
27015
- { agent: "codex", dir: resolve64(homedir11(), ".codex", "skills"), label: "~/.codex/skills" }
27425
+ { agent: "claude", dir: resolve65(homedir11(), ".claude", "skills"), label: "~/.claude/skills" },
27426
+ { agent: "codex", dir: resolve65(homedir11(), ".codex", "skills"), label: "~/.codex/skills" }
27016
27427
  ];
27017
27428
  var skillsDedupCheck = {
27018
27429
  id: "skills.dedup",
@@ -27027,7 +27438,7 @@ var skillsDedupCheck = {
27027
27438
  const present = [];
27028
27439
  let entries;
27029
27440
  try {
27030
- entries = await readdir22(dir, { withFileTypes: true });
27441
+ entries = await readdir23(dir, { withFileTypes: true });
27031
27442
  } catch {
27032
27443
  continue;
27033
27444
  }
@@ -27086,7 +27497,7 @@ var skillsChecks = [skillsDedupCheck];
27086
27497
 
27087
27498
  // src/utils/doctor/checks/cross-agent.ts
27088
27499
  init_fs();
27089
- import { join as join12, resolve as resolve65 } from "path";
27500
+ import { join as join12, resolve as resolve66 } from "path";
27090
27501
  var CATEGORY11 = "cross-agent";
27091
27502
  async function countSyntaurSkills(dir) {
27092
27503
  if (!await fileExists(dir)) return 0;
@@ -27125,7 +27536,7 @@ var crossAgentSkillsCheck = {
27125
27536
  }
27126
27537
  if (recorded && t.instructions) {
27127
27538
  for (const f of t.instructions.files) {
27128
- const p = resolve65(ctx.cwd, f.path);
27539
+ const p = resolve66(ctx.cwd, f.path);
27129
27540
  if (!await fileExists(p)) {
27130
27541
  problems.push(`${t.displayName}: missing protocol file ${f.path} in cwd`);
27131
27542
  affected.push(p);
@@ -27174,8 +27585,8 @@ var crossAgentChecks = [crossAgentSkillsCheck];
27174
27585
  // src/utils/doctor/checks/bundles.ts
27175
27586
  init_fs();
27176
27587
  init_paths();
27177
- import { resolve as resolve66 } from "path";
27178
- import { readdir as readdir23 } from "fs/promises";
27588
+ import { resolve as resolve67 } from "path";
27589
+ import { readdir as readdir24 } from "fs/promises";
27179
27590
  import { spawnSync as spawnSync10 } from "child_process";
27180
27591
  init_parser2();
27181
27592
  var CATEGORY12 = "bundles";
@@ -27183,7 +27594,7 @@ async function listScopes(ctx) {
27183
27594
  const out = [];
27184
27595
  const td = todosDir();
27185
27596
  if (await fileExists(td)) {
27186
- const entries = await readdir23(td).catch(() => []);
27597
+ const entries = await readdir24(td).catch(() => []);
27187
27598
  for (const f of entries) {
27188
27599
  if (typeof f !== "string") continue;
27189
27600
  if (!f.endsWith(".md") || f.endsWith("-log.md")) continue;
@@ -27199,12 +27610,12 @@ async function listScopes(ctx) {
27199
27610
  }
27200
27611
  }
27201
27612
  if (await fileExists(ctx.config.defaultProjectDir)) {
27202
- const projectEntries = await readdir23(ctx.config.defaultProjectDir, { withFileTypes: true }).catch(() => []);
27613
+ const projectEntries = await readdir24(ctx.config.defaultProjectDir, { withFileTypes: true }).catch(() => []);
27203
27614
  for (const e of projectEntries) {
27204
27615
  if (!e.isDirectory()) continue;
27205
27616
  const slug = e.name;
27206
27617
  if (typeof slug !== "string" || slug.startsWith(".")) continue;
27207
- const projectMd = resolve66(ctx.config.defaultProjectDir, slug, "project.md");
27618
+ const projectMd = resolve67(ctx.config.defaultProjectDir, slug, "project.md");
27208
27619
  if (!await fileExists(projectMd)) continue;
27209
27620
  out.push({
27210
27621
  scopeLabel: `project:${slug}`,
@@ -27493,14 +27904,14 @@ async function finalize(checks) {
27493
27904
  async function readVersion() {
27494
27905
  try {
27495
27906
  const here = fileURLToPath11(import.meta.url);
27496
- let dir = dirname19(here);
27907
+ let dir = dirname20(here);
27497
27908
  for (let i = 0; i < 6; i++) {
27498
27909
  try {
27499
- const raw = await readFile42(join13(dir, "package.json"), "utf-8");
27500
- const parsed = JSON.parse(raw);
27910
+ const raw2 = await readFile42(join13(dir, "package.json"), "utf-8");
27911
+ const parsed = JSON.parse(raw2);
27501
27912
  return typeof parsed.version === "string" ? parsed.version : null;
27502
27913
  } catch {
27503
- dir = dirname19(dir);
27914
+ dir = dirname20(dir);
27504
27915
  }
27505
27916
  }
27506
27917
  return null;
@@ -27593,7 +28004,7 @@ var REQUIRED_WORKSPACE_FIELDS = [
27593
28004
  ];
27594
28005
  var ISO_DATE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;
27595
28006
  async function validateAssignmentFile(inputPath, cwd = process.cwd()) {
27596
- const absolute = isAbsolute10(inputPath) ? inputPath : resolve67(cwd, inputPath);
28007
+ const absolute = isAbsolute10(inputPath) ? inputPath : resolve68(cwd, inputPath);
27597
28008
  const errors = [];
27598
28009
  const warnings = [];
27599
28010
  if (!await fileExists(absolute)) {
@@ -27930,7 +28341,7 @@ init_uuid();
27930
28341
  init_timestamp();
27931
28342
  init_assignment_resolver();
27932
28343
  init_templates();
27933
- import { resolve as resolve68 } from "path";
28344
+ import { resolve as resolve69 } from "path";
27934
28345
  import { readFile as readFile44 } from "fs/promises";
27935
28346
  function shortId() {
27936
28347
  return generateId().split("-")[0];
@@ -27961,7 +28372,7 @@ async function commentCommand(target, text, options = {}) {
27961
28372
  if (!isValidSlug(target)) {
27962
28373
  throw new Error(`Invalid assignment slug "${target}".`);
27963
28374
  }
27964
- assignmentDir = resolve68(baseDir, options.project, "assignments", target);
28375
+ assignmentDir = resolve69(baseDir, options.project, "assignments", target);
27965
28376
  assignmentRef = target;
27966
28377
  } else {
27967
28378
  const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), target);
@@ -27971,7 +28382,7 @@ async function commentCommand(target, text, options = {}) {
27971
28382
  assignmentDir = resolved.assignmentDir;
27972
28383
  assignmentRef = resolved.standalone ? resolved.id : resolved.assignmentSlug;
27973
28384
  }
27974
- const commentsPath = resolve68(assignmentDir, "comments.md");
28385
+ const commentsPath = resolve69(assignmentDir, "comments.md");
27975
28386
  const timestamp = nowTimestamp();
27976
28387
  const author = options.author ?? process.env.USER ?? "unknown";
27977
28388
  let currentContent;
@@ -28011,8 +28422,8 @@ ${entry}`;
28011
28422
  }
28012
28423
 
28013
28424
  // src/commands/capture.ts
28014
- import { resolve as resolve72, relative as relative4, dirname as dirname20 } from "path";
28015
- import { copyFile as copyFile3, mkdir as mkdir9, realpath as realpath2, rm as rm12, stat as stat8, writeFile as writeFile14 } from "fs/promises";
28425
+ import { resolve as resolve73, relative as relative4, dirname as dirname21 } from "path";
28426
+ import { copyFile as copyFile3, mkdir as mkdir10, realpath as realpath2, rm as rm13, stat as stat9, writeFile as writeFile15 } from "fs/promises";
28016
28427
  import { existsSync as existsSync6 } from "fs";
28017
28428
 
28018
28429
  // src/utils/assignment-target.ts
@@ -28022,7 +28433,7 @@ init_config2();
28022
28433
  init_slug();
28023
28434
  init_assignment_resolver();
28024
28435
  init_parser();
28025
- import { resolve as resolve69 } from "path";
28436
+ import { resolve as resolve70 } from "path";
28026
28437
  import { readFile as readFile45 } from "fs/promises";
28027
28438
  var AssignmentTargetError = class extends Error {
28028
28439
  };
@@ -28035,7 +28446,7 @@ function classifyContext(ctx) {
28035
28446
  return "empty";
28036
28447
  }
28037
28448
  async function readAssignmentFrontmatterId(assignmentDir) {
28038
- const path = resolve69(assignmentDir, "assignment.md");
28449
+ const path = resolve70(assignmentDir, "assignment.md");
28039
28450
  if (!await fileExists(path)) return null;
28040
28451
  try {
28041
28452
  const content = await readFile45(path, "utf-8");
@@ -28046,11 +28457,11 @@ async function readAssignmentFrontmatterId(assignmentDir) {
28046
28457
  }
28047
28458
  }
28048
28459
  async function readContextJson(cwd) {
28049
- const path = resolve69(cwd, ".syntaur", "context.json");
28460
+ const path = resolve70(cwd, ".syntaur", "context.json");
28050
28461
  if (!await fileExists(path)) return null;
28051
28462
  try {
28052
- const raw = await readFile45(path, "utf-8");
28053
- return JSON.parse(raw);
28463
+ const raw2 = await readFile45(path, "utf-8");
28464
+ return JSON.parse(raw2);
28054
28465
  } catch {
28055
28466
  return null;
28056
28467
  }
@@ -28070,15 +28481,15 @@ async function resolveAssignmentTarget(input4, opts = {}) {
28070
28481
  if (!isValidSlug(input4)) {
28071
28482
  throw new AssignmentTargetError(`Invalid assignment slug "${input4}".`);
28072
28483
  }
28073
- const projectDir = resolve69(baseDir, opts.project);
28074
- const projectMdPath = resolve69(projectDir, "project.md");
28484
+ const projectDir = resolve70(baseDir, opts.project);
28485
+ const projectMdPath = resolve70(projectDir, "project.md");
28075
28486
  if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
28076
28487
  throw new AssignmentTargetError(
28077
28488
  `Project "${opts.project}" not found at ${projectDir}.`
28078
28489
  );
28079
28490
  }
28080
- const assignmentDir = resolve69(projectDir, "assignments", input4);
28081
- const assignmentMdPath2 = resolve69(assignmentDir, "assignment.md");
28491
+ const assignmentDir = resolve70(projectDir, "assignments", input4);
28492
+ const assignmentMdPath2 = resolve70(assignmentDir, "assignment.md");
28082
28493
  if (!await fileExists(assignmentMdPath2)) {
28083
28494
  throw new AssignmentTargetError(
28084
28495
  `Assignment "${input4}" not found in project "${opts.project}".`
@@ -28117,7 +28528,7 @@ async function resolveAssignmentTarget(input4, opts = {}) {
28117
28528
  }
28118
28529
  if (ctx.assignmentDir) {
28119
28530
  const dir = expandHome(ctx.assignmentDir);
28120
- const assignmentMdPath2 = resolve69(dir, "assignment.md");
28531
+ const assignmentMdPath2 = resolve70(dir, "assignment.md");
28121
28532
  if (!await fileExists(assignmentMdPath2)) {
28122
28533
  throw new AssignmentTargetError(
28123
28534
  `.syntaur/context.json points to a missing assignment dir: ${dir}.`
@@ -28146,8 +28557,8 @@ async function resolveAssignmentTarget(input4, opts = {}) {
28146
28557
  `.syntaur/context.json contains invalid slugs: project="${ctx.projectSlug}" assignment="${ctx.assignmentSlug}".`
28147
28558
  );
28148
28559
  }
28149
- const assignmentDir = resolve69(baseDir, ctx.projectSlug, "assignments", ctx.assignmentSlug);
28150
- const assignmentMdPath2 = resolve69(assignmentDir, "assignment.md");
28560
+ const assignmentDir = resolve70(baseDir, ctx.projectSlug, "assignments", ctx.assignmentSlug);
28561
+ const assignmentMdPath2 = resolve70(assignmentDir, "assignment.md");
28151
28562
  if (!await fileExists(assignmentMdPath2)) {
28152
28563
  throw new AssignmentTargetError(
28153
28564
  `.syntaur/context.json points to a missing assignment: ${assignmentDir}.`
@@ -28170,45 +28581,11 @@ async function resolveAssignmentTarget(input4, opts = {}) {
28170
28581
 
28171
28582
  // src/commands/capture.ts
28172
28583
  init_paths();
28173
-
28174
- // src/utils/proof-artifact-id.ts
28175
- import { randomBytes as randomBytes3 } from "crypto";
28176
- function generateArtifactId() {
28177
- const ts = Date.now().toString(36);
28178
- const rand = randomBytes3(2).toString("hex");
28179
- return `${ts}-${rand}`;
28180
- }
28181
- var EXTENSIONS = {
28182
- screenshot: "png",
28183
- video: "mp4",
28184
- asciinema: "cast",
28185
- http: "txt",
28186
- text: "txt"
28187
- };
28188
- function extensionForKind(kind) {
28189
- const ext = EXTENSIONS[kind];
28190
- if (!ext) {
28191
- throw new Error(`Unknown artifact kind: ${kind}`);
28192
- }
28193
- return ext;
28194
- }
28195
- var ARTIFACT_KINDS = [
28196
- "screenshot",
28197
- "video",
28198
- "asciinema",
28199
- "http",
28200
- "text"
28201
- ];
28202
- function isArtifactKind(value) {
28203
- return typeof value === "string" && ARTIFACT_KINDS.includes(value);
28204
- }
28205
-
28206
- // src/commands/capture.ts
28207
28584
  init_fs();
28208
28585
 
28209
28586
  // src/utils/screencapture.ts
28210
28587
  import { spawn as spawn7 } from "child_process";
28211
- import { mkdtemp as mkdtemp2, rm as rm8, stat as stat6 } from "fs/promises";
28588
+ import { mkdtemp as mkdtemp2, rm as rm9, stat as stat7 } from "fs/promises";
28212
28589
  import { tmpdir as tmpdir3 } from "os";
28213
28590
  import { join as join14 } from "path";
28214
28591
  function argsFor(mode, pngPath) {
@@ -28246,7 +28623,7 @@ async function captureScreenshot(mode) {
28246
28623
  const tmpDir = await mkdtemp2(join14(tmpdir3(), "syntaur-screenshot-"));
28247
28624
  const pngPath = join14(tmpDir, "shot.png");
28248
28625
  const cleanup = async () => {
28249
- await rm8(tmpDir, { recursive: true, force: true }).catch(() => {
28626
+ await rm9(tmpDir, { recursive: true, force: true }).catch(() => {
28250
28627
  });
28251
28628
  };
28252
28629
  try {
@@ -28266,7 +28643,7 @@ async function captureScreenshot(mode) {
28266
28643
  }
28267
28644
  let size = 0;
28268
28645
  try {
28269
- size = (await stat6(pngPath)).size;
28646
+ size = (await stat7(pngPath)).size;
28270
28647
  } catch {
28271
28648
  throw new Error("screencapture exited 0 but produced no image.");
28272
28649
  }
@@ -28282,7 +28659,7 @@ async function captureScreenshot(mode) {
28282
28659
 
28283
28660
  // src/utils/asciinema.ts
28284
28661
  import { spawn as spawn8 } from "child_process";
28285
- import { mkdtemp as mkdtemp3, readFile as readFile46, rm as rm9 } from "fs/promises";
28662
+ import { mkdtemp as mkdtemp3, readFile as readFile46, rm as rm10 } from "fs/promises";
28286
28663
  import { tmpdir as tmpdir4 } from "os";
28287
28664
  import { join as join15 } from "path";
28288
28665
  var SAFE_RE = /^[A-Za-z0-9_@%+=:,./-]+$/;
@@ -28297,10 +28674,10 @@ function joinCommandForShell(argv) {
28297
28674
  function hasRecordedData(text) {
28298
28675
  const lines = text.split("\n");
28299
28676
  for (let i = 1; i < lines.length; i++) {
28300
- const raw = lines[i];
28301
- if (raw === "") continue;
28302
- if (raw.startsWith("#")) continue;
28303
- if (/^\s*\[\s*[\d.eE+-]+\s*,\s*"([oi])"/.test(raw)) return true;
28677
+ const raw2 = lines[i];
28678
+ if (raw2 === "") continue;
28679
+ if (raw2.startsWith("#")) continue;
28680
+ if (/^\s*\[\s*[\d.eE+-]+\s*,\s*"([oi])"/.test(raw2)) return true;
28304
28681
  }
28305
28682
  return false;
28306
28683
  }
@@ -28324,7 +28701,7 @@ async function captureAsciinema(opts) {
28324
28701
  const tmpDir = await mkdtemp3(join15(tmpdir4(), "syntaur-asciinema-"));
28325
28702
  const castPath = join15(tmpDir, "session.cast");
28326
28703
  const cleanup = async () => {
28327
- await rm9(tmpDir, { recursive: true, force: true }).catch(() => {
28704
+ await rm10(tmpDir, { recursive: true, force: true }).catch(() => {
28328
28705
  });
28329
28706
  };
28330
28707
  const noopSigint = () => {
@@ -28373,36 +28750,36 @@ async function captureAsciinema(opts) {
28373
28750
  // src/utils/recording.ts
28374
28751
  init_paths();
28375
28752
  import { spawn as spawn9 } from "child_process";
28376
- import { mkdir as mkdir8, mkdtemp as mkdtemp4, open as open3, readFile as readFile47, rm as rm10, stat as stat7, unlink as unlink9, writeFile as writeFile13 } from "fs/promises";
28753
+ import { mkdir as mkdir9, mkdtemp as mkdtemp4, open as open3, readFile as readFile47, rm as rm11, stat as stat8, unlink as unlink10, writeFile as writeFile14 } from "fs/promises";
28377
28754
  import { tmpdir as tmpdir5 } from "os";
28378
- import { join as join16, resolve as resolve70 } from "path";
28755
+ import { join as join16, resolve as resolve71 } from "path";
28379
28756
  import { setTimeout as sleep } from "timers/promises";
28380
28757
  function sigintPollIntervalMs() {
28381
- const raw = process.env.SYNTAUR_RECORDING_POLL_INTERVAL_MS;
28382
- if (raw === void 0) return 500;
28383
- const parsed = Number(raw);
28758
+ const raw2 = process.env.SYNTAUR_RECORDING_POLL_INTERVAL_MS;
28759
+ if (raw2 === void 0) return 500;
28760
+ const parsed = Number(raw2);
28384
28761
  return Number.isFinite(parsed) && parsed >= 0 ? parsed : 500;
28385
28762
  }
28386
28763
  function sigintPollCount() {
28387
- const raw = process.env.SYNTAUR_RECORDING_POLL_COUNT;
28388
- if (raw === void 0) return 20;
28389
- const parsed = Number(raw);
28764
+ const raw2 = process.env.SYNTAUR_RECORDING_POLL_COUNT;
28765
+ if (raw2 === void 0) return 20;
28766
+ const parsed = Number(raw2);
28390
28767
  return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : 20;
28391
28768
  }
28392
28769
  function sigtermWaitMs() {
28393
- const raw = process.env.SYNTAUR_RECORDING_SIGTERM_WAIT_MS;
28394
- if (raw === void 0) return 1e3;
28395
- const parsed = Number(raw);
28770
+ const raw2 = process.env.SYNTAUR_RECORDING_SIGTERM_WAIT_MS;
28771
+ if (raw2 === void 0) return 1e3;
28772
+ const parsed = Number(raw2);
28396
28773
  return Number.isFinite(parsed) && parsed >= 0 ? parsed : 1e3;
28397
28774
  }
28398
28775
  function pidfilePath() {
28399
- return resolve70(syntaurRoot(), "recording.pid");
28776
+ return resolve71(syntaurRoot(), "recording.pid");
28400
28777
  }
28401
28778
  function logPath2() {
28402
- return resolve70(syntaurRoot(), "recording.log");
28779
+ return resolve71(syntaurRoot(), "recording.log");
28403
28780
  }
28404
28781
  function sidecarPath() {
28405
- return resolve70(syntaurRoot(), "recording.json");
28782
+ return resolve71(syntaurRoot(), "recording.json");
28406
28783
  }
28407
28784
  function ffmpegArgs(device, fps, mp4Path) {
28408
28785
  return [
@@ -28427,9 +28804,9 @@ function ffmpegArgs(device, fps, mp4Path) {
28427
28804
  ];
28428
28805
  }
28429
28806
  function defaultWarmupMs() {
28430
- const raw = process.env.SYNTAUR_RECORDING_WARMUP_MS;
28431
- if (raw === void 0) return 1500;
28432
- const parsed = Number(raw);
28807
+ const raw2 = process.env.SYNTAUR_RECORDING_WARMUP_MS;
28808
+ if (raw2 === void 0) return 1500;
28809
+ const parsed = Number(raw2);
28433
28810
  return Number.isFinite(parsed) && parsed >= 0 ? parsed : 1500;
28434
28811
  }
28435
28812
  var STARTING_SENTINEL_PREFIX = "STARTING:";
@@ -28456,7 +28833,7 @@ async function acquirePidfile(pidfile) {
28456
28833
  `Recording startup already in progress (parent PID ${parentPid}). Wait a moment and retry, or kill ${parentPid} and remove ${pidfile} manually if it's truly stuck.`
28457
28834
  );
28458
28835
  }
28459
- await unlink9(pidfile).catch(() => {
28836
+ await unlink10(pidfile).catch(() => {
28460
28837
  });
28461
28838
  continue;
28462
28839
  }
@@ -28472,7 +28849,7 @@ async function acquirePidfile(pidfile) {
28472
28849
  `Recording already in progress (PID ${existingPid}). Stop with: syntaur capture --kind video --stop`
28473
28850
  );
28474
28851
  }
28475
- await unlink9(pidfile).catch(() => {
28852
+ await unlink10(pidfile).catch(() => {
28476
28853
  });
28477
28854
  continue;
28478
28855
  }
@@ -28489,7 +28866,7 @@ async function startRecording(input4) {
28489
28866
  );
28490
28867
  }
28491
28868
  const root = syntaurRoot();
28492
- await mkdir8(root, { recursive: true });
28869
+ await mkdir9(root, { recursive: true });
28493
28870
  const pidfile = pidfilePath();
28494
28871
  const log = logPath2();
28495
28872
  const sidecar = sidecarPath();
@@ -28544,7 +28921,7 @@ async function startRecording(input4) {
28544
28921
  const pid = await pidReady;
28545
28922
  acquiredPid = pid;
28546
28923
  child.unref();
28547
- await writeFile13(pidfile, String(pid));
28924
+ await writeFile14(pidfile, String(pid));
28548
28925
  await logHandle.close();
28549
28926
  logHandle = null;
28550
28927
  if (warmupMs > 0) await sleep(warmupMs);
@@ -28572,7 +28949,7 @@ ${tail}`
28572
28949
  device: input4.device,
28573
28950
  fps: input4.fps
28574
28951
  };
28575
- await writeFile13(sidecar, JSON.stringify(sidecarData, null, 2));
28952
+ await writeFile14(sidecar, JSON.stringify(sidecarData, null, 2));
28576
28953
  return {
28577
28954
  pid,
28578
28955
  logPath: log,
@@ -28596,9 +28973,9 @@ ${tail}`
28596
28973
  }
28597
28974
  if (logHandle) await logHandle.close().catch(() => {
28598
28975
  });
28599
- if (tmpDir) await rm10(tmpDir, { recursive: true, force: true }).catch(() => {
28976
+ if (tmpDir) await rm11(tmpDir, { recursive: true, force: true }).catch(() => {
28600
28977
  });
28601
- await unlink9(pidfile).catch(() => {
28978
+ await unlink10(pidfile).catch(() => {
28602
28979
  });
28603
28980
  throw err2;
28604
28981
  }
@@ -28661,19 +29038,19 @@ async function stopRecording() {
28661
29038
  if (alive) {
28662
29039
  throw new Error(`ffmpeg (PID ${pid}) refused to die after SIGKILL`);
28663
29040
  }
28664
- const st = await stat7(sidecarData.mp4Path).catch(() => null);
29041
+ const st = await stat8(sidecarData.mp4Path).catch(() => null);
28665
29042
  if (st === null || st.size === 0) {
28666
- await unlink9(pidfile).catch(() => {
29043
+ await unlink10(pidfile).catch(() => {
28667
29044
  });
28668
- await unlink9(sidecar).catch(() => {
29045
+ await unlink10(sidecar).catch(() => {
28669
29046
  });
28670
29047
  throw new Error(
28671
29048
  `ffmpeg produced no output at ${sidecarData.mp4Path}. Check ${sidecarData.logPath} for errors.`
28672
29049
  );
28673
29050
  }
28674
- await unlink9(pidfile).catch(() => {
29051
+ await unlink10(pidfile).catch(() => {
28675
29052
  });
28676
- await unlink9(sidecar).catch(() => {
29053
+ await unlink10(sidecar).catch(() => {
28677
29054
  });
28678
29055
  return { mp4Path: sidecarData.mp4Path, sidecar: sidecarData };
28679
29056
  }
@@ -28681,7 +29058,7 @@ async function stopRecording() {
28681
29058
  // src/db/proof-db.ts
28682
29059
  init_paths();
28683
29060
  import Database5 from "better-sqlite3";
28684
- import { resolve as resolve71 } from "path";
29061
+ import { resolve as resolve72 } from "path";
28685
29062
  var db4 = null;
28686
29063
  var PROOF_SCHEMA_VERSION = "1";
28687
29064
  var SCHEMA_SQL4 = `
@@ -28701,7 +29078,7 @@ CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT);
28701
29078
  `;
28702
29079
  function initProofDb(dbPath) {
28703
29080
  if (db4) return db4;
28704
- const finalPath = dbPath ?? resolve71(syntaurRoot(), "syntaur.db");
29081
+ const finalPath = dbPath ?? resolve72(syntaurRoot(), "syntaur.db");
28705
29082
  db4 = new Database5(finalPath);
28706
29083
  db4.pragma("journal_mode = WAL");
28707
29084
  db4.exec(SCHEMA_SQL4);
@@ -28749,7 +29126,7 @@ function listArtifactsByAssignment(assignmentId) {
28749
29126
 
28750
29127
  // src/utils/transcribers/elevenlabs.ts
28751
29128
  import { spawn as spawn10 } from "child_process";
28752
- import { mkdtemp as mkdtemp5, readFile as readFile48, rm as rm11 } from "fs/promises";
29129
+ import { mkdtemp as mkdtemp5, readFile as readFile48, rm as rm12 } from "fs/promises";
28753
29130
  import { tmpdir as tmpdir6 } from "os";
28754
29131
  import { join as join17 } from "path";
28755
29132
  var SCRIBE_URL = "https://api.elevenlabs.io/v1/speech-to-text";
@@ -28847,7 +29224,7 @@ var elevenLabsScribe = {
28847
29224
  await extractAudio(videoAbsPath, wav);
28848
29225
  return await callScribe(wav, apiKey, opts);
28849
29226
  } finally {
28850
- await rm11(tmp, { recursive: true, force: true }).catch(() => {
29227
+ await rm12(tmp, { recursive: true, force: true }).catch(() => {
28851
29228
  });
28852
29229
  }
28853
29230
  }
@@ -28897,10 +29274,10 @@ function groupIntoPhrases(words, silenceThresholdSec = 0.5) {
28897
29274
  const parts = [];
28898
29275
  for (const w of currentWords) {
28899
29276
  const t = w.type ?? "word";
28900
- let raw = (w.text ?? "").trim();
28901
- if (!raw) continue;
28902
- if (t === "audio_event" && !raw.startsWith("(")) raw = `(${raw})`;
28903
- parts.push(raw);
29277
+ let raw2 = (w.text ?? "").trim();
29278
+ if (!raw2) continue;
29279
+ if (t === "audio_event" && !raw2.startsWith("(")) raw2 = `(${raw2})`;
29280
+ parts.push(raw2);
28904
29281
  }
28905
29282
  if (parts.length === 0) {
28906
29283
  currentWords = [];
@@ -28968,17 +29345,17 @@ function renderMarkdown(phrases) {
28968
29345
 
28969
29346
  // src/commands/capture.ts
28970
29347
  var MAX_ID_RETRIES = 5;
28971
- function normalizeCriterionIndex(raw) {
28972
- if (raw === void 0 || raw === null || raw === "") return null;
28973
- if (typeof raw === "number") {
28974
- if (!Number.isInteger(raw) || raw < 0) {
28975
- throw new Error(`--criterion must be a non-negative integer (got "${raw}")`);
29348
+ function normalizeCriterionIndex(raw2) {
29349
+ if (raw2 === void 0 || raw2 === null || raw2 === "") return null;
29350
+ if (typeof raw2 === "number") {
29351
+ if (!Number.isInteger(raw2) || raw2 < 0) {
29352
+ throw new Error(`--criterion must be a non-negative integer (got "${raw2}")`);
28976
29353
  }
28977
- return raw;
29354
+ return raw2;
28978
29355
  }
28979
- const s = String(raw).trim();
29356
+ const s = String(raw2).trim();
28980
29357
  if (!/^\d+$/.test(s)) {
28981
- throw new Error(`--criterion must be a non-negative integer (got "${raw}")`);
29358
+ throw new Error(`--criterion must be a non-negative integer (got "${raw2}")`);
28982
29359
  }
28983
29360
  return parseInt(s, 10);
28984
29361
  }
@@ -29116,9 +29493,9 @@ async function captureCommand(target, options = {}) {
29116
29493
  criterionIndex = sidecar.criterionIndex;
29117
29494
  stopNote = sidecar.note;
29118
29495
  resolvedSource = mp4Path;
29119
- const mp4TmpDir = dirname20(mp4Path);
29496
+ const mp4TmpDir = dirname21(mp4Path);
29120
29497
  shelloutCleanup = async () => {
29121
- await rm12(mp4TmpDir, { recursive: true, force: true }).catch(() => {
29498
+ await rm13(mp4TmpDir, { recursive: true, force: true }).catch(() => {
29122
29499
  });
29123
29500
  };
29124
29501
  } else {
@@ -29129,7 +29506,7 @@ async function captureCommand(target, options = {}) {
29129
29506
  });
29130
29507
  }
29131
29508
  if (options.file) {
29132
- const expanded = options.file.startsWith("~/") ? resolve72(process.env.HOME ?? "", options.file.slice(2)) : resolve72(options.file);
29509
+ const expanded = options.file.startsWith("~/") ? resolve73(process.env.HOME ?? "", options.file.slice(2)) : resolve73(options.file);
29133
29510
  if (!await fileExists(expanded)) {
29134
29511
  throw new Error(`--file does not exist: ${options.file}`);
29135
29512
  }
@@ -29141,7 +29518,7 @@ async function captureCommand(target, options = {}) {
29141
29518
  `--file is unreadable: ${options.file} (${e instanceof Error ? e.message : String(e)})`
29142
29519
  );
29143
29520
  }
29144
- const st = await stat8(real);
29521
+ const st = await stat9(real);
29145
29522
  if (!st.isFile()) {
29146
29523
  throw new Error(`--file is not a regular file: ${options.file}`);
29147
29524
  }
@@ -29170,8 +29547,8 @@ async function captureCommand(target, options = {}) {
29170
29547
  }
29171
29548
  initProofDb();
29172
29549
  const subdir = criterionIndex === null ? "untagged" : String(criterionIndex);
29173
- const destDir = resolve72(proofDir(resolved.assignmentDir), subdir);
29174
- if (resolvedSource) await mkdir9(destDir, { recursive: true });
29550
+ const destDir = resolve73(proofDir(resolved.assignmentDir), subdir);
29551
+ if (resolvedSource) await mkdir10(destDir, { recursive: true });
29175
29552
  const ext = resolvedSource ? extensionForKind(kind) : null;
29176
29553
  let id = null;
29177
29554
  let relativeFilePath = null;
@@ -29179,7 +29556,7 @@ async function captureCommand(target, options = {}) {
29179
29556
  let lastErr = null;
29180
29557
  for (let attempt = 0; attempt < MAX_ID_RETRIES; attempt += 1) {
29181
29558
  const candidate = generateArtifactId();
29182
- const candidateAbsPath = resolvedSource && ext ? resolve72(destDir, `${candidate}.${ext}`) : null;
29559
+ const candidateAbsPath = resolvedSource && ext ? resolve73(destDir, `${candidate}.${ext}`) : null;
29183
29560
  const candidateRel = candidateAbsPath ? relative4(resolved.assignmentDir, candidateAbsPath) : null;
29184
29561
  try {
29185
29562
  insertArtifact({
@@ -29223,7 +29600,7 @@ async function captureCommand(target, options = {}) {
29223
29600
  }
29224
29601
  }
29225
29602
  if (options.transcribe && kind === "video" && absPath && id) {
29226
- const sidecarPath2 = resolve72(destDir, `${id}.transcript.md`);
29603
+ const sidecarPath2 = resolve73(destDir, `${id}.transcript.md`);
29227
29604
  if (existsSync6(sidecarPath2)) {
29228
29605
  console.warn(
29229
29606
  `transcript: ${sidecarPath2} already exists, skipping (delete to re-transcribe)`
@@ -29232,7 +29609,7 @@ async function captureCommand(target, options = {}) {
29232
29609
  try {
29233
29610
  const json = await getTranscriber().transcribe(absPath);
29234
29611
  const md = renderMarkdown(groupIntoPhrases(json.words ?? []));
29235
- await writeFile14(sidecarPath2, md, "utf8");
29612
+ await writeFile15(sidecarPath2, md, "utf8");
29236
29613
  console.log(`transcript: ${sidecarPath2}`);
29237
29614
  } catch (err2) {
29238
29615
  if (err2 instanceof TranscribeFfmpegMissingError) {
@@ -29255,7 +29632,7 @@ async function captureCommand(target, options = {}) {
29255
29632
  const tagSuffix = criterionIndex === null ? "untagged" : `criterion ${criterionIndex}`;
29256
29633
  console.log(`Captured artifact ${id} (${kind}) for ${ref} \u2014 ${tagSuffix}.`);
29257
29634
  if (relativeFilePath) {
29258
- console.log(` file: ${resolve72(resolved.assignmentDir, relativeFilePath)}`);
29635
+ console.log(` file: ${resolve73(resolved.assignmentDir, relativeFilePath)}`);
29259
29636
  }
29260
29637
  } catch (err2) {
29261
29638
  if (options.stop && kind === "video" && shelloutCleanup && resolvedSource) {
@@ -29278,8 +29655,8 @@ async function captureCommand(target, options = {}) {
29278
29655
 
29279
29656
  // src/commands/proof.ts
29280
29657
  import { Command as Command6 } from "commander";
29281
- import { readFile as readFile49, writeFile as writeFile15, rename as rename9, stat as stat9 } from "fs/promises";
29282
- import { resolve as resolve73, relative as relative5, isAbsolute as isAbsolute11, dirname as dirname21 } from "path";
29658
+ import { readFile as readFile49, writeFile as writeFile16, rename as rename10, stat as stat10 } from "fs/promises";
29659
+ import { resolve as resolve74, relative as relative5, isAbsolute as isAbsolute11, dirname as dirname22 } from "path";
29283
29660
  import { randomBytes as randomBytes4 } from "crypto";
29284
29661
 
29285
29662
  // src/utils/acceptance-criteria-parse.ts
@@ -29519,7 +29896,7 @@ function renderProofHtml(params2, inlineFiles = /* @__PURE__ */ new Map(), trans
29519
29896
 
29520
29897
  // src/commands/proof.ts
29521
29898
  async function readAssignmentMeta(assignmentDir) {
29522
- const path = resolve73(assignmentDir, "assignment.md");
29899
+ const path = resolve74(assignmentDir, "assignment.md");
29523
29900
  if (!await fileExists(path)) {
29524
29901
  return { title: "", body: "" };
29525
29902
  }
@@ -29529,16 +29906,16 @@ async function readAssignmentMeta(assignmentDir) {
29529
29906
  if (fmMatch) {
29530
29907
  const titleLine = fmMatch[1].split("\n").find((l) => /^title:\s/i.test(l));
29531
29908
  if (titleLine) {
29532
- const raw = titleLine.replace(/^title:\s*/i, "").trim();
29533
- title = raw.replace(/^["']|["']$/g, "");
29909
+ const raw2 = titleLine.replace(/^title:\s*/i, "").trim();
29910
+ title = raw2.replace(/^["']|["']$/g, "");
29534
29911
  }
29535
29912
  }
29536
29913
  return { title, body: content };
29537
29914
  }
29538
29915
  async function atomicWrite(destPath, content) {
29539
29916
  const tmp = `${destPath}.${randomBytes4(4).toString("hex")}.tmp`;
29540
- await writeFile15(tmp, content, "utf-8");
29541
- await rename9(tmp, destPath);
29917
+ await writeFile16(tmp, content, "utf-8");
29918
+ await rename10(tmp, destPath);
29542
29919
  }
29543
29920
  function isWithin(root, target) {
29544
29921
  const rel = relative5(root, target);
@@ -29570,7 +29947,7 @@ async function loadInlineFiles(rows, assignmentDir) {
29570
29947
  for (const r of rows) {
29571
29948
  if (!r.file_path) continue;
29572
29949
  if (r.kind !== "http" && r.kind !== "text") continue;
29573
- const abs = resolve73(assignmentDir, r.file_path);
29950
+ const abs = resolve74(assignmentDir, r.file_path);
29574
29951
  if (!isWithin(proofRoot, abs)) {
29575
29952
  out.set(r.file_path, null);
29576
29953
  continue;
@@ -29579,7 +29956,7 @@ async function loadInlineFiles(rows, assignmentDir) {
29579
29956
  out.set(r.file_path, null);
29580
29957
  continue;
29581
29958
  }
29582
- const st = await stat9(abs);
29959
+ const st = await stat10(abs);
29583
29960
  if (st.size > INLINE_TEXT_LIMIT_BYTES) {
29584
29961
  out.set(r.file_path, null);
29585
29962
  continue;
@@ -29597,11 +29974,11 @@ async function loadTranscriptSidecars(rows, assignmentDir) {
29597
29974
  const proofRoot = proofDir(assignmentDir);
29598
29975
  for (const r of rows) {
29599
29976
  if (r.kind !== "video" || !r.file_path) continue;
29600
- const videoAbs = resolve73(assignmentDir, r.file_path);
29601
- const sidecar = resolve73(dirname21(videoAbs), `${r.id}.transcript.md`);
29977
+ const videoAbs = resolve74(assignmentDir, r.file_path);
29978
+ const sidecar = resolve74(dirname22(videoAbs), `${r.id}.transcript.md`);
29602
29979
  if (!isWithin(proofRoot, sidecar)) continue;
29603
29980
  if (!await fileExists(sidecar)) continue;
29604
- const st = await stat9(sidecar);
29981
+ const st = await stat10(sidecar);
29605
29982
  if (st.size > INLINE_TEXT_LIMIT_BYTES) continue;
29606
29983
  try {
29607
29984
  out.set(r.id, await readFile49(sidecar, "utf-8"));
@@ -29638,8 +30015,8 @@ async function proofBuildCommand(target, options = {}) {
29638
30015
  };
29639
30016
  const md = renderProofMarkdown(renderParams);
29640
30017
  const html = renderProofHtml(renderParams, inlineFiles, transcriptSidecars);
29641
- const mdPath = resolve73(resolved.assignmentDir, "proof.md");
29642
- const htmlPath = resolve73(resolved.assignmentDir, "proof.html");
30018
+ const mdPath = resolve74(resolved.assignmentDir, "proof.md");
30019
+ const htmlPath = resolve74(resolved.assignmentDir, "proof.html");
29643
30020
  await atomicWrite(mdPath, md);
29644
30021
  await atomicWrite(htmlPath, html);
29645
30022
  console.log(`Wrote ${htmlPath}`);
@@ -29675,12 +30052,12 @@ function parseDuration(input4, fallbackSeconds) {
29675
30052
  function parseMetadataFlags(values) {
29676
30053
  if (!values || values.length === 0) return void 0;
29677
30054
  const out = {};
29678
- for (const raw of values) {
29679
- const eq = raw.indexOf("=");
30055
+ for (const raw2 of values) {
30056
+ const eq = raw2.indexOf("=");
29680
30057
  if (eq < 0) {
29681
- throw new Error(`invalid -m flag "${raw}" \u2014 use key=value`);
30058
+ throw new Error(`invalid -m flag "${raw2}" \u2014 use key=value`);
29682
30059
  }
29683
- out[raw.slice(0, eq)] = raw.slice(eq + 1);
30060
+ out[raw2.slice(0, eq)] = raw2.slice(eq + 1);
29684
30061
  }
29685
30062
  return out;
29686
30063
  }
@@ -30149,41 +30526,41 @@ function parseCcusageSession(payload, nowIso6 = () => (/* @__PURE__ */ new Date(
30149
30526
  }
30150
30527
  const rows = [];
30151
30528
  let highWaterIso = null;
30152
- for (const raw of sessions) {
30153
- if (!raw || typeof raw !== "object") {
30529
+ for (const raw2 of sessions) {
30530
+ if (!raw2 || typeof raw2 !== "object") {
30154
30531
  warnings.push("skipped non-object session row");
30155
30532
  continue;
30156
30533
  }
30157
- const tool = typeof raw.agent === "string" ? raw.agent : null;
30158
- const period = typeof raw.period === "string" ? raw.period : null;
30534
+ const tool = typeof raw2.agent === "string" ? raw2.agent : null;
30535
+ const period = typeof raw2.period === "string" ? raw2.period : null;
30159
30536
  if (!tool || !period) {
30160
30537
  warnings.push("skipped session row missing agent or period");
30161
30538
  continue;
30162
30539
  }
30163
30540
  const sessionId = extractSessionId(tool, period);
30164
- const breakdowns = Array.isArray(raw.modelBreakdowns) ? raw.modelBreakdowns : [];
30541
+ const breakdowns = Array.isArray(raw2.modelBreakdowns) ? raw2.modelBreakdowns : [];
30165
30542
  const eventTs = normalizeLastActivity(
30166
- raw.metadata?.lastActivity,
30543
+ raw2.metadata?.lastActivity,
30167
30544
  nowIso6
30168
30545
  );
30169
30546
  if (eventTs && (!highWaterIso || eventTs > highWaterIso)) {
30170
30547
  highWaterIso = eventTs;
30171
30548
  }
30172
30549
  if (breakdowns.length === 0) {
30173
- const modelsUsed = Array.isArray(raw.modelsUsed) ? raw.modelsUsed : [];
30550
+ const modelsUsed = Array.isArray(raw2.modelsUsed) ? raw2.modelsUsed : [];
30174
30551
  const fallbackModel = typeof modelsUsed[0] === "string" ? modelsUsed[0] : "unknown";
30175
30552
  rows.push({
30176
30553
  sessionId,
30177
30554
  model: fallbackModel,
30178
30555
  tool,
30179
30556
  eventTs,
30180
- inputTokens: toInt(raw.inputTokens),
30181
- outputTokens: toInt(raw.outputTokens),
30182
- cacheCreationTokens: toInt(raw.cacheCreationTokens),
30183
- cacheReadTokens: toInt(raw.cacheReadTokens),
30184
- totalTokens: toInt(raw.totalTokens),
30185
- totalCost: toNumber(raw.totalCost),
30186
- rawJson: JSON.stringify(raw)
30557
+ inputTokens: toInt(raw2.inputTokens),
30558
+ outputTokens: toInt(raw2.outputTokens),
30559
+ cacheCreationTokens: toInt(raw2.cacheCreationTokens),
30560
+ cacheReadTokens: toInt(raw2.cacheReadTokens),
30561
+ totalTokens: toInt(raw2.totalTokens),
30562
+ totalCost: toNumber(raw2.totalCost),
30563
+ rawJson: JSON.stringify(raw2)
30187
30564
  });
30188
30565
  continue;
30189
30566
  }
@@ -30213,7 +30590,7 @@ function parseCcusageSession(payload, nowIso6 = () => (/* @__PURE__ */ new Date(
30213
30590
  cacheReadTokens,
30214
30591
  totalTokens,
30215
30592
  totalCost: toNumber(b.cost),
30216
- rawJson: JSON.stringify(raw)
30593
+ rawJson: JSON.stringify(raw2)
30217
30594
  });
30218
30595
  }
30219
30596
  }
@@ -30304,7 +30681,7 @@ async function runCcusage(opts = {}) {
30304
30681
  };
30305
30682
  }
30306
30683
  function runOnce(binary, args, env, timeoutMs, maxOutputBytes) {
30307
- return new Promise((resolve82) => {
30684
+ return new Promise((resolve83) => {
30308
30685
  const child = spawn11(binary, args, {
30309
30686
  env: env ?? process.env,
30310
30687
  stdio: ["ignore", "pipe", "pipe"]
@@ -30318,7 +30695,7 @@ function runOnce(binary, args, env, timeoutMs, maxOutputBytes) {
30318
30695
  if (settled) return;
30319
30696
  settled = true;
30320
30697
  clearTimeout(timer2);
30321
- resolve82(result);
30698
+ resolve83(result);
30322
30699
  };
30323
30700
  const timer2 = setTimeout(() => {
30324
30701
  timedOut = true;
@@ -30362,7 +30739,7 @@ function isoToCcusageDate(iso) {
30362
30739
 
30363
30740
  // src/usage/cwd-extractor.ts
30364
30741
  init_paths();
30365
- import { open as open4, readdir as readdir24, stat as stat10 } from "fs/promises";
30742
+ import { open as open4, readdir as readdir25, stat as stat11 } from "fs/promises";
30366
30743
  import { join as join18 } from "path";
30367
30744
  import { homedir as homedir12 } from "os";
30368
30745
  var SCAN_LINE_CAP = 50;
@@ -30371,8 +30748,8 @@ var TAIL_READ_BYTES_MAX = 64 * 1024;
30371
30748
  async function extractClaudeSessionMeta(jsonlPath) {
30372
30749
  const cwd = await derivePathFromTranscript(jsonlPath);
30373
30750
  if (!cwd) return null;
30374
- const basename6 = jsonlPath.split("/").pop() ?? "";
30375
- const sessionId = basename6.replace(/\.jsonl$/, "");
30751
+ const basename7 = jsonlPath.split("/").pop() ?? "";
30752
+ const sessionId = basename7.replace(/\.jsonl$/, "");
30376
30753
  if (!sessionId) return null;
30377
30754
  const startTs = await readFirstTimestamp(jsonlPath);
30378
30755
  const endTs = await readLastTimestamp(jsonlPath);
@@ -30465,8 +30842,8 @@ async function* walkClaudeProjects(opts = {}) {
30465
30842
  async function* walkCodexSessions(opts = {}) {
30466
30843
  const root = resolveCodexSessionsRoot(opts.root);
30467
30844
  for await (const filePath of walkJsonlRecursive(root)) {
30468
- const basename6 = filePath.split("/").pop() ?? "";
30469
- if (!basename6.endsWith(".jsonl")) continue;
30845
+ const basename7 = filePath.split("/").pop() ?? "";
30846
+ if (!basename7.endsWith(".jsonl")) continue;
30470
30847
  if (opts.sinceMtimeMs !== void 0) {
30471
30848
  const mtime = await mtimeMs(filePath);
30472
30849
  if (mtime !== null && mtime < opts.sinceMtimeMs) continue;
@@ -30485,7 +30862,7 @@ function resolveCodexSessionsRoot(override) {
30485
30862
  }
30486
30863
  async function listDirSafe(path) {
30487
30864
  try {
30488
- const entries = await readdir24(path, { withFileTypes: true });
30865
+ const entries = await readdir25(path, { withFileTypes: true });
30489
30866
  return entries.map((e) => ({
30490
30867
  name: e.name,
30491
30868
  isFile: e.isFile(),
@@ -30512,7 +30889,7 @@ async function* walkJsonlRecursive(root) {
30512
30889
  }
30513
30890
  async function mtimeMs(path) {
30514
30891
  try {
30515
- const s = await stat10(path);
30892
+ const s = await stat11(path);
30516
30893
  return s.mtimeMs;
30517
30894
  } catch {
30518
30895
  return null;
@@ -30840,7 +31217,7 @@ init_slug();
30840
31217
  init_timestamp();
30841
31218
  init_assignment_resolver();
30842
31219
  init_assignment_todos();
30843
- import { resolve as resolve74 } from "path";
31220
+ import { resolve as resolve75 } from "path";
30844
31221
  import { readFile as readFile50 } from "fs/promises";
30845
31222
  async function requestCommand(target, text, options = {}) {
30846
31223
  if (!text || !text.trim()) {
@@ -30857,7 +31234,7 @@ async function requestCommand(target, text, options = {}) {
30857
31234
  if (!isValidSlug(target)) {
30858
31235
  throw new Error(`Invalid assignment slug "${target}".`);
30859
31236
  }
30860
- assignmentDir = resolve74(baseDir, options.project, "assignments", target);
31237
+ assignmentDir = resolve75(baseDir, options.project, "assignments", target);
30861
31238
  targetRef = target;
30862
31239
  } else {
30863
31240
  const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), target);
@@ -30867,7 +31244,7 @@ async function requestCommand(target, text, options = {}) {
30867
31244
  assignmentDir = resolved.assignmentDir;
30868
31245
  targetRef = resolved.standalone ? resolved.id : resolved.assignmentSlug;
30869
31246
  }
30870
- const assignmentMdPath2 = resolve74(assignmentDir, "assignment.md");
31247
+ const assignmentMdPath2 = resolve75(assignmentDir, "assignment.md");
30871
31248
  if (!await fileExists(assignmentMdPath2)) {
30872
31249
  throw new Error(`assignment.md not found at ${assignmentMdPath2}`);
30873
31250
  }
@@ -30885,14 +31262,14 @@ async function requestCommand(target, text, options = {}) {
30885
31262
  init_fs();
30886
31263
  init_paths();
30887
31264
  import { Command as Command9 } from "commander";
30888
- import { readFile as readFile51, readdir as readdir25 } from "fs/promises";
30889
- import { resolve as resolve75 } from "path";
31265
+ import { readFile as readFile51, readdir as readdir26 } from "fs/promises";
31266
+ import { resolve as resolve76 } from "path";
30890
31267
  async function readContextAssignmentDir(cwd) {
30891
- const path = resolve75(cwd, ".syntaur", "context.json");
31268
+ const path = resolve76(cwd, ".syntaur", "context.json");
30892
31269
  if (!await fileExists(path)) return null;
30893
31270
  try {
30894
- const raw = await readFile51(path, "utf-8");
30895
- const ctx = JSON.parse(raw);
31271
+ const raw2 = await readFile51(path, "utf-8");
31272
+ const ctx = JSON.parse(raw2);
30896
31273
  if (typeof ctx.assignmentDir === "string" && ctx.assignmentDir.length > 0) {
30897
31274
  return ctx.assignmentDir;
30898
31275
  }
@@ -30905,9 +31282,9 @@ async function resolveAssignmentDir(opts) {
30905
31282
  const cwd = opts.cwd ?? process.cwd();
30906
31283
  if (opts.assignment) {
30907
31284
  if (opts.project) {
30908
- return resolve75(defaultProjectDir(), opts.project, "assignments", opts.assignment);
31285
+ return resolve76(defaultProjectDir(), opts.project, "assignments", opts.assignment);
30909
31286
  }
30910
- return resolve75(assignmentsDir(), opts.assignment);
31287
+ return resolve76(assignmentsDir(), opts.assignment);
30911
31288
  }
30912
31289
  const fromCtx = await readContextAssignmentDir(cwd);
30913
31290
  if (fromCtx) return fromCtx;
@@ -30918,7 +31295,7 @@ async function resolveAssignmentDir(opts) {
30918
31295
  var PLAN_PATTERN = /^plan(?:-v(\d+))?\.md$/;
30919
31296
  async function listPlanFiles(assignmentDir) {
30920
31297
  if (!await fileExists(assignmentDir)) return [];
30921
- const entries = await readdir25(assignmentDir, { withFileTypes: true });
31298
+ const entries = await readdir26(assignmentDir, { withFileTypes: true });
30922
31299
  const out = [];
30923
31300
  for (const e of entries) {
30924
31301
  if (!e.isFile()) continue;
@@ -31050,7 +31427,7 @@ async function runPlanVersion(options) {
31050
31427
  if (!await fileExists(assignmentDir)) {
31051
31428
  throw new Error(`Assignment directory does not exist: ${assignmentDir}`);
31052
31429
  }
31053
- const assignmentMdPath2 = resolve75(assignmentDir, "assignment.md");
31430
+ const assignmentMdPath2 = resolve76(assignmentDir, "assignment.md");
31054
31431
  if (!await fileExists(assignmentMdPath2)) {
31055
31432
  throw new Error(`Missing assignment.md at: ${assignmentMdPath2}`);
31056
31433
  }
@@ -31062,14 +31439,14 @@ async function runPlanVersion(options) {
31062
31439
  }
31063
31440
  const current = planFiles[planFiles.length - 1];
31064
31441
  const next = nextPlanFileName(current.version);
31065
- const newPath = resolve75(assignmentDir, next.fileName);
31442
+ const newPath = resolve76(assignmentDir, next.fileName);
31066
31443
  if (await fileExists(newPath) && !options.force) {
31067
31444
  throw new Error(`${next.fileName} already exists. Use --force to overwrite.`);
31068
31445
  }
31069
31446
  const assignmentMd = await readFile51(assignmentMdPath2, "utf-8");
31070
31447
  const slugMatch = assignmentMd.match(/^slug:\s*(.+?)\s*$/m);
31071
31448
  const slug = slugMatch ? slugMatch[1].trim() : assignmentDir.split("/").pop() ?? "";
31072
- const oldPlanPath = resolve75(assignmentDir, current.fileName);
31449
+ const oldPlanPath = resolve76(assignmentDir, current.fileName);
31073
31450
  const oldPlanContent = await readFile51(oldPlanPath, "utf-8");
31074
31451
  const oldBody = oldPlanContent.replace(/^---[\s\S]*?\n---\n?/, "");
31075
31452
  const carriedTodos = extractUncheckedTodos(oldBody);
@@ -31107,28 +31484,28 @@ planCommand.command("version").description(
31107
31484
  // src/commands/session.ts
31108
31485
  init_fs();
31109
31486
  import { Command as Command10 } from "commander";
31110
- import { readFile as readFile52, readdir as readdir26, stat as stat11 } from "fs/promises";
31111
- import { resolve as resolve76 } from "path";
31487
+ import { readFile as readFile52, readdir as readdir27, stat as stat12 } from "fs/promises";
31488
+ import { resolve as resolve77 } from "path";
31112
31489
  async function readContext(cwd) {
31113
- const path = resolve76(cwd, ".syntaur", "context.json");
31490
+ const path = resolve77(cwd, ".syntaur", "context.json");
31114
31491
  if (!await fileExists(path)) return null;
31115
31492
  try {
31116
- const raw = await readFile52(path, "utf-8");
31117
- return JSON.parse(raw);
31493
+ const raw2 = await readFile52(path, "utf-8");
31494
+ return JSON.parse(raw2);
31118
31495
  } catch {
31119
31496
  return null;
31120
31497
  }
31121
31498
  }
31122
31499
  async function findLatestSessionSummary(assignmentDir) {
31123
- const sessionsRoot = resolve76(assignmentDir, "sessions");
31500
+ const sessionsRoot = resolve77(assignmentDir, "sessions");
31124
31501
  if (!await fileExists(sessionsRoot)) return null;
31125
- const entries = await readdir26(sessionsRoot, { withFileTypes: true });
31502
+ const entries = await readdir27(sessionsRoot, { withFileTypes: true });
31126
31503
  let best = null;
31127
31504
  for (const entry of entries) {
31128
31505
  if (!entry.isDirectory()) continue;
31129
- const summaryPath = resolve76(sessionsRoot, entry.name, "summary.md");
31506
+ const summaryPath = resolve77(sessionsRoot, entry.name, "summary.md");
31130
31507
  if (!await fileExists(summaryPath)) continue;
31131
- const st = await stat11(summaryPath);
31508
+ const st = await stat12(summaryPath);
31132
31509
  if (best === null || st.mtime.getTime() > best.mtime.getTime()) {
31133
31510
  best = { sessionId: entry.name, path: summaryPath, mtime: st.mtime };
31134
31511
  }
@@ -31136,7 +31513,7 @@ async function findLatestSessionSummary(assignmentDir) {
31136
31513
  return best;
31137
31514
  }
31138
31515
  async function findOpenHandoff(assignmentDir) {
31139
- const handoffPath = resolve76(assignmentDir, "handoff.md");
31516
+ const handoffPath = resolve77(assignmentDir, "handoff.md");
31140
31517
  if (!await fileExists(handoffPath)) return null;
31141
31518
  const content = await readFile52(handoffPath, "utf-8");
31142
31519
  const body = content.replace(/^---[\s\S]*?\n---\n?/, "").trim();
@@ -31247,9 +31624,9 @@ init_fs();
31247
31624
  init_paths();
31248
31625
  import { Command as Command11 } from "commander";
31249
31626
  import { readFile as readFile53 } from "fs/promises";
31250
- import { resolve as resolve77 } from "path";
31627
+ import { resolve as resolve78 } from "path";
31251
31628
  async function readContext2(cwd) {
31252
- const path = resolve77(cwd, ".syntaur", "context.json");
31629
+ const path = resolve78(cwd, ".syntaur", "context.json");
31253
31630
  if (!await fileExists(path)) return null;
31254
31631
  try {
31255
31632
  return JSON.parse(await readFile53(path, "utf-8"));
@@ -31260,7 +31637,7 @@ async function readContext2(cwd) {
31260
31637
  async function resolveAssignmentPath2(opts) {
31261
31638
  if (opts.assignment) {
31262
31639
  if (opts.project) {
31263
- return resolve77(
31640
+ return resolve78(
31264
31641
  defaultProjectDir(),
31265
31642
  opts.project,
31266
31643
  "assignments",
@@ -31268,10 +31645,10 @@ async function resolveAssignmentPath2(opts) {
31268
31645
  "assignment.md"
31269
31646
  );
31270
31647
  }
31271
- return resolve77(assignmentsDir(), opts.assignment, "assignment.md");
31648
+ return resolve78(assignmentsDir(), opts.assignment, "assignment.md");
31272
31649
  }
31273
31650
  const ctx = await readContext2(opts.cwd);
31274
- if (ctx?.assignmentDir) return resolve77(ctx.assignmentDir, "assignment.md");
31651
+ if (ctx?.assignmentDir) return resolve78(ctx.assignmentDir, "assignment.md");
31275
31652
  throw new Error(
31276
31653
  "No active assignment. Pass --assignment <slug> [--project <slug>] or run from a workspace with .syntaur/context.json."
31277
31654
  );
@@ -31282,7 +31659,7 @@ async function runWorktreeCreate(options, cwd = process.cwd()) {
31282
31659
  }
31283
31660
  const repository = options.repository ?? cwd;
31284
31661
  const parentBranch = options.parentBranch ?? "main";
31285
- const worktreePath = options.worktreePath ?? resolve77(repository, ".worktrees", options.branch);
31662
+ const worktreePath = options.worktreePath ?? resolve78(repository, ".worktrees", options.branch);
31286
31663
  const assignmentPath = await resolveAssignmentPath2({
31287
31664
  assignment: options.assignment,
31288
31665
  project: options.project,
@@ -31319,13 +31696,13 @@ init_paths();
31319
31696
  init_fs();
31320
31697
  init_slug();
31321
31698
  import { Command as Command12 } from "commander";
31322
- import { resolve as resolve79 } from "path";
31699
+ import { resolve as resolve80 } from "path";
31323
31700
 
31324
31701
  // src/utils/project-indexes.ts
31325
31702
  init_parser();
31326
31703
  init_fs();
31327
- import { readdir as readdir27, readFile as readFile54 } from "fs/promises";
31328
- import { resolve as resolve78 } from "path";
31704
+ import { readdir as readdir28, readFile as readFile54 } from "fs/promises";
31705
+ import { resolve as resolve79 } from "path";
31329
31706
  function nowIso3() {
31330
31707
  return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
31331
31708
  }
@@ -31334,7 +31711,7 @@ function readProjectSlug(projectDir) {
31334
31711
  }
31335
31712
  async function listSlugFiles(dir) {
31336
31713
  if (!await fileExists(dir)) return [];
31337
- const entries = await readdir27(dir, { withFileTypes: true });
31714
+ const entries = await readdir28(dir, { withFileTypes: true });
31338
31715
  return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && !e.name.startsWith("_")).map((e) => e.name).sort();
31339
31716
  }
31340
31717
  function escapeCell(value) {
@@ -31344,7 +31721,7 @@ function joinList(items) {
31344
31721
  return items.length === 0 ? "\u2014" : items.map(escapeCell).join(", ");
31345
31722
  }
31346
31723
  async function rebuildResourcesIndex(projectDir) {
31347
- const dir = resolve78(projectDir, "resources");
31724
+ const dir = resolve79(projectDir, "resources");
31348
31725
  await ensureDir(dir);
31349
31726
  const files = await listSlugFiles(dir);
31350
31727
  const slug = readProjectSlug(projectDir);
@@ -31360,7 +31737,7 @@ async function rebuildResourcesIndex(projectDir) {
31360
31737
  lines.push("| Name | Category | Source | Related Assignments | Updated |");
31361
31738
  lines.push("|------|----------|--------|---------------------|---------|");
31362
31739
  for (const fileName of files) {
31363
- const content = await readFile54(resolve78(dir, fileName), "utf-8");
31740
+ const content = await readFile54(resolve79(dir, fileName), "utf-8");
31364
31741
  const parsed = parseResource(content);
31365
31742
  const slugBase = fileName.replace(/\.md$/, "");
31366
31743
  const name = parsed.name || slugBase;
@@ -31370,12 +31747,12 @@ async function rebuildResourcesIndex(projectDir) {
31370
31747
  );
31371
31748
  }
31372
31749
  lines.push("");
31373
- const indexPath = resolve78(dir, "_index.md");
31750
+ const indexPath = resolve79(dir, "_index.md");
31374
31751
  await writeFileForce(indexPath, lines.join("\n"));
31375
31752
  return { total: files.length, path: indexPath };
31376
31753
  }
31377
31754
  async function rebuildMemoriesIndex(projectDir) {
31378
- const dir = resolve78(projectDir, "memories");
31755
+ const dir = resolve79(projectDir, "memories");
31379
31756
  await ensureDir(dir);
31380
31757
  const files = await listSlugFiles(dir);
31381
31758
  const slug = readProjectSlug(projectDir);
@@ -31391,7 +31768,7 @@ async function rebuildMemoriesIndex(projectDir) {
31391
31768
  lines.push("| Name | Source | Scope | Source Assignment | Updated |");
31392
31769
  lines.push("|------|--------|-------|-------------------|---------|");
31393
31770
  for (const fileName of files) {
31394
- const content = await readFile54(resolve78(dir, fileName), "utf-8");
31771
+ const content = await readFile54(resolve79(dir, fileName), "utf-8");
31395
31772
  const parsed = parseMemory(content);
31396
31773
  const slugBase = fileName.replace(/\.md$/, "");
31397
31774
  const name = parsed.name || slugBase;
@@ -31401,7 +31778,7 @@ async function rebuildMemoriesIndex(projectDir) {
31401
31778
  );
31402
31779
  }
31403
31780
  lines.push("");
31404
- const indexPath = resolve78(dir, "_index.md");
31781
+ const indexPath = resolve79(dir, "_index.md");
31405
31782
  await writeFileForce(indexPath, lines.join("\n"));
31406
31783
  return { total: files.length, path: indexPath };
31407
31784
  }
@@ -31439,8 +31816,8 @@ async function runResourceAdd(options) {
31439
31816
  if (!isValidSlug(options.project)) {
31440
31817
  throw new Error(`Invalid project slug: "${options.project}".`);
31441
31818
  }
31442
- const projectDir = resolve79(defaultProjectDir(), options.project);
31443
- if (!await fileExists(resolve79(projectDir, "project.md"))) {
31819
+ const projectDir = resolve80(defaultProjectDir(), options.project);
31820
+ if (!await fileExists(resolve80(projectDir, "project.md"))) {
31444
31821
  throw new Error(`Project "${options.project}" not found at ${projectDir}.`);
31445
31822
  }
31446
31823
  if (!options.name) throw new Error("--name is required.");
@@ -31449,7 +31826,7 @@ async function runResourceAdd(options) {
31449
31826
  if (!isValidSlug(slug)) {
31450
31827
  throw new Error(`Invalid resource slug: "${slug}".`);
31451
31828
  }
31452
- const filePath = resolve79(projectDir, "resources", `${slug}.md`);
31829
+ const filePath = resolve80(projectDir, "resources", `${slug}.md`);
31453
31830
  if (await fileExists(filePath) && !options.force) {
31454
31831
  throw new Error(
31455
31832
  `Resource "${slug}" already exists at ${filePath}. Use --force to overwrite.`
@@ -31484,7 +31861,7 @@ init_paths();
31484
31861
  init_fs();
31485
31862
  init_slug();
31486
31863
  import { Command as Command13 } from "commander";
31487
- import { resolve as resolve80 } from "path";
31864
+ import { resolve as resolve81 } from "path";
31488
31865
  function nowIso5() {
31489
31866
  return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
31490
31867
  }
@@ -31519,8 +31896,8 @@ async function runMemoryAdd(options) {
31519
31896
  if (!isValidSlug(options.project)) {
31520
31897
  throw new Error(`Invalid project slug: "${options.project}".`);
31521
31898
  }
31522
- const projectDir = resolve80(defaultProjectDir(), options.project);
31523
- if (!await fileExists(resolve80(projectDir, "project.md"))) {
31899
+ const projectDir = resolve81(defaultProjectDir(), options.project);
31900
+ if (!await fileExists(resolve81(projectDir, "project.md"))) {
31524
31901
  throw new Error(`Project "${options.project}" not found at ${projectDir}.`);
31525
31902
  }
31526
31903
  if (!options.name) throw new Error("--name is required.");
@@ -31529,7 +31906,7 @@ async function runMemoryAdd(options) {
31529
31906
  if (!isValidSlug(slug)) {
31530
31907
  throw new Error(`Invalid memory slug: "${slug}".`);
31531
31908
  }
31532
- const filePath = resolve80(projectDir, "memories", `${slug}.md`);
31909
+ const filePath = resolve81(projectDir, "memories", `${slug}.md`);
31533
31910
  if (await fileExists(filePath) && !options.force) {
31534
31911
  throw new Error(
31535
31912
  `Memory "${slug}" already exists at ${filePath}. Use --force to overwrite.`
@@ -31567,7 +31944,7 @@ init_fs();
31567
31944
  init_frontmatter();
31568
31945
  import { Command as Command14 } from "commander";
31569
31946
  import { readFile as readFile55 } from "fs/promises";
31570
- import { resolve as resolve81 } from "path";
31947
+ import { resolve as resolve82 } from "path";
31571
31948
  var AGE_PATTERN = /^(\d+)([dhwm])$/i;
31572
31949
  function parseAgeToCutoff(age) {
31573
31950
  const match = age.match(AGE_PATTERN);
@@ -31586,7 +31963,7 @@ function parseAgeToCutoff(age) {
31586
31963
  }
31587
31964
  function assignmentMdPath(item) {
31588
31965
  if (item.projectSlug) {
31589
- return resolve81(
31966
+ return resolve82(
31590
31967
  defaultProjectDir(),
31591
31968
  item.projectSlug,
31592
31969
  "assignments",
@@ -31594,7 +31971,7 @@ function assignmentMdPath(item) {
31594
31971
  "assignment.md"
31595
31972
  );
31596
31973
  }
31597
- return resolve81(assignmentsDir(), item.id, "assignment.md");
31974
+ return resolve82(assignmentsDir(), item.id, "assignment.md");
31598
31975
  }
31599
31976
  async function loadTags(item) {
31600
31977
  const path = assignmentMdPath(item);
@@ -32024,10 +32401,10 @@ viewsCommand.command("delete").description("Delete a saved view by id").argument
32024
32401
 
32025
32402
  // src/cli-default-command.ts
32026
32403
  init_config2();
32027
- import { readdir as readdir28 } from "fs/promises";
32404
+ import { readdir as readdir29 } from "fs/promises";
32028
32405
  async function hasAnyProjectContent(projectsDir2) {
32029
32406
  try {
32030
- const entries = await readdir28(projectsDir2, { withFileTypes: true });
32407
+ const entries = await readdir29(projectsDir2, { withFileTypes: true });
32031
32408
  return entries.some((entry) => entry.isDirectory());
32032
32409
  } catch {
32033
32410
  return false;