syntaur 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +218 -54
  2. package/dashboard/dist/assets/{_basePickBy-BhaCV7eH.js → _basePickBy-CWivToyi.js} +1 -1
  3. package/dashboard/dist/assets/{_baseUniq-CDPcqrs2.js → _baseUniq-C-qj6E4l.js} +1 -1
  4. package/dashboard/dist/assets/{arc-BP0RxLwl.js → arc-Dn5BIqMa.js} +1 -1
  5. package/dashboard/dist/assets/{architectureDiagram-2XIMDMQ5-BDzvaeJp.js → architectureDiagram-2XIMDMQ5-D5D0K7rY.js} +1 -1
  6. package/dashboard/dist/assets/{blockDiagram-WCTKOSBZ-ZeL9mROo.js → blockDiagram-WCTKOSBZ-DVmYPMbu.js} +1 -1
  7. package/dashboard/dist/assets/{c4Diagram-IC4MRINW-7S5bvFLp.js → c4Diagram-IC4MRINW-BEasxbnl.js} +1 -1
  8. package/dashboard/dist/assets/channel-DqU_8tiy.js +1 -0
  9. package/dashboard/dist/assets/{chunk-4BX2VUAB-Ca7R4nv5.js → chunk-4BX2VUAB-LDIrtI5E.js} +1 -1
  10. package/dashboard/dist/assets/{chunk-55IACEB6-flEv13FB.js → chunk-55IACEB6-CaEBUJYu.js} +1 -1
  11. package/dashboard/dist/assets/{chunk-FMBD7UC4-CfcYWBM6.js → chunk-FMBD7UC4-B-GjCpdr.js} +1 -1
  12. package/dashboard/dist/assets/{chunk-JSJVCQXG-Dw4yL0VS.js → chunk-JSJVCQXG-BLVVcezm.js} +1 -1
  13. package/dashboard/dist/assets/{chunk-KX2RTZJC-B2cDe40G.js → chunk-KX2RTZJC-DqCNEw4h.js} +1 -1
  14. package/dashboard/dist/assets/{chunk-NQ4KR5QH-LZVm0IWg.js → chunk-NQ4KR5QH-BCPbFf5I.js} +1 -1
  15. package/dashboard/dist/assets/{chunk-QZHKN3VN-Dg0EeHNI.js → chunk-QZHKN3VN-Ci0C85q_.js} +1 -1
  16. package/dashboard/dist/assets/{chunk-WL4C6EOR-v3rXNwXc.js → chunk-WL4C6EOR-VVhAMMYU.js} +1 -1
  17. package/dashboard/dist/assets/classDiagram-VBA2DB6C-D29Eeoe8.js +1 -0
  18. package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-D29Eeoe8.js +1 -0
  19. package/dashboard/dist/assets/clone-Bok8Q3Jj.js +1 -0
  20. package/dashboard/dist/assets/{cose-bilkent-S5V4N54A-D-3JzLoS.js → cose-bilkent-S5V4N54A-CO9uwgYO.js} +1 -1
  21. package/dashboard/dist/assets/{dagre-KLK3FWXG-d_mbczhU.js → dagre-KLK3FWXG-bwLLXcL4.js} +1 -1
  22. package/dashboard/dist/assets/{diagram-E7M64L7V-BUyAp8pW.js → diagram-E7M64L7V-RuS5R6V1.js} +1 -1
  23. package/dashboard/dist/assets/{diagram-IFDJBPK2-C8doXcyQ.js → diagram-IFDJBPK2-BQDJAHQd.js} +1 -1
  24. package/dashboard/dist/assets/{diagram-P4PSJMXO-BUSmHa55.js → diagram-P4PSJMXO-yLEsgzE5.js} +1 -1
  25. package/dashboard/dist/assets/{erDiagram-INFDFZHY-Bn5_0LPU.js → erDiagram-INFDFZHY-na6dUhY0.js} +1 -1
  26. package/dashboard/dist/assets/{flowDiagram-PKNHOUZH-CnEjerQM.js → flowDiagram-PKNHOUZH-BIcrzwJR.js} +1 -1
  27. package/dashboard/dist/assets/{ganttDiagram-A5KZAMGK-CL94fbyy.js → ganttDiagram-A5KZAMGK-DHWRJn-D.js} +1 -1
  28. package/dashboard/dist/assets/{gitGraphDiagram-K3NZZRJ6-4i_PeG8V.js → gitGraphDiagram-K3NZZRJ6-LGxDjL71.js} +1 -1
  29. package/dashboard/dist/assets/{graph-BtoFhoAd.js → graph-BUqNu277.js} +1 -1
  30. package/dashboard/dist/assets/{index-Dv_-SxuL.js → index-D-fepllQ.js} +3 -3
  31. package/dashboard/dist/assets/index-DnHyQJJH.css +1 -0
  32. package/dashboard/dist/assets/{infoDiagram-LFFYTUFH-CdUsuNgZ.js → infoDiagram-LFFYTUFH-DidoA2hb.js} +1 -1
  33. package/dashboard/dist/assets/{ishikawaDiagram-PHBUUO56-BjggRlUx.js → ishikawaDiagram-PHBUUO56-CdlZkbhV.js} +1 -1
  34. package/dashboard/dist/assets/{journeyDiagram-4ABVD52K-V4AgexlR.js → journeyDiagram-4ABVD52K-luhcz_gn.js} +1 -1
  35. package/dashboard/dist/assets/{kanban-definition-K7BYSVSG-ChlylQRf.js → kanban-definition-K7BYSVSG-Coidw9XE.js} +1 -1
  36. package/dashboard/dist/assets/{layout-DLcz9AmA.js → layout-_aBAAleE.js} +1 -1
  37. package/dashboard/dist/assets/{linear-l2xnSHze.js → linear-D8mFnDSx.js} +1 -1
  38. package/dashboard/dist/assets/{mermaid.core-DKO1ytRW.js → mermaid.core-BpP2keU-.js} +4 -4
  39. package/dashboard/dist/assets/{mindmap-definition-YRQLILUH-DTmTPHrT.js → mindmap-definition-YRQLILUH-LjvrTe2z.js} +1 -1
  40. package/dashboard/dist/assets/{pieDiagram-SKSYHLDU-CwK80y8Y.js → pieDiagram-SKSYHLDU-CkA2iU6e.js} +1 -1
  41. package/dashboard/dist/assets/{quadrantDiagram-337W2JSQ-Be1xqW_w.js → quadrantDiagram-337W2JSQ-BRmhKHQG.js} +1 -1
  42. package/dashboard/dist/assets/{requirementDiagram-Z7DCOOCP-JcspXCs0.js → requirementDiagram-Z7DCOOCP-BYCQ4uFX.js} +1 -1
  43. package/dashboard/dist/assets/{sankeyDiagram-WA2Y5GQK-nJb1BInq.js → sankeyDiagram-WA2Y5GQK-C8SVk50M.js} +1 -1
  44. package/dashboard/dist/assets/{sequenceDiagram-2WXFIKYE-DUrclEgA.js → sequenceDiagram-2WXFIKYE-CbA_2lnP.js} +1 -1
  45. package/dashboard/dist/assets/{stateDiagram-RAJIS63D-CjinnNtF.js → stateDiagram-RAJIS63D-D6ZtjAHE.js} +1 -1
  46. package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-DeYN4wV6.js +1 -0
  47. package/dashboard/dist/assets/{timeline-definition-YZTLITO2-kM-oVLNz.js → timeline-definition-YZTLITO2-B2Uf-emK.js} +1 -1
  48. package/dashboard/dist/assets/{treemap-KZPCXAKY-CYziFlrQ.js → treemap-KZPCXAKY-CYnFKsuJ.js} +1 -1
  49. package/dashboard/dist/assets/{vennDiagram-LZ73GAT5-DX0DbxBN.js → vennDiagram-LZ73GAT5-Cnj0qiDO.js} +1 -1
  50. package/dashboard/dist/assets/{xychartDiagram-JWTSCODW-BGqM42ZM.js → xychartDiagram-JWTSCODW-BJy2mbL9.js} +1 -1
  51. package/dashboard/dist/index.html +4 -4
  52. package/dist/index.js +380 -149
  53. package/dist/index.js.map +1 -1
  54. package/package.json +3 -1
  55. package/scripts/postinstall-submodules.mjs +40 -0
  56. package/statusline/statusline.sh +166 -46
  57. package/dashboard/dist/assets/channel-CcB_wcgb.js +0 -1
  58. package/dashboard/dist/assets/classDiagram-VBA2DB6C-BJr38z2g.js +0 -1
  59. package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-BJr38z2g.js +0 -1
  60. package/dashboard/dist/assets/clone-Cfs2GUGt.js +0 -1
  61. package/dashboard/dist/assets/index-DZUGYrvE.css +0 -1
  62. package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-yfclw-nM.js +0 -1
package/dist/index.js CHANGED
@@ -4429,7 +4429,7 @@ function App({ projectsDir: projectsDir2, onLaunch }) {
4429
4429
  collapseNode,
4430
4430
  currentNode
4431
4431
  } = useTreeState(nodes, filteredIds);
4432
- useInput((input2, key) => {
4432
+ useInput((input3, key) => {
4433
4433
  if (searchActive) {
4434
4434
  if (key.escape) {
4435
4435
  setSearchActive(false);
@@ -4442,19 +4442,19 @@ function App({ projectsDir: projectsDir2, onLaunch }) {
4442
4442
  }
4443
4443
  return;
4444
4444
  }
4445
- if (input2 === "q" || key.escape) {
4445
+ if (input3 === "q" || key.escape) {
4446
4446
  exit();
4447
4447
  return;
4448
4448
  }
4449
- if (input2 === "/") {
4449
+ if (input3 === "/") {
4450
4450
  setSearchActive(true);
4451
4451
  return;
4452
4452
  }
4453
- if (key.upArrow || input2 === "k") {
4453
+ if (key.upArrow || input3 === "k") {
4454
4454
  moveUp();
4455
4455
  return;
4456
4456
  }
4457
- if (key.downArrow || input2 === "j") {
4457
+ if (key.downArrow || input3 === "j") {
4458
4458
  moveDown();
4459
4459
  return;
4460
4460
  }
@@ -4546,8 +4546,8 @@ __export(launch_exports, {
4546
4546
  launchAgent: () => launchAgent
4547
4547
  });
4548
4548
  import { spawn as spawn2 } from "child_process";
4549
- import { mkdir as mkdir4, writeFile as writeFile8 } from "fs/promises";
4550
- import { resolve as resolve30 } from "path";
4549
+ import { mkdir as mkdir4, writeFile as writeFile9 } from "fs/promises";
4550
+ import { resolve as resolve31 } from "path";
4551
4551
  async function launchAgent(options) {
4552
4552
  const { projectsDir: projectsDir2, projectSlug, assignmentSlug, agent } = options;
4553
4553
  const command = AGENT_COMMANDS[agent];
@@ -4557,9 +4557,9 @@ async function launchAgent(options) {
4557
4557
  process.exit(1);
4558
4558
  }
4559
4559
  const workspaceDir = detail.workspace.worktreePath ?? (detail.workspace.repository?.startsWith("/") ? detail.workspace.repository : null) ?? process.cwd();
4560
- const projectDir = resolve30(projectsDir2, projectSlug);
4561
- const assignmentDir = resolve30(projectDir, "assignments", assignmentSlug);
4562
- const contextDir = resolve30(workspaceDir, ".syntaur");
4560
+ const projectDir = resolve31(projectsDir2, projectSlug);
4561
+ const assignmentDir = resolve31(projectDir, "assignments", assignmentSlug);
4562
+ const contextDir = resolve31(workspaceDir, ".syntaur");
4563
4563
  await mkdir4(contextDir, { recursive: true });
4564
4564
  const context = {
4565
4565
  projectSlug,
@@ -4571,8 +4571,8 @@ async function launchAgent(options) {
4571
4571
  branch: detail.workspace.branch ?? null,
4572
4572
  grabbedAt: (/* @__PURE__ */ new Date()).toISOString()
4573
4573
  };
4574
- await writeFile8(
4575
- resolve30(contextDir, "context.json"),
4574
+ await writeFile9(
4575
+ resolve31(contextDir, "context.json"),
4576
4576
  JSON.stringify(context, null, 2) + "\n"
4577
4577
  );
4578
4578
  return new Promise((resolvePromise, reject) => {
@@ -5909,8 +5909,8 @@ async function migrateFromMarkdown(projectsDir2) {
5909
5909
  return allSessions.length;
5910
5910
  }
5911
5911
  async function parseMarkdownSessionsIndex(filePath, projectSlug) {
5912
- const { readFile: readFile28 } = await import("fs/promises");
5913
- const raw = await readFile28(filePath, "utf-8");
5912
+ const { readFile: readFile29 } = await import("fs/promises");
5913
+ const raw = await readFile29(filePath, "utf-8");
5914
5914
  const sessions = [];
5915
5915
  const lines = raw.split("\n");
5916
5916
  let inTable = false;
@@ -7637,8 +7637,8 @@ ${entry}`;
7637
7637
  });
7638
7638
  return router;
7639
7639
  }
7640
- function slugifyLocal(input2) {
7641
- return input2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "untitled";
7640
+ function slugifyLocal(input3) {
7641
+ return input3.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "untitled";
7642
7642
  }
7643
7643
  async function appendCommentTo(assignmentDir, assignmentRef, req, res, reloadDetail) {
7644
7644
  const commentsPath = resolve15(assignmentDir, "comments.md");
@@ -8218,8 +8218,8 @@ function createTodosRouter(todosDir2, broadcast) {
8218
8218
  router.post("/:workspace/archive", async (req, res) => {
8219
8219
  try {
8220
8220
  const { archivePath: archivePath2 } = await Promise.resolve().then(() => (init_parser2(), parser_exports));
8221
- const { resolve: resolve44 } = await import("path");
8222
- const { readFile: readFile28 } = await import("fs/promises");
8221
+ const { resolve: resolve45 } = await import("path");
8222
+ const { readFile: readFile29 } = await import("fs/promises");
8223
8223
  const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
8224
8224
  const workspace = getWorkspaceParam(req.params.workspace);
8225
8225
  const checklist = await readChecklist(todosDir2, workspace);
@@ -8235,10 +8235,10 @@ function createTodosRouter(todosDir2, broadcast) {
8235
8235
  (e) => e.itemIds.every((id) => completedIds.has(id))
8236
8236
  );
8237
8237
  const archFile = archivePath2(todosDir2, workspace, checklist.archiveInterval);
8238
- await ensureDir(resolve44(todosDir2, "archive"));
8238
+ await ensureDir(resolve45(todosDir2, "archive"));
8239
8239
  let archContent = "";
8240
8240
  if (await fileExists(archFile)) {
8241
- archContent = await readFile28(archFile, "utf-8");
8241
+ archContent = await readFile29(archFile, "utf-8");
8242
8242
  archContent = archContent.trimEnd() + "\n\n";
8243
8243
  } else {
8244
8244
  archContent = `---
@@ -10753,17 +10753,230 @@ async function installPluginCommand(options) {
10753
10753
  // src/commands/install-statusline.ts
10754
10754
  init_paths();
10755
10755
  init_fs();
10756
- import { readFile as readFile17, writeFile as writeFile7, copyFile as copyFile2, rm as rm5, stat as stat3, symlink as symlink2, unlink as unlink6, lstat as lstat2 } from "fs/promises";
10757
- import { resolve as resolve26, dirname as dirname8 } from "path";
10756
+ import { readFile as readFile18, writeFile as writeFile8, copyFile as copyFile2, rm as rm5, stat as stat3, symlink as symlink2, unlink as unlink6, lstat as lstat2 } from "fs/promises";
10757
+ import { resolve as resolve27, dirname as dirname9 } from "path";
10758
10758
  import { homedir as homedir4 } from "os";
10759
10759
  import { fileURLToPath as fileURLToPath5 } from "url";
10760
+
10761
+ // src/commands/configure-statusline.ts
10762
+ init_paths();
10763
+ init_fs();
10764
+ import { readFile as readFile17, writeFile as writeFile7 } from "fs/promises";
10765
+ import { resolve as resolve26, dirname as dirname8 } from "path";
10766
+ import { spawnSync } from "child_process";
10767
+ import { checkbox, input as input2, confirm } from "@inquirer/prompts";
10768
+ var AVAILABLE_SEGMENTS = [
10769
+ { name: "git", preview: "syntaur:main* +2", description: "repo:branch (with dirty marker and ahead/behind)" },
10770
+ { name: "assignment", preview: "my-proj/demo-assn \u2014 Demo Assignment", description: "active syntaur assignment (project/slug or standalone/uuid)" },
10771
+ { name: "external", preview: "PROJ-123, ENG-456", description: "external tracker IDs from assignment externalIds (Jira, Linear, \u2026)" },
10772
+ { name: "session", preview: "\u2026ccddeeff", description: "Claude Code session id \u2014 last 8 chars prefixed by \u2026" },
10773
+ { name: "model", preview: "Opus 4.7", description: "Claude model display name" },
10774
+ { name: "ctx", preview: "ctx:[####------] 42%", description: "context window fill bar" },
10775
+ { name: "cwd", preview: "syntaur", description: "basename of current working directory" },
10776
+ { name: "wrap", preview: "<output of an external script>", description: "compose another statusline script as a leading segment" }
10777
+ ];
10778
+ var PRESETS = {
10779
+ minimal: { segments: ["git", "session"], separator: " \xB7 " },
10780
+ syntaur: { segments: ["git", "assignment", "session"], separator: " \xB7 " },
10781
+ full: { segments: ["wrap", "git", "assignment", "external", "model", "ctx", "session"], separator: " \xB7 " },
10782
+ dev: { segments: ["git", "assignment", "external", "ctx", "session"], separator: " \xB7 " },
10783
+ tracker: { segments: ["git", "assignment", "external", "session"], separator: " \xB7 " }
10784
+ };
10785
+ function getConfigPath(installRoot) {
10786
+ return resolve26(installRoot, "statusline.config.json");
10787
+ }
10788
+ async function readConfig2(path) {
10789
+ if (!await fileExists(path)) return null;
10790
+ try {
10791
+ const raw = await readFile17(path, "utf-8");
10792
+ const parsed = JSON.parse(raw);
10793
+ if (!parsed || typeof parsed !== "object") return null;
10794
+ const segments = Array.isArray(parsed.segments) ? parsed.segments.filter(isSegmentName) : [];
10795
+ const separator = typeof parsed.separator === "string" ? parsed.separator : " \xB7 ";
10796
+ const wrap = typeof parsed.wrap === "string" ? parsed.wrap : void 0;
10797
+ return { segments, separator, wrap };
10798
+ } catch {
10799
+ return null;
10800
+ }
10801
+ }
10802
+ function isSegmentName(value) {
10803
+ return typeof value === "string" && AVAILABLE_SEGMENTS.some((s) => s.name === value);
10804
+ }
10805
+ function parseSegmentsFlag(flag) {
10806
+ const parts = flag.split(",").map((s) => s.trim()).filter(Boolean);
10807
+ const invalid = parts.filter((p) => !AVAILABLE_SEGMENTS.some((s) => s.name === p));
10808
+ if (invalid.length > 0) {
10809
+ throw new Error(
10810
+ `Unknown segment${invalid.length > 1 ? "s" : ""}: ${invalid.join(", ")}. Valid segments: ${AVAILABLE_SEGMENTS.map((s) => s.name).join(", ")}.`
10811
+ );
10812
+ }
10813
+ return parts;
10814
+ }
10815
+ async function promptSegmentsInteractive(current) {
10816
+ const canonicalOrder = ["wrap", "git", "assignment", "external", "session", "model", "ctx", "cwd"];
10817
+ const selectedSet = new Set(current?.segments ?? ["git", "assignment", "session"]);
10818
+ const choices = canonicalOrder.map((name) => {
10819
+ const def = AVAILABLE_SEGMENTS.find((s) => s.name === name);
10820
+ return {
10821
+ name: `${def.name.padEnd(11)} ${def.description}`,
10822
+ value: name,
10823
+ checked: selectedSet.has(name),
10824
+ description: `preview: ${def.preview}`
10825
+ };
10826
+ });
10827
+ const selected = await checkbox({
10828
+ message: "Pick segments (space to toggle, enter to confirm):",
10829
+ choices,
10830
+ loop: false,
10831
+ pageSize: choices.length,
10832
+ required: true
10833
+ });
10834
+ const defaultReorderHint = selected.join(", ");
10835
+ let orderedSegments = [...selected];
10836
+ const wantReorder = await confirm({
10837
+ message: `Order will be: ${defaultReorderHint}. Customize order?`,
10838
+ default: false
10839
+ });
10840
+ if (wantReorder) {
10841
+ const raw = await input2({
10842
+ message: `Enter the segments in the order you want, comma-separated:`,
10843
+ default: defaultReorderHint,
10844
+ validate: (value) => {
10845
+ const parts = value.split(",").map((s) => s.trim()).filter(Boolean);
10846
+ const invalid = parts.filter((p) => !canonicalOrder.includes(p));
10847
+ if (invalid.length > 0) {
10848
+ return `Unknown: ${invalid.join(", ")}. Valid: ${canonicalOrder.join(", ")}.`;
10849
+ }
10850
+ const missing = selected.filter((s) => !parts.includes(s));
10851
+ if (missing.length > 0) {
10852
+ return `Missing previously-selected segment(s): ${missing.join(", ")}. Include all of them or go back.`;
10853
+ }
10854
+ return true;
10855
+ }
10856
+ });
10857
+ orderedSegments = raw.split(",").map((s) => s.trim()).filter(Boolean);
10858
+ }
10859
+ const separator = await input2({
10860
+ message: "Separator between segments:",
10861
+ default: current?.separator ?? " \xB7 "
10862
+ });
10863
+ let wrap = current?.wrap;
10864
+ if (orderedSegments.includes("wrap")) {
10865
+ wrap = await input2({
10866
+ message: "Path to external script to wrap (leave blank to skip):",
10867
+ default: current?.wrap ?? ""
10868
+ });
10869
+ wrap = wrap.trim() ? wrap.trim() : void 0;
10870
+ }
10871
+ return { segments: orderedSegments, separator, wrap };
10872
+ }
10873
+ function renderPreview(config, statuslineScript, cwd) {
10874
+ const payload = {
10875
+ session_id: "preview-demo-0000000000abcdef12",
10876
+ cwd,
10877
+ model: { display_name: "Opus 4.7" },
10878
+ context_window: { used_percentage: 42 }
10879
+ };
10880
+ const res = spawnSync("bash", [statuslineScript], {
10881
+ input: JSON.stringify(payload),
10882
+ encoding: "utf-8",
10883
+ env: {
10884
+ ...process.env,
10885
+ // Force the child to pick up the freshly-written config from install root.
10886
+ HOME: dirname8(dirname8(statuslineScript))
10887
+ }
10888
+ });
10889
+ if (res.status !== 0) return null;
10890
+ return res.stdout;
10891
+ }
10892
+ async function configureStatuslineCommand(options = {}) {
10893
+ const installRoot = options.installRoot ?? syntaurRoot();
10894
+ const configPath = getConfigPath(installRoot);
10895
+ const current = await readConfig2(configPath);
10896
+ let segments;
10897
+ let separator;
10898
+ let wrap;
10899
+ if (options.preset) {
10900
+ const preset = PRESETS[options.preset.toLowerCase()];
10901
+ if (!preset) {
10902
+ throw new Error(
10903
+ `Unknown preset "${options.preset}". Presets: ${Object.keys(PRESETS).join(", ")}.`
10904
+ );
10905
+ }
10906
+ segments = [...preset.segments];
10907
+ separator = options.separator ?? preset.separator;
10908
+ wrap = options.wrap ?? current?.wrap;
10909
+ } else if (options.segments) {
10910
+ segments = parseSegmentsFlag(options.segments);
10911
+ separator = options.separator ?? current?.separator ?? " \xB7 ";
10912
+ wrap = options.wrap ?? current?.wrap;
10913
+ } else if (isInteractiveTerminal()) {
10914
+ const answers = await promptSegmentsInteractive(current);
10915
+ segments = answers.segments;
10916
+ separator = answers.separator;
10917
+ wrap = answers.wrap;
10918
+ } else {
10919
+ throw new Error(
10920
+ "Non-interactive invocation requires --preset, --segments, or run in a TTY."
10921
+ );
10922
+ }
10923
+ if (segments.includes("wrap") && !wrap) {
10924
+ console.warn(
10925
+ `Note: the "wrap" segment is selected but no wrap path is configured. Set one with --wrap <path> or edit ${configPath} afterwards.`
10926
+ );
10927
+ }
10928
+ const config = { segments, separator, ...wrap ? { wrap } : {} };
10929
+ if (options.preview) {
10930
+ console.log("Segments: " + config.segments.join(", "));
10931
+ console.log("Separator: " + JSON.stringify(config.separator));
10932
+ if (config.wrap) console.log("Wrap: " + config.wrap);
10933
+ console.log("");
10934
+ console.log("(preview mode \u2014 config NOT written)");
10935
+ return;
10936
+ }
10937
+ await ensureDir(dirname8(configPath));
10938
+ await writeFile7(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
10939
+ console.log("Wrote statusline config:");
10940
+ console.log(` path: ${configPath}`);
10941
+ console.log(` segments: ${config.segments.join(", ")}`);
10942
+ console.log(` separator: ${JSON.stringify(config.separator)}`);
10943
+ if (config.wrap) console.log(` wrap: ${config.wrap}`);
10944
+ const script = options.statuslineScript ?? resolve26(installRoot, "statusline.sh");
10945
+ if (await fileExists(script)) {
10946
+ console.log("");
10947
+ console.log("Live preview:");
10948
+ const out = renderPreview(config, script, process.cwd());
10949
+ if (out) {
10950
+ console.log(" " + out);
10951
+ } else {
10952
+ console.log(" (preview failed \u2014 run `syntaur install-statusline` if the script is missing)");
10953
+ }
10954
+ } else {
10955
+ console.log("");
10956
+ console.log(
10957
+ "(statusline script not yet installed \u2014 run `syntaur install-statusline` to wire it up)"
10958
+ );
10959
+ }
10960
+ }
10961
+ async function writeDefaultConfigIfMissing(installRoot) {
10962
+ const path = getConfigPath(installRoot);
10963
+ if (await fileExists(path)) return;
10964
+ await ensureDir(dirname8(path));
10965
+ const defaultConfig = {
10966
+ segments: ["git", "assignment", "session"],
10967
+ separator: " \xB7 "
10968
+ };
10969
+ await writeFile7(path, JSON.stringify(defaultConfig, null, 2) + "\n", "utf-8");
10970
+ }
10971
+
10972
+ // src/commands/install-statusline.ts
10760
10973
  function getPackageStatuslineSource() {
10761
- const here = dirname8(fileURLToPath5(import.meta.url));
10762
- return resolve26(here, "..", "statusline", "statusline.sh");
10974
+ const here = dirname9(fileURLToPath5(import.meta.url));
10975
+ return resolve27(here, "..", "statusline", "statusline.sh");
10763
10976
  }
10764
10977
  async function readSettingsJson(settingsPath) {
10765
10978
  if (!await fileExists(settingsPath)) return {};
10766
- const raw = await readFile17(settingsPath, "utf-8");
10979
+ const raw = await readFile18(settingsPath, "utf-8");
10767
10980
  if (raw.trim() === "") return {};
10768
10981
  try {
10769
10982
  const parsed = JSON.parse(raw);
@@ -10775,8 +10988,8 @@ async function readSettingsJson(settingsPath) {
10775
10988
  }
10776
10989
  }
10777
10990
  async function writeSettingsJson(settingsPath, data) {
10778
- await ensureDir(dirname8(settingsPath));
10779
- await writeFile7(settingsPath, JSON.stringify(data, null, 2) + "\n", "utf-8");
10991
+ await ensureDir(dirname9(settingsPath));
10992
+ await writeFile8(settingsPath, JSON.stringify(data, null, 2) + "\n", "utf-8");
10780
10993
  }
10781
10994
  async function resolveMode(mode, existingCommand, ourCommand) {
10782
10995
  if (mode !== "ask") return mode;
@@ -10810,8 +11023,8 @@ function extractExistingCommand(settings) {
10810
11023
  };
10811
11024
  }
10812
11025
  async function backupSettings(settingsSnapshot, backupPath) {
10813
- await ensureDir(dirname8(backupPath));
10814
- await writeFile7(
11026
+ await ensureDir(dirname9(backupPath));
11027
+ await writeFile8(
10815
11028
  backupPath,
10816
11029
  JSON.stringify(
10817
11030
  {
@@ -10827,7 +11040,7 @@ async function backupSettings(settingsSnapshot, backupPath) {
10827
11040
  );
10828
11041
  }
10829
11042
  async function installScript(sourceScript, destScript, link) {
10830
- await ensureDir(dirname8(destScript));
11043
+ await ensureDir(dirname9(destScript));
10831
11044
  try {
10832
11045
  const s = await lstat2(destScript);
10833
11046
  if (s.isSymbolicLink() || s.isFile()) {
@@ -10843,18 +11056,19 @@ async function installScript(sourceScript, destScript, link) {
10843
11056
  }
10844
11057
  async function installStatuslineCommand(options = {}) {
10845
11058
  const mode = options.mode ?? "ask";
10846
- const settingsPath = options.settingsPath ?? resolve26(homedir4(), ".claude", "settings.json");
11059
+ const settingsPath = options.settingsPath ?? resolve27(homedir4(), ".claude", "settings.json");
10847
11060
  const installRoot = options.installRoot ?? syntaurRoot();
10848
11061
  const sourceScript = options.sourceScript ?? getPackageStatuslineSource();
10849
- const destScript = resolve26(installRoot, "statusline.sh");
10850
- const confPath = resolve26(installRoot, "statusline.conf");
10851
- const backupPath = resolve26(installRoot, "statusline.backup.json");
11062
+ const destScript = resolve27(installRoot, "statusline.sh");
11063
+ const confPath = resolve27(installRoot, "statusline.conf");
11064
+ const backupPath = resolve27(installRoot, "statusline.backup.json");
10852
11065
  if (!await fileExists(sourceScript)) {
10853
11066
  throw new Error(
10854
11067
  `Statusline source script not found at ${sourceScript}. Try re-installing syntaur (npm install -g syntaur) or pass --source-script explicitly.`
10855
11068
  );
10856
11069
  }
10857
11070
  await installScript(sourceScript, destScript, Boolean(options.link));
11071
+ await writeDefaultConfigIfMissing(installRoot);
10858
11072
  const settings = await readSettingsJson(settingsPath);
10859
11073
  const existingStatusLine = extractExistingCommand(settings);
10860
11074
  const existingCommand = existingStatusLine?.command;
@@ -10883,19 +11097,19 @@ async function installStatuslineCommand(options = {}) {
10883
11097
  if (parsed) {
10884
11098
  wrapTarget = parsed;
10885
11099
  } else {
10886
- const wrapperPath = resolve26(installRoot, "statusline-wrapped.sh");
11100
+ const wrapperPath = resolve27(installRoot, "statusline-wrapped.sh");
10887
11101
  const wrapperBody = `#!/usr/bin/env bash
10888
11102
  # Auto-generated by syntaur install-statusline.
10889
11103
  # Executes the previously configured statusLine command.
10890
11104
  exec ${existingCommand}
10891
11105
  `;
10892
- await writeFile7(wrapperPath, wrapperBody, "utf-8");
11106
+ await writeFile8(wrapperPath, wrapperBody, "utf-8");
10893
11107
  await chmodExec(wrapperPath);
10894
11108
  wrapTarget = wrapperPath;
10895
11109
  }
10896
11110
  }
10897
- await ensureDir(dirname8(confPath));
10898
- await writeFile7(
11111
+ await ensureDir(dirname9(confPath));
11112
+ await writeFile8(
10899
11113
  confPath,
10900
11114
  wrapTarget ? `# Wrap target \u2014 the command below is invoked with the same stdin; its
10901
11115
  # stdout becomes the leading segment of the statusline. Remove this
@@ -10938,19 +11152,19 @@ async function chmodExec(path) {
10938
11152
  }
10939
11153
  }
10940
11154
  async function uninstallStatuslineCommand(options = {}) {
10941
- const settingsPath = options.settingsPath ?? resolve26(homedir4(), ".claude", "settings.json");
11155
+ const settingsPath = options.settingsPath ?? resolve27(homedir4(), ".claude", "settings.json");
10942
11156
  const installRoot = options.installRoot ?? syntaurRoot();
10943
- const destScript = resolve26(installRoot, "statusline.sh");
10944
- const confPath = resolve26(installRoot, "statusline.conf");
10945
- const backupPath = resolve26(installRoot, "statusline.backup.json");
10946
- const wrapperPath = resolve26(installRoot, "statusline-wrapped.sh");
11157
+ const destScript = resolve27(installRoot, "statusline.sh");
11158
+ const confPath = resolve27(installRoot, "statusline.conf");
11159
+ const backupPath = resolve27(installRoot, "statusline.backup.json");
11160
+ const wrapperPath = resolve27(installRoot, "statusline-wrapped.sh");
10947
11161
  const settings = await readSettingsJson(settingsPath);
10948
11162
  const existing = extractExistingCommand(settings);
10949
11163
  const ourCommand = `bash ${destScript}`;
10950
11164
  let restored = null;
10951
11165
  if (await fileExists(backupPath)) {
10952
11166
  try {
10953
- const raw = await readFile17(backupPath, "utf-8");
11167
+ const raw = await readFile18(backupPath, "utf-8");
10954
11168
  const parsed = JSON.parse(raw);
10955
11169
  const prev = parsed?.previousStatusLine;
10956
11170
  if (prev && typeof prev === "object" && typeof prev.command === "string") {
@@ -10971,7 +11185,8 @@ async function uninstallStatuslineCommand(options = {}) {
10971
11185
  await writeSettingsJson(settingsPath, settings);
10972
11186
  }
10973
11187
  if (!options.keepScript) {
10974
- for (const path of [destScript, confPath, backupPath, wrapperPath]) {
11188
+ const configPath = resolve27(installRoot, "statusline.config.json");
11189
+ for (const path of [destScript, confPath, backupPath, wrapperPath, configPath]) {
10975
11190
  try {
10976
11191
  await rm5(path, { force: true });
10977
11192
  } catch {
@@ -11225,7 +11440,7 @@ async function setupCommand(options) {
11225
11440
  }
11226
11441
 
11227
11442
  // src/commands/uninstall.ts
11228
- import { resolve as resolve27 } from "path";
11443
+ import { resolve as resolve28 } from "path";
11229
11444
  init_paths();
11230
11445
  function expandTargets(options) {
11231
11446
  if (options.all) {
@@ -11305,7 +11520,7 @@ async function uninstallCommand(options) {
11305
11520
  const configuredProjectDir = await getConfiguredProjectDir();
11306
11521
  await removeSyntaurData();
11307
11522
  console.log(`Removed ${syntaurRoot()}`);
11308
- if (configuredProjectDir && resolve27(configuredProjectDir) !== resolve27(syntaurRoot(), "projects")) {
11523
+ if (configuredProjectDir && resolve28(configuredProjectDir) !== resolve28(syntaurRoot(), "projects")) {
11309
11524
  console.warn(
11310
11525
  `Warning: config.md pointed to an external project directory (${configuredProjectDir}). That directory was not removed automatically.`
11311
11526
  );
@@ -11320,7 +11535,7 @@ async function uninstallCommand(options) {
11320
11535
  init_paths();
11321
11536
  init_fs();
11322
11537
  init_config2();
11323
- import { resolve as resolve28 } from "path";
11538
+ import { resolve as resolve29 } from "path";
11324
11539
  var SUPPORTED_FRAMEWORKS = ["cursor", "codex", "opencode"];
11325
11540
  async function setupAdapterCommand(framework, options) {
11326
11541
  if (!SUPPORTED_FRAMEWORKS.includes(framework)) {
@@ -11346,19 +11561,19 @@ async function setupAdapterCommand(framework, options) {
11346
11561
  }
11347
11562
  const config = await readConfig();
11348
11563
  const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
11349
- const projectDir = resolve28(baseDir, options.project);
11350
- const assignmentDir = resolve28(
11564
+ const projectDir = resolve29(baseDir, options.project);
11565
+ const assignmentDir = resolve29(
11351
11566
  projectDir,
11352
11567
  "assignments",
11353
11568
  options.assignment
11354
11569
  );
11355
- const projectMdPath = resolve28(projectDir, "project.md");
11570
+ const projectMdPath = resolve29(projectDir, "project.md");
11356
11571
  if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
11357
11572
  throw new Error(
11358
11573
  `Project "${options.project}" not found at ${projectDir}.`
11359
11574
  );
11360
11575
  }
11361
- const assignmentMdPath = resolve28(assignmentDir, "assignment.md");
11576
+ const assignmentMdPath = resolve29(assignmentDir, "assignment.md");
11362
11577
  if (!await fileExists(assignmentDir) || !await fileExists(assignmentMdPath)) {
11363
11578
  throw new Error(
11364
11579
  `Assignment "${options.assignment}" not found at ${assignmentDir}.`
@@ -11386,15 +11601,15 @@ async function setupAdapterCommand(framework, options) {
11386
11601
  }
11387
11602
  }
11388
11603
  if (framework === "cursor") {
11389
- const protocolPath = resolve28(cwd, ".cursor", "rules", "syntaur-protocol.mdc");
11390
- const assignmentPath = resolve28(cwd, ".cursor", "rules", "syntaur-assignment.mdc");
11604
+ const protocolPath = resolve29(cwd, ".cursor", "rules", "syntaur-protocol.mdc");
11605
+ const assignmentPath = resolve29(cwd, ".cursor", "rules", "syntaur-assignment.mdc");
11391
11606
  await writeAdapterFile(protocolPath, renderCursorProtocol());
11392
11607
  await writeAdapterFile(assignmentPath, renderCursorAssignment(rendererParams));
11393
11608
  } else if (framework === "codex" || framework === "opencode") {
11394
- const agentsPath = resolve28(cwd, "AGENTS.md");
11609
+ const agentsPath = resolve29(cwd, "AGENTS.md");
11395
11610
  await writeAdapterFile(agentsPath, renderCodexAgents(rendererParams));
11396
11611
  if (framework === "opencode") {
11397
- const configPath = resolve28(cwd, "opencode.json");
11612
+ const configPath = resolve29(cwd, "opencode.json");
11398
11613
  await writeAdapterFile(configPath, renderOpenCodeConfig({ projectDir }));
11399
11614
  }
11400
11615
  }
@@ -11419,7 +11634,7 @@ async function setupAdapterCommand(framework, options) {
11419
11634
  init_paths();
11420
11635
  init_fs();
11421
11636
  init_config2();
11422
- import { resolve as resolve29 } from "path";
11637
+ import { resolve as resolve30 } from "path";
11423
11638
  async function trackSessionCommand(options) {
11424
11639
  if (!options.agent) {
11425
11640
  throw new Error("--agent <name> is required.");
@@ -11432,7 +11647,7 @@ async function trackSessionCommand(options) {
11432
11647
  if (options.project) {
11433
11648
  const config = await readConfig();
11434
11649
  const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
11435
- const projectDir = resolve29(baseDir, options.project);
11650
+ const projectDir = resolve30(baseDir, options.project);
11436
11651
  if (!await fileExists(projectDir)) {
11437
11652
  throw new Error(
11438
11653
  `Project "${options.project}" not found at ${projectDir}.`
@@ -11487,7 +11702,7 @@ async function browseCommand(options) {
11487
11702
  }
11488
11703
 
11489
11704
  // src/commands/create-playbook.ts
11490
- import { resolve as resolve31 } from "path";
11705
+ import { resolve as resolve32 } from "path";
11491
11706
  init_timestamp();
11492
11707
  init_paths();
11493
11708
  init_fs();
@@ -11503,7 +11718,7 @@ async function createPlaybookCommand(name, options) {
11503
11718
  }
11504
11719
  const dir = playbooksDir();
11505
11720
  await ensureDir(dir);
11506
- const filePath = resolve31(dir, `${slug}.md`);
11721
+ const filePath = resolve32(dir, `${slug}.md`);
11507
11722
  if (await fileExists(filePath)) {
11508
11723
  throw new Error(
11509
11724
  `Playbook "${slug}" already exists at ${filePath}
@@ -11524,8 +11739,8 @@ Use --slug to specify a different slug.`
11524
11739
  init_paths();
11525
11740
  init_fs();
11526
11741
  init_parser();
11527
- import { readdir as readdir12, readFile as readFile18 } from "fs/promises";
11528
- import { resolve as resolve32 } from "path";
11742
+ import { readdir as readdir12, readFile as readFile19 } from "fs/promises";
11743
+ import { resolve as resolve33 } from "path";
11529
11744
  async function listPlaybooksCommand() {
11530
11745
  const dir = playbooksDir();
11531
11746
  if (!await fileExists(dir)) {
@@ -11543,8 +11758,8 @@ async function listPlaybooksCommand() {
11543
11758
  console.log(`${"Slug".padEnd(30)} ${"Name".padEnd(30)} Description`);
11544
11759
  console.log(`${"\u2500".repeat(30)} ${"\u2500".repeat(30)} ${"\u2500".repeat(40)}`);
11545
11760
  for (const entry of mdFiles) {
11546
- const filePath = resolve32(dir, entry.name);
11547
- const raw = await readFile18(filePath, "utf-8");
11761
+ const filePath = resolve33(dir, entry.name);
11762
+ const raw = await readFile19(filePath, "utf-8");
11548
11763
  const parsed = parsePlaybook(raw);
11549
11764
  const slug = parsed.slug || entry.name.replace(/\.md$/, "");
11550
11765
  const name = parsed.name || slug;
@@ -11558,8 +11773,8 @@ init_paths();
11558
11773
  init_parser2();
11559
11774
  init_fs();
11560
11775
  import { Command } from "commander";
11561
- import { readFile as readFile19 } from "fs/promises";
11562
- import { resolve as resolve33 } from "path";
11776
+ import { readFile as readFile20 } from "fs/promises";
11777
+ import { resolve as resolve34 } from "path";
11563
11778
  var WORKSPACE_REGEX2 = /^[a-z0-9_][a-z0-9-]*$/;
11564
11779
  function resolveWorkspace(options) {
11565
11780
  if (options.global) return "_global";
@@ -11840,10 +12055,10 @@ todoCommand.command("archive").description("Archive completed todos and their lo
11840
12055
  (e) => e.itemIds.every((id) => completedIds.has(id))
11841
12056
  );
11842
12057
  const archFile = archivePath(todosPath, workspace, checklist.archiveInterval);
11843
- await ensureDir(resolve33(todosPath, "archive"));
12058
+ await ensureDir(resolve34(todosPath, "archive"));
11844
12059
  let archContent = "";
11845
12060
  if (await fileExists(archFile)) {
11846
- archContent = await readFile19(archFile, "utf-8");
12061
+ archContent = await readFile20(archFile, "utf-8");
11847
12062
  archContent = archContent.trimEnd() + "\n\n";
11848
12063
  } else {
11849
12064
  archContent = `---
@@ -12032,19 +12247,19 @@ import { Command as Command3 } from "commander";
12032
12247
 
12033
12248
  // src/utils/doctor/index.ts
12034
12249
  import { fileURLToPath as fileURLToPath7 } from "url";
12035
- import { readFile as readFile23 } from "fs/promises";
12036
- import { dirname as dirname10, join as join5 } from "path";
12250
+ import { readFile as readFile24 } from "fs/promises";
12251
+ import { dirname as dirname11, join as join5 } from "path";
12037
12252
 
12038
12253
  // src/utils/doctor/context.ts
12039
12254
  init_config2();
12040
12255
  init_paths();
12041
12256
  init_fs();
12042
12257
  import Database2 from "better-sqlite3";
12043
- import { resolve as resolve34 } from "path";
12258
+ import { resolve as resolve35 } from "path";
12044
12259
  async function buildCheckContext(cwd = process.cwd()) {
12045
12260
  const config = await readConfig();
12046
12261
  const root = syntaurRoot();
12047
- const dbPath = resolve34(root, "syntaur.db");
12262
+ const dbPath = resolve35(root, "syntaur.db");
12048
12263
  let db2 = null;
12049
12264
  let dbError = null;
12050
12265
  if (await fileExists(dbPath)) {
@@ -12078,10 +12293,10 @@ function closeCheckContext(ctx) {
12078
12293
  // src/utils/doctor/checks/env.ts
12079
12294
  init_fs();
12080
12295
  init_paths();
12081
- import { resolve as resolve35, isAbsolute as isAbsolute3 } from "path";
12082
- import { readFile as readFile20, stat as stat4 } from "fs/promises";
12296
+ import { resolve as resolve36, isAbsolute as isAbsolute3 } from "path";
12297
+ import { readFile as readFile21, stat as stat4 } from "fs/promises";
12083
12298
  import { fileURLToPath as fileURLToPath6 } from "url";
12084
- import { dirname as dirname9, join as join4 } from "path";
12299
+ import { dirname as dirname10, join as join4 } from "path";
12085
12300
  var CATEGORY = "env";
12086
12301
  var syntaurRootExists = {
12087
12302
  id: "env.syntaur-root-exists",
@@ -12119,7 +12334,7 @@ var configValid = {
12119
12334
  category: CATEGORY,
12120
12335
  title: "~/.syntaur/config.md is valid",
12121
12336
  async run(ctx) {
12122
- const configPath = resolve35(ctx.syntaurRoot, "config.md");
12337
+ const configPath = resolve36(ctx.syntaurRoot, "config.md");
12123
12338
  if (!await fileExists(configPath)) {
12124
12339
  return {
12125
12340
  id: this.id,
@@ -12136,7 +12351,7 @@ var configValid = {
12136
12351
  autoFixable: false
12137
12352
  };
12138
12353
  }
12139
- const content = await readFile20(configPath, "utf-8");
12354
+ const content = await readFile21(configPath, "utf-8");
12140
12355
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
12141
12356
  if (!fmMatch || fmMatch[1].trim() === "") {
12142
12357
  return {
@@ -12412,14 +12627,14 @@ async function readLocalVersion() {
12412
12627
  async function readLocalPkg() {
12413
12628
  try {
12414
12629
  const here = fileURLToPath6(import.meta.url);
12415
- let dir = dirname9(here);
12630
+ let dir = dirname10(here);
12416
12631
  for (let i = 0; i < 6; i++) {
12417
12632
  const candidate = join4(dir, "package.json");
12418
12633
  try {
12419
- const text = await readFile20(candidate, "utf-8");
12634
+ const text = await readFile21(candidate, "utf-8");
12420
12635
  return JSON.parse(text);
12421
12636
  } catch {
12422
- dir = dirname9(dir);
12637
+ dir = dirname10(dir);
12423
12638
  }
12424
12639
  }
12425
12640
  return null;
@@ -12468,7 +12683,7 @@ function versionGte(a, b) {
12468
12683
 
12469
12684
  // src/utils/doctor/checks/structure.ts
12470
12685
  init_fs();
12471
- import { resolve as resolve36 } from "path";
12686
+ import { resolve as resolve37 } from "path";
12472
12687
  import { readdir as readdir13, stat as stat5 } from "fs/promises";
12473
12688
  var CATEGORY2 = "structure";
12474
12689
  var KNOWN_TOP_LEVEL = /* @__PURE__ */ new Set([
@@ -12488,7 +12703,7 @@ var projectsDir = {
12488
12703
  category: CATEGORY2,
12489
12704
  title: "projects/ directory exists",
12490
12705
  async run(ctx) {
12491
- const p = resolve36(ctx.syntaurRoot, "projects");
12706
+ const p = resolve37(ctx.syntaurRoot, "projects");
12492
12707
  if (!await fileExists(p)) {
12493
12708
  return {
12494
12709
  id: this.id,
@@ -12513,7 +12728,7 @@ var playbooksDir2 = {
12513
12728
  category: CATEGORY2,
12514
12729
  title: "playbooks/ directory exists",
12515
12730
  async run(ctx) {
12516
- const p = resolve36(ctx.syntaurRoot, "playbooks");
12731
+ const p = resolve37(ctx.syntaurRoot, "playbooks");
12517
12732
  if (!await fileExists(p)) {
12518
12733
  return {
12519
12734
  id: this.id,
@@ -12538,7 +12753,7 @@ var todosDirValid = {
12538
12753
  category: CATEGORY2,
12539
12754
  title: "todos/ directory is readable (if present)",
12540
12755
  async run(ctx) {
12541
- const p = resolve36(ctx.syntaurRoot, "todos");
12756
+ const p = resolve37(ctx.syntaurRoot, "todos");
12542
12757
  if (!await fileExists(p)) {
12543
12758
  return {
12544
12759
  id: this.id,
@@ -12569,7 +12784,7 @@ var serversDirValid = {
12569
12784
  category: CATEGORY2,
12570
12785
  title: "servers/ directory is readable (if present)",
12571
12786
  async run(ctx) {
12572
- const p = resolve36(ctx.syntaurRoot, "servers");
12787
+ const p = resolve37(ctx.syntaurRoot, "servers");
12573
12788
  if (!await fileExists(p)) {
12574
12789
  return {
12575
12790
  id: this.id,
@@ -12614,7 +12829,7 @@ var knownFilesRecognized = {
12614
12829
  title: this.title,
12615
12830
  status: "warn",
12616
12831
  detail: `unexpected top-level entries: ${unexpected.join(", ")}`,
12617
- affected: unexpected.map((n) => resolve36(ctx.syntaurRoot, n)),
12832
+ affected: unexpected.map((n) => resolve37(ctx.syntaurRoot, n)),
12618
12833
  remediation: {
12619
12834
  kind: "manual",
12620
12835
  suggestion: "Review these entries \u2014 they may be leftover state from older versions",
@@ -12643,7 +12858,7 @@ function pass2(check) {
12643
12858
 
12644
12859
  // src/utils/doctor/checks/project.ts
12645
12860
  init_fs();
12646
- import { resolve as resolve37 } from "path";
12861
+ import { resolve as resolve38 } from "path";
12647
12862
  import { readdir as readdir14, stat as stat6 } from "fs/promises";
12648
12863
  var CATEGORY3 = "project";
12649
12864
  var REQUIRED_PROJECT_FILES = [
@@ -12673,10 +12888,10 @@ async function listProjects2(ctx) {
12673
12888
  for (const e of entries) {
12674
12889
  if (!e.isDirectory()) continue;
12675
12890
  if (e.name.startsWith(".") || e.name.startsWith("_")) continue;
12676
- const projectDir = resolve37(dir, e.name);
12891
+ const projectDir = resolve38(dir, e.name);
12677
12892
  let looksLikeProject = false;
12678
12893
  for (const marker of PROJECT_MARKERS) {
12679
- if (await fileExists(resolve37(projectDir, marker))) {
12894
+ if (await fileExists(resolve38(projectDir, marker))) {
12680
12895
  looksLikeProject = true;
12681
12896
  break;
12682
12897
  }
@@ -12695,7 +12910,7 @@ var requiredFiles = {
12695
12910
  for (const projectDir of projects) {
12696
12911
  const missing = [];
12697
12912
  for (const rel of REQUIRED_PROJECT_FILES) {
12698
- const p = resolve37(projectDir, rel);
12913
+ const p = resolve38(projectDir, rel);
12699
12914
  if (!await fileExists(p)) missing.push(rel);
12700
12915
  }
12701
12916
  if (missing.length === 0) continue;
@@ -12705,7 +12920,7 @@ var requiredFiles = {
12705
12920
  title: this.title,
12706
12921
  status: "error",
12707
12922
  detail: `project at ${projectDir} is missing: ${missing.join(", ")}`,
12708
- affected: missing.map((m) => resolve37(projectDir, m)),
12923
+ affected: missing.map((m) => resolve38(projectDir, m)),
12709
12924
  remediation: {
12710
12925
  kind: "manual",
12711
12926
  suggestion: "Recreate the missing scaffold files from templates",
@@ -12728,7 +12943,7 @@ var manifestStale = {
12728
12943
  const projects = await listProjects2(ctx);
12729
12944
  const results = [];
12730
12945
  for (const projectDir of projects) {
12731
- const manifestPath = resolve37(projectDir, "manifest.md");
12946
+ const manifestPath = resolve38(projectDir, "manifest.md");
12732
12947
  if (!await fileExists(manifestPath)) continue;
12733
12948
  const manifestMtime = (await stat6(manifestPath)).mtimeMs;
12734
12949
  const newestAssignment = await newestAssignmentMtime(projectDir);
@@ -12777,7 +12992,7 @@ var orphanFiles = {
12777
12992
  title: this.title,
12778
12993
  status: "warn",
12779
12994
  detail: `project at ${projectDir} has unexpected entries: ${orphans.join(", ")}`,
12780
- affected: orphans.map((o) => resolve37(projectDir, o)),
12995
+ affected: orphans.map((o) => resolve38(projectDir, o)),
12781
12996
  autoFixable: false
12782
12997
  });
12783
12998
  }
@@ -12787,7 +13002,7 @@ var orphanFiles = {
12787
13002
  };
12788
13003
  var projectChecks = [requiredFiles, manifestStale, orphanFiles];
12789
13004
  async function newestAssignmentMtime(projectDir) {
12790
- const assignmentsRoot = resolve37(projectDir, "assignments");
13005
+ const assignmentsRoot = resolve38(projectDir, "assignments");
12791
13006
  if (!await fileExists(assignmentsRoot)) return 0;
12792
13007
  let newest = 0;
12793
13008
  let entries;
@@ -12798,7 +13013,7 @@ async function newestAssignmentMtime(projectDir) {
12798
13013
  }
12799
13014
  for (const e of entries) {
12800
13015
  if (!e.isDirectory()) continue;
12801
- const assignmentMd = resolve37(assignmentsRoot, e.name, "assignment.md");
13016
+ const assignmentMd = resolve38(assignmentsRoot, e.name, "assignment.md");
12802
13017
  try {
12803
13018
  const s = await stat6(assignmentMd);
12804
13019
  if (s.mtimeMs > newest) newest = s.mtimeMs;
@@ -12822,8 +13037,8 @@ init_fs();
12822
13037
  init_parser();
12823
13038
  init_types();
12824
13039
  init_paths();
12825
- import { resolve as resolve38 } from "path";
12826
- import { readdir as readdir15, readFile as readFile21 } from "fs/promises";
13040
+ import { resolve as resolve39 } from "path";
13041
+ import { readdir as readdir15, readFile as readFile22 } from "fs/promises";
12827
13042
  var CATEGORY4 = "assignment";
12828
13043
  var STATUSES_REQUIRING_HANDOFF = /* @__PURE__ */ new Set(["review", "completed"]);
12829
13044
  async function listAssignments(ctx) {
@@ -12834,16 +13049,16 @@ async function listAssignments(ctx) {
12834
13049
  for (const m of projects) {
12835
13050
  if (!m.isDirectory()) continue;
12836
13051
  if (m.name.startsWith(".") || m.name.startsWith("_")) continue;
12837
- const assignmentsDir2 = resolve38(projectsDir2, m.name, "assignments");
13052
+ const assignmentsDir2 = resolve39(projectsDir2, m.name, "assignments");
12838
13053
  if (!await fileExists(assignmentsDir2)) continue;
12839
13054
  const entries = await readdir15(assignmentsDir2, { withFileTypes: true });
12840
13055
  for (const a of entries) {
12841
13056
  if (!a.isDirectory()) continue;
12842
13057
  if (a.name.startsWith(".") || a.name.startsWith("_")) continue;
12843
- const assignmentDir = resolve38(assignmentsDir2, a.name);
12844
- const assignmentMd = resolve38(assignmentDir, "assignment.md");
13058
+ const assignmentDir = resolve39(assignmentsDir2, a.name);
13059
+ const assignmentMd = resolve39(assignmentDir, "assignment.md");
12845
13060
  const entry = {
12846
- projectDir: resolve38(projectsDir2, m.name),
13061
+ projectDir: resolve39(projectsDir2, m.name),
12847
13062
  projectSlug: m.name,
12848
13063
  assignmentDir,
12849
13064
  assignmentSlug: a.name,
@@ -12863,8 +13078,8 @@ async function listAssignments(ctx) {
12863
13078
  for (const a of entries) {
12864
13079
  if (!a.isDirectory()) continue;
12865
13080
  if (a.name.startsWith(".") || a.name.startsWith("_")) continue;
12866
- const assignmentDir = resolve38(standaloneRoot, a.name);
12867
- const assignmentMd = resolve38(assignmentDir, "assignment.md");
13081
+ const assignmentDir = resolve39(standaloneRoot, a.name);
13082
+ const assignmentMd = resolve39(assignmentDir, "assignment.md");
12868
13083
  const entry = {
12869
13084
  projectDir: standaloneRoot,
12870
13085
  projectSlug: null,
@@ -12942,7 +13157,7 @@ var invalidStatus = {
12942
13157
  const allowed = configuredStatuses(ctx);
12943
13158
  const results = [];
12944
13159
  for (const a of withAssignmentMd) {
12945
- const path = resolve38(a.assignmentDir, "assignment.md");
13160
+ const path = resolve39(a.assignmentDir, "assignment.md");
12946
13161
  const parsed = await parseSafe(path);
12947
13162
  if (!parsed) continue;
12948
13163
  if (!allowed.has(parsed.status)) {
@@ -12975,7 +13190,7 @@ var workspaceMissing = {
12975
13190
  const terminal = terminalStatuses(ctx);
12976
13191
  const results = [];
12977
13192
  for (const a of withAssignmentMd) {
12978
- const path = resolve38(a.assignmentDir, "assignment.md");
13193
+ const path = resolve39(a.assignmentDir, "assignment.md");
12979
13194
  const parsed = await parseSafe(path);
12980
13195
  if (!parsed) continue;
12981
13196
  if (terminal.has(parsed.status)) continue;
@@ -13022,12 +13237,12 @@ var requiredFilesByStatus = {
13022
13237
  const { withAssignmentMd } = await listAssignments(ctx);
13023
13238
  const results = [];
13024
13239
  for (const a of withAssignmentMd) {
13025
- const assignmentPath = resolve38(a.assignmentDir, "assignment.md");
13240
+ const assignmentPath = resolve39(a.assignmentDir, "assignment.md");
13026
13241
  const parsed = await parseSafe(assignmentPath);
13027
13242
  if (!parsed) continue;
13028
13243
  const missing = [];
13029
13244
  if (STATUSES_REQUIRING_HANDOFF.has(parsed.status)) {
13030
- const handoffPath = resolve38(a.assignmentDir, "handoff.md");
13245
+ const handoffPath = resolve39(a.assignmentDir, "handoff.md");
13031
13246
  if (!await fileExists(handoffPath)) missing.push("handoff.md");
13032
13247
  }
13033
13248
  if (missing.length === 0) continue;
@@ -13037,7 +13252,7 @@ var requiredFilesByStatus = {
13037
13252
  title: this.title,
13038
13253
  status: "warn",
13039
13254
  detail: `${a.projectSlug}/${a.assignmentSlug} (status: ${parsed.status}) is missing ${missing.join(", ")}`,
13040
- affected: missing.map((m) => resolve38(a.assignmentDir, m)),
13255
+ affected: missing.map((m) => resolve39(a.assignmentDir, m)),
13041
13256
  remediation: {
13042
13257
  kind: "manual",
13043
13258
  suggestion: `Create the missing ${missing.join(" and ")} files for this assignment`,
@@ -13060,7 +13275,7 @@ var companionFilesScaffolded = {
13060
13275
  for (const a of withAssignmentMd) {
13061
13276
  const missing = [];
13062
13277
  for (const filename of ["progress.md", "comments.md"]) {
13063
- if (!await fileExists(resolve38(a.assignmentDir, filename))) {
13278
+ if (!await fileExists(resolve39(a.assignmentDir, filename))) {
13064
13279
  missing.push(filename);
13065
13280
  }
13066
13281
  }
@@ -13072,7 +13287,7 @@ var companionFilesScaffolded = {
13072
13287
  title: this.title,
13073
13288
  status: "warn",
13074
13289
  detail: `${label} is missing ${missing.join(" and ")} (pre-v2.0 assignment \u2014 not required, but scaffolding them keeps the dashboard and CLIs consistent)`,
13075
- affected: missing.map((m) => resolve38(a.assignmentDir, m)),
13290
+ affected: missing.map((m) => resolve39(a.assignmentDir, m)),
13076
13291
  remediation: {
13077
13292
  kind: "manual",
13078
13293
  suggestion: `Create ${missing.join(" and ")} with the renderProgress/renderComments templates, or re-scaffold via the CLI`,
@@ -13105,7 +13320,7 @@ var typeDefinition = {
13105
13320
  const { withAssignmentMd } = await listAssignments(ctx);
13106
13321
  const results = [];
13107
13322
  for (const a of withAssignmentMd) {
13108
- const path = resolve38(a.assignmentDir, "assignment.md");
13323
+ const path = resolve39(a.assignmentDir, "assignment.md");
13109
13324
  const parsed = await parseSafe(path);
13110
13325
  if (!parsed) continue;
13111
13326
  if (!parsed.type) continue;
@@ -13139,7 +13354,7 @@ var projectFrontmatterMatchesContainer = {
13139
13354
  const { withAssignmentMd } = await listAssignments(ctx);
13140
13355
  const results = [];
13141
13356
  for (const a of withAssignmentMd) {
13142
- const path = resolve38(a.assignmentDir, "assignment.md");
13357
+ const path = resolve39(a.assignmentDir, "assignment.md");
13143
13358
  const parsed = await parseSafe(path);
13144
13359
  if (!parsed) continue;
13145
13360
  if (a.standalone) {
@@ -13194,7 +13409,7 @@ var assignmentChecks = [
13194
13409
  ];
13195
13410
  async function parseSafe(path) {
13196
13411
  try {
13197
- const content = await readFile21(path, "utf-8");
13412
+ const content = await readFile22(path, "utf-8");
13198
13413
  return parseAssignmentFull(content);
13199
13414
  } catch {
13200
13415
  return null;
@@ -13213,7 +13428,7 @@ function pass4(check, detail) {
13213
13428
 
13214
13429
  // src/utils/doctor/checks/dashboard.ts
13215
13430
  init_fs();
13216
- import { resolve as resolve39 } from "path";
13431
+ import { resolve as resolve40 } from "path";
13217
13432
  var CATEGORY5 = "dashboard";
13218
13433
  var dbReachable = {
13219
13434
  id: "dashboard.db-reachable",
@@ -13227,7 +13442,7 @@ var dbReachable = {
13227
13442
  title: this.title,
13228
13443
  status: "error",
13229
13444
  detail: `could not open syntaur.db: ${ctx.dbError ?? "unknown error"}`,
13230
- affected: [resolve39(ctx.syntaurRoot, "syntaur.db")],
13445
+ affected: [resolve40(ctx.syntaurRoot, "syntaur.db")],
13231
13446
  remediation: {
13232
13447
  kind: "manual",
13233
13448
  suggestion: "Start the dashboard once (`syntaur dashboard`) to initialize the DB, or restore it from backup",
@@ -13245,7 +13460,7 @@ var dbReachable = {
13245
13460
  title: this.title,
13246
13461
  status: "error",
13247
13462
  detail: 'syntaur.db is missing the expected "sessions" table',
13248
- affected: [resolve39(ctx.syntaurRoot, "syntaur.db")],
13463
+ affected: [resolve40(ctx.syntaurRoot, "syntaur.db")],
13249
13464
  autoFixable: false
13250
13465
  };
13251
13466
  }
@@ -13257,7 +13472,7 @@ var dbReachable = {
13257
13472
  title: this.title,
13258
13473
  status: "error",
13259
13474
  detail: `syntaur.db query failed: ${err2 instanceof Error ? err2.message : String(err2)}`,
13260
- affected: [resolve39(ctx.syntaurRoot, "syntaur.db")],
13475
+ affected: [resolve40(ctx.syntaurRoot, "syntaur.db")],
13261
13476
  autoFixable: false
13262
13477
  };
13263
13478
  }
@@ -13283,7 +13498,7 @@ var ghostSessions = {
13283
13498
  const results = [];
13284
13499
  for (const row of rows) {
13285
13500
  if (!row.project_slug) continue;
13286
- const projectPath = resolve39(projectsDir2, row.project_slug, "project.md");
13501
+ const projectPath = resolve40(projectsDir2, row.project_slug, "project.md");
13287
13502
  if (!await fileExists(projectPath)) {
13288
13503
  results.push({
13289
13504
  id: this.id,
@@ -13302,7 +13517,7 @@ var ghostSessions = {
13302
13517
  continue;
13303
13518
  }
13304
13519
  if (row.assignment_slug) {
13305
- const assignmentPath = resolve39(
13520
+ const assignmentPath = resolve40(
13306
13521
  projectsDir2,
13307
13522
  row.project_slug,
13308
13523
  "assignments",
@@ -13459,8 +13674,8 @@ function skipped2(check, reason) {
13459
13674
  init_fs();
13460
13675
  init_parser();
13461
13676
  init_types();
13462
- import { resolve as resolve40 } from "path";
13463
- import { readFile as readFile22 } from "fs/promises";
13677
+ import { resolve as resolve41 } from "path";
13678
+ import { readFile as readFile23 } from "fs/promises";
13464
13679
  var CATEGORY7 = "workspace";
13465
13680
  var ASSIGNMENT_FIELDS = ["projectSlug", "assignmentSlug", "projectDir", "assignmentDir"];
13466
13681
  function hasAnyAssignmentField(ctx) {
@@ -13472,12 +13687,12 @@ function isStandaloneSession(ctx) {
13472
13687
  return !hasAnyAssignmentField(ctx) && typeof ctx.sessionId === "string" && ctx.sessionId.length > 0;
13473
13688
  }
13474
13689
  async function loadContext(ctx) {
13475
- const path = resolve40(ctx.cwd, ".syntaur", "context.json");
13690
+ const path = resolve41(ctx.cwd, ".syntaur", "context.json");
13476
13691
  if (!await fileExists(path)) {
13477
13692
  return { data: null, path, exists: false, parseError: null };
13478
13693
  }
13479
13694
  try {
13480
- const raw = await readFile22(path, "utf-8");
13695
+ const raw = await readFile23(path, "utf-8");
13481
13696
  return { data: JSON.parse(raw), path, exists: true, parseError: null };
13482
13697
  } catch (err2) {
13483
13698
  return {
@@ -13552,7 +13767,7 @@ var contextAssignmentResolves = {
13552
13767
  if (!exists) return skipped3(this, "no context to resolve");
13553
13768
  if (isStandaloneSession(data)) return skipped3(this, "standalone session context \u2014 no assignment to resolve");
13554
13769
  if (!data?.assignmentDir) return skipped3(this, "context has no assignmentDir");
13555
- const assignmentMd = resolve40(data.assignmentDir, "assignment.md");
13770
+ const assignmentMd = resolve41(data.assignmentDir, "assignment.md");
13556
13771
  if (!await fileExists(assignmentMd)) {
13557
13772
  return {
13558
13773
  id: this.id,
@@ -13581,10 +13796,10 @@ var contextTerminal = {
13581
13796
  if (!exists) return skipped3(this, "no context to check");
13582
13797
  if (isStandaloneSession(data)) return skipped3(this, "standalone session context \u2014 no assignment to check");
13583
13798
  if (!data?.assignmentDir) return skipped3(this, "context has no assignmentDir");
13584
- const assignmentMd = resolve40(data.assignmentDir, "assignment.md");
13799
+ const assignmentMd = resolve41(data.assignmentDir, "assignment.md");
13585
13800
  if (!await fileExists(assignmentMd)) return skipped3(this, "assignment file missing");
13586
13801
  try {
13587
- const content = await readFile22(assignmentMd, "utf-8");
13802
+ const content = await readFile23(assignmentMd, "utf-8");
13588
13803
  const parsed = parseAssignmentFull(content);
13589
13804
  const terminal = terminalStatuses2(ctx);
13590
13805
  if (terminal.has(parsed.status)) {
@@ -13728,14 +13943,14 @@ async function finalize(checks) {
13728
13943
  async function readVersion() {
13729
13944
  try {
13730
13945
  const here = fileURLToPath7(import.meta.url);
13731
- let dir = dirname10(here);
13946
+ let dir = dirname11(here);
13732
13947
  for (let i = 0; i < 6; i++) {
13733
13948
  try {
13734
- const raw = await readFile23(join5(dir, "package.json"), "utf-8");
13949
+ const raw = await readFile24(join5(dir, "package.json"), "utf-8");
13735
13950
  const parsed = JSON.parse(raw);
13736
13951
  return typeof parsed.version === "string" ? parsed.version : null;
13737
13952
  } catch {
13738
- dir = dirname10(dir);
13953
+ dir = dirname11(dir);
13739
13954
  }
13740
13955
  }
13741
13956
  return null;
@@ -13868,8 +14083,8 @@ var doctorCommand = new Command3("doctor").description("Diagnose Syntaur state a
13868
14083
  init_paths();
13869
14084
  init_fs();
13870
14085
  init_config2();
13871
- import { resolve as resolve41 } from "path";
13872
- import { readFile as readFile24 } from "fs/promises";
14086
+ import { resolve as resolve42 } from "path";
14087
+ import { readFile as readFile25 } from "fs/promises";
13873
14088
  init_timestamp();
13874
14089
  init_assignment_resolver();
13875
14090
  function shortId() {
@@ -13901,7 +14116,7 @@ async function commentCommand(target, text, options = {}) {
13901
14116
  if (!isValidSlug(target)) {
13902
14117
  throw new Error(`Invalid assignment slug "${target}".`);
13903
14118
  }
13904
- assignmentDir = resolve41(baseDir, options.project, "assignments", target);
14119
+ assignmentDir = resolve42(baseDir, options.project, "assignments", target);
13905
14120
  assignmentRef = target;
13906
14121
  } else {
13907
14122
  const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), target);
@@ -13911,13 +14126,13 @@ async function commentCommand(target, text, options = {}) {
13911
14126
  assignmentDir = resolved.assignmentDir;
13912
14127
  assignmentRef = resolved.standalone ? resolved.id : resolved.assignmentSlug;
13913
14128
  }
13914
- const commentsPath = resolve41(assignmentDir, "comments.md");
14129
+ const commentsPath = resolve42(assignmentDir, "comments.md");
13915
14130
  const timestamp = nowTimestamp();
13916
14131
  const author = options.author ?? process.env.USER ?? "unknown";
13917
14132
  let currentContent;
13918
14133
  let currentCount = 0;
13919
14134
  if (await fileExists(commentsPath)) {
13920
- currentContent = await readFile24(commentsPath, "utf-8");
14135
+ currentContent = await readFile25(commentsPath, "utf-8");
13921
14136
  const countMatch = currentContent.match(/^entryCount:\s*(\d+)/m);
13922
14137
  if (countMatch) currentCount = parseInt(countMatch[1], 10);
13923
14138
  } else {
@@ -13954,8 +14169,8 @@ ${entry}`;
13954
14169
  init_paths();
13955
14170
  init_fs();
13956
14171
  init_config2();
13957
- import { resolve as resolve42 } from "path";
13958
- import { readFile as readFile25 } from "fs/promises";
14172
+ import { resolve as resolve43 } from "path";
14173
+ import { readFile as readFile26 } from "fs/promises";
13959
14174
  init_timestamp();
13960
14175
  init_assignment_resolver();
13961
14176
  function setTopLevelField3(content, key, value) {
@@ -13980,7 +14195,7 @@ async function requestCommand(target, text, options = {}) {
13980
14195
  if (!isValidSlug(target)) {
13981
14196
  throw new Error(`Invalid assignment slug "${target}".`);
13982
14197
  }
13983
- assignmentDir = resolve42(baseDir, options.project, "assignments", target);
14198
+ assignmentDir = resolve43(baseDir, options.project, "assignments", target);
13984
14199
  targetRef = target;
13985
14200
  } else {
13986
14201
  const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), target);
@@ -13990,12 +14205,12 @@ async function requestCommand(target, text, options = {}) {
13990
14205
  assignmentDir = resolved.assignmentDir;
13991
14206
  targetRef = resolved.standalone ? resolved.id : resolved.assignmentSlug;
13992
14207
  }
13993
- const assignmentMdPath = resolve42(assignmentDir, "assignment.md");
14208
+ const assignmentMdPath = resolve43(assignmentDir, "assignment.md");
13994
14209
  if (!await fileExists(assignmentMdPath)) {
13995
14210
  throw new Error(`assignment.md not found at ${assignmentMdPath}`);
13996
14211
  }
13997
14212
  const source = options.from ?? process.env.SYNTAUR_ASSIGNMENT ?? "unknown";
13998
- let content = await readFile25(assignmentMdPath, "utf-8");
14213
+ let content = await readFile26(assignmentMdPath, "utf-8");
13999
14214
  const todoLine = `- [ ] ${text.trim()} (from: ${source})`;
14000
14215
  const todosHeading = /^## Todos\s*$/m;
14001
14216
  if (todosHeading.test(content)) {
@@ -14063,20 +14278,20 @@ async function getDefaultCommandName() {
14063
14278
  init_paths();
14064
14279
  init_fs();
14065
14280
  import { fileURLToPath as fileURLToPath9 } from "url";
14066
- import { readFile as readFile27 } from "fs/promises";
14067
- import { dirname as dirname12, join as join7, resolve as resolve43 } from "path";
14281
+ import { readFile as readFile28 } from "fs/promises";
14282
+ import { dirname as dirname13, join as join7, resolve as resolve44 } from "path";
14068
14283
  import { spawn as spawn3 } from "child_process";
14069
14284
  import { createInterface as createInterface2 } from "readline/promises";
14070
14285
 
14071
14286
  // src/utils/version.ts
14072
14287
  import { fileURLToPath as fileURLToPath8 } from "url";
14073
- import { readFile as readFile26 } from "fs/promises";
14074
- import { dirname as dirname11, join as join6 } from "path";
14288
+ import { readFile as readFile27 } from "fs/promises";
14289
+ import { dirname as dirname12, join as join6 } from "path";
14075
14290
  async function readPackageVersion(scriptUrl) {
14076
14291
  try {
14077
14292
  const scriptPath = fileURLToPath8(scriptUrl);
14078
- const pkgRoot = dirname11(dirname11(scriptPath));
14079
- const raw = await readFile26(join6(pkgRoot, "package.json"), "utf-8");
14293
+ const pkgRoot = dirname12(dirname12(scriptPath));
14294
+ const raw = await readFile27(join6(pkgRoot, "package.json"), "utf-8");
14080
14295
  const parsed = JSON.parse(raw);
14081
14296
  return typeof parsed.version === "string" ? parsed.version : null;
14082
14297
  } catch {
@@ -14085,7 +14300,7 @@ async function readPackageVersion(scriptUrl) {
14085
14300
  }
14086
14301
 
14087
14302
  // src/utils/npx-prompt.ts
14088
- var STATE_FILE = resolve43(syntaurRoot(), "npx-install.json");
14303
+ var STATE_FILE = resolve44(syntaurRoot(), "npx-install.json");
14089
14304
  var META_ARGS = /* @__PURE__ */ new Set(["-h", "--help", "-V", "--version", "help"]);
14090
14305
  var GLOBAL_VERSION_TIMEOUT_MS = 2e3;
14091
14306
  function isRunningViaNpx(scriptUrl) {
@@ -14106,7 +14321,7 @@ function isRunningViaNpx(scriptUrl) {
14106
14321
  async function readState() {
14107
14322
  if (!await fileExists(STATE_FILE)) return null;
14108
14323
  try {
14109
- const raw = await readFile27(STATE_FILE, "utf-8");
14324
+ const raw = await readFile28(STATE_FILE, "utf-8");
14110
14325
  return JSON.parse(raw);
14111
14326
  } catch {
14112
14327
  return null;
@@ -14117,7 +14332,7 @@ async function writeState(state) {
14117
14332
  `);
14118
14333
  }
14119
14334
  async function resolveNpmBin() {
14120
- const nodeDir = dirname12(process.execPath);
14335
+ const nodeDir = dirname13(process.execPath);
14121
14336
  const isWin = process.platform === "win32";
14122
14337
  const npmName = isWin ? "npm.cmd" : "npm";
14123
14338
  const nearNode = join7(nodeDir, npmName);
@@ -14165,7 +14380,7 @@ async function readGlobalVersion() {
14165
14380
  try {
14166
14381
  const manifestPath = join7(rootPath, "syntaur", "package.json");
14167
14382
  if (!await fileExists(manifestPath)) return null;
14168
- const raw = await readFile27(manifestPath, "utf-8");
14383
+ const raw = await readFile28(manifestPath, "utf-8");
14169
14384
  const parsed = JSON.parse(raw);
14170
14385
  return typeof parsed.version === "string" ? parsed.version : null;
14171
14386
  } catch {
@@ -14501,6 +14716,22 @@ program.command("uninstall-statusline").description(
14501
14716
  process.exit(1);
14502
14717
  }
14503
14718
  });
14719
+ program.command("configure-statusline").description(
14720
+ "Configure which segments (git, assignment, session, model, ctx, cwd, wrap) appear in the syntaur statusLine and in what order."
14721
+ ).option(
14722
+ "--preset <name>",
14723
+ `Preset shortcut. Choices: ${Object.keys(PRESETS).join(", ")}.`
14724
+ ).option(
14725
+ "--segments <list>",
14726
+ 'Comma-separated segment list, e.g. "git,assignment,session,model,ctx".'
14727
+ ).option("--separator <string>", 'Segment separator (default " \xB7 ")').option("--wrap <path>", 'Path to an external statusline script to compose as a "wrap" segment').option("--preview", "Print the resolved config and a preview line without writing").action(async (options) => {
14728
+ try {
14729
+ await configureStatuslineCommand(options);
14730
+ } catch (error) {
14731
+ console.error("Error:", error instanceof Error ? error.message : String(error));
14732
+ process.exit(1);
14733
+ }
14734
+ });
14504
14735
  program.command("uninstall-skills").description("Remove Syntaur protocol skills from ~/.claude/skills and/or ~/.codex/skills").option("--claude", "Remove from ~/.claude/skills").option("--codex", "Remove from ~/.codex/skills").option("--all", "Remove from both").action(async (options) => {
14505
14736
  try {
14506
14737
  await uninstallSkillsCommand(options);