syntaur 0.32.0 → 0.34.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 (70) hide show
  1. package/dashboard/dist/assets/{_basePickBy-CV3s3ZBR.js → _basePickBy-BBDt2N1-.js} +1 -1
  2. package/dashboard/dist/assets/{_baseUniq-BTBb-kpx.js → _baseUniq-CX9QmA6j.js} +1 -1
  3. package/dashboard/dist/assets/{arc-DroCaru_.js → arc-CQ6470MS.js} +1 -1
  4. package/dashboard/dist/assets/{architectureDiagram-2XIMDMQ5-hL5g0oNx.js → architectureDiagram-2XIMDMQ5-q_340vb1.js} +1 -1
  5. package/dashboard/dist/assets/{blockDiagram-WCTKOSBZ-H-mOZOGQ.js → blockDiagram-WCTKOSBZ-DDcJVm3I.js} +1 -1
  6. package/dashboard/dist/assets/{c4Diagram-IC4MRINW-C7JTywql.js → c4Diagram-IC4MRINW-Bu7rCnPq.js} +1 -1
  7. package/dashboard/dist/assets/channel-C1JmUAYK.js +1 -0
  8. package/dashboard/dist/assets/{chunk-4BX2VUAB-C5NgL7Ud.js → chunk-4BX2VUAB-D4mCzHM1.js} +1 -1
  9. package/dashboard/dist/assets/{chunk-55IACEB6-CpqlZIZp.js → chunk-55IACEB6-qZy5S9aK.js} +1 -1
  10. package/dashboard/dist/assets/{chunk-FMBD7UC4-DOEJuCgN.js → chunk-FMBD7UC4-CP-aSp5R.js} +1 -1
  11. package/dashboard/dist/assets/{chunk-JSJVCQXG-DTvwZQeC.js → chunk-JSJVCQXG-Bjd2-Jbp.js} +1 -1
  12. package/dashboard/dist/assets/{chunk-KX2RTZJC-DtM5R3Ro.js → chunk-KX2RTZJC-BHALK3O8.js} +1 -1
  13. package/dashboard/dist/assets/{chunk-NQ4KR5QH-BRf7XeyG.js → chunk-NQ4KR5QH-EJgFAbBI.js} +1 -1
  14. package/dashboard/dist/assets/{chunk-QZHKN3VN-CkRK4_hm.js → chunk-QZHKN3VN-LIJprKdb.js} +1 -1
  15. package/dashboard/dist/assets/{chunk-WL4C6EOR-D40xff82.js → chunk-WL4C6EOR-Bp9peutH.js} +1 -1
  16. package/dashboard/dist/assets/classDiagram-VBA2DB6C-CL5uYMtW.js +1 -0
  17. package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-CL5uYMtW.js +1 -0
  18. package/dashboard/dist/assets/clone-BGt3nn5b.js +1 -0
  19. package/dashboard/dist/assets/{cose-bilkent-S5V4N54A-BzAx8dWI.js → cose-bilkent-S5V4N54A-D2Khnalp.js} +1 -1
  20. package/dashboard/dist/assets/{dagre-KLK3FWXG-DqBzOGFn.js → dagre-KLK3FWXG-A7FKInZZ.js} +1 -1
  21. package/dashboard/dist/assets/{diagram-E7M64L7V-BU3Nv4BP.js → diagram-E7M64L7V-CpCC84EE.js} +1 -1
  22. package/dashboard/dist/assets/{diagram-IFDJBPK2-9173qxjV.js → diagram-IFDJBPK2-UN3agGn6.js} +1 -1
  23. package/dashboard/dist/assets/{diagram-P4PSJMXO-CDO7XNao.js → diagram-P4PSJMXO-r7USVjRa.js} +1 -1
  24. package/dashboard/dist/assets/{erDiagram-INFDFZHY-DkO9AjCM.js → erDiagram-INFDFZHY-BqjWbP4d.js} +1 -1
  25. package/dashboard/dist/assets/{flowDiagram-PKNHOUZH-9Fjhsq_p.js → flowDiagram-PKNHOUZH-D3_hInoz.js} +1 -1
  26. package/dashboard/dist/assets/{ganttDiagram-A5KZAMGK-FL3oGbo9.js → ganttDiagram-A5KZAMGK-Dzf0OcUQ.js} +1 -1
  27. package/dashboard/dist/assets/{gitGraphDiagram-K3NZZRJ6-FS9HpxFJ.js → gitGraphDiagram-K3NZZRJ6-DDVNfYsD.js} +1 -1
  28. package/dashboard/dist/assets/{graph-COu71lol.js → graph-XQCpDL3e.js} +1 -1
  29. package/dashboard/dist/assets/index-BlO8cOgL.css +1 -0
  30. package/dashboard/dist/assets/{index-D1FxzsMS.js → index-DTGG1F6E.js} +130 -125
  31. package/dashboard/dist/assets/{infoDiagram-LFFYTUFH-Cb7nqRMJ.js → infoDiagram-LFFYTUFH-Bn7xCldX.js} +1 -1
  32. package/dashboard/dist/assets/{ishikawaDiagram-PHBUUO56-DU44jQ_t.js → ishikawaDiagram-PHBUUO56-BMaPOOT_.js} +1 -1
  33. package/dashboard/dist/assets/{journeyDiagram-4ABVD52K-Dvf5wmhX.js → journeyDiagram-4ABVD52K-CfYBwIWr.js} +1 -1
  34. package/dashboard/dist/assets/{kanban-definition-K7BYSVSG-NNnzIiBX.js → kanban-definition-K7BYSVSG-DQoSgSWy.js} +1 -1
  35. package/dashboard/dist/assets/{layout-BWL1q6XW.js → layout-CFxopkD1.js} +1 -1
  36. package/dashboard/dist/assets/{linear-BpjXUE-L.js → linear-q1lde7uY.js} +1 -1
  37. package/dashboard/dist/assets/{mermaid.core-C1YuKa7V.js → mermaid.core-CclSNuh7.js} +4 -4
  38. package/dashboard/dist/assets/{mindmap-definition-YRQLILUH-BUS-7SSM.js → mindmap-definition-YRQLILUH-C_XHOwF9.js} +1 -1
  39. package/dashboard/dist/assets/{pieDiagram-SKSYHLDU-CId0D08y.js → pieDiagram-SKSYHLDU-C8xZgEA3.js} +1 -1
  40. package/dashboard/dist/assets/{quadrantDiagram-337W2JSQ-lrdlvDFz.js → quadrantDiagram-337W2JSQ-JZOm4MlZ.js} +1 -1
  41. package/dashboard/dist/assets/{requirementDiagram-Z7DCOOCP-CijOr4BN.js → requirementDiagram-Z7DCOOCP-0o-kjUyz.js} +1 -1
  42. package/dashboard/dist/assets/{sankeyDiagram-WA2Y5GQK-Bz63rCum.js → sankeyDiagram-WA2Y5GQK-BQVypVuO.js} +1 -1
  43. package/dashboard/dist/assets/{sequenceDiagram-2WXFIKYE-0ojwsRXQ.js → sequenceDiagram-2WXFIKYE-eHOgK4bp.js} +1 -1
  44. package/dashboard/dist/assets/{stateDiagram-RAJIS63D-DvTark-k.js → stateDiagram-RAJIS63D-D08VAF0t.js} +1 -1
  45. package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-9uffSM-p.js +1 -0
  46. package/dashboard/dist/assets/{timeline-definition-YZTLITO2-B4EQprf1.js → timeline-definition-YZTLITO2-BGqUaDJh.js} +1 -1
  47. package/dashboard/dist/assets/{treemap-KZPCXAKY-ht_xOxVL.js → treemap-KZPCXAKY-DDilTqSL.js} +1 -1
  48. package/dashboard/dist/assets/{vennDiagram-LZ73GAT5-C4DqZkvq.js → vennDiagram-LZ73GAT5-CGMFf3rB.js} +1 -1
  49. package/dashboard/dist/assets/{xychartDiagram-JWTSCODW-eoymvv9D.js → xychartDiagram-JWTSCODW-DxpH1jvd.js} +1 -1
  50. package/dashboard/dist/index.html +2 -2
  51. package/dist/dashboard/server.js +9 -1
  52. package/dist/dashboard/server.js.map +1 -1
  53. package/dist/index.js +772 -452
  54. package/dist/index.js.map +1 -1
  55. package/package.json +1 -1
  56. package/platforms/README.md +38 -7
  57. package/platforms/hermes/plugins/syntaur/README.md +37 -0
  58. package/platforms/hermes/plugins/syntaur/__init__.py +151 -0
  59. package/platforms/hermes/plugins/syntaur/__pycache__/__init__.cpython-312.pyc +0 -0
  60. package/platforms/hermes/plugins/syntaur/__pycache__/boundary.cpython-312.pyc +0 -0
  61. package/platforms/hermes/plugins/syntaur/boundary.py +99 -0
  62. package/platforms/hermes/plugins/syntaur/plugin.yaml +6 -0
  63. package/platforms/pi/extensions/syntaur/README.md +34 -0
  64. package/platforms/pi/extensions/syntaur/index.ts +265 -0
  65. package/dashboard/dist/assets/channel-X6-lrXLw.js +0 -1
  66. package/dashboard/dist/assets/classDiagram-VBA2DB6C-DfkR91Os.js +0 -1
  67. package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-DfkR91Os.js +0 -1
  68. package/dashboard/dist/assets/clone--OUSRwbL.js +0 -1
  69. package/dashboard/dist/assets/index-BohN_jjP.css +0 -1
  70. package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-CiT1CTy0.js +0 -1
package/dist/index.js CHANGED
@@ -2760,9 +2760,9 @@ function normalizeAgentsFromConfig(agents) {
2760
2760
  validateAgentList(normalized);
2761
2761
  return normalized;
2762
2762
  } catch (err2) {
2763
- const msg = err2 instanceof Error ? err2.message : String(err2);
2763
+ const msg2 = err2 instanceof Error ? err2.message : String(err2);
2764
2764
  console.warn(
2765
- `Warning: ~/.syntaur/config.md agents block is invalid (${msg}) \u2014 using built-in defaults`
2765
+ `Warning: ~/.syntaur/config.md agents block is invalid (${msg2}) \u2014 using built-in defaults`
2766
2766
  );
2767
2767
  return null;
2768
2768
  }
@@ -3152,8 +3152,8 @@ async function readConfig() {
3152
3152
  try {
3153
3153
  return parseTerminalConfig(fm["terminal"]);
3154
3154
  } catch (err2) {
3155
- const msg = err2 instanceof TerminalConfigError ? err2.message : String(err2);
3156
- console.warn(`Warning: ${msg} \u2014 falling back to default`);
3155
+ const msg2 = err2 instanceof TerminalConfigError ? err2.message : String(err2);
3156
+ console.warn(`Warning: ${msg2} \u2014 falling back to default`);
3157
3157
  return null;
3158
3158
  }
3159
3159
  })(),
@@ -5382,8 +5382,8 @@ async function migrateFromMarkdown(projectsDir2) {
5382
5382
  return allSessions.length;
5383
5383
  }
5384
5384
  async function parseMarkdownSessionsIndex(filePath, projectSlug) {
5385
- const { readFile: readFile63 } = await import("fs/promises");
5386
- const raw2 = await readFile63(filePath, "utf-8");
5385
+ const { readFile: readFile64 } = await import("fs/promises");
5386
+ const raw2 = await readFile64(filePath, "utf-8");
5387
5387
  const sessions = [];
5388
5388
  const lines = raw2.split("\n");
5389
5389
  let inTable = false;
@@ -5819,8 +5819,8 @@ function scanKey(serversDir2, projectsDir2, assignmentsDir2) {
5819
5819
  return `${serversDir2}\0${projectsDir2}\0${assignmentsDir2 ?? ""}`;
5820
5820
  }
5821
5821
  function delay(ms) {
5822
- return new Promise((resolve86) => {
5823
- const timer2 = setTimeout(resolve86, ms);
5822
+ return new Promise((resolve87) => {
5823
+ const timer2 = setTimeout(resolve87, ms);
5824
5824
  if (typeof timer2.unref === "function") {
5825
5825
  timer2.unref();
5826
5826
  }
@@ -8802,7 +8802,7 @@ import {
8802
8802
  unlinkSync
8803
8803
  } from "fs";
8804
8804
  import { fileURLToPath as fileURLToPath9, pathToFileURL } from "url";
8805
- import { dirname as dirname17, resolve as resolve50, join as join9 } from "path";
8805
+ import { dirname as dirname18, resolve as resolve51, join as join10 } from "path";
8806
8806
  import { homedir as homedir9, tmpdir as tmpdir2 } from "os";
8807
8807
  import { spawnSync as spawnSync7 } from "child_process";
8808
8808
  function syntaurRootMjs() {
@@ -8810,7 +8810,7 @@ function syntaurRootMjs() {
8810
8810
  if (override && override.length > 0) {
8811
8811
  return override;
8812
8812
  }
8813
- return join9(homedir9(), ".syntaur");
8813
+ return join10(homedir9(), ".syntaur");
8814
8814
  }
8815
8815
  async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
8816
8816
  const { throwOnFailure } = options;
@@ -8824,38 +8824,38 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
8824
8824
  }
8825
8825
  const stateRoot = syntaurRootMjs();
8826
8826
  mkdirSync2(stateRoot, { recursive: true });
8827
- const lockPath = resolve50(stateRoot, "install-url-handler.lock");
8827
+ const lockPath = resolve51(stateRoot, "install-url-handler.lock");
8828
8828
  let lockFd;
8829
8829
  try {
8830
8830
  lockFd = openSync(lockPath, "wx");
8831
8831
  } catch (err2) {
8832
8832
  if (err2 && err2.code === "EEXIST") {
8833
- const msg = `Another syntaur:// handler registration is in progress (lock at ${lockPath}). Wait for it to finish or remove the stale lock.`;
8833
+ const msg2 = `Another syntaur:// handler registration is in progress (lock at ${lockPath}). Wait for it to finish or remove the stale lock.`;
8834
8834
  if (throwOnFailure) {
8835
- throw new Error(msg);
8835
+ throw new Error(msg2);
8836
8836
  }
8837
- console.warn(`syntaur: skipping macOS URL-handler registration (${msg})`);
8837
+ console.warn(`syntaur: skipping macOS URL-handler registration (${msg2})`);
8838
8838
  return { bundlePath: "" };
8839
8839
  }
8840
8840
  throw err2;
8841
8841
  }
8842
8842
  try {
8843
- const pkgRoot = resolve50(dirname17(fileURLToPath9(import.meta.url)), "..");
8844
- const cliBin = realpathSync3(resolve50(pkgRoot, "bin/syntaur.js"));
8843
+ const pkgRoot = resolve51(dirname18(fileURLToPath9(import.meta.url)), "..");
8844
+ const cliBin = realpathSync3(resolve51(pkgRoot, "bin/syntaur.js"));
8845
8845
  const nodeBin = process.execPath;
8846
- const bundleParent = join9(
8846
+ const bundleParent = join10(
8847
8847
  homedir9(),
8848
8848
  "Library",
8849
8849
  "Application Support",
8850
8850
  "Syntaur"
8851
8851
  );
8852
- const bundlePath = join9(bundleParent, "syntaur-url.app");
8852
+ const bundlePath = join10(bundleParent, "syntaur-url.app");
8853
8853
  mkdirSync2(bundleParent, { recursive: true });
8854
8854
  if (existsSync5(bundlePath)) {
8855
8855
  rmSync(bundlePath, { recursive: true, force: true });
8856
8856
  }
8857
8857
  const installedTerminals = detectInstalledTerminals();
8858
- const scriptPath = join9(
8858
+ const scriptPath = join10(
8859
8859
  tmpdir2(),
8860
8860
  `syntaur-url-handler-${process.pid}.applescript`
8861
8861
  );
@@ -8874,7 +8874,7 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
8874
8874
  `osacompile exited with code ${compile.status}: ${compile.stderr || compile.stdout}`
8875
8875
  );
8876
8876
  }
8877
- const infoPlistPath = join9(bundlePath, "Contents", "Info.plist");
8877
+ const infoPlistPath = join10(bundlePath, "Contents", "Info.plist");
8878
8878
  if (!existsSync5(infoPlistPath)) {
8879
8879
  throw new Error(`osacompile did not produce ${infoPlistPath}`);
8880
8880
  }
@@ -8914,23 +8914,23 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
8914
8914
  { stdio: "pipe", encoding: "utf-8" }
8915
8915
  );
8916
8916
  if (sign.status !== 0) {
8917
- const msg = `codesign returned ${sign.status} while re-signing ${bundlePath}: ${sign.stderr || sign.stdout || "(no output)"}`;
8917
+ const msg2 = `codesign returned ${sign.status} while re-signing ${bundlePath}: ${sign.stderr || sign.stdout || "(no output)"}`;
8918
8918
  if (throwOnFailure) {
8919
- throw new Error(msg);
8919
+ throw new Error(msg2);
8920
8920
  }
8921
- console.warn(`syntaur: ${msg} \u2014 macOS may deny Automation permission.`);
8921
+ console.warn(`syntaur: ${msg2} \u2014 macOS may deny Automation permission.`);
8922
8922
  }
8923
8923
  const ls = spawnSync7(LSREGISTER, ["-f", bundlePath], {
8924
8924
  stdio: "pipe",
8925
8925
  encoding: "utf-8"
8926
8926
  });
8927
8927
  if (ls.status !== 0) {
8928
- const msg = `lsregister returned ${ls.status} while registering ${bundlePath}: ${ls.stderr || ls.stdout || "(no output)"}`;
8928
+ const msg2 = `lsregister returned ${ls.status} while registering ${bundlePath}: ${ls.stderr || ls.stdout || "(no output)"}`;
8929
8929
  if (throwOnFailure) {
8930
- throw new Error(msg);
8930
+ throw new Error(msg2);
8931
8931
  }
8932
8932
  console.warn(
8933
- `syntaur: ${msg} \u2014 \`open syntaur://...\` may not route through the CLI handler until you run \`${LSREGISTER} -f ${bundlePath}\` manually.`
8933
+ `syntaur: ${msg2} \u2014 \`open syntaur://...\` may not route through the CLI handler until you run \`${LSREGISTER} -f ${bundlePath}\` manually.`
8934
8934
  );
8935
8935
  }
8936
8936
  try {
@@ -8953,8 +8953,8 @@ async function main() {
8953
8953
  try {
8954
8954
  await registerMacosUrlHandler({ throwOnFailure: false });
8955
8955
  } catch (err2) {
8956
- const msg = err2 instanceof Error ? err2.message : String(err2);
8957
- console.warn(`syntaur: skipping macOS URL-handler registration (${msg})`);
8956
+ const msg2 = err2 instanceof Error ? err2.message : String(err2);
8957
+ console.warn(`syntaur: skipping macOS URL-handler registration (${msg2})`);
8958
8958
  }
8959
8959
  }
8960
8960
  function detectInstalledTerminals() {
@@ -8969,7 +8969,7 @@ function detectInstalledTerminals() {
8969
8969
  ghostty: "Ghostty.app",
8970
8970
  warp: "Warp.app"
8971
8971
  };
8972
- const appDirs = ["/Applications", join9(homedir9(), "Applications")];
8972
+ const appDirs = ["/Applications", join10(homedir9(), "Applications")];
8973
8973
  for (const [id, bundleId] of Object.entries(bundleIds)) {
8974
8974
  const r = spawnSync7(
8975
8975
  "mdfind",
@@ -8981,7 +8981,7 @@ function detectInstalledTerminals() {
8981
8981
  continue;
8982
8982
  }
8983
8983
  const name = bundleNames[id];
8984
- if (name && appDirs.some((dir) => existsSync5(join9(dir, name)))) {
8984
+ if (name && appDirs.some((dir) => existsSync5(join10(dir, name)))) {
8985
8985
  installed.add(id);
8986
8986
  }
8987
8987
  }
@@ -10431,6 +10431,10 @@ var TABLE_COLUMN_IDS = [
10431
10431
  function isTableColumnId(value) {
10432
10432
  return typeof value === "string" && TABLE_COLUMN_IDS.includes(value);
10433
10433
  }
10434
+ var WIDGET_SIZES = ["small", "wide", "tall", "large"];
10435
+ function isWidgetSize(value) {
10436
+ return typeof value === "string" && WIDGET_SIZES.includes(value);
10437
+ }
10434
10438
  var DEFAULT_FILTERS = {
10435
10439
  status: "all",
10436
10440
  priority: "all",
@@ -10523,6 +10527,7 @@ function isDashboardSlot(value) {
10523
10527
  if (!value || typeof value !== "object") return false;
10524
10528
  const obj = value;
10525
10529
  if (typeof obj.id !== "string" || obj.id.length === 0) return false;
10530
+ if (obj.size !== void 0 && !isWidgetSize(obj.size)) return false;
10526
10531
  if (obj.widget === null) return true;
10527
10532
  return isWidgetConfig(obj.widget);
10528
10533
  }
@@ -10753,7 +10758,10 @@ function validateDashboardBody(body) {
10753
10758
  return { ok: false, error: "slots must be an array" };
10754
10759
  }
10755
10760
  if (!obj.slots.every(isDashboardSlot)) {
10756
- return { ok: false, error: "every slot must be { id: string, widget: WidgetConfig | null }" };
10761
+ return {
10762
+ ok: false,
10763
+ error: "every slot must be { id: string, widget: WidgetConfig | null, size?: WidgetSize }"
10764
+ };
10757
10765
  }
10758
10766
  return { ok: true, value: obj.slots };
10759
10767
  }
@@ -16160,12 +16168,12 @@ function createPlaybooksRouter(playbooksDir3) {
16160
16168
  const result = await setPlaybookEnabled(playbooksDir3, req.params.slug, true);
16161
16169
  res.json({ slug: result.slug, enabled: result.enabled, changed: result.changed });
16162
16170
  } catch (error) {
16163
- const msg = error instanceof Error ? error.message : "Failed to enable playbook";
16164
- if (msg.startsWith("Playbook ")) {
16165
- res.status(404).json({ error: msg });
16171
+ const msg2 = error instanceof Error ? error.message : "Failed to enable playbook";
16172
+ if (msg2.startsWith("Playbook ")) {
16173
+ res.status(404).json({ error: msg2 });
16166
16174
  return;
16167
16175
  }
16168
- res.status(500).json({ error: msg });
16176
+ res.status(500).json({ error: msg2 });
16169
16177
  }
16170
16178
  });
16171
16179
  router.post("/:slug/disable", async (req, res) => {
@@ -16173,12 +16181,12 @@ function createPlaybooksRouter(playbooksDir3) {
16173
16181
  const result = await setPlaybookEnabled(playbooksDir3, req.params.slug, false);
16174
16182
  res.json({ slug: result.slug, enabled: result.enabled, changed: result.changed });
16175
16183
  } catch (error) {
16176
- const msg = error instanceof Error ? error.message : "Failed to disable playbook";
16177
- if (msg.startsWith("Playbook ")) {
16178
- res.status(404).json({ error: msg });
16184
+ const msg2 = error instanceof Error ? error.message : "Failed to disable playbook";
16185
+ if (msg2.startsWith("Playbook ")) {
16186
+ res.status(404).json({ error: msg2 });
16179
16187
  return;
16180
16188
  }
16181
- res.status(500).json({ error: msg });
16189
+ res.status(500).json({ error: msg2 });
16182
16190
  }
16183
16191
  });
16184
16192
  router.get("/:slug", async (req, res) => {
@@ -16916,8 +16924,8 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
16916
16924
  router.post("/:workspace/archive", async (req, res) => {
16917
16925
  try {
16918
16926
  const { archivePath: archivePath2 } = await Promise.resolve().then(() => (init_parser2(), parser_exports));
16919
- const { resolve: resolve86 } = await import("path");
16920
- const { readFile: readFile63 } = await import("fs/promises");
16927
+ const { resolve: resolve87 } = await import("path");
16928
+ const { readFile: readFile64 } = await import("fs/promises");
16921
16929
  const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
16922
16930
  const workspace = getWorkspaceParam(req.params.workspace);
16923
16931
  const outcome = await wsLock(workspace, async () => {
@@ -16933,10 +16941,10 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
16933
16941
  (e) => e.itemIds.every((id) => completedIds.has(id))
16934
16942
  );
16935
16943
  const archFile = archivePath2(todosDir2, workspace, checklist.archiveInterval);
16936
- await ensureDir(resolve86(todosDir2, "archive"));
16944
+ await ensureDir(resolve87(todosDir2, "archive"));
16937
16945
  let archContent = "";
16938
16946
  if (await fileExists(archFile)) {
16939
- archContent = await readFile63(archFile, "utf-8");
16947
+ archContent = await readFile64(archFile, "utf-8");
16940
16948
  archContent = archContent.trimEnd() + "\n\n";
16941
16949
  } else {
16942
16950
  archContent = `---
@@ -17225,7 +17233,7 @@ workspace: ${workspace}
17225
17233
  const { readConfig: readConfig3 } = await Promise.resolve().then(() => (init_config2(), config_exports));
17226
17234
  const { assignmentsDir: assignmentsDirFn } = await Promise.resolve().then(() => (init_paths(), paths_exports));
17227
17235
  const { fileExists: fileExists2, writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
17228
- const { readFile: readFile63 } = await import("fs/promises");
17236
+ const { readFile: readFile64 } = await import("fs/promises");
17229
17237
  const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
17230
17238
  const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
17231
17239
  let assignmentRef;
@@ -17246,7 +17254,7 @@ workspace: ${workspace}
17246
17254
  }
17247
17255
  const assignmentMdPath2 = resolvePath2(assignmentDir, "assignment.md");
17248
17256
  if (!await fileExists2(assignmentMdPath2)) return { error: `Target assignment not found: ${assignmentMdPath2}` };
17249
- let content = await readFile63(assignmentMdPath2, "utf-8");
17257
+ let content = await readFile64(assignmentMdPath2, "utf-8");
17250
17258
  content = appendTodosToAssignmentBody2(
17251
17259
  content,
17252
17260
  items.map((it) => ({
@@ -18920,8 +18928,8 @@ async function restoreFromGithub(overrides) {
18920
18928
  await safeRestoreCategory(localPath, repoSrcPath, isFile);
18921
18929
  restored.push(category);
18922
18930
  } catch (error) {
18923
- const msg = error instanceof Error ? error.message : String(error);
18924
- console.error(`Failed to restore "${category}": ${msg}`);
18931
+ const msg2 = error instanceof Error ? error.message : String(error);
18932
+ console.error(`Failed to restore "${category}": ${msg2}`);
18925
18933
  failed.push(category);
18926
18934
  }
18927
18935
  }
@@ -22083,13 +22091,13 @@ async function executeLaunchPlan(plan, spawnFn = realSpawn) {
22083
22091
  env: plan.env
22084
22092
  });
22085
22093
  } catch (err2) {
22086
- const msg = err2 instanceof Error ? err2.message : String(err2);
22094
+ const msg2 = err2 instanceof Error ? err2.message : String(err2);
22087
22095
  throw new TerminalNotFoundError(
22088
22096
  plan.terminal,
22089
- `Spawn failed: ${msg}. Verify the terminal is installed and on PATH.`
22097
+ `Spawn failed: ${msg2}. Verify the terminal is installed and on PATH.`
22090
22098
  );
22091
22099
  }
22092
- await new Promise((resolve86, reject) => {
22100
+ await new Promise((resolve87, reject) => {
22093
22101
  let settled = false;
22094
22102
  let stderr = "";
22095
22103
  const finishOk = () => {
@@ -22099,7 +22107,7 @@ async function executeLaunchPlan(plan, spawnFn = realSpawn) {
22099
22107
  child.unref();
22100
22108
  } catch {
22101
22109
  }
22102
- resolve86();
22110
+ resolve87();
22103
22111
  };
22104
22112
  const finishErr = (remediation) => {
22105
22113
  if (settled) return;
@@ -22270,7 +22278,7 @@ function normalizeSlashes(p) {
22270
22278
  }
22271
22279
  function detectInstallKind(scriptUrl, opts = {}) {
22272
22280
  const realpath3 = opts.realpath ?? realpathSync.native;
22273
- const readFile63 = opts.readFile ?? ((p) => readFileSync(p, "utf-8"));
22281
+ const readFile64 = opts.readFile ?? ((p) => readFileSync(p, "utf-8"));
22274
22282
  const ua = opts.envUserAgent !== void 0 ? opts.envUserAgent : process.env.npm_config_user_agent ?? "";
22275
22283
  const resolved = resolveScriptPath(scriptUrl, realpath3);
22276
22284
  if (resolved === null) {
@@ -22291,7 +22299,7 @@ function detectInstallKind(scriptUrl, opts = {}) {
22291
22299
  const pkgJsonPath = join5(dir, "package.json");
22292
22300
  let raw2;
22293
22301
  try {
22294
- raw2 = readFile63(pkgJsonPath);
22302
+ raw2 = readFile64(pkgJsonPath);
22295
22303
  } catch {
22296
22304
  const parent2 = dirname12(dir);
22297
22305
  if (parent2 === dir) break;
@@ -23428,36 +23436,267 @@ init_config2();
23428
23436
  // src/commands/cross-agent-install.ts
23429
23437
  init_fs();
23430
23438
  import { spawnSync as spawnSync6 } from "child_process";
23431
- import { resolve as resolve47 } from "path";
23432
- import { readFile as readFile31 } from "fs/promises";
23439
+ import { dirname as dirname17, join as join9, resolve as resolve48 } from "path";
23440
+ import { cp as cp4, mkdir as mkdir8, readFile as readFile32 } from "fs/promises";
23433
23441
 
23434
23442
  // src/commands/setup-adapter.ts
23435
23443
  init_paths();
23436
23444
  init_fs();
23437
23445
  init_config2();
23438
23446
  init_slug();
23439
- import { resolve as resolve46 } from "path";
23447
+ import { resolve as resolve47 } from "path";
23440
23448
 
23441
23449
  // src/targets/registry.ts
23442
23450
  init_fs();
23443
23451
  import { homedir as homedir8 } from "os";
23452
+ import { resolve as resolve46 } from "path";
23453
+
23454
+ // src/targets/user-descriptors.ts
23455
+ init_fs();
23456
+ init_paths();
23444
23457
  import { resolve as resolve45 } from "path";
23458
+ import { readFile as readFile31, readdir as readdir17 } from "fs/promises";
23459
+
23460
+ // src/targets/renderers.ts
23461
+ init_cursor_rules();
23462
+ init_codex_agents();
23463
+ init_opencode_config();
23464
+ init_hermes_soul();
23465
+ var RENDERERS = {
23466
+ codexAgents: (ctx) => renderCodexAgents(ctx),
23467
+ cursorProtocol: () => renderCursorProtocol(),
23468
+ cursorAssignment: (ctx) => renderCursorAssignment(ctx),
23469
+ openCodeConfig: (ctx) => renderOpenCodeConfig({ projectDir: ctx.projectDir }),
23470
+ hermesSoul: (ctx) => renderHermesSoul(ctx)
23471
+ };
23472
+
23473
+ // src/targets/user-descriptors.ts
23474
+ function userTargetsDir() {
23475
+ return resolve45(syntaurRoot(), "targets");
23476
+ }
23477
+ var ID_RE = /^[a-z0-9][a-z0-9_-]*$/;
23478
+ var VALID_RENDERER_KEYS = new Set(Object.keys(RENDERERS));
23479
+ var ALLOWED_TOP_KEYS = /* @__PURE__ */ new Set([
23480
+ "id",
23481
+ "displayName",
23482
+ "skillsShAgentId",
23483
+ "detect",
23484
+ "skillsDir",
23485
+ "instructions"
23486
+ ]);
23487
+ function msg(err2) {
23488
+ return err2 instanceof Error ? err2.message : String(err2);
23489
+ }
23490
+ function expandHomeAndEnv(p) {
23491
+ const envExpanded = p.replace(
23492
+ /\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Za-z_][A-Za-z0-9_]*)/g,
23493
+ (_m, braced, bare) => {
23494
+ const name = braced ?? bare ?? "";
23495
+ const v = process.env[name];
23496
+ return v ?? "";
23497
+ }
23498
+ );
23499
+ return resolve45(expandHome(envExpanded));
23500
+ }
23501
+ function compileDetect(spec) {
23502
+ switch (spec.kind) {
23503
+ case "pathExists": {
23504
+ const p = expandHomeAndEnv(spec.path);
23505
+ return () => fileExists(p);
23506
+ }
23507
+ case "anyPathExists": {
23508
+ const ps = spec.paths.map(expandHomeAndEnv);
23509
+ return async () => {
23510
+ for (const p of ps) {
23511
+ if (await fileExists(p)) return true;
23512
+ }
23513
+ return false;
23514
+ };
23515
+ }
23516
+ case "envSet": {
23517
+ const env = spec.env;
23518
+ return async () => {
23519
+ const v = process.env[env];
23520
+ return typeof v === "string" && v.length > 0;
23521
+ };
23522
+ }
23523
+ }
23524
+ }
23525
+ function isPlainObject(v) {
23526
+ return typeof v === "object" && v !== null && !Array.isArray(v);
23527
+ }
23528
+ function validateDetect(detect, errors) {
23529
+ if (!isPlainObject(detect)) {
23530
+ errors.push("detect must be an object");
23531
+ return;
23532
+ }
23533
+ switch (detect.kind) {
23534
+ case "pathExists":
23535
+ if (typeof detect.path !== "string" || detect.path.length === 0)
23536
+ errors.push('detect.path must be a non-empty string for kind "pathExists"');
23537
+ break;
23538
+ case "anyPathExists":
23539
+ if (!Array.isArray(detect.paths) || detect.paths.length === 0 || !detect.paths.every((p) => typeof p === "string" && p.length > 0))
23540
+ errors.push('detect.paths must be a non-empty string[] for kind "anyPathExists"');
23541
+ break;
23542
+ case "envSet":
23543
+ if (typeof detect.env !== "string" || detect.env.length === 0)
23544
+ errors.push('detect.env must be a non-empty string for kind "envSet"');
23545
+ break;
23546
+ default:
23547
+ errors.push(
23548
+ `detect.kind must be one of pathExists|anyPathExists|envSet (got ${JSON.stringify(detect.kind)})`
23549
+ );
23550
+ }
23551
+ }
23552
+ function validateInstructions(instructions, errors) {
23553
+ if (!isPlainObject(instructions)) {
23554
+ errors.push("instructions must be an object");
23555
+ return;
23556
+ }
23557
+ if (!Array.isArray(instructions.files) || instructions.files.length === 0) {
23558
+ errors.push("instructions.files must be a non-empty array");
23559
+ return;
23560
+ }
23561
+ instructions.files.forEach((f, i) => {
23562
+ if (!isPlainObject(f)) {
23563
+ errors.push(`instructions.files[${i}] must be an object`);
23564
+ return;
23565
+ }
23566
+ if (typeof f.path !== "string" || f.path.length === 0)
23567
+ errors.push(`instructions.files[${i}].path must be a non-empty string`);
23568
+ if (typeof f.renderer !== "string" || !VALID_RENDERER_KEYS.has(f.renderer))
23569
+ errors.push(
23570
+ `instructions.files[${i}].renderer ${JSON.stringify(f.renderer)} is not a known renderer (valid: ${[...VALID_RENDERER_KEYS].join(", ")})`
23571
+ );
23572
+ });
23573
+ }
23574
+ function validateUserDescriptor(data, builtinIds) {
23575
+ const errors = [];
23576
+ if (!isPlainObject(data)) {
23577
+ return { ok: false, errors: ["descriptor must be a JSON object"] };
23578
+ }
23579
+ for (const k of Object.keys(data)) {
23580
+ if (!ALLOWED_TOP_KEYS.has(k)) errors.push(`unknown field "${k}"`);
23581
+ }
23582
+ if (typeof data.id !== "string" || data.id.length === 0) {
23583
+ errors.push("id is required and must be a non-empty string");
23584
+ } else if (!ID_RE.test(data.id)) {
23585
+ errors.push(`id "${data.id}" must match ${ID_RE.source}`);
23586
+ } else if (builtinIds.has(data.id)) {
23587
+ errors.push(
23588
+ `id "${data.id}" collides with a built-in agent (built-ins cannot be overridden)`
23589
+ );
23590
+ }
23591
+ if (typeof data.displayName !== "string" || data.displayName.trim().length === 0) {
23592
+ errors.push("displayName is required and must be a non-empty string");
23593
+ }
23594
+ if (data.skillsShAgentId !== void 0 && (typeof data.skillsShAgentId !== "string" || data.skillsShAgentId.length === 0)) {
23595
+ errors.push("skillsShAgentId must be a non-empty string when present");
23596
+ }
23597
+ if (data.detect === void 0) {
23598
+ errors.push("detect is required");
23599
+ } else {
23600
+ validateDetect(data.detect, errors);
23601
+ }
23602
+ if (data.skillsDir !== void 0) {
23603
+ if (!isPlainObject(data.skillsDir)) {
23604
+ errors.push("skillsDir must be an object");
23605
+ } else {
23606
+ for (const k of Object.keys(data.skillsDir)) {
23607
+ if (k !== "project" && k !== "global") errors.push(`skillsDir.${k} is not a valid key`);
23608
+ }
23609
+ if (data.skillsDir.project !== void 0 && typeof data.skillsDir.project !== "string")
23610
+ errors.push("skillsDir.project must be a string");
23611
+ if (data.skillsDir.global !== void 0 && typeof data.skillsDir.global !== "string")
23612
+ errors.push("skillsDir.global must be a string");
23613
+ }
23614
+ }
23615
+ if (data.instructions !== void 0) {
23616
+ validateInstructions(data.instructions, errors);
23617
+ }
23618
+ if (errors.length > 0) return { ok: false, errors };
23619
+ return { ok: true, value: data };
23620
+ }
23621
+ function compileDescriptor(desc) {
23622
+ const target = {
23623
+ id: desc.id,
23624
+ displayName: desc.displayName,
23625
+ detect: compileDetect(desc.detect)
23626
+ };
23627
+ if (desc.skillsShAgentId) target.skillsShAgentId = desc.skillsShAgentId;
23628
+ if (desc.skillsDir) {
23629
+ const skillsDir = {};
23630
+ if (desc.skillsDir.global) skillsDir.global = expandHomeAndEnv(desc.skillsDir.global);
23631
+ if (desc.skillsDir.project) skillsDir.project = desc.skillsDir.project;
23632
+ target.skillsDir = skillsDir;
23633
+ }
23634
+ if (desc.instructions) target.instructions = desc.instructions;
23635
+ return target;
23636
+ }
23637
+ async function loadUserDescriptors(opts = {}) {
23638
+ const dir = opts.dir ?? userTargetsDir();
23639
+ const builtinIds = opts.builtinIds ?? /* @__PURE__ */ new Set();
23640
+ const warnings = [];
23641
+ if (!await fileExists(dir)) return { targets: [], warnings };
23642
+ let files;
23643
+ try {
23644
+ files = (await readdir17(dir)).filter((f) => f.endsWith(".json")).sort();
23645
+ } catch (err2) {
23646
+ return { targets: [], warnings: [`could not read ${dir}: ${msg(err2)}`] };
23647
+ }
23648
+ const targets = [];
23649
+ const seen = /* @__PURE__ */ new Set();
23650
+ for (const file of files) {
23651
+ const full = resolve45(dir, file);
23652
+ let raw2;
23653
+ try {
23654
+ raw2 = await readFile31(full, "utf-8");
23655
+ } catch (err2) {
23656
+ warnings.push(`skipped ${file}: ${msg(err2)}`);
23657
+ continue;
23658
+ }
23659
+ let parsed;
23660
+ try {
23661
+ parsed = JSON.parse(raw2);
23662
+ } catch (err2) {
23663
+ warnings.push(`skipped ${file}: invalid JSON: ${msg(err2)}`);
23664
+ continue;
23665
+ }
23666
+ const result = validateUserDescriptor(parsed, builtinIds);
23667
+ if (!result.ok) {
23668
+ warnings.push(`skipped ${file}: ${result.errors.join("; ")}`);
23669
+ continue;
23670
+ }
23671
+ if (seen.has(result.value.id)) {
23672
+ warnings.push(
23673
+ `skipped ${file}: duplicate id "${result.value.id}" (already loaded from an earlier file)`
23674
+ );
23675
+ continue;
23676
+ }
23677
+ seen.add(result.value.id);
23678
+ targets.push(compileDescriptor(result.value));
23679
+ }
23680
+ return { targets, warnings };
23681
+ }
23682
+
23683
+ // src/targets/registry.ts
23445
23684
  function home(...segments) {
23446
- return resolve45(homedir8(), ...segments);
23685
+ return resolve46(homedir8(), ...segments);
23447
23686
  }
23448
23687
  function hermesHome() {
23449
23688
  const env = process.env.HERMES_HOME;
23450
- return env && env.length > 0 ? resolve45(env) : home(".hermes");
23689
+ return env && env.length > 0 ? resolve46(env) : home(".hermes");
23451
23690
  }
23452
23691
  function hermesSkillsDir() {
23453
- return resolve45(hermesHome(), "skills");
23692
+ return resolve46(hermesHome(), "skills");
23454
23693
  }
23455
23694
  function isHermesHomeCustom() {
23456
23695
  return hermesHome() !== home(".hermes");
23457
23696
  }
23458
23697
  function codexHome() {
23459
23698
  const env = process.env.CODEX_HOME;
23460
- return env && env.length > 0 ? resolve45(env) : home(".codex");
23699
+ return env && env.length > 0 ? resolve46(env) : home(".codex");
23461
23700
  }
23462
23701
  var detectDir = (dir) => () => fileExists(dir);
23463
23702
  var AGENT_TARGETS = [
@@ -23481,7 +23720,7 @@ var AGENT_TARGETS = [
23481
23720
  skillsShAgentId: "codex",
23482
23721
  nativePlugin: "codex",
23483
23722
  detect: detectDir(codexHome()),
23484
- skillsDir: { global: resolve45(codexHome(), "skills") },
23723
+ skillsDir: { global: resolve46(codexHome(), "skills") },
23485
23724
  instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] }
23486
23725
  },
23487
23726
  {
@@ -23513,7 +23752,13 @@ var AGENT_TARGETS = [
23513
23752
  skillsShAgentId: "pi",
23514
23753
  detect: detectDir(home(".pi")),
23515
23754
  skillsDir: { global: home(".pi", "agent", "skills") },
23516
- instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] }
23755
+ instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] },
23756
+ tier3: {
23757
+ kind: "pi-extension",
23758
+ source: "platforms/pi/extensions/syntaur",
23759
+ installDir: () => home(".pi", "agent", "extensions", "syntaur"),
23760
+ entry: "index.ts"
23761
+ }
23517
23762
  },
23518
23763
  {
23519
23764
  id: "openclaw",
@@ -23521,7 +23766,15 @@ var AGENT_TARGETS = [
23521
23766
  skillsShAgentId: "openclaw",
23522
23767
  detect: detectDir(home(".openclaw")),
23523
23768
  skillsDir: { global: home(".openclaw", "skills") },
23524
- instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] }
23769
+ instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] },
23770
+ // OpenClaw runs on pi-coding-agent (design memo), so it reuses the pi
23771
+ // extension SOURCE; only the install dir differs.
23772
+ tier3: {
23773
+ kind: "pi-extension",
23774
+ source: "platforms/pi/extensions/syntaur",
23775
+ installDir: () => home(".openclaw", "extensions", "syntaur"),
23776
+ entry: "index.ts"
23777
+ }
23525
23778
  },
23526
23779
  {
23527
23780
  id: "hermes",
@@ -23529,42 +23782,34 @@ var AGENT_TARGETS = [
23529
23782
  skillsShAgentId: "hermes-agent",
23530
23783
  detect: () => fileExists(hermesHome()),
23531
23784
  skillsDir: { global: hermesSkillsDir() },
23532
- instructions: { files: [{ path: "SOUL.md", renderer: "hermesSoul" }] }
23785
+ instructions: { files: [{ path: "SOUL.md", renderer: "hermesSoul" }] },
23786
+ tier3: {
23787
+ kind: "hermes-plugin",
23788
+ source: "platforms/hermes/plugins/syntaur",
23789
+ installDir: () => resolve46(hermesHome(), "plugins", "syntaur"),
23790
+ entry: "plugin.yaml"
23791
+ }
23533
23792
  }
23534
23793
  ];
23535
23794
  var AGENT_TARGETS_BY_ID = Object.fromEntries(
23536
23795
  AGENT_TARGETS.map((t) => [t.id, t])
23537
23796
  );
23538
- function getAgentTarget(id) {
23539
- return AGENT_TARGETS_BY_ID[id];
23540
- }
23541
- function agentTargetIds() {
23542
- return AGENT_TARGETS.map((t) => t.id);
23543
- }
23544
- function adapterTargets() {
23545
- return AGENT_TARGETS.filter((t) => t.instructions !== void 0);
23797
+ async function resolveAgentTargets() {
23798
+ const { targets: user, warnings } = await loadUserDescriptors({
23799
+ builtinIds: new Set(AGENT_TARGETS.map((t) => t.id))
23800
+ });
23801
+ return { targets: [...AGENT_TARGETS, ...user], warnings };
23546
23802
  }
23547
23803
 
23548
- // src/targets/renderers.ts
23549
- init_cursor_rules();
23550
- init_codex_agents();
23551
- init_opencode_config();
23552
- init_hermes_soul();
23553
- var RENDERERS = {
23554
- codexAgents: (ctx) => renderCodexAgents(ctx),
23555
- cursorProtocol: () => renderCursorProtocol(),
23556
- cursorAssignment: (ctx) => renderCursorAssignment(ctx),
23557
- openCodeConfig: (ctx) => renderOpenCodeConfig({ projectDir: ctx.projectDir }),
23558
- hermesSoul: (ctx) => renderHermesSoul(ctx)
23559
- };
23560
-
23561
23804
  // src/commands/setup-adapter.ts
23562
23805
  async function setupAdapterCommand(framework, options) {
23563
- const target = getAgentTarget(framework);
23806
+ const { targets: known, warnings } = await resolveAgentTargets();
23807
+ const target = known.find((t) => t.id === framework);
23564
23808
  if (!target || !target.instructions) {
23565
- const supported = adapterTargets().map((t) => t.id).join(", ");
23809
+ const supported = known.filter((t) => t.instructions !== void 0).map((t) => t.id).join(", ");
23810
+ const warn2 = warnings.length ? ` (descriptor warnings: ${warnings.join("; ")})` : "";
23566
23811
  throw new Error(
23567
- `Unsupported framework "${framework}". Supported: ${supported}`
23812
+ `Unsupported framework "${framework}". Supported: ${supported}.${warn2}`
23568
23813
  );
23569
23814
  }
23570
23815
  if (!options.project) {
@@ -23585,13 +23830,13 @@ async function setupAdapterCommand(framework, options) {
23585
23830
  }
23586
23831
  const config = await readConfig();
23587
23832
  const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
23588
- const projectDir = resolve46(baseDir, options.project);
23589
- const assignmentDir = resolve46(projectDir, "assignments", options.assignment);
23590
- const projectMdPath = resolve46(projectDir, "project.md");
23833
+ const projectDir = resolve47(baseDir, options.project);
23834
+ const assignmentDir = resolve47(projectDir, "assignments", options.assignment);
23835
+ const projectMdPath = resolve47(projectDir, "project.md");
23591
23836
  if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
23592
23837
  throw new Error(`Project "${options.project}" not found at ${projectDir}.`);
23593
23838
  }
23594
- const assignmentMdPath2 = resolve46(assignmentDir, "assignment.md");
23839
+ const assignmentMdPath2 = resolve47(assignmentDir, "assignment.md");
23595
23840
  if (!await fileExists(assignmentDir) || !await fileExists(assignmentMdPath2)) {
23596
23841
  throw new Error(
23597
23842
  `Assignment "${options.assignment}" not found at ${assignmentDir}.`
@@ -23608,7 +23853,7 @@ async function setupAdapterCommand(framework, options) {
23608
23853
  const upToDateFiles = [];
23609
23854
  const skippedFiles = [];
23610
23855
  for (const file of target.instructions.files) {
23611
- const filePath = resolve46(cwd, file.path);
23856
+ const filePath = resolve47(cwd, file.path);
23612
23857
  const content = RENDERERS[file.renderer](rendererParams);
23613
23858
  const status = await writeFileReport(filePath, content, {
23614
23859
  force: options.force
@@ -23647,6 +23892,33 @@ async function setupAdapterCommand(framework, options) {
23647
23892
  // src/commands/cross-agent-install.ts
23648
23893
  init_config2();
23649
23894
  var DEFAULT_SKILLS_SOURCE = "prong-horn/syntaur";
23895
+ async function installTier3Plugin(t, opts = {}) {
23896
+ if (!t.tier3) return "none";
23897
+ const plugin = t.tier3;
23898
+ const installDir = plugin.installDir();
23899
+ const prefix = opts.prefix ?? "";
23900
+ if (opts.dryRun) {
23901
+ console.log(`${prefix}Tier 3 (${t.id}): ${plugin.source} -> ${installDir}`);
23902
+ return "dry-run";
23903
+ }
23904
+ if (await fileExists(join9(installDir, plugin.entry)) && !opts.force) {
23905
+ console.log(
23906
+ `Tier 3 (${t.id}): already installed at ${installDir} (use --force to overwrite).`
23907
+ );
23908
+ return "already-present";
23909
+ }
23910
+ try {
23911
+ const sourceDir = resolve48(await findPackageRoot(plugin.source), plugin.source);
23912
+ await mkdir8(dirname17(installDir), { recursive: true });
23913
+ await cp4(sourceDir, installDir, { recursive: true, force: true });
23914
+ console.log(`Tier 3 (${t.id}): installed ${plugin.kind} -> ${installDir}`);
23915
+ return "installed";
23916
+ } catch (err2) {
23917
+ const msg2 = err2 instanceof Error ? err2.message : String(err2);
23918
+ console.log(`Tier 3 for ${t.id} FAILED: ${msg2}`);
23919
+ return "failed";
23920
+ }
23921
+ }
23650
23922
  function parseTargetIds(options) {
23651
23923
  const raw2 = [options.target, options.agent].filter(Boolean).join(",");
23652
23924
  const ids = raw2.split(",").map((s) => s.trim()).filter(Boolean);
@@ -23661,10 +23933,10 @@ function isNpxAvailable() {
23661
23933
  }
23662
23934
  }
23663
23935
  async function readAssignmentContext() {
23664
- const p = resolve47(process.cwd(), ".syntaur", "context.json");
23936
+ const p = resolve48(process.cwd(), ".syntaur", "context.json");
23665
23937
  if (!await fileExists(p)) return null;
23666
23938
  try {
23667
- return JSON.parse(await readFile31(p, "utf-8"));
23939
+ return JSON.parse(await readFile32(p, "utf-8"));
23668
23940
  } catch {
23669
23941
  return null;
23670
23942
  }
@@ -23674,12 +23946,15 @@ async function crossAgentInstallCommand(options) {
23674
23946
  if (ids.length === 0) {
23675
23947
  throw new Error("No agents specified. Use --target <id> or --agent <id>.");
23676
23948
  }
23949
+ const { targets: known, warnings } = await resolveAgentTargets();
23950
+ for (const w of warnings) console.log(`Warning (user target): ${w}`);
23951
+ const byId = new Map(known.map((t) => [t.id, t]));
23677
23952
  const targets = [];
23678
23953
  for (const id of ids) {
23679
- const t = getAgentTarget(id);
23954
+ const t = byId.get(id);
23680
23955
  if (!t) {
23681
23956
  throw new Error(
23682
- `Unknown agent "${id}". Known agents: ${agentTargetIds().join(", ")}`
23957
+ `Unknown agent "${id}". Known agents: ${known.map((k) => k.id).join(", ")}`
23683
23958
  );
23684
23959
  }
23685
23960
  if (t.nativePlugin) {
@@ -23713,8 +23988,15 @@ async function crossAgentInstallCommand(options) {
23713
23988
  }
23714
23989
  for (const t of targets) {
23715
23990
  const globalDir = t.id === "hermes" ? hermesSkillsDir() : t.skillsDir?.global;
23716
- if (!globalDir) continue;
23717
23991
  const offlineNeeded = !tier1Done;
23992
+ if (!globalDir) {
23993
+ if (offlineNeeded && !dryRun) {
23994
+ console.log(
23995
+ `Warning: skills NOT installed for ${t.displayName} \u2014 Tier-1 (npx skills add) was unavailable/failed and the descriptor has no skillsDir.global for an offline copy.`
23996
+ );
23997
+ }
23998
+ continue;
23999
+ }
23718
24000
  const hermesCustom = t.id === "hermes" && isHermesHomeCustom();
23719
24001
  if (!offlineNeeded && !hermesCustom) continue;
23720
24002
  if (dryRun) {
@@ -23726,15 +24008,15 @@ async function crossAgentInstallCommand(options) {
23726
24008
  await installSkillsToDir({ targetDir: globalDir, force });
23727
24009
  console.log(`Copied skills -> ${globalDir}${reason}`);
23728
24010
  }
23729
- const adapterTargets2 = targets.filter((t) => t.instructions);
23730
- if (adapterTargets2.length > 0) {
24011
+ const adapterTargets = targets.filter((t) => t.instructions);
24012
+ if (adapterTargets.length > 0) {
23731
24013
  const ctx = await readAssignmentContext();
23732
24014
  const haveCtx = Boolean(ctx?.projectSlug && ctx?.assignmentSlug);
23733
- for (const t of adapterTargets2) {
24015
+ for (const t of adapterTargets) {
23734
24016
  if (dryRun) {
23735
24017
  for (const f of t.instructions.files) {
23736
24018
  console.log(
23737
- `${prefix}Tier 2 (${t.id}): ${resolve47(process.cwd(), f.path)}`
24019
+ `${prefix}Tier 2 (${t.id}): ${resolve48(process.cwd(), f.path)}`
23738
24020
  );
23739
24021
  }
23740
24022
  continue;
@@ -23752,11 +24034,21 @@ async function crossAgentInstallCommand(options) {
23752
24034
  force
23753
24035
  });
23754
24036
  } catch (err2) {
23755
- const msg = err2 instanceof Error ? err2.message : String(err2);
23756
- console.log(`Tier 2 for ${t.id} skipped: ${msg}`);
24037
+ const msg2 = err2 instanceof Error ? err2.message : String(err2);
24038
+ console.log(`Tier 2 for ${t.id} skipped: ${msg2}`);
23757
24039
  }
23758
24040
  }
23759
24041
  }
24042
+ const tier3Failures = [];
24043
+ for (const t of targets.filter((x) => x.tier3)) {
24044
+ const result = await installTier3Plugin(t, { dryRun, force, prefix });
24045
+ if (result === "failed") tier3Failures.push(t.displayName);
24046
+ }
24047
+ if (tier3Failures.length > 0) {
24048
+ throw new Error(
24049
+ `Tier-3 enforcement plugin failed to install for: ${tier3Failures.join(", ")}. Enforcement is NOT active for ${tier3Failures.length > 1 ? "those agents" : "that agent"} \u2014 check permissions and re-run \`syntaur setup --target <id> --force\`.`
24050
+ );
24051
+ }
23760
24052
  if (!dryRun) {
23761
24053
  const current = (await readConfig()).integrations.installedAgents ?? {};
23762
24054
  const next = { ...current };
@@ -23881,7 +24173,7 @@ async function setupCommand(options) {
23881
24173
  }
23882
24174
 
23883
24175
  // src/commands/uninstall.ts
23884
- import { resolve as resolve48 } from "path";
24176
+ import { resolve as resolve49 } from "path";
23885
24177
  init_paths();
23886
24178
  function expandTargets(options) {
23887
24179
  if (options.all) {
@@ -23961,7 +24253,7 @@ async function uninstallCommand(options) {
23961
24253
  const configuredProjectDir = await getConfiguredProjectDir();
23962
24254
  await removeSyntaurData();
23963
24255
  console.log(`Removed ${syntaurRoot()}`);
23964
- if (configuredProjectDir && resolve48(configuredProjectDir) !== resolve48(syntaurRoot(), "projects")) {
24256
+ if (configuredProjectDir && resolve49(configuredProjectDir) !== resolve49(syntaurRoot(), "projects")) {
23965
24257
  console.warn(
23966
24258
  `Warning: config.md pointed to an external project directory (${configuredProjectDir}). That directory was not removed automatically.`
23967
24259
  );
@@ -23976,7 +24268,7 @@ async function uninstallCommand(options) {
23976
24268
  init_paths();
23977
24269
  init_fs();
23978
24270
  init_config2();
23979
- import { resolve as resolve49 } from "path";
24271
+ import { resolve as resolve50 } from "path";
23980
24272
  init_git_worktree();
23981
24273
  init_cwd();
23982
24274
  init_session_db();
@@ -23993,7 +24285,7 @@ async function trackSessionCommand(options) {
23993
24285
  if (options.project) {
23994
24286
  const config = await readConfig();
23995
24287
  const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
23996
- const projectDir = resolve49(baseDir, options.project);
24288
+ const projectDir = resolve50(baseDir, options.project);
23997
24289
  if (!await fileExists(projectDir)) {
23998
24290
  throw new Error(
23999
24291
  `Project "${options.project}" not found at ${projectDir}.`
@@ -24127,8 +24419,8 @@ function formatInstallUrlHandlerError(err2) {
24127
24419
  init_config2();
24128
24420
  init_paths();
24129
24421
  init_fs();
24130
- import { resolve as resolve51, isAbsolute as isAbsolute8 } from "path";
24131
- import { readFile as readFile32 } from "fs/promises";
24422
+ import { resolve as resolve52, isAbsolute as isAbsolute8 } from "path";
24423
+ import { readFile as readFile33 } from "fs/promises";
24132
24424
  import { select, confirm as confirm2, input as input3 } from "@inquirer/prompts";
24133
24425
  async function browseCommand(options) {
24134
24426
  const config = await readConfig();
@@ -24197,7 +24489,7 @@ async function pickAgent2(agents) {
24197
24489
  return picked;
24198
24490
  }
24199
24491
  async function ensureWorktree(opts) {
24200
- const assignmentPath = resolve51(
24492
+ const assignmentPath = resolve52(
24201
24493
  opts.projectsDir,
24202
24494
  opts.projectSlug,
24203
24495
  "assignments",
@@ -24207,7 +24499,7 @@ async function ensureWorktree(opts) {
24207
24499
  if (!await fileExists(assignmentPath)) {
24208
24500
  return void 0;
24209
24501
  }
24210
- const content = await readFile32(assignmentPath, "utf-8");
24502
+ const content = await readFile33(assignmentPath, "utf-8");
24211
24503
  const { parseAssignmentFrontmatter: parseAssignmentFrontmatter2 } = await Promise.resolve().then(() => (init_frontmatter(), frontmatter_exports));
24212
24504
  const fm = parseAssignmentFrontmatter2(content);
24213
24505
  const { workspace } = fm;
@@ -24277,7 +24569,7 @@ async function ensureWorktree(opts) {
24277
24569
  async function runCreate(opts) {
24278
24570
  const { createWorktreeAndRecord: createWorktreeAndRecord2, GitWorktreeError: GitWorktreeError2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
24279
24571
  const expandedWorktree = expandHome(opts.worktreePath);
24280
- const absWorktree = isAbsolute8(expandedWorktree) ? expandedWorktree : resolve51(expandedWorktree);
24572
+ const absWorktree = isAbsolute8(expandedWorktree) ? expandedWorktree : resolve52(expandedWorktree);
24281
24573
  try {
24282
24574
  await createWorktreeAndRecord2({
24283
24575
  assignmentPath: opts.assignmentPath,
@@ -24289,11 +24581,11 @@ async function runCreate(opts) {
24289
24581
  console.log(`syntaur: created worktree at ${absWorktree} on branch ${opts.branch}`);
24290
24582
  return absWorktree;
24291
24583
  } catch (err2) {
24292
- const msg = err2 instanceof Error ? err2.message : String(err2);
24584
+ const msg2 = err2 instanceof Error ? err2.message : String(err2);
24293
24585
  if (err2 instanceof GitWorktreeError2) {
24294
- console.error(`syntaur: ${msg}`);
24586
+ console.error(`syntaur: ${msg2}`);
24295
24587
  } else {
24296
- console.error(`syntaur: ${msg}`);
24588
+ console.error(`syntaur: ${msg2}`);
24297
24589
  }
24298
24590
  process.exit(1);
24299
24591
  }
@@ -24306,7 +24598,7 @@ init_paths();
24306
24598
  init_fs();
24307
24599
  init_playbook();
24308
24600
  init_playbooks();
24309
- import { resolve as resolve52 } from "path";
24601
+ import { resolve as resolve53 } from "path";
24310
24602
  async function createPlaybookCommand(name, options) {
24311
24603
  if (!name.trim()) {
24312
24604
  throw new Error("Playbook name cannot be empty.");
@@ -24319,7 +24611,7 @@ async function createPlaybookCommand(name, options) {
24319
24611
  }
24320
24612
  const dir = playbooksDir();
24321
24613
  await ensureDir(dir);
24322
- const filePath = resolve52(dir, `${slug}.md`);
24614
+ const filePath = resolve53(dir, `${slug}.md`);
24323
24615
  if (await fileExists(filePath)) {
24324
24616
  throw new Error(
24325
24617
  `Playbook "${slug}" already exists at ${filePath}
@@ -24341,8 +24633,8 @@ init_paths();
24341
24633
  init_fs();
24342
24634
  init_parser();
24343
24635
  init_config2();
24344
- import { readdir as readdir17, readFile as readFile33 } from "fs/promises";
24345
- import { resolve as resolve53 } from "path";
24636
+ import { readdir as readdir18, readFile as readFile34 } from "fs/promises";
24637
+ import { resolve as resolve54 } from "path";
24346
24638
  async function listPlaybooksCommand(options = {}) {
24347
24639
  const dir = playbooksDir();
24348
24640
  if (!await fileExists(dir)) {
@@ -24351,14 +24643,14 @@ async function listPlaybooksCommand(options = {}) {
24351
24643
  }
24352
24644
  const config = await readConfig();
24353
24645
  const disabledSet = new Set(config.playbooks.disabled);
24354
- const entries = await readdir17(dir, { withFileTypes: true });
24646
+ const entries = await readdir18(dir, { withFileTypes: true });
24355
24647
  const mdFiles = entries.filter(
24356
24648
  (e) => e.isFile() && e.name.endsWith(".md") && !e.name.startsWith("_") && e.name !== "manifest.md"
24357
24649
  );
24358
24650
  const rows = [];
24359
24651
  for (const entry of mdFiles) {
24360
- const filePath = resolve53(dir, entry.name);
24361
- const raw2 = await readFile33(filePath, "utf-8");
24652
+ const filePath = resolve54(dir, entry.name);
24653
+ const raw2 = await readFile34(filePath, "utf-8");
24362
24654
  const parsed = parsePlaybook(raw2);
24363
24655
  const slug = parsed.slug || entry.name.replace(/\.md$/, "");
24364
24656
  const disabled = disabledSet.has(slug);
@@ -24481,14 +24773,14 @@ init_fs();
24481
24773
  init_config2();
24482
24774
  init_slug();
24483
24775
  import { Command as Command2 } from "commander";
24484
- import { readFile as readFile35 } from "fs/promises";
24485
- import { resolve as resolve55 } from "path";
24776
+ import { readFile as readFile36 } from "fs/promises";
24777
+ import { resolve as resolve56 } from "path";
24486
24778
 
24487
24779
  // src/commands/bundle.ts
24488
24780
  init_paths();
24489
24781
  import { Command } from "commander";
24490
- import { mkdir as mkdir8, readFile as readFile34, readdir as readdir18, rm as rm8, writeFile as writeFile13 } from "fs/promises";
24491
- import { resolve as resolve54 } from "path";
24782
+ import { mkdir as mkdir9, readFile as readFile35, readdir as readdir19, rm as rm8, writeFile as writeFile13 } from "fs/promises";
24783
+ import { resolve as resolve55 } from "path";
24492
24784
  init_parser2();
24493
24785
  init_fs();
24494
24786
  init_config2();
@@ -24506,7 +24798,7 @@ async function resolveBundleScope(options) {
24506
24798
  throw new Error(`Invalid project slug: "${options.project}".`);
24507
24799
  }
24508
24800
  const config = await readConfig();
24509
- const projectMd = resolve54(config.defaultProjectDir, options.project, "project.md");
24801
+ const projectMd = resolve55(config.defaultProjectDir, options.project, "project.md");
24510
24802
  if (!await fileExists(projectMd)) {
24511
24803
  throw new Error(`Project "${options.project}" not found.`);
24512
24804
  }
@@ -24576,10 +24868,10 @@ function pickNextPlanFile(planDir, existingFiles) {
24576
24868
  const m = f.match(/^plan-v(\d+)\.md$/);
24577
24869
  if (m) versions.add(parseInt(m[1], 10));
24578
24870
  }
24579
- if (versions.size === 0) return { target: resolve54(planDir, "plan.md"), version: 1 };
24871
+ if (versions.size === 0) return { target: resolve55(planDir, "plan.md"), version: 1 };
24580
24872
  let n = 2;
24581
24873
  while (versions.has(n)) n++;
24582
- return { target: resolve54(planDir, `plan-v${n}.md`), version: n };
24874
+ return { target: resolve55(planDir, `plan-v${n}.md`), version: n };
24583
24875
  }
24584
24876
  function dedupePreserveOrder(ids) {
24585
24877
  const out = [];
@@ -24663,7 +24955,7 @@ bundleCommand.command("new").description("Create a new bundle from 2+ existing t
24663
24955
  if (options.plan) {
24664
24956
  const planDir = bundlePlanDir(sc.todosPath, sc.scopeId, id);
24665
24957
  await ensureDir(planDir);
24666
- const target = resolve54(planDir, "plan.md");
24958
+ const target = resolve55(planDir, "plan.md");
24667
24959
  const memberLines = items.map((it) => `- ${it.description} [t:${it.id}]`).join("\n");
24668
24960
  const stub = [
24669
24961
  "---",
@@ -24780,7 +25072,7 @@ bundleCommand.command("plan").description("Create or open the bundle's shared pl
24780
25072
  }
24781
25073
  const planDir = bundlePlanDir(sc.todosPath, sc.scopeId, id);
24782
25074
  await ensureDir(planDir);
24783
- const existing = (await readdir18(planDir).catch(() => [])).filter((f) => /^plan(?:-v\d+)?\.md$/.test(f));
25075
+ const existing = (await readdir19(planDir).catch(() => [])).filter((f) => /^plan(?:-v\d+)?\.md$/.test(f));
24784
25076
  const { target } = pickNextPlanFile(planDir, existing);
24785
25077
  const checklist = await readChecklist(sc.todosPath, sc.checklistKey);
24786
25078
  if (!await fileExists(target)) {
@@ -24839,7 +25131,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
24839
25131
  }
24840
25132
  const repository = options.repository ?? process.cwd();
24841
25133
  const parentBranch = options.parentBranch ?? "main";
24842
- const worktreePath = options.worktreePath ?? resolve54(repository, ".worktrees", options.branch);
25134
+ const worktreePath = options.worktreePath ?? resolve55(repository, ".worktrees", options.branch);
24843
25135
  const checklist = await readChecklist(sc.todosPath, sc.checklistKey);
24844
25136
  for (const memberId of bundle.todoIds) {
24845
25137
  const item = checklist.items.find((i) => i.id === memberId);
@@ -24849,8 +25141,8 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
24849
25141
  }
24850
25142
  const bundlesFilePath = bundlesPath(sc.todosPath);
24851
25143
  const checklistFilePath = checklistPath(sc.todosPath, sc.checklistKey);
24852
- const bundlesSnapshot = await fileExists(bundlesFilePath) ? await readFile34(bundlesFilePath, "utf-8") : null;
24853
- const checklistSnapshot = await fileExists(checklistFilePath) ? await readFile34(checklistFilePath, "utf-8") : null;
25144
+ const bundlesSnapshot = await fileExists(bundlesFilePath) ? await readFile35(bundlesFilePath, "utf-8") : null;
25145
+ const checklistSnapshot = await fileExists(checklistFilePath) ? await readFile35(checklistFilePath, "utf-8") : null;
24854
25146
  const record = async () => {
24855
25147
  bundle.branch = options.branch;
24856
25148
  bundle.worktreePath = worktreePath;
@@ -24866,8 +25158,8 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
24866
25158
  try {
24867
25159
  await writeBundles(sc.todosPath, bundles);
24868
25160
  await writeChecklist(sc.todosPath, checklist);
24869
- const ctxDir = resolve54(worktreePath, ".syntaur");
24870
- await mkdir8(ctxDir, { recursive: true });
25161
+ const ctxDir = resolve55(worktreePath, ".syntaur");
25162
+ await mkdir9(ctxDir, { recursive: true });
24871
25163
  const payload = {
24872
25164
  bundleId: bundle.id,
24873
25165
  bundleSlug: bundle.slug,
@@ -24880,7 +25172,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
24880
25172
  repository,
24881
25173
  boundAt: nowISO()
24882
25174
  };
24883
- await writeFile13(resolve54(ctxDir, "context.json"), JSON.stringify(payload, null, 2) + "\n");
25175
+ await writeFile13(resolve55(ctxDir, "context.json"), JSON.stringify(payload, null, 2) + "\n");
24884
25176
  } catch (err2) {
24885
25177
  try {
24886
25178
  if (bundlesSnapshot === null) {
@@ -25070,7 +25362,7 @@ async function resolveScope(options) {
25070
25362
  throw new Error(`Invalid project slug: "${options.project}".`);
25071
25363
  }
25072
25364
  const config = await readConfig();
25073
- const projectMd = resolve55(config.defaultProjectDir, options.project, "project.md");
25365
+ const projectMd = resolve56(config.defaultProjectDir, options.project, "project.md");
25074
25366
  if (!await fileExists(projectMd)) {
25075
25367
  throw new Error(`Project "${options.project}" not found.`);
25076
25368
  }
@@ -25393,10 +25685,10 @@ todoCommand.command("archive").description("Archive completed todos and their lo
25393
25685
  (e) => e.itemIds.every((id) => completedIds.has(id))
25394
25686
  );
25395
25687
  const archFile = archivePath(todosPath, workspace, checklist.archiveInterval);
25396
- await ensureDir(resolve55(todosPath, "archive"));
25688
+ await ensureDir(resolve56(todosPath, "archive"));
25397
25689
  let archContent = "";
25398
25690
  if (await fileExists(archFile)) {
25399
- archContent = await readFile35(archFile, "utf-8");
25691
+ archContent = await readFile36(archFile, "utf-8");
25400
25692
  archContent = archContent.trimEnd() + "\n\n";
25401
25693
  } else {
25402
25694
  archContent = `---
@@ -25573,12 +25865,12 @@ function describeScope(scope) {
25573
25865
  }
25574
25866
  async function injectPromotedTodos(assignmentDir, todos, scopeLabel) {
25575
25867
  const { resolve: resolvePath2 } = await import("path");
25576
- const { readFile: readFile63 } = await import("fs/promises");
25868
+ const { readFile: readFile64 } = await import("fs/promises");
25577
25869
  const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
25578
25870
  const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
25579
25871
  const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
25580
25872
  const assignmentMdPath2 = resolvePath2(assignmentDir, "assignment.md");
25581
- let content = await readFile63(assignmentMdPath2, "utf-8");
25873
+ let content = await readFile64(assignmentMdPath2, "utf-8");
25582
25874
  content = appendTodosToAssignmentBody2(
25583
25875
  content,
25584
25876
  todos.map((t) => ({
@@ -25623,13 +25915,13 @@ todoCommand.command("plan").description("Create or open a plan directory for a t
25623
25915
  }
25624
25916
  const planDir = todoPlanDir(todosPath, workspace, id);
25625
25917
  await ensureDir(planDir);
25626
- const { readdir: readdir32 } = await import("fs/promises");
25627
- const existingFiles = (await readdir32(planDir).catch(() => [])).filter(
25918
+ const { readdir: readdir33 } = await import("fs/promises");
25919
+ const existingFiles = (await readdir33(planDir).catch(() => [])).filter(
25628
25920
  (f) => /^plan(?:-v\d+)?\.md$/.test(f)
25629
25921
  );
25630
25922
  let target;
25631
25923
  if (existingFiles.length === 0) {
25632
- target = resolve55(planDir, "plan.md");
25924
+ target = resolve56(planDir, "plan.md");
25633
25925
  } else {
25634
25926
  const versions = /* @__PURE__ */ new Set();
25635
25927
  for (const f of existingFiles) {
@@ -25639,7 +25931,7 @@ todoCommand.command("plan").description("Create or open a plan directory for a t
25639
25931
  }
25640
25932
  let n = 2;
25641
25933
  while (versions.has(n)) n++;
25642
- target = resolve55(planDir, `plan-v${n}.md`);
25934
+ target = resolve56(planDir, `plan-v${n}.md`);
25643
25935
  }
25644
25936
  if (!await fileExists(target)) {
25645
25937
  const stub = `---
@@ -25709,9 +26001,9 @@ async function moveTodo(id, options) {
25709
26001
  if (await fileExists(newPlanDir)) {
25710
26002
  throw new Error(`Plan directory already exists at target: ${newPlanDir}; refusing to move.`);
25711
26003
  }
25712
- const { rename: rename11, mkdir: mkdir11 } = await import("fs/promises");
25713
- const { dirname: dirname23 } = await import("path");
25714
- await mkdir11(dirname23(newPlanDir), { recursive: true });
26004
+ const { rename: rename11, mkdir: mkdir12 } = await import("fs/promises");
26005
+ const { dirname: dirname24 } = await import("path");
26006
+ await mkdir12(dirname24(newPlanDir), { recursive: true });
25715
26007
  await rename11(item.planDir, newPlanDir);
25716
26008
  item.planDir = newPlanDir;
25717
26009
  }
@@ -25828,24 +26120,24 @@ backupCommand.command("config").description("Show or update backup configuration
25828
26120
 
25829
26121
  // src/commands/doctor.ts
25830
26122
  import { Command as Command4 } from "commander";
25831
- import { readFile as readFile45 } from "fs/promises";
25832
- import { isAbsolute as isAbsolute11, resolve as resolve68 } from "path";
26123
+ import { readFile as readFile46 } from "fs/promises";
26124
+ import { isAbsolute as isAbsolute11, resolve as resolve69 } from "path";
25833
26125
 
25834
26126
  // src/utils/doctor/index.ts
25835
26127
  import { fileURLToPath as fileURLToPath11 } from "url";
25836
- import { readFile as readFile44 } from "fs/promises";
25837
- import { dirname as dirname20, join as join13 } from "path";
26128
+ import { readFile as readFile45 } from "fs/promises";
26129
+ import { dirname as dirname21, join as join14 } from "path";
25838
26130
 
25839
26131
  // src/utils/doctor/context.ts
25840
26132
  init_config2();
25841
26133
  init_paths();
25842
26134
  init_fs();
25843
26135
  import Database4 from "better-sqlite3";
25844
- import { resolve as resolve56 } from "path";
26136
+ import { resolve as resolve57 } from "path";
25845
26137
  async function buildCheckContext(cwd = process.cwd()) {
25846
26138
  const config = await readConfig();
25847
26139
  const root = syntaurRoot();
25848
- const dbPath = resolve56(root, "syntaur.db");
26140
+ const dbPath = resolve57(root, "syntaur.db");
25849
26141
  let db5 = null;
25850
26142
  let dbError = null;
25851
26143
  if (await fileExists(dbPath)) {
@@ -25879,10 +26171,10 @@ function closeCheckContext(ctx) {
25879
26171
  // src/utils/doctor/checks/env.ts
25880
26172
  init_fs();
25881
26173
  init_paths();
25882
- import { resolve as resolve57, isAbsolute as isAbsolute9 } from "path";
25883
- import { readFile as readFile36, stat as stat4 } from "fs/promises";
26174
+ import { resolve as resolve58, isAbsolute as isAbsolute9 } from "path";
26175
+ import { readFile as readFile37, stat as stat4 } from "fs/promises";
25884
26176
  import { fileURLToPath as fileURLToPath10 } from "url";
25885
- import { dirname as dirname18, join as join10 } from "path";
26177
+ import { dirname as dirname19, join as join11 } from "path";
25886
26178
  var CATEGORY = "env";
25887
26179
  var syntaurRootExists = {
25888
26180
  id: "env.syntaur-root-exists",
@@ -25920,7 +26212,7 @@ var configValid = {
25920
26212
  category: CATEGORY,
25921
26213
  title: "~/.syntaur/config.md is valid",
25922
26214
  async run(ctx) {
25923
- const configPath2 = resolve57(ctx.syntaurRoot, "config.md");
26215
+ const configPath2 = resolve58(ctx.syntaurRoot, "config.md");
25924
26216
  if (!await fileExists(configPath2)) {
25925
26217
  return {
25926
26218
  id: this.id,
@@ -25937,7 +26229,7 @@ var configValid = {
25937
26229
  autoFixable: false
25938
26230
  };
25939
26231
  }
25940
- const content = await readFile36(configPath2, "utf-8");
26232
+ const content = await readFile37(configPath2, "utf-8");
25941
26233
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
25942
26234
  if (!fmMatch || fmMatch[1].trim() === "") {
25943
26235
  return {
@@ -26213,14 +26505,14 @@ async function readLocalVersion() {
26213
26505
  async function readLocalPkg() {
26214
26506
  try {
26215
26507
  const here = fileURLToPath10(import.meta.url);
26216
- let dir = dirname18(here);
26508
+ let dir = dirname19(here);
26217
26509
  for (let i = 0; i < 6; i++) {
26218
- const candidate = join10(dir, "package.json");
26510
+ const candidate = join11(dir, "package.json");
26219
26511
  try {
26220
- const text = await readFile36(candidate, "utf-8");
26512
+ const text = await readFile37(candidate, "utf-8");
26221
26513
  return JSON.parse(text);
26222
26514
  } catch {
26223
- dir = dirname18(dir);
26515
+ dir = dirname19(dir);
26224
26516
  }
26225
26517
  }
26226
26518
  return null;
@@ -26269,8 +26561,8 @@ function versionGte(a, b) {
26269
26561
 
26270
26562
  // src/utils/doctor/checks/structure.ts
26271
26563
  init_fs();
26272
- import { resolve as resolve58 } from "path";
26273
- import { readdir as readdir19, stat as stat5 } from "fs/promises";
26564
+ import { resolve as resolve59 } from "path";
26565
+ import { readdir as readdir20, stat as stat5 } from "fs/promises";
26274
26566
  var CATEGORY2 = "structure";
26275
26567
  var KNOWN_TOP_LEVEL = /* @__PURE__ */ new Set([
26276
26568
  "projects",
@@ -26289,7 +26581,7 @@ var projectsDir = {
26289
26581
  category: CATEGORY2,
26290
26582
  title: "projects/ directory exists",
26291
26583
  async run(ctx) {
26292
- const p = resolve58(ctx.syntaurRoot, "projects");
26584
+ const p = resolve59(ctx.syntaurRoot, "projects");
26293
26585
  if (!await fileExists(p)) {
26294
26586
  return {
26295
26587
  id: this.id,
@@ -26314,7 +26606,7 @@ var playbooksDir2 = {
26314
26606
  category: CATEGORY2,
26315
26607
  title: "playbooks/ directory exists",
26316
26608
  async run(ctx) {
26317
- const p = resolve58(ctx.syntaurRoot, "playbooks");
26609
+ const p = resolve59(ctx.syntaurRoot, "playbooks");
26318
26610
  if (!await fileExists(p)) {
26319
26611
  return {
26320
26612
  id: this.id,
@@ -26339,7 +26631,7 @@ var todosDirValid = {
26339
26631
  category: CATEGORY2,
26340
26632
  title: "todos/ directory is readable (if present)",
26341
26633
  async run(ctx) {
26342
- const p = resolve58(ctx.syntaurRoot, "todos");
26634
+ const p = resolve59(ctx.syntaurRoot, "todos");
26343
26635
  if (!await fileExists(p)) {
26344
26636
  return {
26345
26637
  id: this.id,
@@ -26370,7 +26662,7 @@ var serversDirValid = {
26370
26662
  category: CATEGORY2,
26371
26663
  title: "servers/ directory is readable (if present)",
26372
26664
  async run(ctx) {
26373
- const p = resolve58(ctx.syntaurRoot, "servers");
26665
+ const p = resolve59(ctx.syntaurRoot, "servers");
26374
26666
  if (!await fileExists(p)) {
26375
26667
  return {
26376
26668
  id: this.id,
@@ -26401,7 +26693,7 @@ var knownFilesRecognized = {
26401
26693
  category: CATEGORY2,
26402
26694
  title: "No unexpected top-level entries under ~/.syntaur/",
26403
26695
  async run(ctx) {
26404
- const entries = await readdir19(ctx.syntaurRoot, { withFileTypes: true });
26696
+ const entries = await readdir20(ctx.syntaurRoot, { withFileTypes: true });
26405
26697
  const unexpected = [];
26406
26698
  for (const e of entries) {
26407
26699
  if (e.name.startsWith(".")) continue;
@@ -26415,7 +26707,7 @@ var knownFilesRecognized = {
26415
26707
  title: this.title,
26416
26708
  status: "warn",
26417
26709
  detail: `unexpected top-level entries: ${unexpected.join(", ")}`,
26418
- affected: unexpected.map((n) => resolve58(ctx.syntaurRoot, n)),
26710
+ affected: unexpected.map((n) => resolve59(ctx.syntaurRoot, n)),
26419
26711
  remediation: {
26420
26712
  kind: "manual",
26421
26713
  suggestion: "Review these entries \u2014 they may be leftover state from older versions",
@@ -26444,8 +26736,8 @@ function pass2(check) {
26444
26736
 
26445
26737
  // src/utils/doctor/checks/project.ts
26446
26738
  init_fs();
26447
- import { resolve as resolve59 } from "path";
26448
- import { readdir as readdir20, stat as stat6 } from "fs/promises";
26739
+ import { resolve as resolve60 } from "path";
26740
+ import { readdir as readdir21, stat as stat6 } from "fs/promises";
26449
26741
  var CATEGORY3 = "project";
26450
26742
  var REQUIRED_PROJECT_FILES = [
26451
26743
  "project.md",
@@ -26469,15 +26761,15 @@ var PROJECT_MARKERS = ["project.md", "manifest.md", "assignments"];
26469
26761
  async function listProjects2(ctx) {
26470
26762
  const dir = ctx.config.defaultProjectDir;
26471
26763
  if (!await fileExists(dir)) return [];
26472
- const entries = await readdir20(dir, { withFileTypes: true });
26764
+ const entries = await readdir21(dir, { withFileTypes: true });
26473
26765
  const result = [];
26474
26766
  for (const e of entries) {
26475
26767
  if (!e.isDirectory()) continue;
26476
26768
  if (e.name.startsWith(".") || e.name.startsWith("_")) continue;
26477
- const projectDir = resolve59(dir, e.name);
26769
+ const projectDir = resolve60(dir, e.name);
26478
26770
  let looksLikeProject = false;
26479
26771
  for (const marker of PROJECT_MARKERS) {
26480
- if (await fileExists(resolve59(projectDir, marker))) {
26772
+ if (await fileExists(resolve60(projectDir, marker))) {
26481
26773
  looksLikeProject = true;
26482
26774
  break;
26483
26775
  }
@@ -26496,7 +26788,7 @@ var requiredFiles = {
26496
26788
  for (const projectDir of projects) {
26497
26789
  const missing = [];
26498
26790
  for (const rel of REQUIRED_PROJECT_FILES) {
26499
- const p = resolve59(projectDir, rel);
26791
+ const p = resolve60(projectDir, rel);
26500
26792
  if (!await fileExists(p)) missing.push(rel);
26501
26793
  }
26502
26794
  if (missing.length === 0) continue;
@@ -26506,7 +26798,7 @@ var requiredFiles = {
26506
26798
  title: this.title,
26507
26799
  status: "error",
26508
26800
  detail: `project at ${projectDir} is missing: ${missing.join(", ")}`,
26509
- affected: missing.map((m) => resolve59(projectDir, m)),
26801
+ affected: missing.map((m) => resolve60(projectDir, m)),
26510
26802
  remediation: {
26511
26803
  kind: "manual",
26512
26804
  suggestion: "Recreate the missing scaffold files from templates",
@@ -26529,7 +26821,7 @@ var manifestStale = {
26529
26821
  const projects = await listProjects2(ctx);
26530
26822
  const results = [];
26531
26823
  for (const projectDir of projects) {
26532
- const manifestPath = resolve59(projectDir, "manifest.md");
26824
+ const manifestPath = resolve60(projectDir, "manifest.md");
26533
26825
  if (!await fileExists(manifestPath)) continue;
26534
26826
  const manifestMtime = (await stat6(manifestPath)).mtimeMs;
26535
26827
  const newestAssignment = await newestAssignmentMtime(projectDir);
@@ -26563,7 +26855,7 @@ var orphanFiles = {
26563
26855
  const projects = await listProjects2(ctx);
26564
26856
  const results = [];
26565
26857
  for (const projectDir of projects) {
26566
- const entries = await readdir20(projectDir, { withFileTypes: true });
26858
+ const entries = await readdir21(projectDir, { withFileTypes: true });
26567
26859
  const orphans = [];
26568
26860
  for (const e of entries) {
26569
26861
  if (e.name.startsWith(".")) continue;
@@ -26578,7 +26870,7 @@ var orphanFiles = {
26578
26870
  title: this.title,
26579
26871
  status: "warn",
26580
26872
  detail: `project at ${projectDir} has unexpected entries: ${orphans.join(", ")}`,
26581
- affected: orphans.map((o) => resolve59(projectDir, o)),
26873
+ affected: orphans.map((o) => resolve60(projectDir, o)),
26582
26874
  autoFixable: false
26583
26875
  });
26584
26876
  }
@@ -26588,18 +26880,18 @@ var orphanFiles = {
26588
26880
  };
26589
26881
  var projectChecks = [requiredFiles, manifestStale, orphanFiles];
26590
26882
  async function newestAssignmentMtime(projectDir) {
26591
- const assignmentsRoot = resolve59(projectDir, "assignments");
26883
+ const assignmentsRoot = resolve60(projectDir, "assignments");
26592
26884
  if (!await fileExists(assignmentsRoot)) return 0;
26593
26885
  let newest = 0;
26594
26886
  let entries;
26595
26887
  try {
26596
- entries = await readdir20(assignmentsRoot, { withFileTypes: true });
26888
+ entries = await readdir21(assignmentsRoot, { withFileTypes: true });
26597
26889
  } catch {
26598
26890
  return 0;
26599
26891
  }
26600
26892
  for (const e of entries) {
26601
26893
  if (!e.isDirectory()) continue;
26602
- const assignmentMd = resolve59(assignmentsRoot, e.name, "assignment.md");
26894
+ const assignmentMd = resolve60(assignmentsRoot, e.name, "assignment.md");
26603
26895
  try {
26604
26896
  const s = await stat6(assignmentMd);
26605
26897
  if (s.mtimeMs > newest) newest = s.mtimeMs;
@@ -26623,8 +26915,8 @@ init_fs();
26623
26915
  init_parser();
26624
26916
  init_types();
26625
26917
  init_paths();
26626
- import { resolve as resolve60 } from "path";
26627
- import { readFile as readFile37, readdir as readdir21 } from "fs/promises";
26918
+ import { resolve as resolve61 } from "path";
26919
+ import { readFile as readFile38, readdir as readdir22 } from "fs/promises";
26628
26920
  var CATEGORY4 = "assignment";
26629
26921
  var STATUSES_REQUIRING_HANDOFF = /* @__PURE__ */ new Set(["review", "completed"]);
26630
26922
  var PRE_WORKSPACE_STATUSES = /* @__PURE__ */ new Set([
@@ -26718,7 +27010,7 @@ var invalidStatus = {
26718
27010
  const allowed = configuredStatuses(ctx);
26719
27011
  const results = [];
26720
27012
  for (const a of withAssignmentMd) {
26721
- const path = resolve60(a.assignmentDir, "assignment.md");
27013
+ const path = resolve61(a.assignmentDir, "assignment.md");
26722
27014
  const parsed = await parseSafe2(path);
26723
27015
  if (!parsed) continue;
26724
27016
  if (!allowed.has(parsed.status)) {
@@ -26751,7 +27043,7 @@ var workspaceMissing = {
26751
27043
  const terminal = terminalStatuses(ctx);
26752
27044
  const results = [];
26753
27045
  for (const a of withAssignmentMd) {
26754
- const path = resolve60(a.assignmentDir, "assignment.md");
27046
+ const path = resolve61(a.assignmentDir, "assignment.md");
26755
27047
  const parsed = await parseSafe2(path);
26756
27048
  if (!parsed) continue;
26757
27049
  if (terminal.has(parsed.status)) continue;
@@ -26798,12 +27090,12 @@ var requiredFilesByStatus = {
26798
27090
  const { withAssignmentMd } = await listAssignments(ctx);
26799
27091
  const results = [];
26800
27092
  for (const a of withAssignmentMd) {
26801
- const assignmentPath = resolve60(a.assignmentDir, "assignment.md");
27093
+ const assignmentPath = resolve61(a.assignmentDir, "assignment.md");
26802
27094
  const parsed = await parseSafe2(assignmentPath);
26803
27095
  if (!parsed) continue;
26804
27096
  const missing = [];
26805
27097
  if (STATUSES_REQUIRING_HANDOFF.has(parsed.status)) {
26806
- const handoffPath = resolve60(a.assignmentDir, "handoff.md");
27098
+ const handoffPath = resolve61(a.assignmentDir, "handoff.md");
26807
27099
  if (!await fileExists(handoffPath)) missing.push("handoff.md");
26808
27100
  }
26809
27101
  if (missing.length === 0) continue;
@@ -26813,7 +27105,7 @@ var requiredFilesByStatus = {
26813
27105
  title: this.title,
26814
27106
  status: "warn",
26815
27107
  detail: `${a.projectSlug}/${a.assignmentSlug} (status: ${parsed.status}) is missing ${missing.join(", ")}`,
26816
- affected: missing.map((m) => resolve60(a.assignmentDir, m)),
27108
+ affected: missing.map((m) => resolve61(a.assignmentDir, m)),
26817
27109
  remediation: {
26818
27110
  kind: "manual",
26819
27111
  suggestion: `Create the missing ${missing.join(" and ")} files for this assignment`,
@@ -26836,7 +27128,7 @@ var companionFilesScaffolded = {
26836
27128
  for (const a of withAssignmentMd) {
26837
27129
  const missing = [];
26838
27130
  for (const filename of ["progress.md", "comments.md"]) {
26839
- if (!await fileExists(resolve60(a.assignmentDir, filename))) {
27131
+ if (!await fileExists(resolve61(a.assignmentDir, filename))) {
26840
27132
  missing.push(filename);
26841
27133
  }
26842
27134
  }
@@ -26848,7 +27140,7 @@ var companionFilesScaffolded = {
26848
27140
  title: this.title,
26849
27141
  status: "warn",
26850
27142
  detail: `${label} is missing ${missing.join(" and ")} (pre-v2.0 assignment \u2014 not required, but scaffolding them keeps the dashboard and CLIs consistent)`,
26851
- affected: missing.map((m) => resolve60(a.assignmentDir, m)),
27143
+ affected: missing.map((m) => resolve61(a.assignmentDir, m)),
26852
27144
  remediation: {
26853
27145
  kind: "manual",
26854
27146
  suggestion: `Create ${missing.join(" and ")} with the renderProgress/renderComments templates, or re-scaffold via the CLI`,
@@ -26881,7 +27173,7 @@ var typeDefinition = {
26881
27173
  const { withAssignmentMd } = await listAssignments(ctx);
26882
27174
  const results = [];
26883
27175
  for (const a of withAssignmentMd) {
26884
- const path = resolve60(a.assignmentDir, "assignment.md");
27176
+ const path = resolve61(a.assignmentDir, "assignment.md");
26885
27177
  const parsed = await parseSafe2(path);
26886
27178
  if (!parsed) continue;
26887
27179
  if (!parsed.type) continue;
@@ -26915,7 +27207,7 @@ var projectFrontmatterMatchesContainer = {
26915
27207
  const { withAssignmentMd } = await listAssignments(ctx);
26916
27208
  const results = [];
26917
27209
  for (const a of withAssignmentMd) {
26918
- const path = resolve60(a.assignmentDir, "assignment.md");
27210
+ const path = resolve61(a.assignmentDir, "assignment.md");
26919
27211
  const parsed = await parseSafe2(path);
26920
27212
  if (!parsed) continue;
26921
27213
  if (a.standalone) {
@@ -26966,13 +27258,13 @@ var draftMissingObjective = {
26966
27258
  const { withAssignmentMd } = await listAssignments(ctx);
26967
27259
  const results = [];
26968
27260
  for (const a of withAssignmentMd) {
26969
- const path = resolve60(a.assignmentDir, "assignment.md");
27261
+ const path = resolve61(a.assignmentDir, "assignment.md");
26970
27262
  const parsed = await parseSafe2(path);
26971
27263
  if (!parsed) continue;
26972
27264
  if (parsed.status !== "draft") continue;
26973
27265
  let raw2;
26974
27266
  try {
26975
- raw2 = await readFile37(path, "utf-8");
27267
+ raw2 = await readFile38(path, "utf-8");
26976
27268
  } catch {
26977
27269
  continue;
26978
27270
  }
@@ -27005,16 +27297,16 @@ var readyToImplementMissingPlan = {
27005
27297
  const { withAssignmentMd } = await listAssignments(ctx);
27006
27298
  const results = [];
27007
27299
  for (const a of withAssignmentMd) {
27008
- const path = resolve60(a.assignmentDir, "assignment.md");
27300
+ const path = resolve61(a.assignmentDir, "assignment.md");
27009
27301
  const parsed = await parseSafe2(path);
27010
27302
  if (!parsed) continue;
27011
27303
  if (parsed.status !== "ready_to_implement") continue;
27012
- const entries = await readdir21(a.assignmentDir).catch(() => []);
27304
+ const entries = await readdir22(a.assignmentDir).catch(() => []);
27013
27305
  const planFiles = entries.filter((f) => /^plan(?:-v\d+)?\.md$/i.test(f));
27014
27306
  let hasPlanContent = false;
27015
27307
  for (const f of planFiles) {
27016
27308
  try {
27017
- const c2 = await readFile37(resolve60(a.assignmentDir, f), "utf-8");
27309
+ const c2 = await readFile38(resolve61(a.assignmentDir, f), "utf-8");
27018
27310
  if (c2.trim().length > 0) {
27019
27311
  hasPlanContent = true;
27020
27312
  break;
@@ -27030,7 +27322,7 @@ var readyToImplementMissingPlan = {
27030
27322
  title: this.title,
27031
27323
  status: "warn",
27032
27324
  detail: `${label} (status: ready_to_implement) has no plan.md or plan-v<N>.md`,
27033
- affected: [resolve60(a.assignmentDir, "plan.md")],
27325
+ affected: [resolve61(a.assignmentDir, "plan.md")],
27034
27326
  remediation: {
27035
27327
  kind: "manual",
27036
27328
  suggestion: `Write a plan with '/plan-assignment' (or 'syntaur plan'), then re-mark ready_to_implement`,
@@ -27057,7 +27349,7 @@ var assignmentChecks = [
27057
27349
  ];
27058
27350
  async function parseSafe2(path) {
27059
27351
  try {
27060
- const content = await readFile37(path, "utf-8");
27352
+ const content = await readFile38(path, "utf-8");
27061
27353
  return parseAssignmentFull(content);
27062
27354
  } catch {
27063
27355
  return null;
@@ -27076,7 +27368,7 @@ function pass4(check, detail) {
27076
27368
 
27077
27369
  // src/utils/doctor/checks/dashboard.ts
27078
27370
  init_fs();
27079
- import { resolve as resolve61 } from "path";
27371
+ import { resolve as resolve62 } from "path";
27080
27372
  var CATEGORY5 = "dashboard";
27081
27373
  var dbReachable = {
27082
27374
  id: "dashboard.db-reachable",
@@ -27090,7 +27382,7 @@ var dbReachable = {
27090
27382
  title: this.title,
27091
27383
  status: "error",
27092
27384
  detail: `could not open syntaur.db: ${ctx.dbError ?? "unknown error"}`,
27093
- affected: [resolve61(ctx.syntaurRoot, "syntaur.db")],
27385
+ affected: [resolve62(ctx.syntaurRoot, "syntaur.db")],
27094
27386
  remediation: {
27095
27387
  kind: "manual",
27096
27388
  suggestion: "Start the dashboard once (`syntaur dashboard`) to initialize the DB, or restore it from backup",
@@ -27108,7 +27400,7 @@ var dbReachable = {
27108
27400
  title: this.title,
27109
27401
  status: "error",
27110
27402
  detail: 'syntaur.db is missing the expected "sessions" table',
27111
- affected: [resolve61(ctx.syntaurRoot, "syntaur.db")],
27403
+ affected: [resolve62(ctx.syntaurRoot, "syntaur.db")],
27112
27404
  autoFixable: false
27113
27405
  };
27114
27406
  }
@@ -27120,7 +27412,7 @@ var dbReachable = {
27120
27412
  title: this.title,
27121
27413
  status: "error",
27122
27414
  detail: `syntaur.db query failed: ${err2 instanceof Error ? err2.message : String(err2)}`,
27123
- affected: [resolve61(ctx.syntaurRoot, "syntaur.db")],
27415
+ affected: [resolve62(ctx.syntaurRoot, "syntaur.db")],
27124
27416
  autoFixable: false
27125
27417
  };
27126
27418
  }
@@ -27146,7 +27438,7 @@ var ghostSessions = {
27146
27438
  const results = [];
27147
27439
  for (const row of rows) {
27148
27440
  if (!row.project_slug) continue;
27149
- const projectPath = resolve61(projectsDir2, row.project_slug, "project.md");
27441
+ const projectPath = resolve62(projectsDir2, row.project_slug, "project.md");
27150
27442
  if (!await fileExists(projectPath)) {
27151
27443
  results.push({
27152
27444
  id: this.id,
@@ -27165,7 +27457,7 @@ var ghostSessions = {
27165
27457
  continue;
27166
27458
  }
27167
27459
  if (row.assignment_slug) {
27168
- const assignmentPath = resolve61(
27460
+ const assignmentPath = resolve62(
27169
27461
  projectsDir2,
27170
27462
  row.project_slug,
27171
27463
  "assignments",
@@ -27217,8 +27509,8 @@ function skipped(check, reason) {
27217
27509
 
27218
27510
  // src/utils/doctor/checks/integrations.ts
27219
27511
  init_fs();
27220
- import { resolve as resolve62, dirname as dirname19, basename as basename6 } from "path";
27221
- import { readdir as readdir22, readFile as readFile38 } from "fs/promises";
27512
+ import { resolve as resolve63, dirname as dirname20, basename as basename6 } from "path";
27513
+ import { readdir as readdir23, readFile as readFile39 } from "fs/promises";
27222
27514
  import { homedir as homedir10 } from "os";
27223
27515
  var CATEGORY6 = "integrations";
27224
27516
  var claudePluginLinked = {
@@ -27281,7 +27573,7 @@ var backupConfigured = {
27281
27573
  if (ctx.config.backup?.repo) return pass6(this);
27282
27574
  const projectsDir2 = ctx.config.defaultProjectDir;
27283
27575
  if (!await fileExists(projectsDir2)) return skipped2(this, "no projects dir");
27284
- const entries = await readdir22(projectsDir2, { withFileTypes: true });
27576
+ const entries = await readdir23(projectsDir2, { withFileTypes: true });
27285
27577
  const hasProjects = entries.some((e) => e.isDirectory() && !e.name.startsWith(".") && !e.name.startsWith("_"));
27286
27578
  if (!hasProjects) return skipped2(this, "no projects yet");
27287
27579
  return {
@@ -27300,10 +27592,10 @@ var backupConfigured = {
27300
27592
  }
27301
27593
  };
27302
27594
  async function readKnownMarketplaces() {
27303
- const path = resolve62(homedir10(), ".claude", "plugins", "known_marketplaces.json");
27595
+ const path = resolve63(homedir10(), ".claude", "plugins", "known_marketplaces.json");
27304
27596
  if (!await fileExists(path)) return {};
27305
27597
  try {
27306
- const raw2 = await readFile38(path, "utf-8");
27598
+ const raw2 = await readFile39(path, "utf-8");
27307
27599
  return JSON.parse(raw2);
27308
27600
  } catch {
27309
27601
  return {};
@@ -27319,7 +27611,7 @@ var claudeMarketplaceRegistered = {
27319
27611
  if (!await fileExists(dir)) {
27320
27612
  return skipped2(this, "claudePluginDir does not exist (run install-plugin)");
27321
27613
  }
27322
- const pluginsParent = dirname19(dir);
27614
+ const pluginsParent = dirname20(dir);
27323
27615
  if (basename6(pluginsParent) !== "plugins") {
27324
27616
  return {
27325
27617
  id: this.id,
@@ -27336,8 +27628,8 @@ var claudeMarketplaceRegistered = {
27336
27628
  autoFixable: false
27337
27629
  };
27338
27630
  }
27339
- const marketplaceRoot = dirname19(pluginsParent);
27340
- const marketplaceManifest = resolve62(marketplaceRoot, ".claude-plugin", "marketplace.json");
27631
+ const marketplaceRoot = dirname20(pluginsParent);
27632
+ const marketplaceManifest = resolve63(marketplaceRoot, ".claude-plugin", "marketplace.json");
27341
27633
  if (!await fileExists(marketplaceManifest)) {
27342
27634
  return {
27343
27635
  id: this.id,
@@ -27356,7 +27648,7 @@ var claudeMarketplaceRegistered = {
27356
27648
  }
27357
27649
  let parsed = {};
27358
27650
  try {
27359
- parsed = JSON.parse(await readFile38(marketplaceManifest, "utf-8"));
27651
+ parsed = JSON.parse(await readFile39(marketplaceManifest, "utf-8"));
27360
27652
  } catch {
27361
27653
  return {
27362
27654
  id: this.id,
@@ -27388,7 +27680,7 @@ var claudeMarketplaceRegistered = {
27388
27680
  title: this.title,
27389
27681
  status: "error",
27390
27682
  detail: issues.join("; "),
27391
- affected: [marketplaceManifest, resolve62(homedir10(), ".claude", "plugins", "known_marketplaces.json")],
27683
+ affected: [marketplaceManifest, resolve63(homedir10(), ".claude", "plugins", "known_marketplaces.json")],
27392
27684
  remediation: {
27393
27685
  kind: "manual",
27394
27686
  suggestion: "Re-run install-plugin to ensure both files are in sync.",
@@ -27428,8 +27720,8 @@ function skipped2(check, reason) {
27428
27720
  init_fs();
27429
27721
  init_parser();
27430
27722
  init_types();
27431
- import { resolve as resolve63 } from "path";
27432
- import { readFile as readFile39 } from "fs/promises";
27723
+ import { resolve as resolve64 } from "path";
27724
+ import { readFile as readFile40 } from "fs/promises";
27433
27725
  var CATEGORY7 = "workspace";
27434
27726
  var ASSIGNMENT_FIELDS = ["projectSlug", "assignmentSlug", "projectDir", "assignmentDir"];
27435
27727
  var BUNDLE_FIELDS = ["bundleId", "bundleScope", "bundleScopeId"];
@@ -27450,12 +27742,12 @@ function isStandaloneSession(ctx) {
27450
27742
  return !hasAnyAssignmentField(ctx) && !hasAnyBundleField(ctx) && typeof ctx.sessionId === "string" && ctx.sessionId.length > 0;
27451
27743
  }
27452
27744
  async function loadContext(ctx) {
27453
- const path = resolve63(ctx.cwd, ".syntaur", "context.json");
27745
+ const path = resolve64(ctx.cwd, ".syntaur", "context.json");
27454
27746
  if (!await fileExists(path)) {
27455
27747
  return { data: null, path, exists: false, parseError: null };
27456
27748
  }
27457
27749
  try {
27458
- const raw2 = await readFile39(path, "utf-8");
27750
+ const raw2 = await readFile40(path, "utf-8");
27459
27751
  return { data: JSON.parse(raw2), path, exists: true, parseError: null };
27460
27752
  } catch (err2) {
27461
27753
  return {
@@ -27549,7 +27841,7 @@ var contextAssignmentResolves = {
27549
27841
  if (isStandaloneSession(data)) return skipped3(this, "standalone session context \u2014 no assignment to resolve");
27550
27842
  if (isBundleContext(data)) return skipped3(this, "bundle context \u2014 no assignment to resolve");
27551
27843
  if (!data?.assignmentDir) return skipped3(this, "context has no assignmentDir");
27552
- const assignmentMd = resolve63(data.assignmentDir, "assignment.md");
27844
+ const assignmentMd = resolve64(data.assignmentDir, "assignment.md");
27553
27845
  if (!await fileExists(assignmentMd)) {
27554
27846
  return {
27555
27847
  id: this.id,
@@ -27579,10 +27871,10 @@ var contextTerminal = {
27579
27871
  if (isStandaloneSession(data)) return skipped3(this, "standalone session context \u2014 no assignment to check");
27580
27872
  if (isBundleContext(data)) return skipped3(this, "bundle context \u2014 no assignment to check");
27581
27873
  if (!data?.assignmentDir) return skipped3(this, "context has no assignmentDir");
27582
- const assignmentMd = resolve63(data.assignmentDir, "assignment.md");
27874
+ const assignmentMd = resolve64(data.assignmentDir, "assignment.md");
27583
27875
  if (!await fileExists(assignmentMd)) return skipped3(this, "assignment file missing");
27584
27876
  try {
27585
- const content = await readFile39(assignmentMd, "utf-8");
27877
+ const content = await readFile40(assignmentMd, "utf-8");
27586
27878
  const parsed = parseAssignmentFull(content);
27587
27879
  const terminal = terminalStatuses2(ctx);
27588
27880
  if (terminal.has(parsed.status)) {
@@ -27728,15 +28020,15 @@ var agentChecks = [agentsResolvable];
27728
28020
  // src/utils/doctor/checks/terminal.ts
27729
28021
  init_config2();
27730
28022
  import { spawnSync as spawnSync9 } from "child_process";
27731
- import { readFile as readFile40 } from "fs/promises";
27732
- import { resolve as resolve64 } from "path";
28023
+ import { readFile as readFile41 } from "fs/promises";
28024
+ import { resolve as resolve65 } from "path";
27733
28025
  init_paths();
27734
28026
  init_fs();
27735
28027
  var CATEGORY9 = "terminal";
27736
28028
  async function readRawTerminalKey() {
27737
- const configPath2 = resolve64(syntaurRoot(), "config.md");
28029
+ const configPath2 = resolve65(syntaurRoot(), "config.md");
27738
28030
  if (!await fileExists(configPath2)) return null;
27739
- const content = await readFile40(configPath2, "utf-8");
28031
+ const content = await readFile41(configPath2, "utf-8");
27740
28032
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
27741
28033
  if (!fmMatch) return null;
27742
28034
  const line = fmMatch[1].split("\n").find((l) => /^terminal:\s*/.test(l));
@@ -27886,13 +28178,13 @@ var terminalChecks = [
27886
28178
 
27887
28179
  // src/utils/doctor/checks/skills.ts
27888
28180
  init_fs();
27889
- import { resolve as resolve65, join as join11 } from "path";
27890
- import { readdir as readdir23, readFile as readFile41, lstat as lstat4 } from "fs/promises";
28181
+ import { resolve as resolve66, join as join12 } from "path";
28182
+ import { readdir as readdir24, readFile as readFile42, lstat as lstat4 } from "fs/promises";
27891
28183
  import { homedir as homedir11 } from "os";
27892
28184
  var CATEGORY10 = "skills";
27893
28185
  var skillTargets = [
27894
- { agent: "claude", dir: resolve65(homedir11(), ".claude", "skills"), label: "~/.claude/skills" },
27895
- { agent: "codex", dir: resolve65(homedir11(), ".codex", "skills"), label: "~/.codex/skills" }
28186
+ { agent: "claude", dir: resolve66(homedir11(), ".claude", "skills"), label: "~/.claude/skills" },
28187
+ { agent: "codex", dir: resolve66(homedir11(), ".codex", "skills"), label: "~/.codex/skills" }
27896
28188
  ];
27897
28189
  var skillsDedupCheck = {
27898
28190
  id: "skills.dedup",
@@ -27907,21 +28199,21 @@ var skillsDedupCheck = {
27907
28199
  const present = [];
27908
28200
  let entries;
27909
28201
  try {
27910
- entries = await readdir23(dir, { withFileTypes: true });
28202
+ entries = await readdir24(dir, { withFileTypes: true });
27911
28203
  } catch {
27912
28204
  continue;
27913
28205
  }
27914
28206
  for (const entry of entries) {
27915
28207
  if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
27916
28208
  if (!KNOWN_SKILLS.includes(entry.name)) continue;
27917
- const skillMd = join11(dir, entry.name, "SKILL.md");
28209
+ const skillMd = join12(dir, entry.name, "SKILL.md");
27918
28210
  if (!await fileExists(skillMd)) continue;
27919
- const content = await readFile41(skillMd, "utf-8").catch(() => "");
28211
+ const content = await readFile42(skillMd, "utf-8").catch(() => "");
27920
28212
  const match = content.match(/^name:\s*(\S+)\s*$/m);
27921
28213
  if (!match || match[1] !== entry.name) continue;
27922
28214
  let isSymlink2 = false;
27923
28215
  try {
27924
- isSymlink2 = (await lstat4(join11(dir, entry.name))).isSymbolicLink();
28216
+ isSymlink2 = (await lstat4(join12(dir, entry.name))).isSymbolicLink();
27925
28217
  } catch {
27926
28218
  }
27927
28219
  present.push({ name: entry.name, isSymlink: isSymlink2 });
@@ -27933,7 +28225,7 @@ var skillsDedupCheck = {
27933
28225
  findings.push(
27934
28226
  `${label}: ${nonSymlink.length} syntaur skill(s) installed globally while the syntaur plugin is enabled (${agent}) \u2014 duplicate registrations`
27935
28227
  );
27936
- for (const p of nonSymlink) affected.push(join11(dir, p.name));
28228
+ for (const p of nonSymlink) affected.push(join12(dir, p.name));
27937
28229
  }
27938
28230
  }
27939
28231
  }
@@ -27966,12 +28258,12 @@ var skillsChecks = [skillsDedupCheck];
27966
28258
 
27967
28259
  // src/utils/doctor/checks/cross-agent.ts
27968
28260
  init_fs();
27969
- import { join as join12, resolve as resolve66 } from "path";
27970
- import { readFile as readFile43 } from "fs/promises";
28261
+ import { join as join13, resolve as resolve67 } from "path";
28262
+ import { readFile as readFile44 } from "fs/promises";
27971
28263
 
27972
28264
  // src/utils/skill-frontmatter.ts
27973
28265
  import { createHash } from "crypto";
27974
- import { readFile as readFile42 } from "fs/promises";
28266
+ import { readFile as readFile43 } from "fs/promises";
27975
28267
  function stripQuotes(raw2) {
27976
28268
  const t = raw2.trim();
27977
28269
  if (t.length >= 2 && (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'"))) {
@@ -28015,7 +28307,7 @@ function readSkillIdentity(skillMdText) {
28015
28307
  return { name, hasDescription };
28016
28308
  }
28017
28309
  async function sha256File(path) {
28018
- return createHash("sha256").update(await readFile42(path)).digest("hex");
28310
+ return createHash("sha256").update(await readFile43(path)).digest("hex");
28019
28311
  }
28020
28312
 
28021
28313
  // src/utils/doctor/checks/cross-agent.ts
@@ -28024,14 +28316,14 @@ async function checkTargetSkillsIntegrity(installedDir, canonicalSkillsDir, know
28024
28316
  const problems = [];
28025
28317
  let valid = 0;
28026
28318
  for (const skill of knownSkills) {
28027
- const installedPath = join12(installedDir, skill, "SKILL.md");
28319
+ const installedPath = join13(installedDir, skill, "SKILL.md");
28028
28320
  if (!await fileExists(installedPath)) {
28029
28321
  problems.push({ skill, kind: "missing" });
28030
28322
  continue;
28031
28323
  }
28032
28324
  let text;
28033
28325
  try {
28034
- text = await readFile43(installedPath, "utf-8");
28326
+ text = await readFile44(installedPath, "utf-8");
28035
28327
  } catch {
28036
28328
  problems.push({ skill, kind: "invalid-frontmatter" });
28037
28329
  continue;
@@ -28042,7 +28334,7 @@ async function checkTargetSkillsIntegrity(installedDir, canonicalSkillsDir, know
28042
28334
  continue;
28043
28335
  }
28044
28336
  valid++;
28045
- const canonicalPath = join12(canonicalSkillsDir, skill, "SKILL.md");
28337
+ const canonicalPath = join13(canonicalSkillsDir, skill, "SKILL.md");
28046
28338
  if (await fileExists(canonicalPath)) {
28047
28339
  const [installedHash, canonicalHash] = await Promise.all([
28048
28340
  sha256File(installedPath),
@@ -28075,6 +28367,7 @@ var crossAgentSkillsCheck = {
28075
28367
  title: "Cross-agent targets have Syntaur skills + protocol files",
28076
28368
  async run(ctx) {
28077
28369
  const installed = ctx.config.integrations.installedAgents ?? {};
28370
+ const { targets: resolvedTargets, warnings: descriptorWarnings } = await resolveAgentTargets();
28078
28371
  const canonicalSkillsDir = await getSkillsDir();
28079
28372
  let knownSkills;
28080
28373
  try {
@@ -28088,7 +28381,7 @@ var crossAgentSkillsCheck = {
28088
28381
  const problems = [];
28089
28382
  const affected = [];
28090
28383
  let considered = 0;
28091
- for (const t of AGENT_TARGETS) {
28384
+ for (const t of resolvedTargets) {
28092
28385
  if (t.nativePlugin) continue;
28093
28386
  const dir = t.skillsDir?.global;
28094
28387
  if (!dir) continue;
@@ -28107,15 +28400,41 @@ var crossAgentSkillsCheck = {
28107
28400
  }
28108
28401
  if (recorded && t.instructions) {
28109
28402
  for (const f of t.instructions.files) {
28110
- const p = resolve66(ctx.cwd, f.path);
28403
+ const p = resolve67(ctx.cwd, f.path);
28111
28404
  if (!await fileExists(p)) {
28112
28405
  problems.push(`${t.displayName}: missing protocol file ${f.path} in cwd`);
28113
28406
  affected.push(p);
28114
28407
  }
28115
28408
  }
28116
28409
  }
28410
+ if (t.tier3) {
28411
+ const installDir = t.tier3.installDir();
28412
+ const installed2 = await fileExists(join13(installDir, t.tier3.entry));
28413
+ lines.push(
28414
+ `${t.displayName}: Tier-3 ${t.tier3.kind} ${installed2 ? "installed" : "absent"} (${installDir})`
28415
+ );
28416
+ if (recorded && !installed2) {
28417
+ problems.push(`${t.displayName}: Tier-3 ${t.tier3.kind} not installed`);
28418
+ affected.push(installDir);
28419
+ }
28420
+ }
28117
28421
  }
28118
28422
  if (considered === 0) {
28423
+ if (descriptorWarnings.length > 0) {
28424
+ return {
28425
+ id: this.id,
28426
+ category: this.category,
28427
+ title: this.title,
28428
+ status: "warn",
28429
+ detail: `User target descriptor issues: ${descriptorWarnings.join("; ")}`,
28430
+ remediation: {
28431
+ kind: "manual",
28432
+ suggestion: `Fix or remove the offending file(s) in ~/.syntaur/targets/ (see references/user-targets.md).`,
28433
+ command: null
28434
+ },
28435
+ autoFixable: false
28436
+ };
28437
+ }
28119
28438
  return {
28120
28439
  id: this.id,
28121
28440
  category: this.category,
@@ -28125,6 +28444,7 @@ var crossAgentSkillsCheck = {
28125
28444
  autoFixable: false
28126
28445
  };
28127
28446
  }
28447
+ for (const w of descriptorWarnings) problems.push(`user target descriptor: ${w}`);
28128
28448
  if (problems.length > 0) {
28129
28449
  return {
28130
28450
  id: this.id,
@@ -28156,8 +28476,8 @@ var crossAgentChecks = [crossAgentSkillsCheck];
28156
28476
  // src/utils/doctor/checks/bundles.ts
28157
28477
  init_fs();
28158
28478
  init_paths();
28159
- import { resolve as resolve67 } from "path";
28160
- import { readdir as readdir24 } from "fs/promises";
28479
+ import { resolve as resolve68 } from "path";
28480
+ import { readdir as readdir25 } from "fs/promises";
28161
28481
  import { spawnSync as spawnSync10 } from "child_process";
28162
28482
  init_parser2();
28163
28483
  var CATEGORY12 = "bundles";
@@ -28165,7 +28485,7 @@ async function listScopes(ctx) {
28165
28485
  const out = [];
28166
28486
  const td = todosDir();
28167
28487
  if (await fileExists(td)) {
28168
- const entries = await readdir24(td).catch(() => []);
28488
+ const entries = await readdir25(td).catch(() => []);
28169
28489
  for (const f of entries) {
28170
28490
  if (typeof f !== "string") continue;
28171
28491
  if (!f.endsWith(".md") || f.endsWith("-log.md")) continue;
@@ -28181,12 +28501,12 @@ async function listScopes(ctx) {
28181
28501
  }
28182
28502
  }
28183
28503
  if (await fileExists(ctx.config.defaultProjectDir)) {
28184
- const projectEntries = await readdir24(ctx.config.defaultProjectDir, { withFileTypes: true }).catch(() => []);
28504
+ const projectEntries = await readdir25(ctx.config.defaultProjectDir, { withFileTypes: true }).catch(() => []);
28185
28505
  for (const e of projectEntries) {
28186
28506
  if (!e.isDirectory()) continue;
28187
28507
  const slug = e.name;
28188
28508
  if (typeof slug !== "string" || slug.startsWith(".")) continue;
28189
- const projectMd = resolve67(ctx.config.defaultProjectDir, slug, "project.md");
28509
+ const projectMd = resolve68(ctx.config.defaultProjectDir, slug, "project.md");
28190
28510
  if (!await fileExists(projectMd)) continue;
28191
28511
  out.push({
28192
28512
  scopeLabel: `project:${slug}`,
@@ -28475,14 +28795,14 @@ async function finalize(checks) {
28475
28795
  async function readVersion() {
28476
28796
  try {
28477
28797
  const here = fileURLToPath11(import.meta.url);
28478
- let dir = dirname20(here);
28798
+ let dir = dirname21(here);
28479
28799
  for (let i = 0; i < 6; i++) {
28480
28800
  try {
28481
- const raw2 = await readFile44(join13(dir, "package.json"), "utf-8");
28801
+ const raw2 = await readFile45(join14(dir, "package.json"), "utf-8");
28482
28802
  const parsed = JSON.parse(raw2);
28483
28803
  return typeof parsed.version === "string" ? parsed.version : null;
28484
28804
  } catch {
28485
- dir = dirname20(dir);
28805
+ dir = dirname21(dir);
28486
28806
  }
28487
28807
  }
28488
28808
  return null;
@@ -28575,7 +28895,7 @@ var REQUIRED_WORKSPACE_FIELDS = [
28575
28895
  ];
28576
28896
  var ISO_DATE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;
28577
28897
  async function validateAssignmentFile(inputPath, cwd = process.cwd()) {
28578
- const absolute = isAbsolute11(inputPath) ? inputPath : resolve68(cwd, inputPath);
28898
+ const absolute = isAbsolute11(inputPath) ? inputPath : resolve69(cwd, inputPath);
28579
28899
  const errors = [];
28580
28900
  const warnings = [];
28581
28901
  if (!await fileExists(absolute)) {
@@ -28588,7 +28908,7 @@ async function validateAssignmentFile(inputPath, cwd = process.cwd()) {
28588
28908
  }
28589
28909
  let content;
28590
28910
  try {
28591
- content = await readFile45(absolute, "utf-8");
28911
+ content = await readFile46(absolute, "utf-8");
28592
28912
  } catch (err2) {
28593
28913
  return {
28594
28914
  ok: false,
@@ -28654,20 +28974,20 @@ var doctorCommand = new Command4("doctor").description("Diagnose Syntaur state a
28654
28974
  process.exit(result.ok ? 0 : 1);
28655
28975
  }
28656
28976
  if (!await fileExists(syntaurRoot())) {
28657
- const msg = "~/.syntaur/ does not exist. Run `syntaur init` first.";
28977
+ const msg2 = "~/.syntaur/ does not exist. Run `syntaur init` first.";
28658
28978
  if (options.json) {
28659
28979
  process.stdout.write(
28660
28980
  JSON.stringify(
28661
28981
  {
28662
28982
  version: "1.0",
28663
- error: msg
28983
+ error: msg2
28664
28984
  },
28665
28985
  null,
28666
28986
  2
28667
28987
  ) + "\n"
28668
28988
  );
28669
28989
  } else {
28670
- process.stderr.write(msg + "\n");
28990
+ process.stderr.write(msg2 + "\n");
28671
28991
  }
28672
28992
  process.exit(2);
28673
28993
  }
@@ -28686,11 +29006,11 @@ var doctorCommand = new Command4("doctor").description("Diagnose Syntaur state a
28686
29006
  const hasError = report.summary.error > 0;
28687
29007
  process.exit(hasError ? 1 : 0);
28688
29008
  } catch (err2) {
28689
- const msg = err2 instanceof Error ? err2.message : String(err2);
29009
+ const msg2 = err2 instanceof Error ? err2.message : String(err2);
28690
29010
  if (options.json) {
28691
- process.stdout.write(JSON.stringify({ version: "1.0", error: msg }, null, 2) + "\n");
29011
+ process.stdout.write(JSON.stringify({ version: "1.0", error: msg2 }, null, 2) + "\n");
28692
29012
  } else {
28693
- process.stderr.write(`doctor itself failed: ${msg}
29013
+ process.stderr.write(`doctor itself failed: ${msg2}
28694
29014
  `);
28695
29015
  }
28696
29016
  process.exit(2);
@@ -28912,8 +29232,8 @@ init_uuid();
28912
29232
  init_timestamp();
28913
29233
  init_assignment_resolver();
28914
29234
  init_templates();
28915
- import { resolve as resolve69 } from "path";
28916
- import { readFile as readFile46 } from "fs/promises";
29235
+ import { resolve as resolve70 } from "path";
29236
+ import { readFile as readFile47 } from "fs/promises";
28917
29237
  function shortId() {
28918
29238
  return generateId().split("-")[0];
28919
29239
  }
@@ -28943,7 +29263,7 @@ async function commentCommand(target, text, options = {}) {
28943
29263
  if (!isValidSlug(target)) {
28944
29264
  throw new Error(`Invalid assignment slug "${target}".`);
28945
29265
  }
28946
- assignmentDir = resolve69(baseDir, options.project, "assignments", target);
29266
+ assignmentDir = resolve70(baseDir, options.project, "assignments", target);
28947
29267
  assignmentRef = target;
28948
29268
  } else {
28949
29269
  const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), target);
@@ -28953,13 +29273,13 @@ async function commentCommand(target, text, options = {}) {
28953
29273
  assignmentDir = resolved.assignmentDir;
28954
29274
  assignmentRef = resolved.standalone ? resolved.id : resolved.assignmentSlug;
28955
29275
  }
28956
- const commentsPath = resolve69(assignmentDir, "comments.md");
29276
+ const commentsPath = resolve70(assignmentDir, "comments.md");
28957
29277
  const timestamp = nowTimestamp();
28958
29278
  const author = options.author ?? process.env.USER ?? "unknown";
28959
29279
  let currentContent;
28960
29280
  let currentCount = 0;
28961
29281
  if (await fileExists(commentsPath)) {
28962
- currentContent = await readFile46(commentsPath, "utf-8");
29282
+ currentContent = await readFile47(commentsPath, "utf-8");
28963
29283
  const countMatch = currentContent.match(/^entryCount:\s*(\d+)/m);
28964
29284
  if (countMatch) currentCount = parseInt(countMatch[1], 10);
28965
29285
  } else {
@@ -28993,8 +29313,8 @@ ${entry}`;
28993
29313
  }
28994
29314
 
28995
29315
  // src/commands/capture.ts
28996
- import { resolve as resolve73, relative as relative4, dirname as dirname21 } from "path";
28997
- import { copyFile as copyFile3, mkdir as mkdir10, realpath as realpath2, rm as rm13, stat as stat9, writeFile as writeFile15 } from "fs/promises";
29316
+ import { resolve as resolve74, relative as relative4, dirname as dirname22 } from "path";
29317
+ import { copyFile as copyFile3, mkdir as mkdir11, realpath as realpath2, rm as rm13, stat as stat9, writeFile as writeFile15 } from "fs/promises";
28998
29318
  import { existsSync as existsSync6 } from "fs";
28999
29319
 
29000
29320
  // src/utils/assignment-target.ts
@@ -29004,8 +29324,8 @@ init_config2();
29004
29324
  init_slug();
29005
29325
  init_assignment_resolver();
29006
29326
  init_parser();
29007
- import { resolve as resolve70 } from "path";
29008
- import { readFile as readFile47 } from "fs/promises";
29327
+ import { resolve as resolve71 } from "path";
29328
+ import { readFile as readFile48 } from "fs/promises";
29009
29329
  var AssignmentTargetError = class extends Error {
29010
29330
  };
29011
29331
  function classifyContext(ctx) {
@@ -29017,10 +29337,10 @@ function classifyContext(ctx) {
29017
29337
  return "empty";
29018
29338
  }
29019
29339
  async function readAssignmentFrontmatterId(assignmentDir) {
29020
- const path = resolve70(assignmentDir, "assignment.md");
29340
+ const path = resolve71(assignmentDir, "assignment.md");
29021
29341
  if (!await fileExists(path)) return null;
29022
29342
  try {
29023
- const content = await readFile47(path, "utf-8");
29343
+ const content = await readFile48(path, "utf-8");
29024
29344
  const [fm] = extractFrontmatter(content);
29025
29345
  return getField(fm, "id");
29026
29346
  } catch {
@@ -29028,10 +29348,10 @@ async function readAssignmentFrontmatterId(assignmentDir) {
29028
29348
  }
29029
29349
  }
29030
29350
  async function readContextJson(cwd) {
29031
- const path = resolve70(cwd, ".syntaur", "context.json");
29351
+ const path = resolve71(cwd, ".syntaur", "context.json");
29032
29352
  if (!await fileExists(path)) return null;
29033
29353
  try {
29034
- const raw2 = await readFile47(path, "utf-8");
29354
+ const raw2 = await readFile48(path, "utf-8");
29035
29355
  return JSON.parse(raw2);
29036
29356
  } catch {
29037
29357
  return null;
@@ -29052,15 +29372,15 @@ async function resolveAssignmentTarget(input4, opts = {}) {
29052
29372
  if (!isValidSlug(input4)) {
29053
29373
  throw new AssignmentTargetError(`Invalid assignment slug "${input4}".`);
29054
29374
  }
29055
- const projectDir = resolve70(baseDir, opts.project);
29056
- const projectMdPath = resolve70(projectDir, "project.md");
29375
+ const projectDir = resolve71(baseDir, opts.project);
29376
+ const projectMdPath = resolve71(projectDir, "project.md");
29057
29377
  if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
29058
29378
  throw new AssignmentTargetError(
29059
29379
  `Project "${opts.project}" not found at ${projectDir}.`
29060
29380
  );
29061
29381
  }
29062
- const assignmentDir = resolve70(projectDir, "assignments", input4);
29063
- const assignmentMdPath2 = resolve70(assignmentDir, "assignment.md");
29382
+ const assignmentDir = resolve71(projectDir, "assignments", input4);
29383
+ const assignmentMdPath2 = resolve71(assignmentDir, "assignment.md");
29064
29384
  if (!await fileExists(assignmentMdPath2)) {
29065
29385
  throw new AssignmentTargetError(
29066
29386
  `Assignment "${input4}" not found in project "${opts.project}".`
@@ -29099,7 +29419,7 @@ async function resolveAssignmentTarget(input4, opts = {}) {
29099
29419
  }
29100
29420
  if (ctx.assignmentDir) {
29101
29421
  const dir = expandHome(ctx.assignmentDir);
29102
- const assignmentMdPath2 = resolve70(dir, "assignment.md");
29422
+ const assignmentMdPath2 = resolve71(dir, "assignment.md");
29103
29423
  if (!await fileExists(assignmentMdPath2)) {
29104
29424
  throw new AssignmentTargetError(
29105
29425
  `.syntaur/context.json points to a missing assignment dir: ${dir}.`
@@ -29128,8 +29448,8 @@ async function resolveAssignmentTarget(input4, opts = {}) {
29128
29448
  `.syntaur/context.json contains invalid slugs: project="${ctx.projectSlug}" assignment="${ctx.assignmentSlug}".`
29129
29449
  );
29130
29450
  }
29131
- const assignmentDir = resolve70(baseDir, ctx.projectSlug, "assignments", ctx.assignmentSlug);
29132
- const assignmentMdPath2 = resolve70(assignmentDir, "assignment.md");
29451
+ const assignmentDir = resolve71(baseDir, ctx.projectSlug, "assignments", ctx.assignmentSlug);
29452
+ const assignmentMdPath2 = resolve71(assignmentDir, "assignment.md");
29133
29453
  if (!await fileExists(assignmentMdPath2)) {
29134
29454
  throw new AssignmentTargetError(
29135
29455
  `.syntaur/context.json points to a missing assignment: ${assignmentDir}.`
@@ -29158,7 +29478,7 @@ init_fs();
29158
29478
  import { spawn as spawn7 } from "child_process";
29159
29479
  import { mkdtemp as mkdtemp2, rm as rm9, stat as stat7 } from "fs/promises";
29160
29480
  import { tmpdir as tmpdir3 } from "os";
29161
- import { join as join14 } from "path";
29481
+ import { join as join15 } from "path";
29162
29482
  function argsFor(mode, pngPath) {
29163
29483
  switch (mode) {
29164
29484
  case "interactive":
@@ -29191,8 +29511,8 @@ async function captureScreenshot(mode) {
29191
29511
  "screencapture is only available on macOS. Use --file <path> to attach an existing image."
29192
29512
  );
29193
29513
  }
29194
- const tmpDir = await mkdtemp2(join14(tmpdir3(), "syntaur-screenshot-"));
29195
- const pngPath = join14(tmpDir, "shot.png");
29514
+ const tmpDir = await mkdtemp2(join15(tmpdir3(), "syntaur-screenshot-"));
29515
+ const pngPath = join15(tmpDir, "shot.png");
29196
29516
  const cleanup = async () => {
29197
29517
  await rm9(tmpDir, { recursive: true, force: true }).catch(() => {
29198
29518
  });
@@ -29230,9 +29550,9 @@ async function captureScreenshot(mode) {
29230
29550
 
29231
29551
  // src/utils/asciinema.ts
29232
29552
  import { spawn as spawn8 } from "child_process";
29233
- import { mkdtemp as mkdtemp3, readFile as readFile48, rm as rm10 } from "fs/promises";
29553
+ import { mkdtemp as mkdtemp3, readFile as readFile49, rm as rm10 } from "fs/promises";
29234
29554
  import { tmpdir as tmpdir4 } from "os";
29235
- import { join as join15 } from "path";
29555
+ import { join as join16 } from "path";
29236
29556
  var SAFE_RE = /^[A-Za-z0-9_@%+=:,./-]+$/;
29237
29557
  function shellQuote2(s) {
29238
29558
  if (s.length === 0) return `''`;
@@ -29269,8 +29589,8 @@ function runAsciinema(args, stdio) {
29269
29589
  });
29270
29590
  }
29271
29591
  async function captureAsciinema(opts) {
29272
- const tmpDir = await mkdtemp3(join15(tmpdir4(), "syntaur-asciinema-"));
29273
- const castPath = join15(tmpDir, "session.cast");
29592
+ const tmpDir = await mkdtemp3(join16(tmpdir4(), "syntaur-asciinema-"));
29593
+ const castPath = join16(tmpDir, "session.cast");
29274
29594
  const cleanup = async () => {
29275
29595
  await rm10(tmpDir, { recursive: true, force: true }).catch(() => {
29276
29596
  });
@@ -29293,7 +29613,7 @@ async function captureAsciinema(opts) {
29293
29613
  }
29294
29614
  throw err2;
29295
29615
  }
29296
- const text = await readFile48(castPath, "utf8").catch(() => null);
29616
+ const text = await readFile49(castPath, "utf8").catch(() => null);
29297
29617
  if (text === null) {
29298
29618
  throw new Error(
29299
29619
  `asciinema produced no cast file at ${castPath} (exit ${exitCode}). Try running 'asciinema rec ${castPath}' directly to diagnose.`
@@ -29321,9 +29641,9 @@ async function captureAsciinema(opts) {
29321
29641
  // src/utils/recording.ts
29322
29642
  init_paths();
29323
29643
  import { spawn as spawn9 } from "child_process";
29324
- import { mkdir as mkdir9, mkdtemp as mkdtemp4, open as open3, readFile as readFile49, rm as rm11, stat as stat8, unlink as unlink10, writeFile as writeFile14 } from "fs/promises";
29644
+ import { mkdir as mkdir10, mkdtemp as mkdtemp4, open as open3, readFile as readFile50, rm as rm11, stat as stat8, unlink as unlink10, writeFile as writeFile14 } from "fs/promises";
29325
29645
  import { tmpdir as tmpdir5 } from "os";
29326
- import { join as join16, resolve as resolve71 } from "path";
29646
+ import { join as join17, resolve as resolve72 } from "path";
29327
29647
  import { setTimeout as sleep } from "timers/promises";
29328
29648
  function sigintPollIntervalMs() {
29329
29649
  const raw2 = process.env.SYNTAUR_RECORDING_POLL_INTERVAL_MS;
@@ -29344,13 +29664,13 @@ function sigtermWaitMs() {
29344
29664
  return Number.isFinite(parsed) && parsed >= 0 ? parsed : 1e3;
29345
29665
  }
29346
29666
  function pidfilePath() {
29347
- return resolve71(syntaurRoot(), "recording.pid");
29667
+ return resolve72(syntaurRoot(), "recording.pid");
29348
29668
  }
29349
29669
  function logPath2() {
29350
- return resolve71(syntaurRoot(), "recording.log");
29670
+ return resolve72(syntaurRoot(), "recording.log");
29351
29671
  }
29352
29672
  function sidecarPath() {
29353
- return resolve71(syntaurRoot(), "recording.json");
29673
+ return resolve72(syntaurRoot(), "recording.json");
29354
29674
  }
29355
29675
  function ffmpegArgs(device, fps, mp4Path) {
29356
29676
  return [
@@ -29395,7 +29715,7 @@ async function acquirePidfile(pidfile) {
29395
29715
  } catch (err2) {
29396
29716
  if (err2.code !== "EEXIST") throw err2;
29397
29717
  if (attempt === 1) throw err2;
29398
- const existing = (await readFile49(pidfile, "utf-8").catch(() => "")).trim();
29718
+ const existing = (await readFile50(pidfile, "utf-8").catch(() => "")).trim();
29399
29719
  if (existing.startsWith(STARTING_SENTINEL_PREFIX)) {
29400
29720
  const parentPidRaw = existing.slice(STARTING_SENTINEL_PREFIX.length);
29401
29721
  const parentPid = Number.parseInt(parentPidRaw, 10);
@@ -29437,7 +29757,7 @@ async function startRecording(input4) {
29437
29757
  );
29438
29758
  }
29439
29759
  const root = syntaurRoot();
29440
- await mkdir9(root, { recursive: true });
29760
+ await mkdir10(root, { recursive: true });
29441
29761
  const pidfile = pidfilePath();
29442
29762
  const log = logPath2();
29443
29763
  const sidecar = sidecarPath();
@@ -29448,8 +29768,8 @@ async function startRecording(input4) {
29448
29768
  let acquiredPid = null;
29449
29769
  try {
29450
29770
  logHandle = await open3(log, "w");
29451
- tmpDir = await mkdtemp4(join16(tmpdir5(), "syntaur-recording-"));
29452
- const mp4Path = join16(tmpDir, "recording.mp4");
29771
+ tmpDir = await mkdtemp4(join17(tmpdir5(), "syntaur-recording-"));
29772
+ const mp4Path = join17(tmpDir, "recording.mp4");
29453
29773
  let child;
29454
29774
  try {
29455
29775
  child = spawn9("ffmpeg", ffmpegArgs(input4.device, input4.fps, mp4Path), {
@@ -29497,7 +29817,7 @@ async function startRecording(input4) {
29497
29817
  logHandle = null;
29498
29818
  if (warmupMs > 0) await sleep(warmupMs);
29499
29819
  if (!await isProcessAlive(pid)) {
29500
- const tail = await readFile49(log, "utf-8").then((s) => s.split("\n").slice(-20).join("\n")).catch(() => "");
29820
+ const tail = await readFile50(log, "utf-8").then((s) => s.split("\n").slice(-20).join("\n")).catch(() => "");
29501
29821
  acquiredPid = null;
29502
29822
  throw new Error(
29503
29823
  `ffmpeg exited during startup \u2014 likely macOS Screen Recording permission missing. Grant access to your terminal in System Settings \u2192 Privacy & Security \u2192 Screen Recording, then retry. Log: ${log}
@@ -29554,7 +29874,7 @@ ${tail}`
29554
29874
  async function stopRecording() {
29555
29875
  const pidfile = pidfilePath();
29556
29876
  const sidecar = sidecarPath();
29557
- const pidRaw = await readFile49(pidfile, "utf-8").catch(() => null);
29877
+ const pidRaw = await readFile50(pidfile, "utf-8").catch(() => null);
29558
29878
  if (pidRaw === null) {
29559
29879
  throw new Error(
29560
29880
  `No active recording found (no pidfile at ${pidfile}). Did you run --start?`
@@ -29564,7 +29884,7 @@ async function stopRecording() {
29564
29884
  if (!Number.isInteger(pid) || pid <= 0) {
29565
29885
  throw new Error(`Pidfile at ${pidfile} is corrupt (got "${pidRaw}").`);
29566
29886
  }
29567
- const sidecarRaw = await readFile49(sidecar, "utf-8").catch(() => null);
29887
+ const sidecarRaw = await readFile50(sidecar, "utf-8").catch(() => null);
29568
29888
  if (sidecarRaw === null) {
29569
29889
  throw new Error(
29570
29890
  `No recording sidecar at ${sidecar}. The recording state is inconsistent \u2014 delete ${pidfile} and re-run --start.`
@@ -29629,7 +29949,7 @@ async function stopRecording() {
29629
29949
  // src/db/proof-db.ts
29630
29950
  init_paths();
29631
29951
  import Database5 from "better-sqlite3";
29632
- import { resolve as resolve72 } from "path";
29952
+ import { resolve as resolve73 } from "path";
29633
29953
  var db4 = null;
29634
29954
  var PROOF_SCHEMA_VERSION = "1";
29635
29955
  var SCHEMA_SQL4 = `
@@ -29649,7 +29969,7 @@ CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT);
29649
29969
  `;
29650
29970
  function initProofDb(dbPath) {
29651
29971
  if (db4) return db4;
29652
- const finalPath = dbPath ?? resolve72(syntaurRoot(), "syntaur.db");
29972
+ const finalPath = dbPath ?? resolve73(syntaurRoot(), "syntaur.db");
29653
29973
  db4 = new Database5(finalPath);
29654
29974
  db4.pragma("journal_mode = WAL");
29655
29975
  db4.exec(SCHEMA_SQL4);
@@ -29697,9 +30017,9 @@ function listArtifactsByAssignment(assignmentId) {
29697
30017
 
29698
30018
  // src/utils/transcribers/elevenlabs.ts
29699
30019
  import { spawn as spawn10 } from "child_process";
29700
- import { mkdtemp as mkdtemp5, readFile as readFile50, rm as rm12 } from "fs/promises";
30020
+ import { mkdtemp as mkdtemp5, readFile as readFile51, rm as rm12 } from "fs/promises";
29701
30021
  import { tmpdir as tmpdir6 } from "os";
29702
- import { join as join17 } from "path";
30022
+ import { join as join18 } from "path";
29703
30023
  var SCRIBE_URL = "https://api.elevenlabs.io/v1/speech-to-text";
29704
30024
  var NO_AUDIO_MARKERS = [
29705
30025
  "Stream map '0:a:0' matches no streams",
@@ -29761,7 +30081,7 @@ async function extractAudio(videoAbsPath, wavOut) {
29761
30081
  throw new TranscribeFfmpegError(`ffmpeg failed (exit ${result.code}): ${tail}`);
29762
30082
  }
29763
30083
  async function callScribe(wavPath, apiKey, opts) {
29764
- const audio = await readFile50(wavPath);
30084
+ const audio = await readFile51(wavPath);
29765
30085
  const form = new FormData();
29766
30086
  form.set("file", new Blob([new Uint8Array(audio)], { type: "audio/wav" }), "audio.wav");
29767
30087
  form.set("model_id", "scribe_v1");
@@ -29789,8 +30109,8 @@ var elevenLabsScribe = {
29789
30109
  "ELEVENLABS_API_KEY is not set. Export it (e.g. `export ELEVENLABS_API_KEY=\u2026`) and re-run. A config-file slot will land later."
29790
30110
  );
29791
30111
  }
29792
- const tmp = await mkdtemp5(join17(tmpdir6(), "syntaur-transcribe-"));
29793
- const wav = join17(tmp, "audio.wav");
30112
+ const tmp = await mkdtemp5(join18(tmpdir6(), "syntaur-transcribe-"));
30113
+ const wav = join18(tmp, "audio.wav");
29794
30114
  try {
29795
30115
  await extractAudio(videoAbsPath, wav);
29796
30116
  return await callScribe(wav, apiKey, opts);
@@ -30064,7 +30384,7 @@ async function captureCommand(target, options = {}) {
30064
30384
  criterionIndex = sidecar.criterionIndex;
30065
30385
  stopNote = sidecar.note;
30066
30386
  resolvedSource = mp4Path;
30067
- const mp4TmpDir = dirname21(mp4Path);
30387
+ const mp4TmpDir = dirname22(mp4Path);
30068
30388
  shelloutCleanup = async () => {
30069
30389
  await rm13(mp4TmpDir, { recursive: true, force: true }).catch(() => {
30070
30390
  });
@@ -30077,7 +30397,7 @@ async function captureCommand(target, options = {}) {
30077
30397
  });
30078
30398
  }
30079
30399
  if (options.file) {
30080
- const expanded = options.file.startsWith("~/") ? resolve73(process.env.HOME ?? "", options.file.slice(2)) : resolve73(options.file);
30400
+ const expanded = options.file.startsWith("~/") ? resolve74(process.env.HOME ?? "", options.file.slice(2)) : resolve74(options.file);
30081
30401
  if (!await fileExists(expanded)) {
30082
30402
  throw new Error(`--file does not exist: ${options.file}`);
30083
30403
  }
@@ -30118,8 +30438,8 @@ async function captureCommand(target, options = {}) {
30118
30438
  }
30119
30439
  initProofDb();
30120
30440
  const subdir = criterionIndex === null ? "untagged" : String(criterionIndex);
30121
- const destDir = resolve73(proofDir(resolved.assignmentDir), subdir);
30122
- if (resolvedSource) await mkdir10(destDir, { recursive: true });
30441
+ const destDir = resolve74(proofDir(resolved.assignmentDir), subdir);
30442
+ if (resolvedSource) await mkdir11(destDir, { recursive: true });
30123
30443
  const ext = resolvedSource ? extensionForKind(kind) : null;
30124
30444
  let id = null;
30125
30445
  let relativeFilePath = null;
@@ -30127,7 +30447,7 @@ async function captureCommand(target, options = {}) {
30127
30447
  let lastErr = null;
30128
30448
  for (let attempt = 0; attempt < MAX_ID_RETRIES; attempt += 1) {
30129
30449
  const candidate = generateArtifactId();
30130
- const candidateAbsPath = resolvedSource && ext ? resolve73(destDir, `${candidate}.${ext}`) : null;
30450
+ const candidateAbsPath = resolvedSource && ext ? resolve74(destDir, `${candidate}.${ext}`) : null;
30131
30451
  const candidateRel = candidateAbsPath ? relative4(resolved.assignmentDir, candidateAbsPath) : null;
30132
30452
  try {
30133
30453
  insertArtifact({
@@ -30171,7 +30491,7 @@ async function captureCommand(target, options = {}) {
30171
30491
  }
30172
30492
  }
30173
30493
  if (options.transcribe && kind === "video" && absPath && id) {
30174
- const sidecarPath2 = resolve73(destDir, `${id}.transcript.md`);
30494
+ const sidecarPath2 = resolve74(destDir, `${id}.transcript.md`);
30175
30495
  if (existsSync6(sidecarPath2)) {
30176
30496
  console.warn(
30177
30497
  `transcript: ${sidecarPath2} already exists, skipping (delete to re-transcribe)`
@@ -30203,7 +30523,7 @@ async function captureCommand(target, options = {}) {
30203
30523
  const tagSuffix = criterionIndex === null ? "untagged" : `criterion ${criterionIndex}`;
30204
30524
  console.log(`Captured artifact ${id} (${kind}) for ${ref} \u2014 ${tagSuffix}.`);
30205
30525
  if (relativeFilePath) {
30206
- console.log(` file: ${resolve73(resolved.assignmentDir, relativeFilePath)}`);
30526
+ console.log(` file: ${resolve74(resolved.assignmentDir, relativeFilePath)}`);
30207
30527
  }
30208
30528
  } catch (err2) {
30209
30529
  if (options.stop && kind === "video" && shelloutCleanup && resolvedSource) {
@@ -30226,8 +30546,8 @@ async function captureCommand(target, options = {}) {
30226
30546
 
30227
30547
  // src/commands/proof.ts
30228
30548
  import { Command as Command6 } from "commander";
30229
- import { readFile as readFile51, writeFile as writeFile16, rename as rename10, stat as stat10 } from "fs/promises";
30230
- import { resolve as resolve74, relative as relative5, isAbsolute as isAbsolute12, dirname as dirname22 } from "path";
30549
+ import { readFile as readFile52, writeFile as writeFile16, rename as rename10, stat as stat10 } from "fs/promises";
30550
+ import { resolve as resolve75, relative as relative5, isAbsolute as isAbsolute12, dirname as dirname23 } from "path";
30231
30551
  import { randomBytes as randomBytes4 } from "crypto";
30232
30552
 
30233
30553
  // src/utils/acceptance-criteria-parse.ts
@@ -30467,11 +30787,11 @@ function renderProofHtml(params2, inlineFiles = /* @__PURE__ */ new Map(), trans
30467
30787
 
30468
30788
  // src/commands/proof.ts
30469
30789
  async function readAssignmentMeta(assignmentDir) {
30470
- const path = resolve74(assignmentDir, "assignment.md");
30790
+ const path = resolve75(assignmentDir, "assignment.md");
30471
30791
  if (!await fileExists(path)) {
30472
30792
  return { title: "", body: "" };
30473
30793
  }
30474
- const content = await readFile51(path, "utf-8");
30794
+ const content = await readFile52(path, "utf-8");
30475
30795
  const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
30476
30796
  let title = "";
30477
30797
  if (fmMatch) {
@@ -30518,7 +30838,7 @@ async function loadInlineFiles(rows, assignmentDir) {
30518
30838
  for (const r of rows) {
30519
30839
  if (!r.file_path) continue;
30520
30840
  if (r.kind !== "http" && r.kind !== "text") continue;
30521
- const abs = resolve74(assignmentDir, r.file_path);
30841
+ const abs = resolve75(assignmentDir, r.file_path);
30522
30842
  if (!isWithin(proofRoot, abs)) {
30523
30843
  out.set(r.file_path, null);
30524
30844
  continue;
@@ -30533,7 +30853,7 @@ async function loadInlineFiles(rows, assignmentDir) {
30533
30853
  continue;
30534
30854
  }
30535
30855
  try {
30536
- out.set(r.file_path, await readFile51(abs, "utf-8"));
30856
+ out.set(r.file_path, await readFile52(abs, "utf-8"));
30537
30857
  } catch {
30538
30858
  out.set(r.file_path, null);
30539
30859
  }
@@ -30545,14 +30865,14 @@ async function loadTranscriptSidecars(rows, assignmentDir) {
30545
30865
  const proofRoot = proofDir(assignmentDir);
30546
30866
  for (const r of rows) {
30547
30867
  if (r.kind !== "video" || !r.file_path) continue;
30548
- const videoAbs = resolve74(assignmentDir, r.file_path);
30549
- const sidecar = resolve74(dirname22(videoAbs), `${r.id}.transcript.md`);
30868
+ const videoAbs = resolve75(assignmentDir, r.file_path);
30869
+ const sidecar = resolve75(dirname23(videoAbs), `${r.id}.transcript.md`);
30550
30870
  if (!isWithin(proofRoot, sidecar)) continue;
30551
30871
  if (!await fileExists(sidecar)) continue;
30552
30872
  const st = await stat10(sidecar);
30553
30873
  if (st.size > INLINE_TEXT_LIMIT_BYTES) continue;
30554
30874
  try {
30555
- out.set(r.id, await readFile51(sidecar, "utf-8"));
30875
+ out.set(r.id, await readFile52(sidecar, "utf-8"));
30556
30876
  } catch {
30557
30877
  }
30558
30878
  }
@@ -30586,8 +30906,8 @@ async function proofBuildCommand(target, options = {}) {
30586
30906
  };
30587
30907
  const md = renderProofMarkdown(renderParams);
30588
30908
  const html = renderProofHtml(renderParams, inlineFiles, transcriptSidecars);
30589
- const mdPath = resolve74(resolved.assignmentDir, "proof.md");
30590
- const htmlPath = resolve74(resolved.assignmentDir, "proof.html");
30909
+ const mdPath = resolve75(resolved.assignmentDir, "proof.md");
30910
+ const htmlPath = resolve75(resolved.assignmentDir, "proof.html");
30591
30911
  await atomicWrite(mdPath, md);
30592
30912
  await atomicWrite(htmlPath, html);
30593
30913
  console.log(`Wrote ${htmlPath}`);
@@ -31252,7 +31572,7 @@ async function runCcusage(opts = {}) {
31252
31572
  };
31253
31573
  }
31254
31574
  function runOnce(binary, args, env, timeoutMs, maxOutputBytes) {
31255
- return new Promise((resolve86) => {
31575
+ return new Promise((resolve87) => {
31256
31576
  const child = spawn11(binary, args, {
31257
31577
  env: env ?? process.env,
31258
31578
  stdio: ["ignore", "pipe", "pipe"]
@@ -31266,7 +31586,7 @@ function runOnce(binary, args, env, timeoutMs, maxOutputBytes) {
31266
31586
  if (settled) return;
31267
31587
  settled = true;
31268
31588
  clearTimeout(timer2);
31269
- resolve86(result);
31589
+ resolve87(result);
31270
31590
  };
31271
31591
  const timer2 = setTimeout(() => {
31272
31592
  timedOut = true;
@@ -31310,8 +31630,8 @@ function isoToCcusageDate(iso) {
31310
31630
 
31311
31631
  // src/usage/cwd-extractor.ts
31312
31632
  init_paths();
31313
- import { open as open4, readdir as readdir25, stat as stat11 } from "fs/promises";
31314
- import { join as join18 } from "path";
31633
+ import { open as open4, readdir as readdir26, stat as stat11 } from "fs/promises";
31634
+ import { join as join19 } from "path";
31315
31635
  import { homedir as homedir12 } from "os";
31316
31636
  var SCAN_LINE_CAP = 50;
31317
31637
  var TAIL_READ_BYTES = 8 * 1024;
@@ -31386,12 +31706,12 @@ async function* walkClaudeProjects(opts = {}) {
31386
31706
  const dirs = await listDirSafe(root);
31387
31707
  for (const dirent of dirs) {
31388
31708
  if (!dirent.isDirectory) continue;
31389
- const dirPath = join18(root, dirent.name);
31709
+ const dirPath = join19(root, dirent.name);
31390
31710
  const files = await listDirSafe(dirPath);
31391
31711
  let cachedCwd = null;
31392
31712
  for (const f of files) {
31393
31713
  if (!f.isFile || !f.name.endsWith(".jsonl")) continue;
31394
- const filePath = join18(dirPath, f.name);
31714
+ const filePath = join19(dirPath, f.name);
31395
31715
  if (opts.sinceMtimeMs !== void 0) {
31396
31716
  const mtime = await mtimeMs(filePath);
31397
31717
  if (mtime !== null && mtime < opts.sinceMtimeMs) continue;
@@ -31428,12 +31748,12 @@ function resolveCodexSessionsRoot(override) {
31428
31748
  const fromSessionsEnv = process.env.CODEX_SESSIONS_DIR;
31429
31749
  if (fromSessionsEnv && fromSessionsEnv.length > 0) return expandHome(fromSessionsEnv);
31430
31750
  const fromHomeEnv = process.env.CODEX_HOME;
31431
- if (fromHomeEnv && fromHomeEnv.length > 0) return join18(expandHome(fromHomeEnv), "sessions");
31432
- return join18(homedir12(), ".codex", "sessions");
31751
+ if (fromHomeEnv && fromHomeEnv.length > 0) return join19(expandHome(fromHomeEnv), "sessions");
31752
+ return join19(homedir12(), ".codex", "sessions");
31433
31753
  }
31434
31754
  async function listDirSafe(path) {
31435
31755
  try {
31436
- const entries = await readdir25(path, { withFileTypes: true });
31756
+ const entries = await readdir26(path, { withFileTypes: true });
31437
31757
  return entries.map((e) => ({
31438
31758
  name: e.name,
31439
31759
  isFile: e.isFile(),
@@ -31449,7 +31769,7 @@ async function* walkJsonlRecursive(root) {
31449
31769
  const current = stack.pop();
31450
31770
  const entries = await listDirSafe(current);
31451
31771
  for (const e of entries) {
31452
- const full = join18(current, e.name);
31772
+ const full = join19(current, e.name);
31453
31773
  if (e.isDirectory) {
31454
31774
  stack.push(full);
31455
31775
  } else if (e.isFile && e.name.endsWith(".jsonl")) {
@@ -31788,8 +32108,8 @@ init_slug();
31788
32108
  init_timestamp();
31789
32109
  init_assignment_resolver();
31790
32110
  init_assignment_todos();
31791
- import { resolve as resolve75 } from "path";
31792
- import { readFile as readFile52 } from "fs/promises";
32111
+ import { resolve as resolve76 } from "path";
32112
+ import { readFile as readFile53 } from "fs/promises";
31793
32113
  async function requestCommand(target, text, options = {}) {
31794
32114
  if (!text || !text.trim()) {
31795
32115
  throw new Error("Request text cannot be empty.");
@@ -31805,7 +32125,7 @@ async function requestCommand(target, text, options = {}) {
31805
32125
  if (!isValidSlug(target)) {
31806
32126
  throw new Error(`Invalid assignment slug "${target}".`);
31807
32127
  }
31808
- assignmentDir = resolve75(baseDir, options.project, "assignments", target);
32128
+ assignmentDir = resolve76(baseDir, options.project, "assignments", target);
31809
32129
  targetRef = target;
31810
32130
  } else {
31811
32131
  const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), target);
@@ -31815,12 +32135,12 @@ async function requestCommand(target, text, options = {}) {
31815
32135
  assignmentDir = resolved.assignmentDir;
31816
32136
  targetRef = resolved.standalone ? resolved.id : resolved.assignmentSlug;
31817
32137
  }
31818
- const assignmentMdPath2 = resolve75(assignmentDir, "assignment.md");
32138
+ const assignmentMdPath2 = resolve76(assignmentDir, "assignment.md");
31819
32139
  if (!await fileExists(assignmentMdPath2)) {
31820
32140
  throw new Error(`assignment.md not found at ${assignmentMdPath2}`);
31821
32141
  }
31822
32142
  const source = options.from ?? process.env.SYNTAUR_ASSIGNMENT ?? "unknown";
31823
- let content = await readFile52(assignmentMdPath2, "utf-8");
32143
+ let content = await readFile53(assignmentMdPath2, "utf-8");
31824
32144
  content = appendTodosToAssignmentBody(content, [
31825
32145
  { description: `${text.trim()} (from: ${source})` }
31826
32146
  ]);
@@ -31834,13 +32154,13 @@ init_fs();
31834
32154
  init_paths();
31835
32155
  init_config2();
31836
32156
  import { Command as Command9 } from "commander";
31837
- import { readFile as readFile53, readdir as readdir26 } from "fs/promises";
31838
- import { resolve as resolve76 } from "path";
32157
+ import { readFile as readFile54, readdir as readdir27 } from "fs/promises";
32158
+ import { resolve as resolve77 } from "path";
31839
32159
  async function readContextAssignmentDir(cwd) {
31840
- const path = resolve76(cwd, ".syntaur", "context.json");
32160
+ const path = resolve77(cwd, ".syntaur", "context.json");
31841
32161
  if (!await fileExists(path)) return null;
31842
32162
  try {
31843
- const raw2 = await readFile53(path, "utf-8");
32163
+ const raw2 = await readFile54(path, "utf-8");
31844
32164
  const ctx = JSON.parse(raw2);
31845
32165
  if (typeof ctx.assignmentDir === "string" && ctx.assignmentDir.length > 0) {
31846
32166
  return ctx.assignmentDir;
@@ -31854,9 +32174,9 @@ async function resolveAssignmentDir(opts) {
31854
32174
  const cwd = opts.cwd ?? process.cwd();
31855
32175
  if (opts.assignment) {
31856
32176
  if (opts.project) {
31857
- return resolve76((await readConfig()).defaultProjectDir, opts.project, "assignments", opts.assignment);
32177
+ return resolve77((await readConfig()).defaultProjectDir, opts.project, "assignments", opts.assignment);
31858
32178
  }
31859
- return resolve76(assignmentsDir(), opts.assignment);
32179
+ return resolve77(assignmentsDir(), opts.assignment);
31860
32180
  }
31861
32181
  const fromCtx = await readContextAssignmentDir(cwd);
31862
32182
  if (fromCtx) return fromCtx;
@@ -31867,7 +32187,7 @@ async function resolveAssignmentDir(opts) {
31867
32187
  var PLAN_PATTERN = /^plan(?:-v(\d+))?\.md$/;
31868
32188
  async function listPlanFiles(assignmentDir) {
31869
32189
  if (!await fileExists(assignmentDir)) return [];
31870
- const entries = await readdir26(assignmentDir, { withFileTypes: true });
32190
+ const entries = await readdir27(assignmentDir, { withFileTypes: true });
31871
32191
  const out = [];
31872
32192
  for (const e of entries) {
31873
32193
  if (!e.isFile()) continue;
@@ -32052,17 +32372,17 @@ async function runPlanCreate(options) {
32052
32372
  if (!await fileExists(assignmentDir)) {
32053
32373
  throw new Error(`Assignment directory does not exist: ${assignmentDir}`);
32054
32374
  }
32055
- const assignmentMdPath2 = resolve76(assignmentDir, "assignment.md");
32375
+ const assignmentMdPath2 = resolve77(assignmentDir, "assignment.md");
32056
32376
  if (!await fileExists(assignmentMdPath2)) {
32057
32377
  throw new Error(`Missing assignment.md at: ${assignmentMdPath2}`);
32058
32378
  }
32059
- const planPath = resolve76(assignmentDir, "plan.md");
32379
+ const planPath = resolve77(assignmentDir, "plan.md");
32060
32380
  if (await fileExists(planPath) && !options.force) {
32061
32381
  throw new Error(
32062
32382
  "plan.md already exists. Use --force to overwrite, or `syntaur plan version` to create the next version."
32063
32383
  );
32064
32384
  }
32065
- const assignmentMd = await readFile53(assignmentMdPath2, "utf-8");
32385
+ const assignmentMd = await readFile54(assignmentMdPath2, "utf-8");
32066
32386
  const slugMatch = assignmentMd.match(/^slug:\s*(.+?)\s*$/m);
32067
32387
  const slug = slugMatch ? slugMatch[1].trim() : assignmentDir.split("/").pop() ?? "";
32068
32388
  await writeFileForce(planPath, buildInitialPlanStub(slug));
@@ -32082,7 +32402,7 @@ async function runPlanVersion(options) {
32082
32402
  if (!await fileExists(assignmentDir)) {
32083
32403
  throw new Error(`Assignment directory does not exist: ${assignmentDir}`);
32084
32404
  }
32085
- const assignmentMdPath2 = resolve76(assignmentDir, "assignment.md");
32405
+ const assignmentMdPath2 = resolve77(assignmentDir, "assignment.md");
32086
32406
  if (!await fileExists(assignmentMdPath2)) {
32087
32407
  throw new Error(`Missing assignment.md at: ${assignmentMdPath2}`);
32088
32408
  }
@@ -32094,15 +32414,15 @@ async function runPlanVersion(options) {
32094
32414
  }
32095
32415
  const current = planFiles[planFiles.length - 1];
32096
32416
  const next = nextPlanFileName(current.version);
32097
- const newPath = resolve76(assignmentDir, next.fileName);
32417
+ const newPath = resolve77(assignmentDir, next.fileName);
32098
32418
  if (await fileExists(newPath) && !options.force) {
32099
32419
  throw new Error(`${next.fileName} already exists. Use --force to overwrite.`);
32100
32420
  }
32101
- const assignmentMd = await readFile53(assignmentMdPath2, "utf-8");
32421
+ const assignmentMd = await readFile54(assignmentMdPath2, "utf-8");
32102
32422
  const slugMatch = assignmentMd.match(/^slug:\s*(.+?)\s*$/m);
32103
32423
  const slug = slugMatch ? slugMatch[1].trim() : assignmentDir.split("/").pop() ?? "";
32104
- const oldPlanPath = resolve76(assignmentDir, current.fileName);
32105
- const oldPlanContent = await readFile53(oldPlanPath, "utf-8");
32424
+ const oldPlanPath = resolve77(assignmentDir, current.fileName);
32425
+ const oldPlanContent = await readFile54(oldPlanPath, "utf-8");
32106
32426
  const oldBody = oldPlanContent.replace(/^---[\s\S]*?\n---\n?/, "");
32107
32427
  const carriedTodos = extractUncheckedTodos(oldBody);
32108
32428
  const stub = buildNewPlanStub({
@@ -32150,26 +32470,26 @@ init_paths();
32150
32470
  init_config2();
32151
32471
  init_timestamp();
32152
32472
  import { Command as Command10 } from "commander";
32153
- import { readFile as readFile54, readdir as readdir27, stat as stat12 } from "fs/promises";
32154
- import { resolve as resolve77 } from "path";
32473
+ import { readFile as readFile55, readdir as readdir28, stat as stat12 } from "fs/promises";
32474
+ import { resolve as resolve78 } from "path";
32155
32475
  async function readContext(cwd) {
32156
- const path = resolve77(cwd, ".syntaur", "context.json");
32476
+ const path = resolve78(cwd, ".syntaur", "context.json");
32157
32477
  if (!await fileExists(path)) return null;
32158
32478
  try {
32159
- const raw2 = await readFile54(path, "utf-8");
32479
+ const raw2 = await readFile55(path, "utf-8");
32160
32480
  return JSON.parse(raw2);
32161
32481
  } catch {
32162
32482
  return null;
32163
32483
  }
32164
32484
  }
32165
32485
  async function findLatestSessionSummary(assignmentDir) {
32166
- const sessionsRoot = resolve77(assignmentDir, "sessions");
32486
+ const sessionsRoot = resolve78(assignmentDir, "sessions");
32167
32487
  if (!await fileExists(sessionsRoot)) return null;
32168
- const entries = await readdir27(sessionsRoot, { withFileTypes: true });
32488
+ const entries = await readdir28(sessionsRoot, { withFileTypes: true });
32169
32489
  let best = null;
32170
32490
  for (const entry of entries) {
32171
32491
  if (!entry.isDirectory()) continue;
32172
- const summaryPath = resolve77(sessionsRoot, entry.name, "summary.md");
32492
+ const summaryPath = resolve78(sessionsRoot, entry.name, "summary.md");
32173
32493
  if (!await fileExists(summaryPath)) continue;
32174
32494
  const st = await stat12(summaryPath);
32175
32495
  if (best === null || st.mtime.getTime() > best.mtime.getTime()) {
@@ -32179,9 +32499,9 @@ async function findLatestSessionSummary(assignmentDir) {
32179
32499
  return best;
32180
32500
  }
32181
32501
  async function findOpenHandoff(assignmentDir) {
32182
- const handoffPath = resolve77(assignmentDir, "handoff.md");
32502
+ const handoffPath = resolve78(assignmentDir, "handoff.md");
32183
32503
  if (!await fileExists(handoffPath)) return null;
32184
- const content = await readFile54(handoffPath, "utf-8");
32504
+ const content = await readFile55(handoffPath, "utf-8");
32185
32505
  const body = content.replace(/^---[\s\S]*?\n---\n?/, "").trim();
32186
32506
  if (body.length === 0) return null;
32187
32507
  if (/^<!--[\s\S]*-->$/.test(body)) return null;
@@ -32276,7 +32596,7 @@ async function resolveSaveTarget(options, cwd) {
32276
32596
  let slug;
32277
32597
  const ctx = await readContext(cwd);
32278
32598
  if (options.assignment) {
32279
- assignmentDir = options.project ? resolve77((await readConfig()).defaultProjectDir, options.project, "assignments", options.assignment) : resolve77(assignmentsDir(), options.assignment);
32599
+ assignmentDir = options.project ? resolve78((await readConfig()).defaultProjectDir, options.project, "assignments", options.assignment) : resolve78(assignmentsDir(), options.assignment);
32280
32600
  slug = options.assignment;
32281
32601
  } else {
32282
32602
  if (!ctx?.assignmentDir) {
@@ -32329,21 +32649,21 @@ function extractCreated(content) {
32329
32649
  }
32330
32650
  async function runSessionSave(options, cwd = process.cwd(), body) {
32331
32651
  const { assignmentDir, slug, sessionId } = await resolveSaveTarget(options, cwd);
32332
- if (!await fileExists(resolve77(assignmentDir, "assignment.md"))) {
32652
+ if (!await fileExists(resolve78(assignmentDir, "assignment.md"))) {
32333
32653
  throw new Error(`No assignment found at ${assignmentDir} (missing assignment.md).`);
32334
32654
  }
32335
- const sessionDir = resolve77(assignmentDir, "sessions", sessionId);
32336
- const summaryPath = resolve77(sessionDir, "summary.md");
32655
+ const sessionDir = resolve78(assignmentDir, "sessions", sessionId);
32656
+ const summaryPath = resolve78(sessionDir, "summary.md");
32337
32657
  const now = nowTimestamp();
32338
32658
  let created = now;
32339
32659
  if (await fileExists(summaryPath)) {
32340
- const existing = await readFile54(summaryPath, "utf-8");
32660
+ const existing = await readFile55(summaryPath, "utf-8");
32341
32661
  created = extractCreated(existing) ?? now;
32342
32662
  }
32343
32663
  let sectionBody = body;
32344
32664
  if (sectionBody === void 0) {
32345
32665
  if (options.fromFile) {
32346
- sectionBody = await readFile54(resolve77(cwd, options.fromFile), "utf-8");
32666
+ sectionBody = await readFile55(resolve78(cwd, options.fromFile), "utf-8");
32347
32667
  } else {
32348
32668
  sectionBody = await readStdin();
32349
32669
  }
@@ -32391,13 +32711,13 @@ init_config2();
32391
32711
  init_timestamp();
32392
32712
  init_frontmatter();
32393
32713
  import { Command as Command11 } from "commander";
32394
- import { readFile as readFile55 } from "fs/promises";
32395
- import { resolve as resolve78 } from "path";
32714
+ import { readFile as readFile56 } from "fs/promises";
32715
+ import { resolve as resolve79 } from "path";
32396
32716
  async function readContext2(cwd) {
32397
- const path = resolve78(cwd, ".syntaur", "context.json");
32717
+ const path = resolve79(cwd, ".syntaur", "context.json");
32398
32718
  if (!await fileExists(path)) return null;
32399
32719
  try {
32400
- return JSON.parse(await readFile55(path, "utf-8"));
32720
+ return JSON.parse(await readFile56(path, "utf-8"));
32401
32721
  } catch {
32402
32722
  return null;
32403
32723
  }
@@ -32406,12 +32726,12 @@ async function resolveAssignmentPath2(opts) {
32406
32726
  if (opts.assignment) {
32407
32727
  if (opts.project) {
32408
32728
  const projectsDir2 = (await readConfig()).defaultProjectDir;
32409
- return resolve78(projectsDir2, opts.project, "assignments", opts.assignment, "assignment.md");
32729
+ return resolve79(projectsDir2, opts.project, "assignments", opts.assignment, "assignment.md");
32410
32730
  }
32411
- return resolve78(assignmentsDir(), opts.assignment, "assignment.md");
32731
+ return resolve79(assignmentsDir(), opts.assignment, "assignment.md");
32412
32732
  }
32413
32733
  const ctx = await readContext2(opts.cwd);
32414
- if (ctx?.assignmentDir) return resolve78(ctx.assignmentDir, "assignment.md");
32734
+ if (ctx?.assignmentDir) return resolve79(ctx.assignmentDir, "assignment.md");
32415
32735
  throw new Error(
32416
32736
  "No active assignment. Pass --assignment <slug> [--project <slug>] or run from a workspace with .syntaur/context.json."
32417
32737
  );
@@ -32422,7 +32742,7 @@ async function runWorktreeCreate(options, cwd = process.cwd()) {
32422
32742
  }
32423
32743
  const repository = options.repository ?? cwd;
32424
32744
  const parentBranch = options.parentBranch ?? "main";
32425
- const worktreePath = options.worktreePath ?? resolve78(repository, ".worktrees", options.branch);
32745
+ const worktreePath = options.worktreePath ?? resolve79(repository, ".worktrees", options.branch);
32426
32746
  const assignmentPath = await resolveAssignmentPath2({
32427
32747
  assignment: options.assignment,
32428
32748
  project: options.project,
@@ -32452,7 +32772,7 @@ async function runWorktreeRemove(options, cwd = process.cwd()) {
32452
32772
  if (!await fileExists(assignmentPath)) {
32453
32773
  throw new Error(`Assignment file not found: ${assignmentPath}`);
32454
32774
  }
32455
- const original = await readFile55(assignmentPath, "utf-8");
32775
+ const original = await readFile56(assignmentPath, "utf-8");
32456
32776
  const fm = parseAssignmentFrontmatter(original);
32457
32777
  const repository = options.repository ?? fm.workspace.repository ?? void 0;
32458
32778
  const worktreePath = fm.workspace.worktreePath ?? void 0;
@@ -32551,14 +32871,14 @@ init_config2();
32551
32871
  init_fs();
32552
32872
  init_slug();
32553
32873
  import { Command as Command12 } from "commander";
32554
- import { resolve as resolve80 } from "path";
32555
- import { readFile as readFile57, readdir as readdir29, rm as rm14 } from "fs/promises";
32874
+ import { resolve as resolve81 } from "path";
32875
+ import { readFile as readFile58, readdir as readdir30, rm as rm14 } from "fs/promises";
32556
32876
 
32557
32877
  // src/utils/project-indexes.ts
32558
32878
  init_parser();
32559
32879
  init_fs();
32560
- import { readdir as readdir28, readFile as readFile56 } from "fs/promises";
32561
- import { resolve as resolve79 } from "path";
32880
+ import { readdir as readdir29, readFile as readFile57 } from "fs/promises";
32881
+ import { resolve as resolve80 } from "path";
32562
32882
  function nowIso3() {
32563
32883
  return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
32564
32884
  }
@@ -32567,7 +32887,7 @@ function readProjectSlug(projectDir) {
32567
32887
  }
32568
32888
  async function listSlugFiles(dir) {
32569
32889
  if (!await fileExists(dir)) return [];
32570
- const entries = await readdir28(dir, { withFileTypes: true });
32890
+ const entries = await readdir29(dir, { withFileTypes: true });
32571
32891
  return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && !e.name.startsWith("_")).map((e) => e.name).sort();
32572
32892
  }
32573
32893
  function escapeCell(value) {
@@ -32577,7 +32897,7 @@ function joinList(items) {
32577
32897
  return items.length === 0 ? "\u2014" : items.map(escapeCell).join(", ");
32578
32898
  }
32579
32899
  async function rebuildResourcesIndex(projectDir) {
32580
- const dir = resolve79(projectDir, "resources");
32900
+ const dir = resolve80(projectDir, "resources");
32581
32901
  await ensureDir(dir);
32582
32902
  const files = await listSlugFiles(dir);
32583
32903
  const slug = readProjectSlug(projectDir);
@@ -32593,7 +32913,7 @@ async function rebuildResourcesIndex(projectDir) {
32593
32913
  lines.push("| Name | Category | Source | Related Assignments | Updated |");
32594
32914
  lines.push("|------|----------|--------|---------------------|---------|");
32595
32915
  for (const fileName of files) {
32596
- const content = await readFile56(resolve79(dir, fileName), "utf-8");
32916
+ const content = await readFile57(resolve80(dir, fileName), "utf-8");
32597
32917
  const parsed = parseResource(content);
32598
32918
  const slugBase = fileName.replace(/\.md$/, "");
32599
32919
  const name = parsed.name || slugBase;
@@ -32603,12 +32923,12 @@ async function rebuildResourcesIndex(projectDir) {
32603
32923
  );
32604
32924
  }
32605
32925
  lines.push("");
32606
- const indexPath = resolve79(dir, "_index.md");
32926
+ const indexPath = resolve80(dir, "_index.md");
32607
32927
  await writeFileForce(indexPath, lines.join("\n"));
32608
32928
  return { total: files.length, path: indexPath };
32609
32929
  }
32610
32930
  async function rebuildMemoriesIndex(projectDir) {
32611
- const dir = resolve79(projectDir, "memories");
32931
+ const dir = resolve80(projectDir, "memories");
32612
32932
  await ensureDir(dir);
32613
32933
  const files = await listSlugFiles(dir);
32614
32934
  const slug = readProjectSlug(projectDir);
@@ -32624,7 +32944,7 @@ async function rebuildMemoriesIndex(projectDir) {
32624
32944
  lines.push("| Name | Source | Scope | Source Assignment | Updated |");
32625
32945
  lines.push("|------|--------|-------|-------------------|---------|");
32626
32946
  for (const fileName of files) {
32627
- const content = await readFile56(resolve79(dir, fileName), "utf-8");
32947
+ const content = await readFile57(resolve80(dir, fileName), "utf-8");
32628
32948
  const parsed = parseMemory(content);
32629
32949
  const slugBase = fileName.replace(/\.md$/, "");
32630
32950
  const name = parsed.name || slugBase;
@@ -32634,7 +32954,7 @@ async function rebuildMemoriesIndex(projectDir) {
32634
32954
  );
32635
32955
  }
32636
32956
  lines.push("");
32637
- const indexPath = resolve79(dir, "_index.md");
32957
+ const indexPath = resolve80(dir, "_index.md");
32638
32958
  await writeFileForce(indexPath, lines.join("\n"));
32639
32959
  return { total: files.length, path: indexPath };
32640
32960
  }
@@ -32698,8 +33018,8 @@ ${opts.body ?? "<!-- Add notes about this resource here. -->"}
32698
33018
  }
32699
33019
  async function resolveProjectDir(project) {
32700
33020
  if (!isValidSlug(project)) throw new Error(`Invalid project slug: "${project}".`);
32701
- const projectDir = resolve80((await readConfig()).defaultProjectDir, project);
32702
- if (!await fileExists(resolve80(projectDir, "project.md"))) {
33021
+ const projectDir = resolve81((await readConfig()).defaultProjectDir, project);
33022
+ if (!await fileExists(resolve81(projectDir, "project.md"))) {
32703
33023
  throw new Error(`Project "${project}" not found at ${projectDir}.`);
32704
33024
  }
32705
33025
  return projectDir;
@@ -32712,7 +33032,7 @@ async function runResourceAdd(options) {
32712
33032
  if (!isValidSlug(slug)) {
32713
33033
  throw new Error(`Invalid resource slug: "${slug}".`);
32714
33034
  }
32715
- const filePath = resolve80(projectDir, "resources", `${slug}.md`);
33035
+ const filePath = resolve81(projectDir, "resources", `${slug}.md`);
32716
33036
  if (await fileExists(filePath) && !options.force) {
32717
33037
  throw new Error(
32718
33038
  `Resource "${slug}" already exists at ${filePath}. Use --force to overwrite.`
@@ -32729,9 +33049,9 @@ async function runResourceAdd(options) {
32729
33049
  return { filePath, indexPath, total };
32730
33050
  }
32731
33051
  async function listResourceSlugs(projectDir) {
32732
- const dir = resolve80(projectDir, "resources");
33052
+ const dir = resolve81(projectDir, "resources");
32733
33053
  if (!await fileExists(dir)) return [];
32734
- const entries = await readdir29(dir, { withFileTypes: true });
33054
+ const entries = await readdir30(dir, { withFileTypes: true });
32735
33055
  return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && e.name !== "_index.md").map((e) => e.name.slice(0, -3)).sort();
32736
33056
  }
32737
33057
  async function runResourceList(project) {
@@ -32739,16 +33059,16 @@ async function runResourceList(project) {
32739
33059
  const slugs = await listResourceSlugs(projectDir);
32740
33060
  const out = [];
32741
33061
  for (const slug of slugs) {
32742
- const parsed = parseResource(await readFile57(resolve80(projectDir, "resources", `${slug}.md`), "utf-8"));
33062
+ const parsed = parseResource(await readFile58(resolve81(projectDir, "resources", `${slug}.md`), "utf-8"));
32743
33063
  out.push({ slug, name: parsed.name, category: parsed.category, source: parsed.source, updated: parsed.updated });
32744
33064
  }
32745
33065
  return out;
32746
33066
  }
32747
33067
  async function runResourceShow(project, slug) {
32748
33068
  const projectDir = await resolveProjectDir(project);
32749
- const filePath = resolve80(projectDir, "resources", `${slug}.md`);
33069
+ const filePath = resolve81(projectDir, "resources", `${slug}.md`);
32750
33070
  if (!await fileExists(filePath)) throw new Error(`Resource "${slug}" not found in project "${project}".`);
32751
- const parsed = parseResource(await readFile57(filePath, "utf-8"));
33071
+ const parsed = parseResource(await readFile58(filePath, "utf-8"));
32752
33072
  return {
32753
33073
  slug,
32754
33074
  name: parsed.name,
@@ -32762,14 +33082,14 @@ async function runResourceShow(project, slug) {
32762
33082
  }
32763
33083
  async function runResourceUpdate(slug, options) {
32764
33084
  const projectDir = await resolveProjectDir(options.project);
32765
- const filePath = resolve80(projectDir, "resources", `${slug}.md`);
33085
+ const filePath = resolve81(projectDir, "resources", `${slug}.md`);
32766
33086
  if (!await fileExists(filePath)) {
32767
33087
  throw new Error(`Resource "${slug}" not found in project "${options.project}".`);
32768
33088
  }
32769
33089
  if (options.name === void 0 && options.source === void 0 && options.category === void 0 && options.relatedAssignments === void 0) {
32770
33090
  throw new Error("Provide at least one of --name, --source, --category, --related-assignments.");
32771
33091
  }
32772
- const original = await readFile57(filePath, "utf-8");
33092
+ const original = await readFile58(filePath, "utf-8");
32773
33093
  const content = editResourceFrontmatter(original, {
32774
33094
  name: options.name,
32775
33095
  category: options.category,
@@ -32782,7 +33102,7 @@ async function runResourceUpdate(slug, options) {
32782
33102
  }
32783
33103
  async function runResourceRemove(slug, options) {
32784
33104
  const projectDir = await resolveProjectDir(options.project);
32785
- const filePath = resolve80(projectDir, "resources", `${slug}.md`);
33105
+ const filePath = resolve81(projectDir, "resources", `${slug}.md`);
32786
33106
  if (!await fileExists(filePath)) {
32787
33107
  throw new Error(`Resource "${slug}" not found in project "${options.project}".`);
32788
33108
  }
@@ -32865,8 +33185,8 @@ init_config2();
32865
33185
  init_fs();
32866
33186
  init_slug();
32867
33187
  import { Command as Command13 } from "commander";
32868
- import { resolve as resolve81 } from "path";
32869
- import { readFile as readFile58, readdir as readdir30, rm as rm15 } from "fs/promises";
33188
+ import { resolve as resolve82 } from "path";
33189
+ import { readFile as readFile59, readdir as readdir31, rm as rm15 } from "fs/promises";
32870
33190
  init_parser();
32871
33191
  function nowIso5() {
32872
33192
  return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
@@ -32930,8 +33250,8 @@ ${opts.body ?? "<!-- Capture the load-bearing context for this memory here. -->"
32930
33250
  }
32931
33251
  async function resolveProjectDir2(project) {
32932
33252
  if (!isValidSlug(project)) throw new Error(`Invalid project slug: "${project}".`);
32933
- const projectDir = resolve81((await readConfig()).defaultProjectDir, project);
32934
- if (!await fileExists(resolve81(projectDir, "project.md"))) {
33253
+ const projectDir = resolve82((await readConfig()).defaultProjectDir, project);
33254
+ if (!await fileExists(resolve82(projectDir, "project.md"))) {
32935
33255
  throw new Error(`Project "${project}" not found at ${projectDir}.`);
32936
33256
  }
32937
33257
  return projectDir;
@@ -32944,7 +33264,7 @@ async function runMemoryAdd(options) {
32944
33264
  if (!isValidSlug(slug)) {
32945
33265
  throw new Error(`Invalid memory slug: "${slug}".`);
32946
33266
  }
32947
- const filePath = resolve81(projectDir, "memories", `${slug}.md`);
33267
+ const filePath = resolve82(projectDir, "memories", `${slug}.md`);
32948
33268
  if (await fileExists(filePath) && !options.force) {
32949
33269
  throw new Error(
32950
33270
  `Memory "${slug}" already exists at ${filePath}. Use --force to overwrite.`
@@ -32962,9 +33282,9 @@ async function runMemoryAdd(options) {
32962
33282
  return { filePath, indexPath, total };
32963
33283
  }
32964
33284
  async function listMemorySlugs(projectDir) {
32965
- const dir = resolve81(projectDir, "memories");
33285
+ const dir = resolve82(projectDir, "memories");
32966
33286
  if (!await fileExists(dir)) return [];
32967
- const entries = await readdir30(dir, { withFileTypes: true });
33287
+ const entries = await readdir31(dir, { withFileTypes: true });
32968
33288
  return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && e.name !== "_index.md").map((e) => e.name.slice(0, -3)).sort();
32969
33289
  }
32970
33290
  async function runMemoryList(project) {
@@ -32972,16 +33292,16 @@ async function runMemoryList(project) {
32972
33292
  const slugs = await listMemorySlugs(projectDir);
32973
33293
  const out = [];
32974
33294
  for (const slug of slugs) {
32975
- const parsed = parseMemory(await readFile58(resolve81(projectDir, "memories", `${slug}.md`), "utf-8"));
33295
+ const parsed = parseMemory(await readFile59(resolve82(projectDir, "memories", `${slug}.md`), "utf-8"));
32976
33296
  out.push({ slug, name: parsed.name, scope: parsed.scope, source: parsed.source, updated: parsed.updated });
32977
33297
  }
32978
33298
  return out;
32979
33299
  }
32980
33300
  async function runMemoryShow(project, slug) {
32981
33301
  const projectDir = await resolveProjectDir2(project);
32982
- const filePath = resolve81(projectDir, "memories", `${slug}.md`);
33302
+ const filePath = resolve82(projectDir, "memories", `${slug}.md`);
32983
33303
  if (!await fileExists(filePath)) throw new Error(`Memory "${slug}" not found in project "${project}".`);
32984
- const parsed = parseMemory(await readFile58(filePath, "utf-8"));
33304
+ const parsed = parseMemory(await readFile59(filePath, "utf-8"));
32985
33305
  return {
32986
33306
  slug,
32987
33307
  name: parsed.name,
@@ -32996,7 +33316,7 @@ async function runMemoryShow(project, slug) {
32996
33316
  }
32997
33317
  async function runMemoryUpdate(slug, options) {
32998
33318
  const projectDir = await resolveProjectDir2(options.project);
32999
- const filePath = resolve81(projectDir, "memories", `${slug}.md`);
33319
+ const filePath = resolve82(projectDir, "memories", `${slug}.md`);
33000
33320
  if (!await fileExists(filePath)) {
33001
33321
  throw new Error(`Memory "${slug}" not found in project "${options.project}".`);
33002
33322
  }
@@ -33005,7 +33325,7 @@ async function runMemoryUpdate(slug, options) {
33005
33325
  "Provide at least one of --name, --source, --scope, --source-assignment, --related-assignments."
33006
33326
  );
33007
33327
  }
33008
- const original = await readFile58(filePath, "utf-8");
33328
+ const original = await readFile59(filePath, "utf-8");
33009
33329
  const content = editMemoryFrontmatter(original, {
33010
33330
  name: options.name,
33011
33331
  source: options.source,
@@ -33019,7 +33339,7 @@ async function runMemoryUpdate(slug, options) {
33019
33339
  }
33020
33340
  async function runMemoryRemove(slug, options) {
33021
33341
  const projectDir = await resolveProjectDir2(options.project);
33022
- const filePath = resolve81(projectDir, "memories", `${slug}.md`);
33342
+ const filePath = resolve82(projectDir, "memories", `${slug}.md`);
33023
33343
  if (!await fileExists(filePath)) {
33024
33344
  throw new Error(`Memory "${slug}" not found in project "${options.project}".`);
33025
33345
  }
@@ -33104,8 +33424,8 @@ init_paths();
33104
33424
  init_fs();
33105
33425
  init_frontmatter();
33106
33426
  import { Command as Command14 } from "commander";
33107
- import { readFile as readFile59 } from "fs/promises";
33108
- import { resolve as resolve82 } from "path";
33427
+ import { readFile as readFile60 } from "fs/promises";
33428
+ import { resolve as resolve83 } from "path";
33109
33429
  var AGE_PATTERN = /^(\d+)([dhwm])$/i;
33110
33430
  function parseAgeToCutoff(age) {
33111
33431
  const match = age.match(AGE_PATTERN);
@@ -33124,7 +33444,7 @@ function parseAgeToCutoff(age) {
33124
33444
  }
33125
33445
  function assignmentMdPath(item) {
33126
33446
  if (item.projectSlug) {
33127
- return resolve82(
33447
+ return resolve83(
33128
33448
  defaultProjectDir(),
33129
33449
  item.projectSlug,
33130
33450
  "assignments",
@@ -33132,13 +33452,13 @@ function assignmentMdPath(item) {
33132
33452
  "assignment.md"
33133
33453
  );
33134
33454
  }
33135
- return resolve82(assignmentsDir(), item.id, "assignment.md");
33455
+ return resolve83(assignmentsDir(), item.id, "assignment.md");
33136
33456
  }
33137
33457
  async function loadTags(item) {
33138
33458
  const path = assignmentMdPath(item);
33139
33459
  if (!await fileExists(path)) return [];
33140
33460
  try {
33141
- const content = await readFile59(path, "utf-8");
33461
+ const content = await readFile60(path, "utf-8");
33142
33462
  return parseAssignmentFrontmatter(content).tags;
33143
33463
  } catch {
33144
33464
  return [];
@@ -33567,8 +33887,8 @@ init_fs();
33567
33887
  init_timestamp();
33568
33888
  init_frontmatter();
33569
33889
  import { Command as Command16 } from "commander";
33570
- import { readFile as readFile60 } from "fs/promises";
33571
- import { resolve as resolve83 } from "path";
33890
+ import { readFile as readFile61 } from "fs/promises";
33891
+ import { resolve as resolve84 } from "path";
33572
33892
  async function scanDirs() {
33573
33893
  const config = await readConfig();
33574
33894
  return { projectsDir: config.defaultProjectDir, standaloneDir: assignmentsDir() };
@@ -33578,12 +33898,12 @@ function fail3(error) {
33578
33898
  process.exit(1);
33579
33899
  }
33580
33900
  function configPath() {
33581
- return resolve83(syntaurRoot(), "config.md");
33901
+ return resolve84(syntaurRoot(), "config.md");
33582
33902
  }
33583
33903
  async function readStatusBlock() {
33584
33904
  const p = configPath();
33585
33905
  if (!await fileExists(p)) return null;
33586
- const content = await readFile60(p, "utf-8");
33906
+ const content = await readFile61(p, "utf-8");
33587
33907
  return parseStatusConfig(content);
33588
33908
  }
33589
33909
  async function requireStatusBlock() {
@@ -33832,7 +34152,7 @@ async function runStatusRename(id, opts) {
33832
34152
  printBlockDiff(before, after);
33833
34153
  const now2 = nowTimestamp();
33834
34154
  for (const a of affected) {
33835
- const original = await readFile60(a.path, "utf-8");
34155
+ const original = await readFile61(a.path, "utf-8");
33836
34156
  const rewritten = updateAssignmentFile(original, { status: newId, updated: now2 });
33837
34157
  console.log(`
33838
34158
  --- ${a.display}/assignment.md`);
@@ -33843,9 +34163,9 @@ async function runStatusRename(id, opts) {
33843
34163
  }
33844
34164
  const cfgPath = configPath();
33845
34165
  const buffers = /* @__PURE__ */ new Map();
33846
- buffers.set(cfgPath, await fileExists(cfgPath) ? await readFile60(cfgPath, "utf-8") : "");
34166
+ buffers.set(cfgPath, await fileExists(cfgPath) ? await readFile61(cfgPath, "utf-8") : "");
33847
34167
  for (const a of affected) {
33848
- buffers.set(a.path, await readFile60(a.path, "utf-8"));
34168
+ buffers.set(a.path, await readFile61(a.path, "utf-8"));
33849
34169
  }
33850
34170
  const now = nowTimestamp();
33851
34171
  try {
@@ -34025,13 +34345,13 @@ init_config2();
34025
34345
  init_timestamp();
34026
34346
  init_frontmatter();
34027
34347
  import { Command as Command17 } from "commander";
34028
- import { readFile as readFile61 } from "fs/promises";
34029
- import { resolve as resolve84 } from "path";
34348
+ import { readFile as readFile62 } from "fs/promises";
34349
+ import { resolve as resolve85 } from "path";
34030
34350
  async function readContext3(cwd) {
34031
- const path = resolve84(cwd, ".syntaur", "context.json");
34351
+ const path = resolve85(cwd, ".syntaur", "context.json");
34032
34352
  if (!await fileExists(path)) return null;
34033
34353
  try {
34034
- return JSON.parse(await readFile61(path, "utf-8"));
34354
+ return JSON.parse(await readFile62(path, "utf-8"));
34035
34355
  } catch {
34036
34356
  return null;
34037
34357
  }
@@ -34040,12 +34360,12 @@ async function resolveAssignmentPath3(opts) {
34040
34360
  if (opts.assignment) {
34041
34361
  if (opts.project) {
34042
34362
  const projectsDir2 = (await readConfig()).defaultProjectDir;
34043
- return resolve84(projectsDir2, opts.project, "assignments", opts.assignment, "assignment.md");
34363
+ return resolve85(projectsDir2, opts.project, "assignments", opts.assignment, "assignment.md");
34044
34364
  }
34045
- return resolve84(assignmentsDir(), opts.assignment, "assignment.md");
34365
+ return resolve85(assignmentsDir(), opts.assignment, "assignment.md");
34046
34366
  }
34047
34367
  const ctx = await readContext3(opts.cwd);
34048
- if (ctx?.assignmentDir) return resolve84(ctx.assignmentDir, "assignment.md");
34368
+ if (ctx?.assignmentDir) return resolve85(ctx.assignmentDir, "assignment.md");
34049
34369
  throw new Error(
34050
34370
  "No active assignment. Pass --assignment <slug> [--project <slug>] or run from a workspace with .syntaur/context.json."
34051
34371
  );
@@ -34082,7 +34402,7 @@ async function runWorkspaceSet(options, cwd = process.cwd()) {
34082
34402
  ${pre.errors.map((e) => ` - ${e}`).join("\n")}`
34083
34403
  );
34084
34404
  }
34085
- const original = await readFile61(path, "utf-8");
34405
+ const original = await readFile62(path, "utf-8");
34086
34406
  let next = updateAssignmentWorkspace(original, partial);
34087
34407
  next = updateAssignmentFile(next, { updated: nowTimestamp() });
34088
34408
  await writeFileForce(path, next);
@@ -34119,13 +34439,13 @@ init_config2();
34119
34439
  init_timestamp();
34120
34440
  init_templates();
34121
34441
  import { Command as Command18 } from "commander";
34122
- import { readFile as readFile62 } from "fs/promises";
34123
- import { resolve as resolve85 } from "path";
34442
+ import { readFile as readFile63 } from "fs/promises";
34443
+ import { resolve as resolve86 } from "path";
34124
34444
  async function readContext4(cwd) {
34125
- const path = resolve85(cwd, ".syntaur", "context.json");
34445
+ const path = resolve86(cwd, ".syntaur", "context.json");
34126
34446
  if (!await fileExists(path)) return null;
34127
34447
  try {
34128
- return JSON.parse(await readFile62(path, "utf-8"));
34448
+ return JSON.parse(await readFile63(path, "utf-8"));
34129
34449
  } catch {
34130
34450
  return null;
34131
34451
  }
@@ -34135,11 +34455,11 @@ async function resolveAssignmentDir2(opts) {
34135
34455
  if (opts.project) {
34136
34456
  const projectsDir2 = (await readConfig()).defaultProjectDir;
34137
34457
  return {
34138
- dir: resolve85(projectsDir2, opts.project, "assignments", opts.assignment),
34458
+ dir: resolve86(projectsDir2, opts.project, "assignments", opts.assignment),
34139
34459
  slug: opts.assignment
34140
34460
  };
34141
34461
  }
34142
- return { dir: resolve85(assignmentsDir(), opts.assignment), slug: opts.assignment };
34462
+ return { dir: resolve86(assignmentsDir(), opts.assignment), slug: opts.assignment };
34143
34463
  }
34144
34464
  const ctx = await readContext4(opts.cwd);
34145
34465
  if (ctx?.assignmentDir) {
@@ -34201,12 +34521,12 @@ async function runProgressLog(text, options, cwd = process.cwd()) {
34201
34521
  project: options.project,
34202
34522
  cwd
34203
34523
  });
34204
- if (!await fileExists(resolve85(dir, "assignment.md"))) {
34524
+ if (!await fileExists(resolve86(dir, "assignment.md"))) {
34205
34525
  throw new Error(`No assignment found at ${dir} (missing assignment.md).`);
34206
34526
  }
34207
- const path = resolve85(dir, "progress.md");
34527
+ const path = resolve86(dir, "progress.md");
34208
34528
  const now = nowTimestamp();
34209
- const content = await fileExists(path) ? await readFile62(path, "utf-8") : renderProgress({ assignment: slug, timestamp: now });
34529
+ const content = await fileExists(path) ? await readFile63(path, "utf-8") : renderProgress({ assignment: slug, timestamp: now });
34210
34530
  const next = appendProgressEntry(content, text, now);
34211
34531
  await writeFileForce(path, next);
34212
34532
  return path;
@@ -34226,10 +34546,10 @@ progressCommand.command("log").description("Append a timestamped entry to the as
34226
34546
 
34227
34547
  // src/cli-default-command.ts
34228
34548
  init_config2();
34229
- import { readdir as readdir31 } from "fs/promises";
34549
+ import { readdir as readdir32 } from "fs/promises";
34230
34550
  async function hasAnyProjectContent(projectsDir2) {
34231
34551
  try {
34232
- const entries = await readdir31(projectsDir2, { withFileTypes: true });
34552
+ const entries = await readdir32(projectsDir2, { withFileTypes: true });
34233
34553
  return entries.some((entry) => entry.isDirectory());
34234
34554
  } catch {
34235
34555
  return false;
@@ -34531,7 +34851,7 @@ program.command("reopen").description("Reopen a completed or failed assignment")
34531
34851
  process.exit(1);
34532
34852
  }
34533
34853
  });
34534
- program.command("setup").description("Initialize Syntaur and optionally install plugins or launch the dashboard").option("--yes", "Skip interactive prompts and perform only the requested flags").option("--claude", "Install the Claude Code plugin").option("--codex", "Install the Codex plugin").option("--claude-dir <path>", "Install the Claude Code plugin at a specific path").option("--codex-dir <path>", "Install the Codex plugin at a specific path").option("--codex-marketplace-path <path>", "Write the Codex marketplace entry to a specific file").option("--dashboard", "Launch the dashboard after setup").option("--target <id>", "Install Syntaur into a cross-agent target (pi, hermes, openclaw, cursor, opencode); comma-separated for several").option("--agent <id>", "Alias for --target; cross-agent target id(s) to install into").option("--force", "Overwrite existing cross-agent protocol files / skills").option("--dry-run", "Print the cross-agent install actions without writing anything").action(async (options) => {
34854
+ program.command("setup").description("Initialize Syntaur and optionally install plugins or launch the dashboard").option("--yes", "Skip interactive prompts and perform only the requested flags").option("--claude", "Install the Claude Code plugin").option("--codex", "Install the Codex plugin").option("--claude-dir <path>", "Install the Claude Code plugin at a specific path").option("--codex-dir <path>", "Install the Codex plugin at a specific path").option("--codex-marketplace-path <path>", "Write the Codex marketplace entry to a specific file").option("--dashboard", "Launch the dashboard after setup").option("--target <id>", "Install Syntaur into a cross-agent target. Built-in ids: pi, hermes, openclaw, cursor, opencode (plus any user descriptors in ~/.syntaur/targets/). Comma-separated for several").option("--agent <id>", "Alias for --target; cross-agent target id(s) to install into").option("--force", "Overwrite existing cross-agent protocol files / skills").option("--dry-run", "Print the cross-agent install actions without writing anything").action(async (options) => {
34535
34855
  try {
34536
34856
  await setupCommand(options);
34537
34857
  } catch (error) {
@@ -34640,7 +34960,7 @@ program.command("uninstall").description("Remove Syntaur integrations and option
34640
34960
  process.exit(1);
34641
34961
  }
34642
34962
  });
34643
- program.command("setup-adapter").description("Generate adapter instruction files for a framework in the current directory").argument("<framework>", "Target framework (cursor, codex, opencode)").option("--project <slug>", "Target project slug (required)").option("--assignment <slug>", "Target assignment slug (required)").option("--force", "Overwrite existing adapter files").option("--dir <path>", "Override default project directory").action(async (framework, options) => {
34963
+ program.command("setup-adapter").description("Generate adapter instruction files for a framework in the current directory").argument("<framework>", "Target framework: built-in ids cursor, codex, opencode, pi, openclaw, hermes (plus any user descriptor with an instructions adapter in ~/.syntaur/targets/)").option("--project <slug>", "Target project slug (required)").option("--assignment <slug>", "Target assignment slug (required)").option("--force", "Overwrite existing adapter files").option("--dir <path>", "Override default project directory").action(async (framework, options) => {
34644
34964
  try {
34645
34965
  await setupAdapterCommand(framework, options);
34646
34966
  } catch (error) {