syntaur 0.76.0 → 0.77.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 (68) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/dashboard/dist/assets/{_basePickBy-BiwSunXO.js → _basePickBy-CmtR3VlC.js} +1 -1
  3. package/dashboard/dist/assets/{_baseUniq-DsjKPXxP.js → _baseUniq-d5yVqkuO.js} +1 -1
  4. package/dashboard/dist/assets/{arc-DlEs4wsF.js → arc-BTfvlUzk.js} +1 -1
  5. package/dashboard/dist/assets/{architectureDiagram-2XIMDMQ5-DPvCrO57.js → architectureDiagram-2XIMDMQ5-ComKmfQn.js} +1 -1
  6. package/dashboard/dist/assets/{blockDiagram-WCTKOSBZ-CpNdCY-r.js → blockDiagram-WCTKOSBZ-69xtTOqC.js} +1 -1
  7. package/dashboard/dist/assets/{c4Diagram-IC4MRINW-CC29QJCs.js → c4Diagram-IC4MRINW-B5MsrIyR.js} +1 -1
  8. package/dashboard/dist/assets/channel-B55sx3Pw.js +1 -0
  9. package/dashboard/dist/assets/{chunk-4BX2VUAB-DKyy-k2D.js → chunk-4BX2VUAB-BV-rQx2S.js} +1 -1
  10. package/dashboard/dist/assets/{chunk-55IACEB6-DjobngQk.js → chunk-55IACEB6-BHoZ0_2C.js} +1 -1
  11. package/dashboard/dist/assets/{chunk-FMBD7UC4-BUftm7dV.js → chunk-FMBD7UC4-BZppz6s9.js} +1 -1
  12. package/dashboard/dist/assets/{chunk-JSJVCQXG-Nv7rQv4t.js → chunk-JSJVCQXG-BKJIycjQ.js} +1 -1
  13. package/dashboard/dist/assets/{chunk-KX2RTZJC-Dg6UhNB9.js → chunk-KX2RTZJC-Drv6rL3f.js} +1 -1
  14. package/dashboard/dist/assets/{chunk-NQ4KR5QH-D8neQrJ_.js → chunk-NQ4KR5QH-u1ws00gN.js} +1 -1
  15. package/dashboard/dist/assets/{chunk-QZHKN3VN-Uj9c1naA.js → chunk-QZHKN3VN-zCyNaZcO.js} +1 -1
  16. package/dashboard/dist/assets/{chunk-WL4C6EOR-DfeSsP3z.js → chunk-WL4C6EOR-Dz0hDBUx.js} +1 -1
  17. package/dashboard/dist/assets/classDiagram-VBA2DB6C-Kgg-J05j.js +1 -0
  18. package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-Kgg-J05j.js +1 -0
  19. package/dashboard/dist/assets/clone-DXxPBQmb.js +1 -0
  20. package/dashboard/dist/assets/{cose-bilkent-S5V4N54A-CLfZNKcO.js → cose-bilkent-S5V4N54A-CO0Ms-ys.js} +1 -1
  21. package/dashboard/dist/assets/{dagre-KLK3FWXG-DyJLICZx.js → dagre-KLK3FWXG-BDBGlQ5i.js} +1 -1
  22. package/dashboard/dist/assets/{diagram-E7M64L7V-DhQc7Ta3.js → diagram-E7M64L7V-C1jhhA3a.js} +1 -1
  23. package/dashboard/dist/assets/{diagram-IFDJBPK2-C6kFO7hB.js → diagram-IFDJBPK2-DYA2G930.js} +1 -1
  24. package/dashboard/dist/assets/{diagram-P4PSJMXO-B6oCiOXk.js → diagram-P4PSJMXO-iox20fhC.js} +1 -1
  25. package/dashboard/dist/assets/{erDiagram-INFDFZHY-BsMPaSwJ.js → erDiagram-INFDFZHY-CdrG4ZUW.js} +1 -1
  26. package/dashboard/dist/assets/{flowDiagram-PKNHOUZH-DLxEqKtZ.js → flowDiagram-PKNHOUZH-CMuagI-6.js} +1 -1
  27. package/dashboard/dist/assets/{ganttDiagram-A5KZAMGK-D70pvqxG.js → ganttDiagram-A5KZAMGK-C8jgdfRO.js} +1 -1
  28. package/dashboard/dist/assets/{gitGraphDiagram-K3NZZRJ6-D74VHtlE.js → gitGraphDiagram-K3NZZRJ6-Chu0FgBt.js} +1 -1
  29. package/dashboard/dist/assets/{graph-C8bz_IEO.js → graph-RWP7g4cL.js} +1 -1
  30. package/dashboard/dist/assets/{index-h-X_8om3.js → index-BFpKR1Z0.js} +163 -148
  31. package/dashboard/dist/assets/{index-BetqH_3H.css → index-C6KBRx3q.css} +1 -1
  32. package/dashboard/dist/assets/{infoDiagram-LFFYTUFH-DivBd0Pz.js → infoDiagram-LFFYTUFH-bIlmxe7x.js} +1 -1
  33. package/dashboard/dist/assets/{ishikawaDiagram-PHBUUO56-BGihUeOE.js → ishikawaDiagram-PHBUUO56-CvvXAmzr.js} +1 -1
  34. package/dashboard/dist/assets/{journeyDiagram-4ABVD52K-C7U4cWHQ.js → journeyDiagram-4ABVD52K-BlSVnlQk.js} +1 -1
  35. package/dashboard/dist/assets/{kanban-definition-K7BYSVSG-CFp_hDTm.js → kanban-definition-K7BYSVSG-D6kAus7L.js} +1 -1
  36. package/dashboard/dist/assets/{layout-DMSDPqCs.js → layout-BIoVL4m2.js} +1 -1
  37. package/dashboard/dist/assets/{linear-CCC-meYc.js → linear-B4ySyXON.js} +1 -1
  38. package/dashboard/dist/assets/{mermaid.core-BDa2cc2K.js → mermaid.core-B_8IjgQO.js} +4 -4
  39. package/dashboard/dist/assets/{mindmap-definition-YRQLILUH-DLKvONhO.js → mindmap-definition-YRQLILUH-B6RTS8xi.js} +1 -1
  40. package/dashboard/dist/assets/{pieDiagram-SKSYHLDU-DAJoGZ93.js → pieDiagram-SKSYHLDU-EntB8Xmg.js} +1 -1
  41. package/dashboard/dist/assets/{quadrantDiagram-337W2JSQ-Bo7haX1W.js → quadrantDiagram-337W2JSQ-UTEbe4g6.js} +1 -1
  42. package/dashboard/dist/assets/{requirementDiagram-Z7DCOOCP-uEvGz33v.js → requirementDiagram-Z7DCOOCP-qG2oV68i.js} +1 -1
  43. package/dashboard/dist/assets/{sankeyDiagram-WA2Y5GQK-cjYoCGCM.js → sankeyDiagram-WA2Y5GQK-C-EzJpn8.js} +1 -1
  44. package/dashboard/dist/assets/{sequenceDiagram-2WXFIKYE-CYXcNklt.js → sequenceDiagram-2WXFIKYE-rCjfcAr5.js} +1 -1
  45. package/dashboard/dist/assets/{stateDiagram-RAJIS63D-B5We7jAw.js → stateDiagram-RAJIS63D-C3hoQmLC.js} +1 -1
  46. package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-rHFeeHzp.js +1 -0
  47. package/dashboard/dist/assets/{timeline-definition-YZTLITO2-CEqVmnVQ.js → timeline-definition-YZTLITO2-2gGWKHHW.js} +1 -1
  48. package/dashboard/dist/assets/{treemap-KZPCXAKY-CE1puPeN.js → treemap-KZPCXAKY-BV6TTFvC.js} +1 -1
  49. package/dashboard/dist/assets/{vennDiagram-LZ73GAT5-CiiuRUjK.js → vennDiagram-LZ73GAT5-C1aeXQ29.js} +1 -1
  50. package/dashboard/dist/assets/{xychartDiagram-JWTSCODW-B0OuxFm9.js → xychartDiagram-JWTSCODW-BDbba6Mg.js} +1 -1
  51. package/dashboard/dist/index.html +2 -2
  52. package/dist/dashboard/server.js +845 -147
  53. package/dist/dashboard/server.js.map +1 -1
  54. package/dist/index.js +1290 -547
  55. package/dist/index.js.map +1 -1
  56. package/dist/launch/index.d.ts +41 -0
  57. package/dist/launch/index.js +200 -21
  58. package/dist/launch/index.js.map +1 -1
  59. package/package.json +1 -1
  60. package/platforms/claude-code/.claude-plugin/plugin.json +1 -1
  61. package/platforms/codex/.codex-plugin/plugin.json +1 -1
  62. package/platforms/hermes/plugins/syntaur/__pycache__/__init__.cpython-312.pyc +0 -0
  63. package/platforms/hermes/plugins/syntaur/__pycache__/boundary.cpython-312.pyc +0 -0
  64. package/dashboard/dist/assets/channel-IutbH48W.js +0 -1
  65. package/dashboard/dist/assets/classDiagram-VBA2DB6C-8IywRj9I.js +0 -1
  66. package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-8IywRj9I.js +0 -1
  67. package/dashboard/dist/assets/clone-C6saGiCd.js +0 -1
  68. package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-CX9-EpBi.js +0 -1
package/dist/index.js CHANGED
@@ -2647,6 +2647,14 @@ function agentNameArgs(agent) {
2647
2647
  const n = agent.agentName?.trim();
2648
2648
  return n ? ["--agent", n] : [];
2649
2649
  }
2650
+ function resolveRunner(agent) {
2651
+ if (agent.runner) return agent.runner;
2652
+ if (agent.agentName && agent.agentName.trim() !== "") return "claude";
2653
+ const cmd = agent.command ?? "";
2654
+ if (/claude/i.test(cmd) || agent.id === "claude") return "claude";
2655
+ if (/codex/i.test(cmd) || agent.id === "codex") return "codex";
2656
+ return "pi";
2657
+ }
2650
2658
  function stripModelFlags(args) {
2651
2659
  const out = [];
2652
2660
  for (let i = 0; i < args.length; i++) {
@@ -3917,6 +3925,7 @@ __export(config_exports, {
3917
3925
  parseStatusConfig: () => parseStatusConfig,
3918
3926
  parseTerminalConfig: () => parseTerminalConfig,
3919
3927
  readConfig: () => readConfig,
3928
+ serializeAgentDiscoveryConfig: () => serializeAgentDiscoveryConfig,
3920
3929
  serializeSearchConfig: () => serializeSearchConfig,
3921
3930
  serializeStatusConfig: () => serializeStatusConfig,
3922
3931
  toTitleCase: () => toTitleCase,
@@ -3930,6 +3939,7 @@ __export(config_exports, {
3930
3939
  validateDeriveShape: () => validateDeriveShape,
3931
3940
  validateFactDeclarations: () => validateFactDeclarations,
3932
3941
  validateStalenessConfig: () => validateStalenessConfig,
3942
+ writeAgentDiscoveryConfig: () => writeAgentDiscoveryConfig,
3933
3943
  writeAgentsConfig: () => writeAgentsConfig,
3934
3944
  writeHotkeyBindingsConfig: () => writeHotkeyBindingsConfig,
3935
3945
  writeSearchConfig: () => writeSearchConfig,
@@ -4022,6 +4032,50 @@ function validateAgentList(agents) {
4022
4032
  `agent "${agent.id}" sets both agentName and model \u2014 the agent definition's own model is authoritative; remove the profile model`
4023
4033
  );
4024
4034
  }
4035
+ if (agent.runner !== void 0 && !RUNNER_KINDS.includes(agent.runner)) {
4036
+ throw new AgentConfigError(
4037
+ `agent "${agent.id}" has invalid runner "${agent.runner}" \u2014 must be one of ${RUNNER_KINDS.join(", ")}`
4038
+ );
4039
+ }
4040
+ if (agent.sourceKind !== void 0 && !AGENT_SOURCE_KINDS.includes(agent.sourceKind)) {
4041
+ throw new AgentConfigError(
4042
+ `agent "${agent.id}" has invalid sourceKind "${agent.sourceKind}" \u2014 must be one of ${AGENT_SOURCE_KINDS.join(", ")}`
4043
+ );
4044
+ }
4045
+ if (agent.sourcePath !== void 0 && /[\r\n]/.test(agent.sourcePath)) {
4046
+ throw new AgentConfigError(
4047
+ `agent "${agent.id}" has invalid sourcePath \u2014 must be a single line (no newlines)`
4048
+ );
4049
+ }
4050
+ if (agent.sourceRepo !== void 0 && /[\r\n]/.test(agent.sourceRepo)) {
4051
+ throw new AgentConfigError(
4052
+ `agent "${agent.id}" has invalid sourceRepo \u2014 must be a single line (no newlines)`
4053
+ );
4054
+ }
4055
+ if (agent.runner === "claude" && agent.workdir !== void 0 && agent.workdir.trim() !== "") {
4056
+ throw new AgentConfigError(
4057
+ `agent "${agent.id}" has runner "claude" but sets workdir \u2014 a claude agent uses agentName, not workdir`
4058
+ );
4059
+ }
4060
+ if ((agent.runner === "pi" || agent.runner === "codex") && agent.agentName !== void 0 && agent.agentName.trim() !== "") {
4061
+ throw new AgentConfigError(
4062
+ `agent "${agent.id}" has runner "${agent.runner}" but sets agentName \u2014 a directory agent uses workdir, not agentName`
4063
+ );
4064
+ }
4065
+ if (agent.runner !== void 0 && agent.sourceKind !== void 0) {
4066
+ const directorySource = agent.sourceKind === "directory";
4067
+ const claudeRunner = agent.runner === "claude";
4068
+ if (directorySource && claudeRunner) {
4069
+ throw new AgentConfigError(
4070
+ `agent "${agent.id}" has sourceKind "directory" but runner "claude" \u2014 a directory source is a pi/codex agent`
4071
+ );
4072
+ }
4073
+ if (!directorySource && !claudeRunner) {
4074
+ throw new AgentConfigError(
4075
+ `agent "${agent.id}" has sourceKind "${agent.sourceKind}" but runner "${agent.runner}" \u2014 a ${agent.sourceKind} source is a claude agent`
4076
+ );
4077
+ }
4078
+ }
4025
4079
  validateSessionInvocation(agent, "resume", agent.resume);
4026
4080
  validateSessionInvocation(agent, "fork", agent.fork);
4027
4081
  if (agent.default) defaults++;
@@ -4124,6 +4178,21 @@ function parseInstalledAgents(fm) {
4124
4178
  }
4125
4179
  return Object.keys(installedAgents).length > 0 ? { installedAgents } : {};
4126
4180
  }
4181
+ function parseAgentDiscoveryFromFm(fm) {
4182
+ const flag = (key, def) => {
4183
+ const v = fm[key];
4184
+ if (v === void 0) return def;
4185
+ return String(v).toLowerCase() === "true";
4186
+ };
4187
+ const rootsRaw = fm["agentDiscovery.roots"];
4188
+ const roots = rootsRaw !== void 0 && String(rootsRaw).trim() !== "" ? String(rootsRaw).split(":").map((r) => r.trim()).filter((r) => r.length > 0) : [];
4189
+ return {
4190
+ claudeGlobal: flag("agentDiscovery.claudeGlobal", true),
4191
+ claudeProject: flag("agentDiscovery.claudeProject", true),
4192
+ directory: flag("agentDiscovery.directory", true),
4193
+ roots: roots.length > 0 ? roots : DEFAULT_CONFIG.agentDiscovery.roots.slice()
4194
+ };
4195
+ }
4127
4196
  function parseStatusConfig(content) {
4128
4197
  const match = content.match(/^---\n([\s\S]*?)\n---/);
4129
4198
  if (!match) return null;
@@ -4632,6 +4701,43 @@ ${cleanedFm}
4632
4701
  ---${afterFrontmatter}`;
4633
4702
  await writeFileForce(configPath2, newContent);
4634
4703
  }
4704
+ function serializeAgentDiscoveryConfig(cfg) {
4705
+ return [
4706
+ "agentDiscovery:",
4707
+ ` claudeGlobal: ${cfg.claudeGlobal}`,
4708
+ ` claudeProject: ${cfg.claudeProject}`,
4709
+ ` directory: ${cfg.directory}`,
4710
+ ` roots: ${cfg.roots.join(":")}`
4711
+ ].join("\n");
4712
+ }
4713
+ async function writeAgentDiscoveryConfig(cfg, standaloneDefaultCwd) {
4714
+ const configPath2 = resolve7(syntaurRoot(), "config.md");
4715
+ const block = serializeAgentDiscoveryConfig(cfg);
4716
+ const scalarLine = standaloneDefaultCwd ? `standaloneDefaultCwd: ${standaloneDefaultCwd}` : "";
4717
+ const additions = [block, scalarLine].filter(Boolean).join("\n");
4718
+ const existing = await fileExists(configPath2) ? await readFile5(configPath2, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
4719
+ const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
4720
+ if (!fmMatch) {
4721
+ const content = `---
4722
+ version: "2.0"
4723
+ defaultProjectDir: ${defaultProjectDir()}
4724
+ ${additions}
4725
+ ---
4726
+ ${existing}`;
4727
+ await writeFileForce(configPath2, content);
4728
+ return;
4729
+ }
4730
+ const fmBlock = fmMatch[2];
4731
+ const afterFrontmatter = existing.slice(fmMatch[0].length);
4732
+ let cleanedFm = stripTopLevelBlock(fmBlock, "agentDiscovery");
4733
+ cleanedFm = stripTopLevelScalar(cleanedFm, "standaloneDefaultCwd");
4734
+ const newFm = `${cleanedFm}
4735
+ ${additions}`.replace(/^\n+/, "").replace(/\n+$/, "");
4736
+ const newContent = `---
4737
+ ${newFm}
4738
+ ---${afterFrontmatter}`;
4739
+ await writeFileForce(configPath2, newContent);
4740
+ }
4635
4741
  function stripTopLevelScalar(fmBlock, key) {
4636
4742
  const lines = fmBlock.split("\n");
4637
4743
  const keyRegex = new RegExp(`^${key}:\\s*\\S`);
@@ -4844,6 +4950,10 @@ function parseAgentsConfig(content) {
4844
4950
  ...current.launchPrompt ? { launchPrompt: current.launchPrompt } : {},
4845
4951
  ...current.agentName ? { agentName: current.agentName } : {},
4846
4952
  ...current.workdir ? { workdir: current.workdir } : {},
4953
+ ...current.runner ? { runner: current.runner } : {},
4954
+ ...current.sourceKind ? { sourceKind: current.sourceKind } : {},
4955
+ ...current.sourcePath ? { sourcePath: current.sourcePath } : {},
4956
+ ...current.sourceRepo ? { sourceRepo: current.sourceRepo } : {},
4847
4957
  ...current.resume ? { resume: current.resume } : {},
4848
4958
  ...current.fork ? { fork: current.fork } : {}
4849
4959
  });
@@ -5041,6 +5151,18 @@ function assignAgentField(target, key, rawValue) {
5041
5151
  case "workdir":
5042
5152
  target.workdir = value;
5043
5153
  break;
5154
+ case "runner":
5155
+ target.runner = value;
5156
+ break;
5157
+ case "sourceKind":
5158
+ target.sourceKind = value;
5159
+ break;
5160
+ case "sourcePath":
5161
+ target.sourcePath = value;
5162
+ break;
5163
+ case "sourceRepo":
5164
+ target.sourceRepo = value;
5165
+ break;
5044
5166
  }
5045
5167
  }
5046
5168
  function yamlQuoteScalar(value) {
@@ -5076,6 +5198,18 @@ function serializeAgentsConfig(agents) {
5076
5198
  if (a.workdir) {
5077
5199
  lines.push(` workdir: ${yamlQuoteScalar(a.workdir)}`);
5078
5200
  }
5201
+ if (a.runner) {
5202
+ lines.push(` runner: ${yamlQuoteScalar(a.runner)}`);
5203
+ }
5204
+ if (a.sourceKind) {
5205
+ lines.push(` sourceKind: ${yamlQuoteScalar(a.sourceKind)}`);
5206
+ }
5207
+ if (a.sourcePath) {
5208
+ lines.push(` sourcePath: ${yamlQuoteScalar(a.sourcePath)}`);
5209
+ }
5210
+ if (a.sourceRepo) {
5211
+ lines.push(` sourceRepo: ${yamlQuoteScalar(a.sourceRepo)}`);
5212
+ }
5079
5213
  if (a.args && a.args.length > 0) {
5080
5214
  lines.push(` args:`);
5081
5215
  for (const arg of a.args) {
@@ -5561,7 +5695,12 @@ async function readConfig() {
5561
5695
  searchConfig: parseSearchConfig(content),
5562
5696
  workspaceVisibility: parseWorkspaceVisibilityConfig(fmBlock),
5563
5697
  staleness: parseStalenessConfig(content),
5564
- stalenessWatchdog: String(fm["stalenessWatchdog"]).toLowerCase() === "true"
5698
+ stalenessWatchdog: String(fm["stalenessWatchdog"]).toLowerCase() === "true",
5699
+ standaloneDefaultCwd: parseOptionalAbsolutePath(
5700
+ fm["standaloneDefaultCwd"],
5701
+ "standaloneDefaultCwd"
5702
+ ),
5703
+ agentDiscovery: parseAgentDiscoveryFromFm(fm)
5565
5704
  };
5566
5705
  }
5567
5706
  function getAssignmentTypes(config) {
@@ -5624,7 +5763,7 @@ async function updateAgentsConfig(mutation, options = {}) {
5624
5763
  await writeAgentsConfig(next);
5625
5764
  return { previous, next, written: true };
5626
5765
  }
5627
- var STALENESS_KEY_TO_FIELD, DURATION_RE, DURATION_UNIT_MS, DEFAULT_ASSIGNMENT_TYPES, DEFAULT_CONFIG, AUTO_CREATE_WORKTREE_VALUES, SESSION_AUTO_TRACK_VALUES, AgentConfigError, DEFAULT_STATUS_COLORS, KNOWN_AGENT_SCALAR_FIELDS, migratedConfigPaths, TerminalConfigError;
5766
+ var STALENESS_KEY_TO_FIELD, DURATION_RE, DURATION_UNIT_MS, DEFAULT_ASSIGNMENT_TYPES, DEFAULT_CONFIG, AUTO_CREATE_WORKTREE_VALUES, SESSION_AUTO_TRACK_VALUES, RUNNER_KINDS, AGENT_SOURCE_KINDS, AgentConfigError, DEFAULT_STATUS_COLORS, KNOWN_AGENT_SCALAR_FIELDS, migratedConfigPaths, TerminalConfigError;
5628
5767
  var init_config2 = __esm({
5629
5768
  "src/utils/config.ts"() {
5630
5769
  "use strict";
@@ -5700,10 +5839,23 @@ var init_config2 = __esm({
5700
5839
  hidden: []
5701
5840
  },
5702
5841
  staleness: null,
5703
- stalenessWatchdog: false
5842
+ stalenessWatchdog: false,
5843
+ standaloneDefaultCwd: null,
5844
+ agentDiscovery: {
5845
+ claudeGlobal: true,
5846
+ claudeProject: true,
5847
+ directory: true,
5848
+ roots: ["~"]
5849
+ }
5704
5850
  };
5705
5851
  AUTO_CREATE_WORKTREE_VALUES = ["skip", "ask", "always"];
5706
5852
  SESSION_AUTO_TRACK_VALUES = ["all", "workspaces-only", "off"];
5853
+ RUNNER_KINDS = ["claude", "pi", "codex"];
5854
+ AGENT_SOURCE_KINDS = [
5855
+ "claude-global",
5856
+ "claude-project",
5857
+ "directory"
5858
+ ];
5707
5859
  AgentConfigError = class extends Error {
5708
5860
  };
5709
5861
  DEFAULT_STATUS_COLORS = {
@@ -5725,7 +5877,11 @@ var init_config2 = __esm({
5725
5877
  "playbook",
5726
5878
  "launchPrompt",
5727
5879
  "agentName",
5728
- "workdir"
5880
+ "workdir",
5881
+ "runner",
5882
+ "sourceKind",
5883
+ "sourcePath",
5884
+ "sourceRepo"
5729
5885
  ]);
5730
5886
  migratedConfigPaths = /* @__PURE__ */ new Set();
5731
5887
  TerminalConfigError = class extends Error {
@@ -7279,6 +7435,7 @@ var init_assignment_resolver = __esm({
7279
7435
 
7280
7436
  // src/launch/cwd.ts
7281
7437
  import { existsSync, statSync } from "fs";
7438
+ import { homedir as homedir2 } from "os";
7282
7439
  import { isAbsolute as isAbsolute2 } from "path";
7283
7440
  function isExistingDir(p) {
7284
7441
  if (!p || !isAbsolute2(p)) return false;
@@ -7324,6 +7481,31 @@ function resolveLaunchCwd(agent, worktreeCwd) {
7324
7481
  }
7325
7482
  return { spawnCwd: worktreeCwd, worktreePath: worktreeCwd, invalidReason: null };
7326
7483
  }
7484
+ function resolveStandaloneCwd(agent, standaloneDefaultCwd) {
7485
+ const wd = agent.workdir?.trim();
7486
+ if (wd) {
7487
+ const expanded = expandHome(wd);
7488
+ if (!isExistingDir(expanded)) {
7489
+ return {
7490
+ cwd: null,
7491
+ invalidReason: `agent "${agent.id}" workdir ${agent.workdir} (resolved ${expanded}) is not an existing directory \u2014 a standalone launch requires a valid workdir.`
7492
+ };
7493
+ }
7494
+ return { cwd: expanded, invalidReason: null };
7495
+ }
7496
+ if (resolveRunner(agent) === "claude") {
7497
+ const configured = standaloneDefaultCwd?.trim();
7498
+ if (configured) {
7499
+ const expanded = expandHome(configured);
7500
+ if (isExistingDir(expanded)) return { cwd: expanded, invalidReason: null };
7501
+ }
7502
+ return { cwd: homedir2(), invalidReason: null };
7503
+ }
7504
+ return {
7505
+ cwd: null,
7506
+ invalidReason: `agent "${agent.id}" has no workdir \u2014 a standalone launch of a ${resolveRunner(agent)} agent requires a valid workdir.`
7507
+ };
7508
+ }
7327
7509
  function formatFallbackCwdWarning(opts) {
7328
7510
  const missing = [];
7329
7511
  if (!opts.worktreePath) missing.push("worktreePath");
@@ -7335,6 +7517,7 @@ function formatFallbackCwdWarning(opts) {
7335
7517
  var init_cwd = __esm({
7336
7518
  "src/launch/cwd.ts"() {
7337
7519
  "use strict";
7520
+ init_agents_schema();
7338
7521
  init_paths();
7339
7522
  }
7340
7523
  });
@@ -9276,8 +9459,8 @@ async function migrateFromMarkdown(projectsDir2) {
9276
9459
  return allSessions.length;
9277
9460
  }
9278
9461
  async function parseMarkdownSessionsIndex(filePath, projectSlug) {
9279
- const { readFile: readFile82 } = await import("fs/promises");
9280
- const raw2 = await readFile82(filePath, "utf-8");
9462
+ const { readFile: readFile85 } = await import("fs/promises");
9463
+ const raw2 = await readFile85(filePath, "utf-8");
9281
9464
  const sessions = [];
9282
9465
  const lines = raw2.split("\n");
9283
9466
  let inTable = false;
@@ -10123,7 +10306,7 @@ function emptyScan() {
10123
10306
  return { sessions: [], tmuxAvailable: false };
10124
10307
  }
10125
10308
  function scanKey(serversDir2, projectsDir2, assignmentsDir2) {
10126
- return `${serversDir2}\0${projectsDir2}\0${assignmentsDir2 ?? ""}`;
10309
+ return JSON.stringify([serversDir2, projectsDir2, assignmentsDir2 ?? ""]);
10127
10310
  }
10128
10311
  function delay(ms) {
10129
10312
  return new Promise((resolve112) => {
@@ -13121,12 +13304,12 @@ var init_transcript = __esm({
13121
13304
  // src/usage/cwd-extractor.ts
13122
13305
  import { open as open3, readdir as readdir14, stat as stat4 } from "fs/promises";
13123
13306
  import { join as join3 } from "path";
13124
- import { homedir as homedir2 } from "os";
13307
+ import { homedir as homedir3 } from "os";
13125
13308
  async function extractClaudeSessionMeta(jsonlPath) {
13126
13309
  const cwd = await derivePathFromTranscript(jsonlPath);
13127
13310
  if (!cwd) return null;
13128
- const basename10 = jsonlPath.split("/").pop() ?? "";
13129
- const sessionId = basename10.replace(/\.jsonl$/, "");
13311
+ const basename11 = jsonlPath.split("/").pop() ?? "";
13312
+ const sessionId = basename11.replace(/\.jsonl$/, "");
13130
13313
  if (!sessionId) return null;
13131
13314
  const startTs = await readFirstTimestamp(jsonlPath);
13132
13315
  const endTs = await readLastTimestamp(jsonlPath);
@@ -13221,8 +13404,8 @@ async function* walkClaudeProjects(opts = {}) {
13221
13404
  async function* walkCodexSessions(opts = {}) {
13222
13405
  const root = resolveCodexSessionsRoot(opts.root);
13223
13406
  for await (const filePath of walkJsonlRecursive(root)) {
13224
- const basename10 = filePath.split("/").pop() ?? "";
13225
- if (!basename10.endsWith(".jsonl")) continue;
13407
+ const basename11 = filePath.split("/").pop() ?? "";
13408
+ if (!basename11.endsWith(".jsonl")) continue;
13226
13409
  if (opts.sinceMtimeMs !== void 0) {
13227
13410
  const mtime = await mtimeMs(filePath);
13228
13411
  if (mtime !== null && mtime < opts.sinceMtimeMs) continue;
@@ -13237,13 +13420,13 @@ function resolveCodexSessionsRoot(override3) {
13237
13420
  if (fromSessionsEnv && fromSessionsEnv.length > 0) return expandHome(fromSessionsEnv);
13238
13421
  const fromHomeEnv = process.env.CODEX_HOME;
13239
13422
  if (fromHomeEnv && fromHomeEnv.length > 0) return join3(expandHome(fromHomeEnv), "sessions");
13240
- return join3(homedir2(), ".codex", "sessions");
13423
+ return join3(homedir3(), ".codex", "sessions");
13241
13424
  }
13242
13425
  async function extractPiSessionMeta(jsonlPath) {
13243
- const basename10 = jsonlPath.split("/").pop() ?? "";
13244
- const underscoreIdx = basename10.lastIndexOf("_");
13426
+ const basename11 = jsonlPath.split("/").pop() ?? "";
13427
+ const underscoreIdx = basename11.lastIndexOf("_");
13245
13428
  if (underscoreIdx === -1) return null;
13246
- const sessionId = basename10.slice(underscoreIdx + 1).replace(/\.jsonl$/, "");
13429
+ const sessionId = basename11.slice(underscoreIdx + 1).replace(/\.jsonl$/, "");
13247
13430
  if (!sessionId) return null;
13248
13431
  let handle;
13249
13432
  try {
@@ -13295,7 +13478,7 @@ function resolvePiSessionsRoot(override3) {
13295
13478
  if (override3) return expandHome(override3);
13296
13479
  const fromHomeEnv = process.env.PI_AGENT_DIR;
13297
13480
  if (fromHomeEnv && fromHomeEnv.length > 0) return join3(expandHome(fromHomeEnv), "sessions");
13298
- return join3(homedir2(), ".pi", "agent", "sessions");
13481
+ return join3(homedir3(), ".pi", "agent", "sessions");
13299
13482
  }
13300
13483
  async function* walkPiSessions(opts = {}) {
13301
13484
  const root = resolvePiSessionsRoot(opts.root);
@@ -13459,7 +13642,7 @@ var init_cwd_extractor = __esm({
13459
13642
  // src/utils/session-id.ts
13460
13643
  import { execFileSync as execFileSync3 } from "child_process";
13461
13644
  import { mkdirSync, readFileSync as readFileSync2, statSync as statSync4, writeFileSync } from "fs";
13462
- import { homedir as homedir3 } from "os";
13645
+ import { homedir as homedir4 } from "os";
13463
13646
  import { dirname as dirname6, join as join4 } from "path";
13464
13647
  function isSafeSessionId(value) {
13465
13648
  return typeof value === "string" && value.length > 0 && value.length <= 256 && SAFE_SESSION_ID.test(value);
@@ -13549,7 +13732,7 @@ async function resolveOwnSessionId(opts = {}, deps = {}) {
13549
13732
  }
13550
13733
  const sideChannel = await resolveSideChannelSessionId(opts, deps);
13551
13734
  if (sideChannel) return { id: sideChannel, provenance: "EXPLICIT" };
13552
- const home2 = deps.homeDir ?? homedir3();
13735
+ const home2 = deps.homeDir ?? homedir4();
13553
13736
  const claudeSessionsDir = deps.claudeSessionsDir ?? join4(home2, ".claude", "sessions");
13554
13737
  const runtimeSessionsDir2 = deps.runtimeSessionsDir ?? join4(home2, ".syntaur", "runtime", "sessions");
13555
13738
  const startPid = deps.startPid ?? process.ppid;
@@ -13832,10 +14015,10 @@ var init_user_descriptors = __esm({
13832
14015
  });
13833
14016
 
13834
14017
  // src/targets/registry.ts
13835
- import { homedir as homedir4 } from "os";
14018
+ import { homedir as homedir5 } from "os";
13836
14019
  import { join as join5, resolve as resolve30 } from "path";
13837
14020
  function home(...segments) {
13838
- return resolve30(homedir4(), ...segments);
14021
+ return resolve30(homedir5(), ...segments);
13839
14022
  }
13840
14023
  function hermesHome() {
13841
14024
  const env = process.env.HERMES_HOME;
@@ -14130,8 +14313,8 @@ __export(launch_exports, {
14130
14313
  shellQuote: () => shellQuote
14131
14314
  });
14132
14315
  import { spawn as spawn2 } from "child_process";
14133
- import { mkdir as mkdir2, writeFile as writeFile4 } from "fs/promises";
14134
- import { isAbsolute as isAbsolute5, resolve as resolve31 } from "path";
14316
+ import { mkdir as mkdir3, writeFile as writeFile5 } from "fs/promises";
14317
+ import { isAbsolute as isAbsolute6, resolve as resolve31 } from "path";
14135
14318
  function shellQuote(arg) {
14136
14319
  if (arg === "") return "''";
14137
14320
  return `'${arg.replace(/'/g, `'\\''`)}'`;
@@ -14146,7 +14329,7 @@ function buildAgentArgv(agent, prompt, env = process.env) {
14146
14329
  const requested = env.SHELL;
14147
14330
  let shell = requested;
14148
14331
  let warning = null;
14149
- if (!shell || !isAbsolute5(shell)) {
14332
+ if (!shell || !isAbsolute6(shell)) {
14150
14333
  warning = `syntaur: $SHELL ${requested ? `("${requested}") is not absolute` : "is unset"} \u2014 falling back to /bin/sh for shell-alias resolution`;
14151
14334
  shell = "/bin/sh";
14152
14335
  }
@@ -14211,7 +14394,7 @@ async function launchAgent(options) {
14211
14394
  const spawnCwd = launchCwd.spawnCwd;
14212
14395
  const worktreePath = launchCwd.worktreePath;
14213
14396
  const contextDir = resolve31(worktreePath, ".syntaur");
14214
- await mkdir2(contextDir, { recursive: true });
14397
+ await mkdir3(contextDir, { recursive: true });
14215
14398
  const context = {
14216
14399
  repository: detail.workspace.repository ?? null,
14217
14400
  branch: detail.workspace.branch ?? null,
@@ -14219,7 +14402,7 @@ async function launchAgent(options) {
14219
14402
  workspaceRoot: worktreePath,
14220
14403
  grabbedAt: (/* @__PURE__ */ new Date()).toISOString()
14221
14404
  };
14222
- await writeFile4(
14405
+ await writeFile5(
14223
14406
  resolve31(contextDir, "context.json"),
14224
14407
  JSON.stringify(context, null, 2) + "\n"
14225
14408
  );
@@ -14852,15 +15035,15 @@ import {
14852
15035
  unlinkSync
14853
15036
  } from "fs";
14854
15037
  import { fileURLToPath as fileURLToPath9, pathToFileURL } from "url";
14855
- import { dirname as dirname21, resolve as resolve74, join as join17 } from "path";
14856
- import { homedir as homedir13, tmpdir as tmpdir2 } from "os";
15038
+ import { dirname as dirname22, resolve as resolve74, join as join19 } from "path";
15039
+ import { homedir as homedir15, tmpdir as tmpdir2 } from "os";
14857
15040
  import { spawnSync as spawnSync7 } from "child_process";
14858
15041
  function syntaurRootMjs() {
14859
15042
  const override3 = process.env.SYNTAUR_HOME;
14860
15043
  if (override3 && override3.length > 0) {
14861
15044
  return override3;
14862
15045
  }
14863
- return join17(homedir13(), ".syntaur");
15046
+ return join19(homedir15(), ".syntaur");
14864
15047
  }
14865
15048
  async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
14866
15049
  const { throwOnFailure } = options;
@@ -14890,22 +15073,22 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
14890
15073
  throw err2;
14891
15074
  }
14892
15075
  try {
14893
- const pkgRoot = resolve74(dirname21(fileURLToPath9(import.meta.url)), "..");
15076
+ const pkgRoot = resolve74(dirname22(fileURLToPath9(import.meta.url)), "..");
14894
15077
  const cliBin = realpathSync4(resolve74(pkgRoot, "bin/syntaur.js"));
14895
15078
  const nodeBin = process.execPath;
14896
- const bundleParent = join17(
14897
- homedir13(),
15079
+ const bundleParent = join19(
15080
+ homedir15(),
14898
15081
  "Library",
14899
15082
  "Application Support",
14900
15083
  "Syntaur"
14901
15084
  );
14902
- const bundlePath = join17(bundleParent, "syntaur-url.app");
15085
+ const bundlePath = join19(bundleParent, "syntaur-url.app");
14903
15086
  mkdirSync3(bundleParent, { recursive: true });
14904
15087
  if (existsSync6(bundlePath)) {
14905
15088
  rmSync(bundlePath, { recursive: true, force: true });
14906
15089
  }
14907
15090
  const installedTerminals = detectInstalledTerminals();
14908
- const scriptPath = join17(
15091
+ const scriptPath = join19(
14909
15092
  tmpdir2(),
14910
15093
  `syntaur-url-handler-${process.pid}.applescript`
14911
15094
  );
@@ -14924,7 +15107,7 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
14924
15107
  `osacompile exited with code ${compile.status}: ${compile.stderr || compile.stdout}`
14925
15108
  );
14926
15109
  }
14927
- const infoPlistPath = join17(bundlePath, "Contents", "Info.plist");
15110
+ const infoPlistPath = join19(bundlePath, "Contents", "Info.plist");
14928
15111
  if (!existsSync6(infoPlistPath)) {
14929
15112
  throw new Error(`osacompile did not produce ${infoPlistPath}`);
14930
15113
  }
@@ -15019,7 +15202,7 @@ function detectInstalledTerminals() {
15019
15202
  ghostty: "Ghostty.app",
15020
15203
  warp: "Warp.app"
15021
15204
  };
15022
- const appDirs = ["/Applications", join17(homedir13(), "Applications")];
15205
+ const appDirs = ["/Applications", join19(homedir15(), "Applications")];
15023
15206
  for (const [id, bundleId] of Object.entries(bundleIds)) {
15024
15207
  const r = spawnSync7(
15025
15208
  "mdfind",
@@ -15031,7 +15214,7 @@ function detectInstalledTerminals() {
15031
15214
  continue;
15032
15215
  }
15033
15216
  const name = bundleNames[id];
15034
- if (name && appDirs.some((dir) => existsSync6(join17(dir, name)))) {
15217
+ if (name && appDirs.some((dir) => existsSync6(join19(dir, name)))) {
15035
15218
  installed.add(id);
15036
15219
  }
15037
15220
  }
@@ -15754,8 +15937,8 @@ __export(launchd_exports, {
15754
15937
  });
15755
15938
  import { execFileSync as execFileSync5 } from "child_process";
15756
15939
  import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync3, rmSync as rmSync2, realpathSync as realpathSync5, openSync as openSync2, closeSync as closeSync2 } from "fs";
15757
- import { homedir as homedir16, userInfo } from "os";
15758
- import { dirname as dirname28, join as join27, resolve as resolve99 } from "path";
15940
+ import { homedir as homedir18, userInfo } from "os";
15941
+ import { dirname as dirname29, join as join29, resolve as resolve99 } from "path";
15759
15942
  function buildPlist(spec) {
15760
15943
  const args = [spec.nodePath, spec.syntaurBin, ...spec.command ?? ["schedule", "tick"]];
15761
15944
  const argXml = args.map((a) => ` <string>${escapeXml(a)}</string>`).join("\n");
@@ -15787,8 +15970,8 @@ function escapeXml(value) {
15787
15970
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
15788
15971
  }
15789
15972
  function defaultAcquireInstallLock(home2) {
15790
- const lockPath = join27(home2, ".syntaur", "install-launch-agent.lock");
15791
- mkdirSync4(dirname28(lockPath), { recursive: true });
15973
+ const lockPath = join29(home2, ".syntaur", "install-launch-agent.lock");
15974
+ mkdirSync4(dirname29(lockPath), { recursive: true });
15792
15975
  const fd = openSync2(lockPath, "wx");
15793
15976
  return () => {
15794
15977
  try {
@@ -15815,7 +15998,7 @@ function defaultRun(command, args) {
15815
15998
  }
15816
15999
  }
15817
16000
  function resolveSpec(config, deps) {
15818
- const home2 = deps.homeDir ?? homedir16();
16001
+ const home2 = deps.homeDir ?? homedir18();
15819
16002
  const uid = deps.uid ?? userInfo().uid;
15820
16003
  const spec = {
15821
16004
  label: config.label,
@@ -15823,22 +16006,22 @@ function resolveSpec(config, deps) {
15823
16006
  nodePath: deps.nodePath ?? process.execPath,
15824
16007
  syntaurBin: absolutize(deps.syntaurBin ?? process.argv[1] ?? "syntaur"),
15825
16008
  intervalSeconds: deps.intervalSeconds ?? config.defaultIntervalSeconds,
15826
- outLog: join27(home2, ".syntaur", "logs", config.outLogName),
15827
- errLog: join27(home2, ".syntaur", "logs", config.errLogName)
16009
+ outLog: join29(home2, ".syntaur", "logs", config.outLogName),
16010
+ errLog: join29(home2, ".syntaur", "logs", config.errLogName)
15828
16011
  };
15829
- const plistPath = join27(home2, "Library", "LaunchAgents", `${spec.label}.plist`);
16012
+ const plistPath = join29(home2, "Library", "LaunchAgents", `${spec.label}.plist`);
15830
16013
  return { spec, plistPath, home: home2, uid };
15831
16014
  }
15832
16015
  function installAgent(config, deps) {
15833
16016
  const { spec, plistPath, home: home2, uid } = resolveSpec(config, deps);
15834
16017
  const mkdirp = deps.mkdirp ?? ((p) => mkdirSync4(p, { recursive: true }));
15835
- const writeFile17 = deps.writeFile ?? ((p, c2) => writeFileSync3(p, c2));
16018
+ const writeFile18 = deps.writeFile ?? ((p, c2) => writeFileSync3(p, c2));
15836
16019
  const run3 = deps.run ?? defaultRun;
15837
16020
  const releaseLock2 = (deps.acquireInstallLock ?? (() => defaultAcquireInstallLock(home2)))();
15838
16021
  try {
15839
- mkdirp(join27(home2, ".syntaur", "logs"));
15840
- mkdirp(join27(home2, "Library", "LaunchAgents"));
15841
- writeFile17(plistPath, buildPlist(spec));
16022
+ mkdirp(join29(home2, ".syntaur", "logs"));
16023
+ mkdirp(join29(home2, "Library", "LaunchAgents"));
16024
+ writeFile18(plistPath, buildPlist(spec));
15842
16025
  const domain = `gui/${uid}`;
15843
16026
  run3("launchctl", ["bootout", `${domain}/${spec.label}`]);
15844
16027
  const boot = run3("launchctl", ["bootstrap", domain, plistPath]);
@@ -16063,7 +16246,7 @@ init_create_assignment();
16063
16246
  init_config2();
16064
16247
  import { spawn as spawn5 } from "child_process";
16065
16248
  import { createServer as createNetServer } from "net";
16066
- import { resolve as resolve51, dirname as dirname13 } from "path";
16249
+ import { resolve as resolve51, dirname as dirname14 } from "path";
16067
16250
  import { fileURLToPath as fileURLToPath3 } from "url";
16068
16251
 
16069
16252
  // src/dashboard/server.ts
@@ -16074,7 +16257,7 @@ init_agent_sessions();
16074
16257
  import express from "express";
16075
16258
  import { createServer } from "http";
16076
16259
  import { resolve as resolve50 } from "path";
16077
- import { writeFile as writeFile8, unlink as unlink9 } from "fs/promises";
16260
+ import { writeFile as writeFile9, unlink as unlink9 } from "fs/promises";
16078
16261
  import { WebSocketServer, WebSocket } from "ws";
16079
16262
 
16080
16263
  // src/dashboard/session-liveness.ts
@@ -20714,6 +20897,7 @@ function createAgentSessionsRouter(projectsDir2, broadcast, assignmentsDir2) {
20714
20897
  init_config2();
20715
20898
  init_agents_schema();
20716
20899
  import { Router as Router5 } from "express";
20900
+ import { access as access4 } from "fs/promises";
20717
20901
 
20718
20902
  // src/targets/agent-definitions.ts
20719
20903
  init_parser();
@@ -20762,7 +20946,293 @@ async function discoverClaudeAgents(root) {
20762
20946
  return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
20763
20947
  }
20764
20948
 
20949
+ // src/targets/agent-discovery.ts
20950
+ init_paths();
20951
+ init_parser();
20952
+ import { access as access2, readdir as readdir17, readFile as readFile22 } from "fs/promises";
20953
+ import { join as join7 } from "path";
20954
+ async function pathExists(p) {
20955
+ try {
20956
+ await access2(p);
20957
+ return true;
20958
+ } catch {
20959
+ return false;
20960
+ }
20961
+ }
20962
+ function coerceRunner(raw2) {
20963
+ return raw2 === "claude" || raw2 === "pi" || raw2 === "codex" ? raw2 : void 0;
20964
+ }
20965
+ async function readSyntaurMeta(file) {
20966
+ let content;
20967
+ try {
20968
+ content = await readFile22(file, "utf-8");
20969
+ } catch {
20970
+ return null;
20971
+ }
20972
+ const [fm] = extractFrontmatter(content);
20973
+ if (!fm) return null;
20974
+ if (!/^syntaur:[ \t]*$/m.test(fm)) return null;
20975
+ return {
20976
+ name: getNestedField(fm, "syntaur", "name")?.trim() || void 0,
20977
+ runner: coerceRunner(getNestedField(fm, "syntaur", "runner")?.trim() || void 0),
20978
+ description: getNestedField(fm, "syntaur", "description")?.trim() || void 0
20979
+ };
20980
+ }
20981
+ async function fileHasSyntaurBlock(file) {
20982
+ return await readSyntaurMeta(file) !== null;
20983
+ }
20984
+ function claudeAlreadyRegistered(agents, path, name) {
20985
+ return agents.some((a) => a.sourcePath === path || !!a.agentName && a.agentName === name);
20986
+ }
20987
+ function directoryAlreadyRegistered(agents, dir) {
20988
+ return agents.some((a) => a.sourcePath === dir || a.workdir === dir);
20989
+ }
20990
+ async function toClaudeCandidate(d, source, agents, sourceRepo) {
20991
+ return {
20992
+ name: d.name,
20993
+ runner: "claude",
20994
+ description: d.description,
20995
+ path: d.path,
20996
+ source,
20997
+ ...sourceRepo ? { sourceRepo } : {},
20998
+ recommended: await fileHasSyntaurBlock(d.path),
20999
+ alreadyRegistered: claudeAlreadyRegistered(agents, d.path, d.name)
21000
+ };
21001
+ }
21002
+ async function inspectDirCandidate(dir, basename11, agents) {
21003
+ const hasPi = await pathExists(join7(dir, ".pi"));
21004
+ const hasMcp = await pathExists(join7(dir, ".mcp.json"));
21005
+ const hasSyntaurMd = await pathExists(join7(dir, "SYNTAUR.md"));
21006
+ const hasAgentsMd = await pathExists(join7(dir, "AGENTS.md"));
21007
+ let syntaur = null;
21008
+ if (hasSyntaurMd) syntaur = await readSyntaurMeta(join7(dir, "SYNTAUR.md"));
21009
+ if (!syntaur && hasAgentsMd) syntaur = await readSyntaurMeta(join7(dir, "AGENTS.md"));
21010
+ const strong = hasPi || hasMcp || syntaur !== null;
21011
+ if (!strong) return null;
21012
+ return {
21013
+ name: syntaur?.name ?? basename11,
21014
+ // A directory agent is pi/codex by definition; a contradictory
21015
+ // `syntaur.runner: claude` opt-in is clamped to pi so the candidate never
21016
+ // carries an impossible directory+claude combo.
21017
+ runner: syntaur?.runner === "codex" ? "codex" : "pi",
21018
+ description: syntaur?.description,
21019
+ path: dir,
21020
+ source: "directory",
21021
+ recommended: syntaur !== null,
21022
+ alreadyRegistered: directoryAlreadyRegistered(agents, dir)
21023
+ };
21024
+ }
21025
+ async function discoverAgents(input4) {
21026
+ const out = [];
21027
+ if (input4.claudeGlobal) {
21028
+ for (const d of await discoverClaudeAgents()) {
21029
+ out.push(await toClaudeCandidate(d, "claude-global", input4.agents));
21030
+ }
21031
+ }
21032
+ if (input4.claudeProject && input4.repo) {
21033
+ const projRoot = join7(input4.repo, ".claude", "agents");
21034
+ for (const d of await discoverClaudeAgents(projRoot)) {
21035
+ out.push(await toClaudeCandidate(d, "claude-project", input4.agents, input4.repo));
21036
+ }
21037
+ }
21038
+ if (input4.directory || input4.claudeProject) {
21039
+ for (const rawRoot of input4.roots) {
21040
+ const root = expandHome(rawRoot);
21041
+ let entries;
21042
+ try {
21043
+ entries = await readdir17(root, { withFileTypes: true });
21044
+ } catch {
21045
+ continue;
21046
+ }
21047
+ for (const e of entries) {
21048
+ if (!e.isDirectory()) continue;
21049
+ const dir = join7(root, e.name);
21050
+ if (input4.directory) {
21051
+ const dirCand = await inspectDirCandidate(dir, e.name, input4.agents);
21052
+ if (dirCand) out.push(dirCand);
21053
+ }
21054
+ if (input4.claudeProject && await pathExists(join7(dir, ".claude", "agents"))) {
21055
+ const projRoot = join7(dir, ".claude", "agents");
21056
+ for (const d of await discoverClaudeAgents(projRoot)) {
21057
+ out.push(await toClaudeCandidate(d, "claude-project", input4.agents, dir));
21058
+ }
21059
+ }
21060
+ }
21061
+ }
21062
+ }
21063
+ const seen = /* @__PURE__ */ new Set();
21064
+ const deduped = [];
21065
+ for (const c2 of out) {
21066
+ const key = JSON.stringify([c2.source, c2.path, c2.name]);
21067
+ if (seen.has(key)) continue;
21068
+ seen.add(key);
21069
+ deduped.push(c2);
21070
+ }
21071
+ deduped.sort(
21072
+ (a, b) => a.recommended === b.recommended ? a.name.localeCompare(b.name) : a.recommended ? -1 : 1
21073
+ );
21074
+ return deduped;
21075
+ }
21076
+
21077
+ // src/targets/agent-authoring.ts
21078
+ init_paths();
21079
+ init_parser();
21080
+ init_agents_schema();
21081
+ import { mkdir as mkdir2, writeFile as writeFile4, access as access3, readFile as readFile23, stat as stat5 } from "fs/promises";
21082
+ import { homedir as homedir6 } from "os";
21083
+ import { basename as basename5, dirname as dirname7, isAbsolute as isAbsolute5, join as join8 } from "path";
21084
+ var RUNNER_COMMAND = {
21085
+ claude: "claude",
21086
+ pi: "pi",
21087
+ codex: "codex"
21088
+ };
21089
+ function requireAbsolutePath(raw2, what = "path") {
21090
+ const p = expandHome(raw2.trim());
21091
+ if (!isAbsolute5(p)) {
21092
+ throw new Error(`${what} must be an absolute path (got ${JSON.stringify(raw2)})`);
21093
+ }
21094
+ return p;
21095
+ }
21096
+ function slugifyAgentId(name) {
21097
+ const slug = name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
21098
+ const safe = /^[a-z0-9]/.test(slug) ? slug : `agent-${slug}`;
21099
+ return AGENT_ID_PATTERN.test(safe) ? safe : "agent";
21100
+ }
21101
+ function uniqueAgentId(base, existingIds) {
21102
+ const taken = new Set(existingIds);
21103
+ if (!taken.has(base)) return base;
21104
+ for (let n = 2; ; n++) {
21105
+ const candidate = `${base}-${n}`;
21106
+ if (!taken.has(candidate)) return candidate;
21107
+ }
21108
+ }
21109
+ function buildRegisteredAgent(input4) {
21110
+ const id = uniqueAgentId(slugifyAgentId(input4.name), input4.existingIds);
21111
+ const agent = {
21112
+ id,
21113
+ label: input4.name,
21114
+ command: RUNNER_COMMAND[input4.runner],
21115
+ runner: input4.runner,
21116
+ sourceKind: input4.sourceKind,
21117
+ sourcePath: input4.sourcePath
21118
+ };
21119
+ if (input4.sourceRepo) agent.sourceRepo = input4.sourceRepo;
21120
+ if (input4.runner === "claude") {
21121
+ agent.agentName = input4.name;
21122
+ } else {
21123
+ agent.workdir = input4.sourcePath;
21124
+ }
21125
+ return agent;
21126
+ }
21127
+ async function pathExists2(p) {
21128
+ try {
21129
+ await access3(p);
21130
+ return true;
21131
+ } catch {
21132
+ return false;
21133
+ }
21134
+ }
21135
+ function frontmatterLines(fields) {
21136
+ const lines = [];
21137
+ for (const [k, v] of Object.entries(fields)) {
21138
+ if (v !== void 0 && v !== "") lines.push(`${k}: ${JSON.stringify(v)}`);
21139
+ }
21140
+ return lines;
21141
+ }
21142
+ function syntaurBlock(name, runner, description) {
21143
+ const lines = ["syntaur:", ` name: ${JSON.stringify(name)}`, ` runner: ${runner}`];
21144
+ if (description) lines.push(` description: ${JSON.stringify(description)}`);
21145
+ return lines;
21146
+ }
21147
+ async function authorAgentDef(input4) {
21148
+ const slug = slugifyAgentId(input4.name);
21149
+ if (input4.runner === "claude") {
21150
+ const dir2 = input4.location ? requireAbsolutePath(input4.location, "location") : join8(homedir6(), ".claude", "agents");
21151
+ const path = join8(dir2, `${slug}.md`);
21152
+ if (await pathExists2(path)) {
21153
+ throw new Error(`refusing to overwrite existing def at ${path}`);
21154
+ }
21155
+ const fm2 = [
21156
+ "---",
21157
+ ...frontmatterLines({
21158
+ name: input4.name,
21159
+ description: input4.description,
21160
+ model: input4.model
21161
+ }),
21162
+ ...syntaurBlock(input4.name, "claude", input4.description),
21163
+ "---"
21164
+ ];
21165
+ await mkdir2(dir2, { recursive: true });
21166
+ await writeFile4(path, `${fm2.join("\n")}
21167
+
21168
+ ${input4.instructions.trim()}
21169
+ `);
21170
+ if (!input4.location) {
21171
+ return { path, sourceKind: "claude-global" };
21172
+ }
21173
+ const sourceRepo = basename5(dir2) === "agents" && basename5(dirname7(dir2)) === ".claude" ? dirname7(dirname7(dir2)) : void 0;
21174
+ return { path, sourceKind: "claude-project", ...sourceRepo ? { sourceRepo } : {} };
21175
+ }
21176
+ const parent = input4.location ? requireAbsolutePath(input4.location, "location") : homedir6();
21177
+ const dir = join8(parent, slug);
21178
+ const agentsMd = join8(dir, "AGENTS.md");
21179
+ if (await pathExists2(agentsMd)) {
21180
+ throw new Error(`refusing to overwrite existing def at ${agentsMd}`);
21181
+ }
21182
+ const fm = ["---", ...syntaurBlock(input4.name, input4.runner, input4.description), "---"];
21183
+ await mkdir2(dir, { recursive: true });
21184
+ await writeFile4(agentsMd, `${fm.join("\n")}
21185
+
21186
+ ${input4.instructions.trim()}
21187
+ `);
21188
+ return { path: dir, sourceKind: "directory" };
21189
+ }
21190
+ async function inferManualAdd(rawPath) {
21191
+ const path = requireAbsolutePath(rawPath);
21192
+ const info = await stat5(path);
21193
+ if (info.isFile()) {
21194
+ const content = await readFile23(path, "utf-8");
21195
+ const [fm] = extractFrontmatter(content);
21196
+ const name = getNestedField(fm, "syntaur", "name")?.trim() || getField(fm, "name")?.trim() || basename5(path).replace(/\.md$/, "");
21197
+ const description = getNestedField(fm, "syntaur", "description")?.trim() || getField(fm, "description")?.trim() || void 0;
21198
+ return { name, runner: "claude", sourceKind: "claude-global", sourcePath: path, description };
21199
+ }
21200
+ let syntaurName;
21201
+ let syntaurRunner;
21202
+ let syntaurDesc;
21203
+ for (const f of ["SYNTAUR.md", "AGENTS.md"]) {
21204
+ const p = join8(path, f);
21205
+ if (await pathExists2(p)) {
21206
+ const [fm] = extractFrontmatter(await readFile23(p, "utf-8"));
21207
+ syntaurName = getNestedField(fm, "syntaur", "name")?.trim() || syntaurName;
21208
+ const r = getNestedField(fm, "syntaur", "runner")?.trim();
21209
+ if (r === "claude" || r === "pi" || r === "codex") syntaurRunner = r;
21210
+ syntaurDesc = getNestedField(fm, "syntaur", "description")?.trim() || syntaurDesc;
21211
+ if (syntaurName || syntaurRunner) break;
21212
+ }
21213
+ }
21214
+ return {
21215
+ name: syntaurName ?? basename5(path),
21216
+ // A directory (pi/codex) agent is never claude — clamp a contradictory
21217
+ // `syntaur.runner: claude` opt-in to pi (parity with inspectDirCandidate).
21218
+ runner: syntaurRunner === "codex" ? "codex" : "pi",
21219
+ sourceKind: "directory",
21220
+ sourcePath: path,
21221
+ description: syntaurDesc
21222
+ };
21223
+ }
21224
+
20765
21225
  // src/dashboard/api-agents.ts
21226
+ async function pathExists3(p) {
21227
+ try {
21228
+ await access4(p);
21229
+ return true;
21230
+ } catch {
21231
+ return false;
21232
+ }
21233
+ }
21234
+ var RUNNER_KINDS_SET = /* @__PURE__ */ new Set(["claude", "pi", "codex"]);
21235
+ var SOURCE_KINDS_SET = /* @__PURE__ */ new Set(["claude-global", "claude-project", "directory"]);
20766
21236
  function mapAgentErrorToFieldErrors(err2) {
20767
21237
  const message = err2.message;
20768
21238
  let match = message.match(/^agent id "([^"]*)" is invalid/);
@@ -21057,6 +21527,22 @@ function coerceAgentRow(raw2, index) {
21057
21527
  const workdir = entry.workdir.trim();
21058
21528
  if (workdir) cleaned.workdir = workdir;
21059
21529
  }
21530
+ for (const field of ["runner", "sourceKind", "sourcePath", "sourceRepo"]) {
21531
+ const raw3 = entry[field];
21532
+ if (raw3 === void 0) continue;
21533
+ if (typeof raw3 !== "string") {
21534
+ return {
21535
+ ok: false,
21536
+ status: 400,
21537
+ body: {
21538
+ error: `agents[${index}].${field} must be a string`,
21539
+ fieldErrors: [{ id, field, message: `${field} must be a string` }]
21540
+ }
21541
+ };
21542
+ }
21543
+ const v = raw3.trim();
21544
+ if (v) cleaned[field] = v;
21545
+ }
21060
21546
  return { ok: true, value: cleaned };
21061
21547
  }
21062
21548
  function createAgentsRouter() {
@@ -21070,6 +21556,164 @@ function createAgentsRouter() {
21070
21556
  res.status(500).json({ error: "Failed to discover Claude agents" });
21071
21557
  }
21072
21558
  });
21559
+ router.get("/discovered", async (req2, res) => {
21560
+ try {
21561
+ const config = await readConfig();
21562
+ const agents = config.agents ?? BUILTIN_AGENTS;
21563
+ const repo = typeof req2.query.repo === "string" && req2.query.repo ? req2.query.repo : null;
21564
+ const d = config.agentDiscovery;
21565
+ const candidates = await discoverAgents({
21566
+ claudeGlobal: d.claudeGlobal,
21567
+ claudeProject: d.claudeProject,
21568
+ directory: d.directory,
21569
+ roots: d.roots,
21570
+ repo,
21571
+ agents
21572
+ });
21573
+ res.json({ candidates });
21574
+ } catch (err2) {
21575
+ console.error("Error discovering agents:", err2);
21576
+ res.status(500).json({ error: "Failed to discover agents" });
21577
+ }
21578
+ });
21579
+ async function appendAndPersist(agent, res) {
21580
+ const config = await readConfig();
21581
+ const base = config.agents ?? BUILTIN_AGENTS;
21582
+ if (agent.sourcePath && base.some((a) => a.sourcePath === agent.sourcePath)) {
21583
+ res.status(409).json({ error: `already registered: ${agent.sourcePath}` });
21584
+ return null;
21585
+ }
21586
+ const next = [...base, agent];
21587
+ try {
21588
+ await writeAgentsConfig(next);
21589
+ } catch (err2) {
21590
+ if (err2 instanceof AgentConfigError) {
21591
+ res.status(400).json(mapAgentErrorToFieldErrors(err2));
21592
+ return null;
21593
+ }
21594
+ throw err2;
21595
+ }
21596
+ return next;
21597
+ }
21598
+ router.post("/register", async (req2, res) => {
21599
+ try {
21600
+ const b = req2.body ?? {};
21601
+ if (!b.path || !b.name || !b.runner || !b.sourceKind) {
21602
+ res.status(400).json({ error: "register requires path, name, runner, sourceKind" });
21603
+ return;
21604
+ }
21605
+ if (!RUNNER_KINDS_SET.has(b.runner) || !SOURCE_KINDS_SET.has(b.sourceKind)) {
21606
+ res.status(400).json({ error: "invalid runner or sourceKind" });
21607
+ return;
21608
+ }
21609
+ let regPath;
21610
+ let sourceRepo;
21611
+ try {
21612
+ regPath = requireAbsolutePath(b.path);
21613
+ sourceRepo = b.sourceRepo ? requireAbsolutePath(b.sourceRepo, "sourceRepo") : void 0;
21614
+ } catch (err2) {
21615
+ res.status(400).json({ error: err2 instanceof Error ? err2.message : "invalid path" });
21616
+ return;
21617
+ }
21618
+ if (!await pathExists3(regPath)) {
21619
+ res.status(400).json({ error: `path not found: ${regPath}` });
21620
+ return;
21621
+ }
21622
+ const config = await readConfig();
21623
+ const base = config.agents ?? BUILTIN_AGENTS;
21624
+ const agent = buildRegisteredAgent({
21625
+ name: b.name,
21626
+ runner: b.runner,
21627
+ sourceKind: b.sourceKind,
21628
+ sourcePath: regPath,
21629
+ sourceRepo,
21630
+ description: b.description,
21631
+ existingIds: base.map((a) => a.id)
21632
+ });
21633
+ const next = await appendAndPersist(agent, res);
21634
+ if (!next) return;
21635
+ res.json({ agent, agents: next, custom: true });
21636
+ } catch (err2) {
21637
+ console.error("Error registering agent:", err2);
21638
+ res.status(500).json({ error: "Failed to register agent" });
21639
+ }
21640
+ });
21641
+ router.post("/manual-add", async (req2, res) => {
21642
+ try {
21643
+ const p = (req2.body ?? {}).path;
21644
+ if (typeof p !== "string" || !p) {
21645
+ res.status(400).json({ error: "manual-add requires a path" });
21646
+ return;
21647
+ }
21648
+ let inferred;
21649
+ try {
21650
+ inferred = await inferManualAdd(p);
21651
+ } catch {
21652
+ res.status(400).json({ error: `path not found or unreadable: ${p}` });
21653
+ return;
21654
+ }
21655
+ const config = await readConfig();
21656
+ const base = config.agents ?? BUILTIN_AGENTS;
21657
+ const agent = buildRegisteredAgent({
21658
+ name: inferred.name,
21659
+ runner: inferred.runner,
21660
+ sourceKind: inferred.sourceKind,
21661
+ sourcePath: inferred.sourcePath,
21662
+ description: inferred.description,
21663
+ existingIds: base.map((a) => a.id)
21664
+ });
21665
+ const next = await appendAndPersist(agent, res);
21666
+ if (!next) return;
21667
+ res.json({ agent, agents: next, custom: true });
21668
+ } catch (err2) {
21669
+ console.error("Error manual-adding agent:", err2);
21670
+ res.status(500).json({ error: "Failed to manual-add agent" });
21671
+ }
21672
+ });
21673
+ router.post("/create", async (req2, res) => {
21674
+ try {
21675
+ const b = req2.body ?? {};
21676
+ if (!b.name || !b.runner || typeof b.instructions !== "string") {
21677
+ res.status(400).json({ error: "create requires name, runner, instructions" });
21678
+ return;
21679
+ }
21680
+ if (!RUNNER_KINDS_SET.has(b.runner)) {
21681
+ res.status(400).json({ error: "invalid runner" });
21682
+ return;
21683
+ }
21684
+ let authored;
21685
+ try {
21686
+ authored = await authorAgentDef({
21687
+ name: b.name,
21688
+ runner: b.runner,
21689
+ model: b.model,
21690
+ description: b.description,
21691
+ instructions: b.instructions,
21692
+ location: b.location
21693
+ });
21694
+ } catch (err2) {
21695
+ res.status(400).json({ error: err2 instanceof Error ? err2.message : "failed to author def" });
21696
+ return;
21697
+ }
21698
+ const config = await readConfig();
21699
+ const base = config.agents ?? BUILTIN_AGENTS;
21700
+ const agent = buildRegisteredAgent({
21701
+ name: b.name,
21702
+ runner: b.runner,
21703
+ sourceKind: authored.sourceKind,
21704
+ sourcePath: authored.path,
21705
+ sourceRepo: authored.sourceRepo,
21706
+ description: b.description,
21707
+ existingIds: base.map((a) => a.id)
21708
+ });
21709
+ const next = await appendAndPersist(agent, res);
21710
+ if (!next) return;
21711
+ res.json({ agent, path: authored.path, agents: next, custom: true });
21712
+ } catch (err2) {
21713
+ console.error("Error creating agent:", err2);
21714
+ res.status(500).json({ error: "Failed to create agent" });
21715
+ }
21716
+ });
21073
21717
  router.get("/", async (_req, res) => {
21074
21718
  try {
21075
21719
  const config = await readConfig();
@@ -21132,8 +21776,8 @@ import { Router as Router6 } from "express";
21132
21776
  // src/utils/terminal-probe.ts
21133
21777
  import { spawnSync as spawnSync4 } from "child_process";
21134
21778
  import { existsSync as existsSync2 } from "fs";
21135
- import { homedir as homedir5 } from "os";
21136
- import { join as join7 } from "path";
21779
+ import { homedir as homedir7 } from "os";
21780
+ import { join as join9 } from "path";
21137
21781
  var APP_BUNDLE_IDS = {
21138
21782
  "terminal-app": "com.apple.Terminal",
21139
21783
  iterm: "com.googlecode.iterm2",
@@ -21150,7 +21794,7 @@ var APP_FIXED_PATHS = {
21150
21794
  "terminal-app": "/System/Applications/Utilities/Terminal.app"
21151
21795
  };
21152
21796
  function defaultApplicationsDirs() {
21153
- return ["/Applications", join7(homedir5(), "Applications")];
21797
+ return ["/Applications", join9(homedir7(), "Applications")];
21154
21798
  }
21155
21799
  function findAppBundle(terminal, dirs = defaultApplicationsDirs()) {
21156
21800
  const fixed = APP_FIXED_PATHS[terminal];
@@ -21158,7 +21802,7 @@ function findAppBundle(terminal, dirs = defaultApplicationsDirs()) {
21158
21802
  const bundleName = APP_BUNDLE_NAMES[terminal];
21159
21803
  if (bundleName) {
21160
21804
  for (const dir of dirs) {
21161
- const candidate = join7(dir, bundleName);
21805
+ const candidate = join9(dir, bundleName);
21162
21806
  if (existsSync2(candidate)) return candidate;
21163
21807
  }
21164
21808
  }
@@ -21188,11 +21832,11 @@ var defaultCmuxLsappinfoRunner = () => {
21188
21832
  function resolveCmuxCli(applicationsDirsOverride, cliDirsOverride, lsappinfoRunnerOverride) {
21189
21833
  const bundle = findAppBundle("cmux", applicationsDirsOverride);
21190
21834
  if (bundle) {
21191
- const cli = join7(bundle, "Contents/Resources/bin/cmux");
21835
+ const cli = join9(bundle, "Contents/Resources/bin/cmux");
21192
21836
  if (existsSync2(cli)) return cli;
21193
21837
  }
21194
21838
  for (const dir of cliDirsOverride ?? CMUX_CLI_DIRS) {
21195
- const cli = join7(dir, "cmux");
21839
+ const cli = join9(dir, "cmux");
21196
21840
  if (existsSync2(cli)) return cli;
21197
21841
  }
21198
21842
  if (process.platform === "darwin") {
@@ -21201,7 +21845,7 @@ function resolveCmuxCli(applicationsDirsOverride, cliDirsOverride, lsappinfoRunn
21201
21845
  if (stdout) {
21202
21846
  const match = stdout.match(/"LSBundlePath"="([^"]+)"/);
21203
21847
  if (match) {
21204
- const cli = join7(match[1], "Contents/Resources/bin/cmux");
21848
+ const cli = join9(match[1], "Contents/Resources/bin/cmux");
21205
21849
  if (existsSync2(cli)) return cli;
21206
21850
  }
21207
21851
  }
@@ -21460,7 +22104,7 @@ init_agent_sessions();
21460
22104
  // src/launch/argv.ts
21461
22105
  init_agents_schema();
21462
22106
  init_launch();
21463
- import { isAbsolute as isAbsolute6 } from "path";
22107
+ import { isAbsolute as isAbsolute7 } from "path";
21464
22108
  var buildFreshArgv = buildAgentArgv;
21465
22109
  function buildSessionArgv(agent, sessionId, mode, env = process.env) {
21466
22110
  const invocation = agent[mode];
@@ -21479,7 +22123,7 @@ function buildSessionArgv(agent, sessionId, mode, env = process.env) {
21479
22123
  const requested = env.SHELL;
21480
22124
  let shell = requested;
21481
22125
  let warning = null;
21482
- if (!shell || !isAbsolute6(shell)) {
22126
+ if (!shell || !isAbsolute7(shell)) {
21483
22127
  warning = `syntaur: $SHELL ${requested ? `("${requested}") is not absolute` : "is unset"} \u2014 falling back to /bin/sh for shell-alias resolution`;
21484
22128
  shell = "/bin/sh";
21485
22129
  }
@@ -21539,18 +22183,14 @@ async function resolveStandalonePlan(input4, terminal) {
21539
22183
  `Agent "${agentId}" requested for a standalone launch is not in your agents list.`
21540
22184
  );
21541
22185
  }
21542
- const wd = agent.workdir?.trim();
21543
- if (!wd) {
21544
- throw new LaunchError(
21545
- "workspace-path-invalid",
21546
- `Agent "${agent.id}" has no workdir \u2014 a standalone launch requires a valid workdir.`
21547
- );
21548
- }
21549
- const expanded = expandHome(wd);
21550
- if (!isExistingDir(expanded)) {
22186
+ const { cwd: spawnCwd, invalidReason } = resolveStandaloneCwd(
22187
+ agent,
22188
+ input4.config.standaloneDefaultCwd
22189
+ );
22190
+ if (spawnCwd === null) {
21551
22191
  throw new LaunchError(
21552
22192
  "workspace-path-invalid",
21553
- `Agent "${agent.id}" workdir ${agent.workdir} (resolved ${expanded}) is not an existing directory \u2014 a standalone launch requires a valid workdir.`
22193
+ invalidReason ?? `Agent "${agent.id}" has no valid standalone launch directory.`
21554
22194
  );
21555
22195
  }
21556
22196
  const knownPlaybookSlugs = await listPlaybookSlugs(playbooksDir());
@@ -21564,7 +22204,7 @@ async function resolveStandalonePlan(input4, terminal) {
21564
22204
  const { argv, shellFallbackWarning } = buildFreshArgv(agent, prompt);
21565
22205
  return {
21566
22206
  terminal,
21567
- cwd: expanded,
22207
+ cwd: spawnCwd,
21568
22208
  argv,
21569
22209
  env: process.env,
21570
22210
  agentId: agent.id,
@@ -21732,8 +22372,8 @@ async function resolveSessionPlan(input4, terminal) {
21732
22372
  // src/launch/execute.ts
21733
22373
  init_launch();
21734
22374
  import { spawn as spawn3 } from "child_process";
21735
- import { homedir as homedir6 } from "os";
21736
- import { basename as basename5, join as join8, resolve as resolve32 } from "path";
22375
+ import { homedir as homedir8 } from "os";
22376
+ import { basename as basename6, join as join10, resolve as resolve32 } from "path";
21737
22377
  init_fs();
21738
22378
  init_config2();
21739
22379
  init_session_id();
@@ -21753,7 +22393,7 @@ var TerminalNotFoundError = class extends Error {
21753
22393
  var realSpawn = (command, args, options) => spawn3(command, args, options);
21754
22394
  var WRAPPER_COMMANDS = /* @__PURE__ */ new Set(["osascript", "open", "sh"]);
21755
22395
  function isWrapperCommand(command) {
21756
- return WRAPPER_COMMANDS.has(basename5(command));
22396
+ return WRAPPER_COMMANDS.has(basename6(command));
21757
22397
  }
21758
22398
  var WRAPPER_EXIT_TIMEOUT_MS = 1500;
21759
22399
  async function executeLaunchPlan(plan, spawnFn = realSpawn) {
@@ -21839,7 +22479,7 @@ async function registerLaunchAtBirth(plan, child) {
21839
22479
  const sessionId = plan.session?.sessionId ?? null;
21840
22480
  const procStart = captureProcessStartedAt(pid);
21841
22481
  const envDir = process.env.SYNTAUR_RUNTIME_SESSIONS_DIR;
21842
- const markerDir = envDir && envDir.length > 0 ? envDir : join8(homedir6(), ".syntaur", "runtime", "sessions");
22482
+ const markerDir = envDir && envDir.length > 0 ? envDir : join10(homedir8(), ".syntaur", "runtime", "sessions");
21843
22483
  writeRuntimeMarker(
21844
22484
  pid,
21845
22485
  {
@@ -22031,7 +22671,7 @@ init_launch_prompt();
22031
22671
  init_paths();
22032
22672
  init_fs();
22033
22673
  import { fileURLToPath as fileURLToPath2 } from "url";
22034
- import { dirname as dirname7, resolve as resolve33, join as join9 } from "path";
22674
+ import { dirname as dirname8, resolve as resolve33, join as join11 } from "path";
22035
22675
  import { realpathSync, readFileSync as readFileSync3, mkdirSync as mkdirSync2 } from "fs";
22036
22676
  var NPX_PATTERNS = [
22037
22677
  { kind: "npm", re: /\/_npx\/([^/]+)\/node_modules(?:\/|$)/ },
@@ -22057,7 +22697,7 @@ function normalizeSlashes(p) {
22057
22697
  }
22058
22698
  function detectInstallKind(scriptUrl, opts = {}) {
22059
22699
  const realpath3 = opts.realpath ?? realpathSync.native;
22060
- const readFile82 = opts.readFile ?? ((p) => readFileSync3(p, "utf-8"));
22700
+ const readFile85 = opts.readFile ?? ((p) => readFileSync3(p, "utf-8"));
22061
22701
  const ua = opts.envUserAgent !== void 0 ? opts.envUserAgent : process.env.npm_config_user_agent ?? "";
22062
22702
  const resolved = resolveScriptPath(scriptUrl, realpath3);
22063
22703
  if (resolved === null) {
@@ -22073,14 +22713,14 @@ function detectInstallKind(scriptUrl, opts = {}) {
22073
22713
  if (GLOBAL_PATTERN.test(norm)) {
22074
22714
  return "global";
22075
22715
  }
22076
- let dir = dirname7(resolved);
22716
+ let dir = dirname8(resolved);
22077
22717
  for (let depth = 0; depth < 8; depth++) {
22078
- const pkgJsonPath = join9(dir, "package.json");
22718
+ const pkgJsonPath = join11(dir, "package.json");
22079
22719
  let raw2;
22080
22720
  try {
22081
- raw2 = readFile82(pkgJsonPath);
22721
+ raw2 = readFile85(pkgJsonPath);
22082
22722
  } catch {
22083
- const parent2 = dirname7(dir);
22723
+ const parent2 = dirname8(dir);
22084
22724
  if (parent2 === dir) break;
22085
22725
  dir = parent2;
22086
22726
  continue;
@@ -22092,7 +22732,7 @@ function detectInstallKind(scriptUrl, opts = {}) {
22092
22732
  }
22093
22733
  } catch {
22094
22734
  }
22095
- const parent = dirname7(dir);
22735
+ const parent = dirname8(dir);
22096
22736
  if (parent === dir) break;
22097
22737
  dir = parent;
22098
22738
  }
@@ -22116,7 +22756,7 @@ function sanitizeHash(hash) {
22116
22756
  return hash.replace(/[^A-Za-z0-9_-]/g, "_") || "_";
22117
22757
  }
22118
22758
  function nudgeStampPath(hash) {
22119
- return join9(nudgeStampDir(), sanitizeHash(hash));
22759
+ return join11(nudgeStampDir(), sanitizeHash(hash));
22120
22760
  }
22121
22761
  async function hasNudgedHash(hash) {
22122
22762
  return fileExists(nudgeStampPath(hash));
@@ -22549,21 +23189,78 @@ function createWorkspaceVisibilityConfigRouter() {
22549
23189
  return router;
22550
23190
  }
22551
23191
 
23192
+ // src/dashboard/api-agent-discovery-config.ts
23193
+ init_config2();
23194
+ import { Router as Router11 } from "express";
23195
+ function createAgentDiscoveryConfigRouter() {
23196
+ const router = Router11();
23197
+ router.get("/", async (_req, res) => {
23198
+ try {
23199
+ const config = await readConfig();
23200
+ res.json({
23201
+ agentDiscovery: config.agentDiscovery,
23202
+ standaloneDefaultCwd: config.standaloneDefaultCwd
23203
+ });
23204
+ } catch (error) {
23205
+ console.error("Error getting agent-discovery config:", error);
23206
+ res.status(500).json({ error: "Failed to get agent-discovery config" });
23207
+ }
23208
+ });
23209
+ router.post("/", async (req2, res) => {
23210
+ try {
23211
+ const b = req2.body ?? {};
23212
+ const d = b.agentDiscovery ?? {};
23213
+ let roots;
23214
+ try {
23215
+ roots = (Array.isArray(d.roots) ? d.roots : []).filter((r) => typeof r === "string" && r.trim() !== "").map((r) => {
23216
+ requireAbsolutePath(r, "root");
23217
+ return r.trim();
23218
+ });
23219
+ } catch (err2) {
23220
+ res.status(400).json({ error: err2 instanceof Error ? err2.message : "invalid root" });
23221
+ return;
23222
+ }
23223
+ const cfg = {
23224
+ // Default-true semantics: only an explicit `false` turns a source off.
23225
+ claudeGlobal: d.claudeGlobal !== false,
23226
+ claudeProject: d.claudeProject !== false,
23227
+ directory: d.directory !== false,
23228
+ roots: roots.length > 0 ? roots : ["~"]
23229
+ };
23230
+ let cwd = null;
23231
+ if (typeof b.standaloneDefaultCwd === "string" && b.standaloneDefaultCwd.trim()) {
23232
+ try {
23233
+ cwd = requireAbsolutePath(b.standaloneDefaultCwd, "standaloneDefaultCwd");
23234
+ } catch (err2) {
23235
+ res.status(400).json({ error: err2 instanceof Error ? err2.message : "invalid cwd" });
23236
+ return;
23237
+ }
23238
+ }
23239
+ await writeAgentDiscoveryConfig(cfg, cwd);
23240
+ res.json({ agentDiscovery: cfg, standaloneDefaultCwd: cwd });
23241
+ } catch (error) {
23242
+ console.error("Error saving agent-discovery config:", error);
23243
+ res.status(500).json({ error: "Failed to save agent-discovery config" });
23244
+ }
23245
+ });
23246
+ return router;
23247
+ }
23248
+
22552
23249
  // src/dashboard/api-status-config.ts
22553
23250
  init_config2();
22554
23251
  init_fact_registry();
22555
23252
  init_state_machine();
22556
23253
  init_api();
22557
23254
  init_derive();
22558
- import { Router as Router11 } from "express";
23255
+ import { Router as Router12 } from "express";
22559
23256
 
22560
23257
  // src/utils/status-config-resolution.ts
22561
23258
  init_frontmatter();
22562
23259
  init_event_emit();
22563
23260
  init_assignment_walk();
22564
23261
  init_timestamp();
22565
- import { readFile as readFile22, writeFile as writeFile5, rm as rm2 } from "fs/promises";
22566
- import { dirname as dirname8 } from "path";
23262
+ import { readFile as readFile24, writeFile as writeFile6, rm as rm2 } from "fs/promises";
23263
+ import { dirname as dirname9 } from "path";
22567
23264
  var StatusResolutionError = class extends Error {
22568
23265
  constructor(message, code) {
22569
23266
  super(message);
@@ -22581,7 +23278,7 @@ async function scanAssignmentsByStatus(projectsDir2, standaloneDir, ids) {
22581
23278
  const assignmentPath = `${entry.assignmentDir}/assignment.md`;
22582
23279
  let content;
22583
23280
  try {
22584
- content = await readFile22(assignmentPath, "utf-8");
23281
+ content = await readFile24(assignmentPath, "utf-8");
22585
23282
  } catch (err2) {
22586
23283
  const code = err2?.code;
22587
23284
  if (code === "ENOENT") {
@@ -22644,7 +23341,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
22644
23341
  const list = affected.get(r.id) ?? [];
22645
23342
  for (const a of list) {
22646
23343
  try {
22647
- const content = await readFile22(a.path, "utf-8");
23344
+ const content = await readFile24(a.path, "utf-8");
22648
23345
  buffer.set(a.path, content);
22649
23346
  } catch (err2) {
22650
23347
  const code = err2?.code;
@@ -22673,7 +23370,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
22673
23370
  for (const a of list) {
22674
23371
  let current;
22675
23372
  try {
22676
- current = await readFile22(a.path, "utf-8");
23373
+ current = await readFile24(a.path, "utf-8");
22677
23374
  } catch (err2) {
22678
23375
  const code = err2?.code;
22679
23376
  if (code === "ENOENT") {
@@ -22696,7 +23393,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
22696
23393
  }),
22697
23394
  { at: now, from: r.id, to: r.target, command: "remap", by: null }
22698
23395
  );
22699
- await writeFile5(a.path, next, "utf-8");
23396
+ await writeFile6(a.path, next, "utf-8");
22700
23397
  pendingRemapEvents.push({
22701
23398
  assignmentId: fm.id,
22702
23399
  projectSlug: a.projectSlug,
@@ -22714,7 +23411,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
22714
23411
  for (const p of writtenPaths) {
22715
23412
  const original = buffer.get(p);
22716
23413
  if (original !== void 0) {
22717
- await writeFile5(p, original, "utf-8").catch((rollbackErr) => {
23414
+ await writeFile6(p, original, "utf-8").catch((rollbackErr) => {
22718
23415
  console.error(
22719
23416
  `status-config-resolution: rollback write failed for ${p}:`,
22720
23417
  rollbackErr
@@ -22744,7 +23441,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
22744
23441
  const list = affected.get(r.id) ?? [];
22745
23442
  for (const a of list) {
22746
23443
  try {
22747
- const current = await readFile22(a.path, "utf-8");
23444
+ const current = await readFile24(a.path, "utf-8");
22748
23445
  const fm = parseAssignmentFrontmatter(current);
22749
23446
  if (fm.status !== r.id) {
22750
23447
  console.warn(
@@ -22755,7 +23452,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
22755
23452
  } catch {
22756
23453
  continue;
22757
23454
  }
22758
- const assignmentDir = dirname8(a.path);
23455
+ const assignmentDir = dirname9(a.path);
22759
23456
  try {
22760
23457
  await rm2(assignmentDir, { recursive: true, force: true });
22761
23458
  deleted++;
@@ -22795,7 +23492,7 @@ async function scanAssignmentsReferencingStatus(projectsDir2, standaloneDir, id)
22795
23492
  const assignmentPath = `${entry.assignmentDir}/assignment.md`;
22796
23493
  let content;
22797
23494
  try {
22798
- content = await readFile22(assignmentPath, "utf-8");
23495
+ content = await readFile24(assignmentPath, "utf-8");
22799
23496
  } catch (err2) {
22800
23497
  const code = err2?.code;
22801
23498
  if (code === "ENOENT") continue;
@@ -22929,7 +23626,7 @@ function mapResolutionErrorToHttp(err2, applied) {
22929
23626
  }
22930
23627
  }
22931
23628
  function createStatusConfigRouter(projectsDir2, assignmentsDir2) {
22932
- const router = Router11();
23629
+ const router = Router12();
22933
23630
  installRecordsInvalidation(router);
22934
23631
  router.get("/", async (_req, res) => {
22935
23632
  try {
@@ -23249,7 +23946,7 @@ function createStatusConfigRouter(projectsDir2, assignmentsDir2) {
23249
23946
  }
23250
23947
 
23251
23948
  // src/dashboard/api-leases.ts
23252
- import { Router as Router12 } from "express";
23949
+ import { Router as Router13 } from "express";
23253
23950
 
23254
23951
  // src/db/leases-db.ts
23255
23952
  init_paths();
@@ -23882,7 +24579,7 @@ function releaseLeasesByRequestedFor(tag) {
23882
24579
 
23883
24580
  // src/dashboard/api-leases.ts
23884
24581
  function createLeasesRouter(broadcast) {
23885
- const router = Router12();
24582
+ const router = Router13();
23886
24583
  router.get("/", (_req, res) => {
23887
24584
  try {
23888
24585
  initLeasesDb();
@@ -23938,14 +24635,14 @@ function createLeasesRouter(broadcast) {
23938
24635
 
23939
24636
  // src/dashboard/api-schedules.ts
23940
24637
  init_timestamp();
23941
- import { Router as Router13 } from "express";
24638
+ import { Router as Router14 } from "express";
23942
24639
 
23943
24640
  // src/schedules/store.ts
23944
24641
  init_fs();
23945
24642
  init_paths();
23946
24643
  init_timestamp();
23947
24644
  import { randomUUID as randomUUID4 } from "crypto";
23948
- import { readFile as readFile23, readdir as readdir17, rm as rm3 } from "fs/promises";
24645
+ import { readFile as readFile25, readdir as readdir18, rm as rm3 } from "fs/promises";
23949
24646
  import { resolve as resolve35 } from "path";
23950
24647
  function schedulesDir() {
23951
24648
  const override3 = process.env.SYNTAUR_SCHEDULES_DIR;
@@ -24078,7 +24775,7 @@ function validateJob(raw2) {
24078
24775
  async function readJob(id) {
24079
24776
  const path = jobPath(id);
24080
24777
  if (!await fileExists(path)) return null;
24081
- return parseJobFile(await readFile23(path, "utf-8"));
24778
+ return parseJobFile(await readFile25(path, "utf-8"));
24082
24779
  }
24083
24780
  async function writeJob(job) {
24084
24781
  const next = { ...job, updatedAt: nowTimestamp() };
@@ -24088,7 +24785,7 @@ async function writeJob(job) {
24088
24785
  async function listJobs() {
24089
24786
  let names;
24090
24787
  try {
24091
- names = await readdir17(schedulesDir());
24788
+ names = await readdir18(schedulesDir());
24092
24789
  } catch {
24093
24790
  return [];
24094
24791
  }
@@ -24096,7 +24793,7 @@ async function listJobs() {
24096
24793
  for (const name of names) {
24097
24794
  if (!name.endsWith(".md")) continue;
24098
24795
  try {
24099
- jobs.push(parseJobFile(await readFile23(resolve35(schedulesDir(), name), "utf-8")));
24796
+ jobs.push(parseJobFile(await readFile25(resolve35(schedulesDir(), name), "utf-8")));
24100
24797
  } catch {
24101
24798
  }
24102
24799
  }
@@ -24106,8 +24803,8 @@ async function listJobs() {
24106
24803
 
24107
24804
  // src/schedules/event-log.ts
24108
24805
  init_timestamp();
24109
- import { appendFile, readFile as readFile24, mkdir as mkdir3 } from "fs/promises";
24110
- import { dirname as dirname9, resolve as resolve36 } from "path";
24806
+ import { appendFile, readFile as readFile26, mkdir as mkdir4 } from "fs/promises";
24807
+ import { dirname as dirname10, resolve as resolve36 } from "path";
24111
24808
  function eventLogPath(jobId) {
24112
24809
  if (!/^[A-Za-z0-9_-]+$/.test(jobId)) {
24113
24810
  throw new Error(`Unsafe schedule id: ${JSON.stringify(jobId)}`);
@@ -24117,7 +24814,7 @@ function eventLogPath(jobId) {
24117
24814
  async function appendEvent(jobId, type, data) {
24118
24815
  const event = { type, at: nowTimestamp(), ...data ? { data } : {} };
24119
24816
  const path = eventLogPath(jobId);
24120
- await mkdir3(dirname9(path), { recursive: true });
24817
+ await mkdir4(dirname10(path), { recursive: true });
24121
24818
  await appendFile(path, `${JSON.stringify(event)}
24122
24819
  `, "utf-8");
24123
24820
  return event;
@@ -24125,7 +24822,7 @@ async function appendEvent(jobId, type, data) {
24125
24822
  async function readEvents(jobId) {
24126
24823
  let content;
24127
24824
  try {
24128
- content = await readFile24(eventLogPath(jobId), "utf-8");
24825
+ content = await readFile26(eventLogPath(jobId), "utf-8");
24129
24826
  } catch {
24130
24827
  return [];
24131
24828
  }
@@ -24144,7 +24841,7 @@ async function readEvents(jobId) {
24144
24841
 
24145
24842
  // src/schedules/attempt.ts
24146
24843
  import { createHash as createHash3 } from "crypto";
24147
- import { open as open4, readFile as readFile25, stat as stat5, unlink as unlink6 } from "fs/promises";
24844
+ import { open as open4, readFile as readFile27, stat as stat6, unlink as unlink6 } from "fs/promises";
24148
24845
  import { resolve as resolve37 } from "path";
24149
24846
 
24150
24847
  // src/schedules/triggers.ts
@@ -24333,7 +25030,7 @@ async function acquireJobLock(id) {
24333
25030
  await handle.close();
24334
25031
  return async () => {
24335
25032
  try {
24336
- const current = await readFile25(lockPath, "utf-8");
25033
+ const current = await readFile27(lockPath, "utf-8");
24337
25034
  if (current === token) await unlink6(lockPath);
24338
25035
  } catch {
24339
25036
  }
@@ -24342,7 +25039,7 @@ async function acquireJobLock(id) {
24342
25039
  const code = err2.code;
24343
25040
  if (code !== "EEXIST") throw err2;
24344
25041
  try {
24345
- const info = await stat5(lockPath);
25042
+ const info = await stat6(lockPath);
24346
25043
  if (Date.now() - info.mtimeMs > LOCK_STALE_MS2) {
24347
25044
  await unlink6(lockPath).catch(() => {
24348
25045
  });
@@ -24681,7 +25378,7 @@ function canFire(job, deps) {
24681
25378
  init_agent_sessions();
24682
25379
  init_session_db();
24683
25380
  function createSchedulesRouter(broadcast) {
24684
- const router = Router13();
25381
+ const router = Router14();
24685
25382
  const notify = () => broadcast?.({ type: "schedules-updated", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
24686
25383
  router.get("/", async (_req, res) => {
24687
25384
  try {
@@ -24806,20 +25503,20 @@ init_config2();
24806
25503
  init_paths();
24807
25504
  init_assignment_resolver();
24808
25505
  init_frontmatter();
24809
- import { readFile as readFile26 } from "fs/promises";
25506
+ import { readFile as readFile28 } from "fs/promises";
24810
25507
  import { resolve as resolve39 } from "path";
24811
25508
 
24812
25509
  // src/schedules/launch-ack.ts
24813
25510
  init_session_id();
24814
25511
  import { readdirSync as readdirSync2 } from "fs";
24815
- import { homedir as homedir7 } from "os";
24816
- import { join as join10 } from "path";
25512
+ import { homedir as homedir9 } from "os";
25513
+ import { join as join12 } from "path";
24817
25514
  function defaultSleep(ms) {
24818
25515
  return new Promise((r) => setTimeout(r, ms));
24819
25516
  }
24820
25517
  function runtimeSessionsDir() {
24821
25518
  const override3 = process.env.SYNTAUR_RUNTIME_SESSIONS_DIR;
24822
- return override3 && override3.length > 0 ? override3 : join10(homedir7(), ".syntaur", "runtime", "sessions");
25519
+ return override3 && override3.length > 0 ? override3 : join12(homedir9(), ".syntaur", "runtime", "sessions");
24823
25520
  }
24824
25521
  function defaultAckProbe(handle) {
24825
25522
  const dir = runtimeSessionsDir();
@@ -24867,7 +25564,7 @@ async function defaultReadAssignment(assignmentId) {
24867
25564
  const resolved = await resolveAssignmentById(projectsDir2, assignmentsDir(), assignmentId);
24868
25565
  if (!resolved) return null;
24869
25566
  try {
24870
- const content = await readFile26(resolve39(resolved.assignmentDir, "assignment.md"), "utf-8");
25567
+ const content = await readFile28(resolve39(resolved.assignmentDir, "assignment.md"), "utf-8");
24871
25568
  return parseAssignmentFrontmatter(content);
24872
25569
  } catch {
24873
25570
  return null;
@@ -24954,7 +25651,7 @@ async function runTick(deps = {}) {
24954
25651
  }
24955
25652
 
24956
25653
  // src/dashboard/api-usage.ts
24957
- import { Router as Router14 } from "express";
25654
+ import { Router as Router15 } from "express";
24958
25655
 
24959
25656
  // src/db/usage-db.ts
24960
25657
  init_paths();
@@ -25404,7 +26101,7 @@ function projectWindowCosts(opts) {
25404
26101
 
25405
26102
  // src/dashboard/api-usage.ts
25406
26103
  function createUsageRouter(projectsDir2, assignmentsDir2) {
25407
- const router = Router14();
26104
+ const router = Router15();
25408
26105
  router.get("/facets", (_req, res) => {
25409
26106
  try {
25410
26107
  initUsageDb();
@@ -25645,11 +26342,11 @@ function projectAssignmentRollup(projectSlug, rows, common) {
25645
26342
  init_fs();
25646
26343
  init_parser();
25647
26344
  init_events_db();
25648
- import { Router as Router15 } from "express";
26345
+ import { Router as Router16 } from "express";
25649
26346
  import { resolve as resolve41 } from "path";
25650
- import { readFile as readFile27 } from "fs/promises";
26347
+ import { readFile as readFile29 } from "fs/promises";
25651
26348
  function createEventsRouter(projectsDir2, assignmentsDir2) {
25652
- const router = Router15();
26349
+ const router = Router16();
25653
26350
  router.get("/projects/:slug/assignments/:aslug/events", async (req2, res) => {
25654
26351
  try {
25655
26352
  const { slug, aslug } = req2.params;
@@ -25686,7 +26383,7 @@ function createEventsRouter(projectsDir2, assignmentsDir2) {
25686
26383
  }
25687
26384
  async function readAssignmentId2(assignmentMdPath2) {
25688
26385
  if (!await fileExists(assignmentMdPath2)) return null;
25689
- const content = await readFile27(assignmentMdPath2, "utf-8");
26386
+ const content = await readFile29(assignmentMdPath2, "utf-8");
25690
26387
  const [fm] = extractFrontmatter(content);
25691
26388
  const id = getField(fm, "id");
25692
26389
  return id && id.length > 0 ? id : null;
@@ -25723,7 +26420,7 @@ function parseFilters(query) {
25723
26420
  }
25724
26421
 
25725
26422
  // src/dashboard/api-inbox.ts
25726
- import { Router as Router16 } from "express";
26423
+ import { Router as Router17 } from "express";
25727
26424
 
25728
26425
  // src/inbox/index.ts
25729
26426
  init_fs();
@@ -25732,7 +26429,7 @@ init_parser();
25732
26429
  init_facts();
25733
26430
  init_state_machine();
25734
26431
  import { resolve as resolve42 } from "path";
25735
- import { readFile as readFile28 } from "fs/promises";
26432
+ import { readFile as readFile30 } from "fs/promises";
25736
26433
 
25737
26434
  // src/inbox/types.ts
25738
26435
  var INBOX_CATEGORIES = [
@@ -25912,7 +26609,7 @@ async function computeInbox(opts) {
25912
26609
  if (opts.project !== void 0 && entry.projectSlug !== opts.project) continue;
25913
26610
  let parsed;
25914
26611
  try {
25915
- const content = await readFile28(resolve42(entry.assignmentDir, "assignment.md"), "utf-8");
26612
+ const content = await readFile30(resolve42(entry.assignmentDir, "assignment.md"), "utf-8");
25916
26613
  parsed = parseAssignmentFull(content);
25917
26614
  } catch {
25918
26615
  continue;
@@ -25958,7 +26655,7 @@ async function computeInbox(opts) {
25958
26655
  const commentsPath = resolve42(entry.assignmentDir, "comments.md");
25959
26656
  if (await fileExists(commentsPath)) {
25960
26657
  try {
25961
- const content = await readFile28(commentsPath, "utf-8");
26658
+ const content = await readFile30(commentsPath, "utf-8");
25962
26659
  const parsedComments = parseComments(content);
25963
26660
  for (const c2 of unresolvedQuestions(parsedComments.entries)) {
25964
26661
  const since = resolveSince("question", parsed, now, c2);
@@ -26014,7 +26711,7 @@ async function computeInbox(opts) {
26014
26711
  init_api();
26015
26712
  init_config2();
26016
26713
  function createInboxRouter(projectsDir2, assignmentsDir2) {
26017
- const router = Router16();
26714
+ const router = Router17();
26018
26715
  router.get("/inbox", async (req2, res) => {
26019
26716
  try {
26020
26717
  const project = typeof req2.query.project === "string" && req2.query.project.length > 0 ? req2.query.project : void 0;
@@ -26070,9 +26767,9 @@ init_timestamp();
26070
26767
  init_fs();
26071
26768
  init_playbook();
26072
26769
  init_playbooks();
26073
- import { Router as Router17 } from "express";
26770
+ import { Router as Router18 } from "express";
26074
26771
  import { resolve as resolve43 } from "path";
26075
- import { readFile as readFile29 } from "fs/promises";
26772
+ import { readFile as readFile31 } from "fs/promises";
26076
26773
  function statusForPlaybookError(code) {
26077
26774
  switch (code) {
26078
26775
  case "manifest":
@@ -26086,7 +26783,7 @@ function statusForPlaybookError(code) {
26086
26783
  }
26087
26784
  }
26088
26785
  function createPlaybooksRouter(playbooksDir3) {
26089
- const router = Router17();
26786
+ const router = Router18();
26090
26787
  router.get("/", async (_req, res) => {
26091
26788
  try {
26092
26789
  const playbooks = await listPlaybooks(playbooksDir3);
@@ -26154,7 +26851,7 @@ function createPlaybooksRouter(playbooksDir3) {
26154
26851
  return;
26155
26852
  }
26156
26853
  const filePath = resolve43(playbooksDir3, resolved.filename);
26157
- const content = await readFile29(filePath, "utf-8");
26854
+ const content = await readFile31(filePath, "utf-8");
26158
26855
  res.json({
26159
26856
  documentType: "playbook",
26160
26857
  title: `Edit Playbook: ${resolved.slug}`,
@@ -26250,10 +26947,10 @@ init_fs_migration();
26250
26947
  init_parser2();
26251
26948
  init_fs();
26252
26949
  init_paths();
26253
- import { Router as Router19 } from "express";
26254
- import { readdir as readdir19 } from "fs/promises";
26255
- import { resolve as resolvePath, dirname as dirname11 } from "path";
26256
- import { rename as rename6, mkdir as mkdir5 } from "fs/promises";
26950
+ import { Router as Router20 } from "express";
26951
+ import { readdir as readdir20 } from "fs/promises";
26952
+ import { resolve as resolvePath, dirname as dirname12 } from "path";
26953
+ import { rename as rename6, mkdir as mkdir6 } from "fs/promises";
26257
26954
  init_slug();
26258
26955
  init_promote_todos();
26259
26956
  init_api();
@@ -26262,8 +26959,8 @@ init_api();
26262
26959
  import { raw } from "express";
26263
26960
 
26264
26961
  // src/todos/attachments.ts
26265
- import { mkdir as mkdir4, readdir as readdir18, stat as stat6, rename as rename5, rm as rm4, unlink as unlink7, writeFile as writeFile6, cp } from "fs/promises";
26266
- import { resolve as resolve44, basename as basename6, dirname as dirname10, extname } from "path";
26962
+ import { mkdir as mkdir5, readdir as readdir19, stat as stat7, rename as rename5, rm as rm4, unlink as unlink7, writeFile as writeFile7, cp } from "fs/promises";
26963
+ import { resolve as resolve44, basename as basename7, dirname as dirname11, extname } from "path";
26267
26964
 
26268
26965
  // src/utils/proof-artifact-id.ts
26269
26966
  import { randomBytes as randomBytes2 } from "crypto";
@@ -26360,7 +27057,7 @@ function isSafeInlineMime(mime) {
26360
27057
  return SAFE_INLINE_MIME.has(mime);
26361
27058
  }
26362
27059
  function sanitizeAttachmentName(name) {
26363
- let n = basename6(name || "").replace(/["'\\/]/g, "_");
27060
+ let n = basename7(name || "").replace(/["'\\/]/g, "_");
26364
27061
  n = Array.from(n, (ch) => {
26365
27062
  const code = ch.charCodeAt(0);
26366
27063
  return code < 32 || code === 127 ? "_" : ch;
@@ -26383,17 +27080,17 @@ function attachmentDirFor(todosDir2, scopeId, todoId) {
26383
27080
  }
26384
27081
  async function dirExists(p) {
26385
27082
  try {
26386
- return (await stat6(p)).isDirectory();
27083
+ return (await stat7(p)).isDirectory();
26387
27084
  } catch {
26388
27085
  return false;
26389
27086
  }
26390
27087
  }
26391
27088
  async function writeAttachment(todosDir2, scopeId, todoId, originalName, bytes) {
26392
27089
  const dir = attachmentDirFor(todosDir2, scopeId, todoId);
26393
- await mkdir4(dir, { recursive: true });
27090
+ await mkdir5(dir, { recursive: true });
26394
27091
  const id = generateArtifactId();
26395
27092
  const filename = sanitizeAttachmentName(originalName);
26396
- await writeFile6(resolve44(dir, `${id}__${filename}`), bytes);
27093
+ await writeFile7(resolve44(dir, `${id}__${filename}`), bytes);
26397
27094
  return {
26398
27095
  id,
26399
27096
  filename,
@@ -26406,7 +27103,7 @@ async function listAttachments(todosDir2, scopeId, todoId) {
26406
27103
  const dir = attachmentDirFor(todosDir2, scopeId, todoId);
26407
27104
  let names;
26408
27105
  try {
26409
- names = await readdir18(dir);
27106
+ names = await readdir19(dir);
26410
27107
  } catch {
26411
27108
  return [];
26412
27109
  }
@@ -26418,7 +27115,7 @@ async function listAttachments(todosDir2, scopeId, todoId) {
26418
27115
  if (!ATTACHMENT_ID_RE.test(id)) continue;
26419
27116
  const filename = stored.slice(sep2 + 2);
26420
27117
  try {
26421
- const st = await stat6(resolve44(dir, stored));
27118
+ const st = await stat7(resolve44(dir, stored));
26422
27119
  if (!st.isFile()) continue;
26423
27120
  out.push({ id, filename, mime: mimeForName(filename), size: st.size, createdAt: st.mtime.toISOString() });
26424
27121
  } catch {
@@ -26432,7 +27129,7 @@ async function readScopeAttachments(todosDir2, scopeId) {
26432
27129
  const scopeDir = resolve44(attachmentsRootDir(todosDir2), scopeId);
26433
27130
  let todoIds;
26434
27131
  try {
26435
- todoIds = await readdir18(scopeDir);
27132
+ todoIds = await readdir19(scopeDir);
26436
27133
  } catch {
26437
27134
  return {};
26438
27135
  }
@@ -26449,7 +27146,7 @@ async function resolveAttachmentFile(todosDir2, scopeId, todoId, attachmentId) {
26449
27146
  const dir = attachmentDirFor(todosDir2, scopeId, todoId);
26450
27147
  let names;
26451
27148
  try {
26452
- names = await readdir18(dir);
27149
+ names = await readdir19(dir);
26453
27150
  } catch {
26454
27151
  return null;
26455
27152
  }
@@ -26477,7 +27174,7 @@ async function moveAttachments(srcTodosDir, srcScopeId, dstTodosDir, dstScopeId,
26477
27174
  const src = attachmentDirFor(srcTodosDir, srcScopeId, todoId);
26478
27175
  if (!await dirExists(src)) return;
26479
27176
  const dst = attachmentDirFor(dstTodosDir, dstScopeId, todoId);
26480
- await mkdir4(dirname10(dst), { recursive: true });
27177
+ await mkdir5(dirname11(dst), { recursive: true });
26481
27178
  try {
26482
27179
  await rename5(src, dst);
26483
27180
  } catch (err2) {
@@ -26619,7 +27316,7 @@ function touchItem3(item) {
26619
27316
  item.updatedAt = now;
26620
27317
  }
26621
27318
  function createTodosRouter(todosDir2, broadcast, projectsDir2) {
26622
- const router = Router19();
27319
+ const router = Router20();
26623
27320
  installRecordsInvalidation(router);
26624
27321
  function broadcastUpdate() {
26625
27322
  broadcast({ type: "todos-updated", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
@@ -26753,7 +27450,7 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
26753
27450
  router.get("/", async (_req, res) => {
26754
27451
  try {
26755
27452
  await ensureDir(todosDir2);
26756
- const files = await readdir19(todosDir2).catch(() => []);
27453
+ const files = await readdir20(todosDir2).catch(() => []);
26757
27454
  const workspaces = [];
26758
27455
  for (const file of files) {
26759
27456
  if (typeof file !== "string") continue;
@@ -26874,7 +27571,7 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
26874
27571
  try {
26875
27572
  const { archivePath: archivePath2 } = await Promise.resolve().then(() => (init_parser2(), parser_exports));
26876
27573
  const { resolve: resolve112 } = await import("path");
26877
- const { readFile: readFile82 } = await import("fs/promises");
27574
+ const { readFile: readFile85 } = await import("fs/promises");
26878
27575
  const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
26879
27576
  const workspace = getWorkspaceParam(req2.params.workspace);
26880
27577
  const outcome = await wsLock(workspace, async () => {
@@ -26893,7 +27590,7 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
26893
27590
  await ensureDir(resolve112(todosDir2, "archive"));
26894
27591
  let archContent = "";
26895
27592
  if (await fileExists(archFile)) {
26896
- archContent = await readFile82(archFile, "utf-8");
27593
+ archContent = await readFile85(archFile, "utf-8");
26897
27594
  archContent = archContent.trimEnd() + "\n\n";
26898
27595
  } else {
26899
27596
  archContent = `---
@@ -27194,7 +27891,7 @@ workspace: ${workspace}
27194
27891
  const { readConfig: readConfig3 } = await Promise.resolve().then(() => (init_config2(), config_exports));
27195
27892
  const { assignmentsDir: assignmentsDirFn } = await Promise.resolve().then(() => (init_paths(), paths_exports));
27196
27893
  const { fileExists: fileExists2, writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
27197
- const { readFile: readFile82 } = await import("fs/promises");
27894
+ const { readFile: readFile85 } = await import("fs/promises");
27198
27895
  const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
27199
27896
  const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
27200
27897
  let assignmentRef;
@@ -27215,7 +27912,7 @@ workspace: ${workspace}
27215
27912
  }
27216
27913
  const assignmentMdPath2 = resolvePath2(assignmentDir, "assignment.md");
27217
27914
  if (!await fileExists2(assignmentMdPath2)) return { error: `Target assignment not found: ${assignmentMdPath2}` };
27218
- let content = await readFile82(assignmentMdPath2, "utf-8");
27915
+ let content = await readFile85(assignmentMdPath2, "utf-8");
27219
27916
  content = appendTodosToAssignmentBody2(
27220
27917
  content,
27221
27918
  items.map((it) => ({
@@ -27332,7 +28029,7 @@ workspace: ${workspace}
27332
28029
  return { status: 409, error: "attachments already exist in target" };
27333
28030
  }
27334
28031
  if (item.planDir && newPlanDir) {
27335
- await mkdir5(dirname11(newPlanDir), { recursive: true });
28032
+ await mkdir6(dirname12(newPlanDir), { recursive: true });
27336
28033
  await rename6(item.planDir, newPlanDir);
27337
28034
  item.planDir = newPlanDir;
27338
28035
  }
@@ -27409,9 +28106,9 @@ init_parser2();
27409
28106
  init_fs();
27410
28107
  init_paths();
27411
28108
  init_slug();
27412
- import { Router as Router20 } from "express";
27413
- import { mkdir as mkdir6, readFile as readFile30, rename as rename7 } from "fs/promises";
27414
- import { resolve as resolve45, dirname as dirname12 } from "path";
28109
+ import { Router as Router21 } from "express";
28110
+ import { mkdir as mkdir7, readFile as readFile32, rename as rename7 } from "fs/promises";
28111
+ import { resolve as resolve45, dirname as dirname13 } from "path";
27415
28112
  init_promote_todos();
27416
28113
  init_api();
27417
28114
  var WORKSPACE_REGEX2 = /^[a-z0-9_][a-z0-9-]*$/;
@@ -27433,7 +28130,7 @@ async function projectExists(projectsDir2, slug) {
27433
28130
  async function ensureProjectTodosDir(projectsDir2, slug) {
27434
28131
  const todosDir2 = projectTodosDir(projectsDir2, slug);
27435
28132
  try {
27436
- await mkdir6(todosDir2, { recursive: false });
28133
+ await mkdir7(todosDir2, { recursive: false });
27437
28134
  } catch (err2) {
27438
28135
  const code = err2.code;
27439
28136
  if (code === "EEXIST") return;
@@ -27445,7 +28142,7 @@ async function ensureProjectTodosDir(projectsDir2, slug) {
27445
28142
  throw err2;
27446
28143
  }
27447
28144
  try {
27448
- await mkdir6(resolve45(todosDir2, "archive"), { recursive: false });
28145
+ await mkdir7(resolve45(todosDir2, "archive"), { recursive: false });
27449
28146
  } catch (err2) {
27450
28147
  const code = err2.code;
27451
28148
  if (code === "EEXIST") return;
@@ -27461,7 +28158,7 @@ function notFound(res, slug) {
27461
28158
  res.status(404).json({ error: `Project "${slug}" not found` });
27462
28159
  }
27463
28160
  function createProjectTodosRouter(projectsDir2, broadcast, workspaceTodosDir) {
27464
- const router = Router20({ mergeParams: true });
28161
+ const router = Router21({ mergeParams: true });
27465
28162
  installRecordsInvalidation(router);
27466
28163
  function broadcastUpdate(projectSlug) {
27467
28164
  broadcast({ type: "todos-updated", projectSlug, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
@@ -27653,7 +28350,7 @@ function createProjectTodosRouter(projectsDir2, broadcast, workspaceTodosDir) {
27653
28350
  const archFile = archivePath(todosDir2, slug, checklist.archiveInterval);
27654
28351
  let archContent = "";
27655
28352
  if (await fileExists(archFile)) {
27656
- archContent = await readFile30(archFile, "utf-8");
28353
+ archContent = await readFile32(archFile, "utf-8");
27657
28354
  archContent = archContent.trimEnd() + "\n\n";
27658
28355
  } else {
27659
28356
  archContent = `---
@@ -28134,7 +28831,7 @@ workspace: ${slug}
28134
28831
  }
28135
28832
  const assignmentMdPath2 = resolve45(assignmentDir, "assignment.md");
28136
28833
  if (!await fileExists(assignmentMdPath2)) return { error: `Target assignment not found: ${assignmentMdPath2}` };
28137
- let content = await readFile30(assignmentMdPath2, "utf-8");
28834
+ let content = await readFile32(assignmentMdPath2, "utf-8");
28138
28835
  content = appendTodosToAssignmentBody2(
28139
28836
  content,
28140
28837
  items.map((it) => ({
@@ -28273,7 +28970,7 @@ workspace: ${slug}
28273
28970
  return { status: 409, error: "attachments already exist in target" };
28274
28971
  }
28275
28972
  if (item.planDir && newPlanDir) {
28276
- await mkdir6(dirname12(newPlanDir), { recursive: true });
28973
+ await mkdir7(dirname13(newPlanDir), { recursive: true });
28277
28974
  await rename7(item.planDir, newPlanDir);
28278
28975
  item.planDir = newPlanDir;
28279
28976
  }
@@ -28336,8 +29033,8 @@ workspace: ${slug}
28336
29033
  }
28337
29034
 
28338
29035
  // src/dashboard/api-bundles.ts
28339
- import { Router as Router21 } from "express";
28340
- import { readdir as readdir20 } from "fs/promises";
29036
+ import { Router as Router22 } from "express";
29037
+ import { readdir as readdir21 } from "fs/promises";
28341
29038
 
28342
29039
  // src/todos/bundle-parser.ts
28343
29040
  init_parser();
@@ -28345,7 +29042,7 @@ init_fs();
28345
29042
  init_paths();
28346
29043
  init_parser2();
28347
29044
  import { randomBytes as randomBytes3 } from "crypto";
28348
- import { readFile as readFile31 } from "fs/promises";
29045
+ import { readFile as readFile33 } from "fs/promises";
28349
29046
  var BUNDLE_ID_REGEX = /^[a-f0-9]{4}$/;
28350
29047
  var SCOPE_VALUES = /* @__PURE__ */ new Set(["workspace", "project", "global"]);
28351
29048
  var SCOPE_ID_REGEX = /^[a-z0-9_][a-z0-9_-]*$/;
@@ -28448,7 +29145,7 @@ ${lines}
28448
29145
  async function readBundles(todosDir2) {
28449
29146
  const path = bundlesPath(todosDir2);
28450
29147
  if (!await fileExists(path)) return [];
28451
- const content = await readFile31(path, "utf-8");
29148
+ const content = await readFile33(path, "utf-8");
28452
29149
  return parseBundles(content).bundles;
28453
29150
  }
28454
29151
  async function writeBundles(todosDir2, bundles) {
@@ -28487,7 +29184,7 @@ function annotate(bundle, items) {
28487
29184
  }
28488
29185
  function createBundlesRouter(todosDir2, broadcast) {
28489
29186
  void broadcast;
28490
- const router = Router21();
29187
+ const router = Router22();
28491
29188
  function validateWorkspace(req2, res, next) {
28492
29189
  const workspace = getWorkspaceParam2(req2.params.workspace);
28493
29190
  if (workspace && !WORKSPACE_REGEX3.test(workspace)) {
@@ -28501,7 +29198,7 @@ function createBundlesRouter(todosDir2, broadcast) {
28501
29198
  try {
28502
29199
  await ensureDir(todosDir2);
28503
29200
  const bundles = await readBundles(todosDir2);
28504
- const workspaceFiles = await readdir20(todosDir2).catch(() => []);
29201
+ const workspaceFiles = await readdir21(todosDir2).catch(() => []);
28505
29202
  const itemsByKey = /* @__PURE__ */ new Map();
28506
29203
  for (const f of workspaceFiles) {
28507
29204
  if (typeof f !== "string") continue;
@@ -28553,7 +29250,7 @@ function createBundlesRouter(todosDir2, broadcast) {
28553
29250
  init_fs();
28554
29251
  init_paths();
28555
29252
  init_slug();
28556
- import { Router as Router22 } from "express";
29253
+ import { Router as Router23 } from "express";
28557
29254
  import { resolve as resolve46 } from "path";
28558
29255
  init_parser2();
28559
29256
  function deriveStatus2(bundle, items) {
@@ -28583,7 +29280,7 @@ function notFound2(res, slug) {
28583
29280
  }
28584
29281
  function createProjectBundlesRouter(projectsDir2, broadcast) {
28585
29282
  void broadcast;
28586
- const router = Router22({ mergeParams: true });
29283
+ const router = Router23({ mergeParams: true });
28587
29284
  function validateProjectId(req2, res, next) {
28588
29285
  const slug = getProjectIdParam2(req2.params.projectId);
28589
29286
  if (!slug || !isValidSlug(slug)) {
@@ -28617,7 +29314,7 @@ function createProjectBundlesRouter(projectsDir2, broadcast) {
28617
29314
  init_config2();
28618
29315
  init_api();
28619
29316
  init_scanner();
28620
- import { Router as Router23 } from "express";
29317
+ import { Router as Router24 } from "express";
28621
29318
 
28622
29319
  // src/utils/github-backup.ts
28623
29320
  init_paths();
@@ -28625,8 +29322,8 @@ init_fs();
28625
29322
  init_config2();
28626
29323
  import { execFile as execFile2 } from "child_process";
28627
29324
  import { promisify as promisify2 } from "util";
28628
- import { cp as cp2, mkdtemp, rm as rm5, readFile as readFile32, writeFile as writeFile7, unlink as unlink8, stat as stat7, open as open5, rename as rename8 } from "fs/promises";
28629
- import { resolve as resolve47, join as join11 } from "path";
29325
+ import { cp as cp2, mkdtemp, rm as rm5, readFile as readFile34, writeFile as writeFile8, unlink as unlink8, stat as stat8, open as open5, rename as rename8 } from "fs/promises";
29326
+ import { resolve as resolve47, join as join13 } from "path";
28630
29327
  import { tmpdir } from "os";
28631
29328
  var exec2 = promisify2(execFile2);
28632
29329
  var VALID_CATEGORIES = ["projects", "playbooks", "todos", "servers", "config"];
@@ -28686,7 +29383,7 @@ async function acquireLock2() {
28686
29383
  return lockPath;
28687
29384
  } catch (err2) {
28688
29385
  if (err2.code === "EEXIST") {
28689
- const pid = await readFile32(lockPath, "utf-8").catch(() => "");
29386
+ const pid = await readFile34(lockPath, "utf-8").catch(() => "");
28690
29387
  throw new Error(
28691
29388
  `Backup operation already in progress (lock file at ${lockPath}, pid ${pid.trim() || "unknown"}). If stale, delete the file and retry.`
28692
29389
  );
@@ -28719,7 +29416,7 @@ async function cloneOrInit(repoUrl, destDir) {
28719
29416
  }
28720
29417
  async function copyRecursive(src, dest) {
28721
29418
  if (!await fileExists(src)) return;
28722
- const s = await stat7(src);
29419
+ const s = await stat8(src);
28723
29420
  if (s.isDirectory()) {
28724
29421
  await ensureDir(dest);
28725
29422
  await cp2(src, dest, { recursive: true, force: true });
@@ -28733,7 +29430,7 @@ function resolveCategoriesStrict(csv) {
28733
29430
  return parseCategoriesStrict(parts);
28734
29431
  }
28735
29432
  async function readSanitizedConfig(configPath2) {
28736
- const content = await readFile32(configPath2, "utf-8");
29433
+ const content = await readFile34(configPath2, "utf-8");
28737
29434
  return content.replace(/^(\s*lastBackup:\s*).*$/m, "$1null").replace(/^(\s*lastRestore:\s*).*$/m, "$1null");
28738
29435
  }
28739
29436
  async function backupToGithub(overrides) {
@@ -28756,11 +29453,11 @@ async function backupToGithub(overrides) {
28756
29453
  let tmpDir = null;
28757
29454
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
28758
29455
  try {
28759
- tmpDir = await mkdtemp(join11(tmpdir(), "syntaur-backup-"));
29456
+ tmpDir = await mkdtemp(join13(tmpdir(), "syntaur-backup-"));
28760
29457
  await cloneOrInit(repo, tmpDir);
28761
29458
  for (const category of categories) {
28762
29459
  const { sourcePath, repoPath, isFile } = await resolveCategoryPath(category);
28763
- const destPath = join11(tmpDir, repoPath);
29460
+ const destPath = join13(tmpDir, repoPath);
28764
29461
  if (isFile) {
28765
29462
  await rm5(destPath, { force: true });
28766
29463
  } else {
@@ -28773,7 +29470,7 @@ async function backupToGithub(overrides) {
28773
29470
  if (category === "config") {
28774
29471
  const sanitized = await readSanitizedConfig(sourcePath);
28775
29472
  await ensureDir(resolve47(destPath, ".."));
28776
- await writeFile7(destPath, sanitized, "utf-8");
29473
+ await writeFile8(destPath, sanitized, "utf-8");
28777
29474
  } else {
28778
29475
  await copyRecursive(sourcePath, destPath);
28779
29476
  }
@@ -28888,7 +29585,7 @@ async function restoreFromGithub(overrides) {
28888
29585
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
28889
29586
  try {
28890
29587
  await updateBackupConfig({ lastRestore: timestamp });
28891
- tmpDir = await mkdtemp(join11(tmpdir(), "syntaur-restore-"));
29588
+ tmpDir = await mkdtemp(join13(tmpdir(), "syntaur-restore-"));
28892
29589
  await cloneOrInit(repo, tmpDir);
28893
29590
  for (const category of categories) {
28894
29591
  if (category === "config") {
@@ -28897,7 +29594,7 @@ async function restoreFromGithub(overrides) {
28897
29594
  }
28898
29595
  try {
28899
29596
  const { sourcePath: localPath, repoPath, isFile } = await resolveCategoryPath(category);
28900
- const repoSrcPath = join11(tmpDir, repoPath);
29597
+ const repoSrcPath = join13(tmpDir, repoPath);
28901
29598
  if (!await fileExists(repoSrcPath)) {
28902
29599
  console.warn(`Category "${category}" not found in backup repo, skipping.`);
28903
29600
  continue;
@@ -28940,7 +29637,7 @@ async function getBackupStatus() {
28940
29637
 
28941
29638
  // src/dashboard/api-backup.ts
28942
29639
  function createBackupRouter() {
28943
- const router = Router23();
29640
+ const router = Router24();
28944
29641
  router.get("/", async (_req, res) => {
28945
29642
  try {
28946
29643
  const status = await getBackupStatus();
@@ -30308,6 +31005,7 @@ function createDashboardServer(options) {
30308
31005
  app.use("/api", createInboxRouter(projectsDir2, assignmentsDir2));
30309
31006
  app.use("/api/agent-sessions", createAgentSessionsRouter(projectsDir2, broadcast, assignmentsDir2));
30310
31007
  app.use("/api/config/agents", createAgentsRouter());
31008
+ app.use("/api/config/agent-discovery", createAgentDiscoveryConfigRouter());
30311
31009
  app.use(
30312
31010
  "/api/launch",
30313
31011
  createLaunchPreflightRouter(projectsDir2, assignmentsDir2)
@@ -30505,7 +31203,7 @@ function createDashboardServer(options) {
30505
31203
  });
30506
31204
  server.listen(port, () => {
30507
31205
  const portFile = resolve50(syntaurRoot(), "dashboard-port");
30508
- writeFile8(portFile, String(port), "utf-8").catch(() => {
31206
+ writeFile9(portFile, String(port), "utf-8").catch(() => {
30509
31207
  });
30510
31208
  resolvePromise();
30511
31209
  });
@@ -30656,7 +31354,7 @@ async function dashboardCommand(options) {
30656
31354
  port = availablePort;
30657
31355
  }
30658
31356
  const thisFile = fileURLToPath3(import.meta.url);
30659
- const packageRoot = resolve51(dirname13(thisFile), "..");
31357
+ const packageRoot = resolve51(dirname14(thisFile), "..");
30660
31358
  const dashboardDist = resolve51(packageRoot, "dashboard", "dist");
30661
31359
  const server = createDashboardServer({
30662
31360
  port,
@@ -30883,8 +31581,8 @@ init_git_worktree();
30883
31581
  init_recompute();
30884
31582
  init_event_emit();
30885
31583
  init_transitions();
30886
- import { readFile as readFile35 } from "fs/promises";
30887
- import { resolve as resolve54, basename as basename7 } from "path";
31584
+ import { readFile as readFile37 } from "fs/promises";
31585
+ import { resolve as resolve54, basename as basename8 } from "path";
30888
31586
 
30889
31587
  // src/utils/assignment-target.ts
30890
31588
  init_paths();
@@ -30894,7 +31592,7 @@ init_slug();
30894
31592
  init_assignment_resolver();
30895
31593
  init_parser();
30896
31594
  import { resolve as resolve53 } from "path";
30897
- import { readFile as readFile33 } from "fs/promises";
31595
+ import { readFile as readFile35 } from "fs/promises";
30898
31596
  var AssignmentTargetError = class extends Error {
30899
31597
  };
30900
31598
  function classifyContext(ctx) {
@@ -30907,7 +31605,7 @@ async function readAssignmentFrontmatterId(assignmentDir) {
30907
31605
  const path = resolve53(assignmentDir, "assignment.md");
30908
31606
  if (!await fileExists(path)) return null;
30909
31607
  try {
30910
- const content = await readFile33(path, "utf-8");
31608
+ const content = await readFile35(path, "utf-8");
30911
31609
  const [fm] = extractFrontmatter(content);
30912
31610
  return getField(fm, "id");
30913
31611
  } catch {
@@ -30918,7 +31616,7 @@ async function readContextJson(cwd) {
30918
31616
  const path = resolve53(cwd, ".syntaur", "context.json");
30919
31617
  if (!await fileExists(path)) return null;
30920
31618
  try {
30921
- const raw2 = await readFile33(path, "utf-8");
31619
+ const raw2 = await readFile35(path, "utf-8");
30922
31620
  return JSON.parse(raw2);
30923
31621
  } catch {
30924
31622
  return null;
@@ -31103,7 +31801,7 @@ init_session_id();
31103
31801
  init_fs();
31104
31802
  init_frontmatter();
31105
31803
  init_recompute();
31106
- import { readFile as readFile34 } from "fs/promises";
31804
+ import { readFile as readFile36 } from "fs/promises";
31107
31805
  function computeDelta(stage, prevStage, fm) {
31108
31806
  const writes = {};
31109
31807
  if (stage === "implement") {
@@ -31121,7 +31819,7 @@ async function assertStageFactOnOpen(input4) {
31121
31819
  const pre = computeDelta(
31122
31820
  input4.stage,
31123
31821
  input4.prevStage,
31124
- parseAssignmentFrontmatter(await readFile34(input4.assignmentPath, "utf-8"))
31822
+ parseAssignmentFrontmatter(await readFile36(input4.assignmentPath, "utf-8"))
31125
31823
  );
31126
31824
  if (Object.keys(pre).length === 0) return;
31127
31825
  const context = await resolveDeriveContext();
@@ -31171,7 +31869,7 @@ async function resolveTarget(assignment, options) {
31171
31869
  async function inferActor(options) {
31172
31870
  if (options.agent) return `agent:${options.agent}`;
31173
31871
  try {
31174
- const raw2 = await readFile35(resolve54(process.cwd(), ".syntaur", "context.json"), "utf-8");
31872
+ const raw2 = await readFile37(resolve54(process.cwd(), ".syntaur", "context.json"), "utf-8");
31175
31873
  const ctx = JSON.parse(raw2);
31176
31874
  if (ctx.sessionId) return `agent:${ctx.sessionId.slice(0, 8)}`;
31177
31875
  } catch {
@@ -31180,10 +31878,10 @@ async function inferActor(options) {
31180
31878
  }
31181
31879
  async function emitDeriveEvent(target, type, actor, details) {
31182
31880
  try {
31183
- const fm = parseAssignmentFrontmatter(await readFile35(target.assignmentPath, "utf-8"));
31881
+ const fm = parseAssignmentFrontmatter(await readFile37(target.assignmentPath, "utf-8"));
31184
31882
  emitEvent({
31185
31883
  assignmentId: fm.id,
31186
- projectSlug: target.projectDir ? basename7(target.projectDir) : null,
31884
+ projectSlug: target.projectDir ? basename8(target.projectDir) : null,
31187
31885
  type,
31188
31886
  actor,
31189
31887
  details
@@ -31241,7 +31939,7 @@ async function planApproveCommand(assignment, options) {
31241
31939
  throw new Error("No plan file found (plan.md / plan-v*.md). Write a plan before approving.");
31242
31940
  }
31243
31941
  approvedFile = planFile;
31244
- const planContent = await readFile35(resolve54(target2.assignmentDir, planFile), "utf-8");
31942
+ const planContent = await readFile37(resolve54(target2.assignmentDir, planFile), "utf-8");
31245
31943
  return updatePlanApproval(content, {
31246
31944
  file: planFile,
31247
31945
  digest: planDigest(planContent),
@@ -31314,7 +32012,7 @@ async function attestCommand(assignment, fact, options) {
31314
32012
  "No plan file found (plan.md / plan-v*.md). Write a plan before attesting a binds:plan fact."
31315
32013
  );
31316
32014
  }
31317
- const planContent = await readFile35(resolve54(target2.assignmentDir, planFile), "utf-8");
32015
+ const planContent = await readFile37(resolve54(target2.assignmentDir, planFile), "utf-8");
31318
32016
  record.file = planFile;
31319
32017
  record.digest = planDigest(planContent);
31320
32018
  } else if (binds === "commit") {
@@ -31405,13 +32103,13 @@ async function requestReviewCommand(assignment, options) {
31405
32103
  }
31406
32104
  const target = await resolveTarget(assignment, options);
31407
32105
  const context = await resolveDeriveContext();
31408
- const fm = parseAssignmentFrontmatter(await readFile35(target.assignmentPath, "utf-8"));
32106
+ const fm = parseAssignmentFrontmatter(await readFile37(target.assignmentPath, "utf-8"));
31409
32107
  await applyStageFact(assignment, options, target, fm, "review", "Review requested", context);
31410
32108
  }
31411
32109
  async function implementStartedCommand(assignment, options) {
31412
32110
  const target = await resolveTarget(assignment, options);
31413
32111
  const context = await resolveDeriveContext();
31414
- const fm = parseAssignmentFrontmatter(await readFile35(target.assignmentPath, "utf-8"));
32112
+ const fm = parseAssignmentFrontmatter(await readFile37(target.assignmentPath, "utf-8"));
31415
32113
  if (fm.dependsOn.length > 0 && target.projectDir) {
31416
32114
  const dep = await checkDependencies(target.projectDir, fm.dependsOn, context.terminalStatuses);
31417
32115
  if (!dep.satisfied) {
@@ -31542,7 +32240,7 @@ init_timestamp();
31542
32240
  init_assignment_resolver();
31543
32241
  init_event_emit();
31544
32242
  import { resolve as resolve55 } from "path";
31545
- import { readFile as readFile36, writeFile as writeFile9 } from "fs/promises";
32243
+ import { readFile as readFile38, writeFile as writeFile10 } from "fs/promises";
31546
32244
  async function resolveTarget2(target, options) {
31547
32245
  const config = await readConfig();
31548
32246
  const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
@@ -31574,19 +32272,19 @@ async function resolveTarget2(target, options) {
31574
32272
  return null;
31575
32273
  }
31576
32274
  async function writeArchiveState(filePath, archived, reason) {
31577
- const content = await readFile36(filePath, "utf-8");
32275
+ const content = await readFile38(filePath, "utf-8");
31578
32276
  const updated = updateAssignmentFile(content, {
31579
32277
  archived,
31580
32278
  archivedAt: archived ? nowTimestamp() : null,
31581
32279
  archivedReason: archived ? reason : null,
31582
32280
  updated: nowTimestamp()
31583
32281
  });
31584
- await writeFile9(filePath, updated, "utf-8");
32282
+ await writeFile10(filePath, updated, "utf-8");
31585
32283
  }
31586
32284
  async function emitArchiveEvent(resolved, type, reason) {
31587
32285
  if (resolved.kind !== "assignment") return;
31588
32286
  try {
31589
- const fm = parseAssignmentFrontmatter(await readFile36(resolved.filePath, "utf-8"));
32287
+ const fm = parseAssignmentFrontmatter(await readFile38(resolved.filePath, "utf-8"));
31590
32288
  emitEvent({
31591
32289
  assignmentId: fm.id,
31592
32290
  projectSlug: fm.project,
@@ -31657,7 +32355,7 @@ init_frontmatter();
31657
32355
  init_timestamp();
31658
32356
  init_event_emit();
31659
32357
  import { resolve as resolve56 } from "path";
31660
- import { readdir as readdir21, readFile as readFile37 } from "fs/promises";
32358
+ import { readdir as readdir22, readFile as readFile39 } from "fs/promises";
31661
32359
  var PROMOTABLE_STATUSES = /* @__PURE__ */ new Set(["pending"]);
31662
32360
  function objectiveIsFleshedOut(content) {
31663
32361
  const match = content.match(/##\s+Objective\s*\n([\s\S]*?)(?=\n##\s+|$)/);
@@ -31675,7 +32373,7 @@ async function collectCandidates(baseDirs) {
31675
32373
  const candidates = [];
31676
32374
  for (const baseDir of baseDirs) {
31677
32375
  if (!await fileExists(baseDir)) continue;
31678
- const projects = await readdir21(baseDir, { withFileTypes: true });
32376
+ const projects = await readdir22(baseDir, { withFileTypes: true });
31679
32377
  for (const m of projects) {
31680
32378
  if (!m.isDirectory()) continue;
31681
32379
  if (m.name.startsWith(".") || m.name.startsWith("_")) continue;
@@ -31683,7 +32381,7 @@ async function collectCandidates(baseDirs) {
31683
32381
  if (await fileExists(directAssignmentMd)) {
31684
32382
  const fm = await parseSafe(directAssignmentMd);
31685
32383
  if (fm && PROMOTABLE_STATUSES.has(fm.status)) {
31686
- const content = await readFile37(directAssignmentMd, "utf-8");
32384
+ const content = await readFile39(directAssignmentMd, "utf-8");
31687
32385
  if (objectiveIsFleshedOut(content) && hasAcceptanceCriteria(content)) {
31688
32386
  candidates.push({
31689
32387
  projectSlug: null,
@@ -31698,7 +32396,7 @@ async function collectCandidates(baseDirs) {
31698
32396
  }
31699
32397
  const assignmentsDir2 = resolve56(baseDir, m.name, "assignments");
31700
32398
  if (!await fileExists(assignmentsDir2)) continue;
31701
- const entries = await readdir21(assignmentsDir2, { withFileTypes: true });
32399
+ const entries = await readdir22(assignmentsDir2, { withFileTypes: true });
31702
32400
  for (const a of entries) {
31703
32401
  if (!a.isDirectory()) continue;
31704
32402
  if (a.name.startsWith(".") || a.name.startsWith("_")) continue;
@@ -31706,7 +32404,7 @@ async function collectCandidates(baseDirs) {
31706
32404
  if (!await fileExists(assignmentMd)) continue;
31707
32405
  const fm = await parseSafe(assignmentMd);
31708
32406
  if (!fm || !PROMOTABLE_STATUSES.has(fm.status)) continue;
31709
- const content = await readFile37(assignmentMd, "utf-8");
32407
+ const content = await readFile39(assignmentMd, "utf-8");
31710
32408
  if (!objectiveIsFleshedOut(content)) continue;
31711
32409
  if (!hasAcceptanceCriteria(content)) continue;
31712
32410
  candidates.push({
@@ -31723,7 +32421,7 @@ async function collectCandidates(baseDirs) {
31723
32421
  }
31724
32422
  async function parseSafe(path) {
31725
32423
  try {
31726
- const content = await readFile37(path, "utf-8");
32424
+ const content = await readFile39(path, "utf-8");
31727
32425
  return parseAssignmentFrontmatter(content);
31728
32426
  } catch {
31729
32427
  return null;
@@ -31753,7 +32451,7 @@ async function migrateStatusesCommand(options) {
31753
32451
  let migrated = 0;
31754
32452
  await withSuppressedEvents(async () => {
31755
32453
  for (const c2 of candidates) {
31756
- const content = await readFile37(c2.assignmentMd, "utf-8");
32454
+ const content = await readFile39(c2.assignmentMd, "utf-8");
31757
32455
  const updated = appendStatusHistoryEntry(
31758
32456
  updateAssignmentFile(content, {
31759
32457
  status: c2.toStatus,
@@ -31776,10 +32474,10 @@ init_frontmatter();
31776
32474
  init_event_emit();
31777
32475
  init_types();
31778
32476
  import { resolve as resolve57 } from "path";
31779
- import { readdir as readdir22, readFile as readFile38 } from "fs/promises";
32477
+ import { readdir as readdir23, readFile as readFile40 } from "fs/promises";
31780
32478
  async function parseSafe2(path) {
31781
32479
  try {
31782
- return parseAssignmentFrontmatter(await readFile38(path, "utf-8"));
32480
+ return parseAssignmentFrontmatter(await readFile40(path, "utf-8"));
31783
32481
  } catch {
31784
32482
  return null;
31785
32483
  }
@@ -31802,7 +32500,7 @@ async function collectTargets(baseDirs, terminalStatuses3) {
31802
32500
  const seen = /* @__PURE__ */ new Set();
31803
32501
  for (const baseDir of baseDirs) {
31804
32502
  if (!await fileExists(baseDir)) continue;
31805
- const entries = await readdir22(baseDir, { withFileTypes: true });
32503
+ const entries = await readdir23(baseDir, { withFileTypes: true });
31806
32504
  for (const m of entries) {
31807
32505
  if (!m.isDirectory()) continue;
31808
32506
  if (m.name.startsWith(".") || m.name.startsWith("_")) continue;
@@ -31823,7 +32521,7 @@ async function collectTargets(baseDirs, terminalStatuses3) {
31823
32521
  }
31824
32522
  const assignmentsBase = resolve57(baseDir, m.name, "assignments");
31825
32523
  if (!await fileExists(assignmentsBase)) continue;
31826
- const slugs = await readdir22(assignmentsBase, { withFileTypes: true });
32524
+ const slugs = await readdir23(assignmentsBase, { withFileTypes: true });
31827
32525
  for (const a of slugs) {
31828
32526
  if (!a.isDirectory()) continue;
31829
32527
  if (a.name.startsWith(".") || a.name.startsWith("_")) continue;
@@ -31871,7 +32569,7 @@ async function migrateStatusHistoryCommand(options) {
31871
32569
  await withSuppressedEvents(async () => {
31872
32570
  for (const t of targets) {
31873
32571
  try {
31874
- const content = await readFile38(t.assignmentMd, "utf-8");
32572
+ const content = await readFile40(t.assignmentMd, "utf-8");
31875
32573
  if (parseAssignmentFrontmatter(content).statusHistory.length > 0) continue;
31876
32574
  const seededContent = appendStatusHistoryEntry(content, {
31877
32575
  at: t.seedAt,
@@ -31900,10 +32598,10 @@ init_config2();
31900
32598
  init_parser();
31901
32599
  init_events_db();
31902
32600
  import { resolve as resolve58 } from "path";
31903
- import { readdir as readdir23, readFile as readFile39 } from "fs/promises";
32601
+ import { readdir as readdir24, readFile as readFile41 } from "fs/promises";
31904
32602
  async function parseSafe3(path) {
31905
32603
  try {
31906
- return parseAssignmentFull(await readFile39(path, "utf-8"));
32604
+ return parseAssignmentFull(await readFile41(path, "utf-8"));
31907
32605
  } catch {
31908
32606
  return null;
31909
32607
  }
@@ -31936,7 +32634,7 @@ async function collectTargets2(baseDirs) {
31936
32634
  const seen = /* @__PURE__ */ new Set();
31937
32635
  for (const baseDir of baseDirs) {
31938
32636
  if (!await fileExists(baseDir)) continue;
31939
- const entries = await readdir23(baseDir, { withFileTypes: true });
32637
+ const entries = await readdir24(baseDir, { withFileTypes: true });
31940
32638
  for (const m of entries) {
31941
32639
  if (!m.isDirectory()) continue;
31942
32640
  if (m.name.startsWith(".") || m.name.startsWith("_")) continue;
@@ -31960,7 +32658,7 @@ async function collectTargets2(baseDirs) {
31960
32658
  }
31961
32659
  const assignmentsBase = resolve58(baseDir, m.name, "assignments");
31962
32660
  if (!await fileExists(assignmentsBase)) continue;
31963
- const slugs = await readdir23(assignmentsBase, { withFileTypes: true });
32661
+ const slugs = await readdir24(assignmentsBase, { withFileTypes: true });
31964
32662
  for (const a of slugs) {
31965
32663
  if (!a.isDirectory()) continue;
31966
32664
  if (a.name.startsWith(".") || a.name.startsWith("_")) continue;
@@ -32045,7 +32743,7 @@ init_frontmatter();
32045
32743
  init_facts();
32046
32744
  init_derive();
32047
32745
  init_recompute();
32048
- import { readdir as readdir24, readFile as readFile40 } from "fs/promises";
32746
+ import { readdir as readdir25, readFile as readFile42 } from "fs/promises";
32049
32747
  import { resolve as resolve59 } from "path";
32050
32748
  var IMPLEMENTATION_STATUSES = /* @__PURE__ */ new Set(["in_progress", "review", "code_review"]);
32051
32749
  var REVIEW_STATUSES = /* @__PURE__ */ new Set(["review", "code_review"]);
@@ -32053,14 +32751,14 @@ async function listTargets(projectsDir2, standaloneDir) {
32053
32751
  const targets = [];
32054
32752
  let projects = [];
32055
32753
  try {
32056
- projects = await readdir24(projectsDir2);
32754
+ projects = await readdir25(projectsDir2);
32057
32755
  } catch {
32058
32756
  }
32059
32757
  for (const project of projects) {
32060
32758
  const projectDir = resolve59(projectsDir2, project);
32061
32759
  let slugs = [];
32062
32760
  try {
32063
- slugs = await readdir24(resolve59(projectDir, "assignments"));
32761
+ slugs = await readdir25(resolve59(projectDir, "assignments"));
32064
32762
  } catch {
32065
32763
  continue;
32066
32764
  }
@@ -32071,7 +32769,7 @@ async function listTargets(projectsDir2, standaloneDir) {
32071
32769
  }
32072
32770
  let ids = [];
32073
32771
  try {
32074
- ids = await readdir24(standaloneDir);
32772
+ ids = await readdir25(standaloneDir);
32075
32773
  } catch {
32076
32774
  }
32077
32775
  for (const id of ids) {
@@ -32131,7 +32829,7 @@ async function migrateDeriveCommand(options) {
32131
32829
  for (const target of targets) {
32132
32830
  let content;
32133
32831
  try {
32134
- content = await readFile40(target.path, "utf-8");
32832
+ content = await readFile42(target.path, "utf-8");
32135
32833
  } catch {
32136
32834
  continue;
32137
32835
  }
@@ -32345,26 +33043,26 @@ init_config2();
32345
33043
  init_fs();
32346
33044
  import {
32347
33045
  cp as cp3,
32348
- readdir as readdir25,
33046
+ readdir as readdir26,
32349
33047
  symlink,
32350
33048
  lstat,
32351
- readFile as readFile41,
33049
+ readFile as readFile43,
32352
33050
  readlink,
32353
33051
  rename as rename9,
32354
33052
  rm as rm6,
32355
33053
  unlink as unlink10,
32356
- writeFile as writeFile10
33054
+ writeFile as writeFile11
32357
33055
  } from "fs/promises";
32358
33056
  import { existsSync as existsSync4 } from "fs";
32359
- import { homedir as homedir8 } from "os";
32360
- import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute7, relative as relative2, resolve as resolve64 } from "path";
33057
+ import { homedir as homedir10 } from "os";
33058
+ import { basename as basename9, dirname as dirname16, isAbsolute as isAbsolute8, relative as relative2, resolve as resolve64 } from "path";
32361
33059
 
32362
33060
  // src/utils/package-root.ts
32363
33061
  init_fs();
32364
- import { dirname as dirname14, resolve as resolve63 } from "path";
33062
+ import { dirname as dirname15, resolve as resolve63 } from "path";
32365
33063
  import { fileURLToPath as fileURLToPath4 } from "url";
32366
33064
  async function findPackageRoot(expectedRelativePath) {
32367
- let currentDir = dirname14(fileURLToPath4(import.meta.url));
33065
+ let currentDir = dirname15(fileURLToPath4(import.meta.url));
32368
33066
  while (true) {
32369
33067
  const candidate = resolve63(currentDir, expectedRelativePath);
32370
33068
  if (await fileExists(candidate)) {
@@ -32390,26 +33088,26 @@ function getPluginManifestRelativePath(pluginKind) {
32390
33088
  return pluginKind === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json";
32391
33089
  }
32392
33090
  function getDefaultPluginTargetDir(pluginKind) {
32393
- const home2 = homedir8();
33091
+ const home2 = homedir10();
32394
33092
  return pluginKind === "claude" ? resolve64(home2, ".claude", "plugins", "syntaur") : resolve64(home2, "plugins", "syntaur");
32395
33093
  }
32396
33094
  function getDefaultMarketplacePath() {
32397
- return resolve64(homedir8(), ".agents", "plugins", "marketplace.json");
33095
+ return resolve64(homedir10(), ".agents", "plugins", "marketplace.json");
32398
33096
  }
32399
33097
  function getClaudeMarketplacesRoot() {
32400
- return resolve64(homedir8(), ".claude", "plugins", "marketplaces");
33098
+ return resolve64(homedir10(), ".claude", "plugins", "marketplaces");
32401
33099
  }
32402
33100
  function getClaudeKnownMarketplacesPath() {
32403
- return resolve64(homedir8(), ".claude", "plugins", "known_marketplaces.json");
33101
+ return resolve64(homedir10(), ".claude", "plugins", "known_marketplaces.json");
32404
33102
  }
32405
33103
  function getClaudeInstalledPluginsPath() {
32406
- return resolve64(homedir8(), ".claude", "plugins", "installed_plugins.json");
33104
+ return resolve64(homedir10(), ".claude", "plugins", "installed_plugins.json");
32407
33105
  }
32408
33106
  function getInstallMarkerPath(targetDir) {
32409
33107
  return resolve64(targetDir, INSTALL_MARKER_FILENAME);
32410
33108
  }
32411
33109
  async function readPackageManifest(packageRoot) {
32412
- const raw2 = await readFile41(resolve64(packageRoot, "package.json"), "utf-8");
33110
+ const raw2 = await readFile43(resolve64(packageRoot, "package.json"), "utf-8");
32413
33111
  return JSON.parse(raw2);
32414
33112
  }
32415
33113
  async function readJsonFileIfExists(pathValue) {
@@ -32417,7 +33115,7 @@ async function readJsonFileIfExists(pathValue) {
32417
33115
  return null;
32418
33116
  }
32419
33117
  try {
32420
- const raw2 = await readFile41(pathValue, "utf-8");
33118
+ const raw2 = await readFile43(pathValue, "utf-8");
32421
33119
  return JSON.parse(raw2);
32422
33120
  } catch {
32423
33121
  return null;
@@ -32433,7 +33131,7 @@ async function readPluginManifestName(targetDir, pluginKind) {
32433
33131
  if (!await fileExists(manifestPath)) {
32434
33132
  return void 0;
32435
33133
  }
32436
- const raw2 = await readFile41(manifestPath, "utf-8");
33134
+ const raw2 = await readFile43(manifestPath, "utf-8");
32437
33135
  const parsed = JSON.parse(raw2);
32438
33136
  return parsed.name;
32439
33137
  }
@@ -32443,7 +33141,7 @@ async function readInstallMetadata(targetDir) {
32443
33141
  return null;
32444
33142
  }
32445
33143
  try {
32446
- const raw2 = await readFile41(markerPath, "utf-8");
33144
+ const raw2 = await readFile43(markerPath, "utf-8");
32447
33145
  return JSON.parse(raw2);
32448
33146
  } catch {
32449
33147
  return null;
@@ -32456,7 +33154,7 @@ async function getInstallStatus(targetDir, pluginKind) {
32456
33154
  const info = await lstat(targetDir);
32457
33155
  if (info.isSymbolicLink()) {
32458
33156
  const symlinkTarget = await readlink(targetDir);
32459
- const resolvedTarget = resolve64(dirname15(targetDir), symlinkTarget);
33157
+ const resolvedTarget = resolve64(dirname16(targetDir), symlinkTarget);
32460
33158
  const manifestName2 = await readPluginManifestName(resolvedTarget, pluginKind);
32461
33159
  return {
32462
33160
  exists: true,
@@ -32485,7 +33183,7 @@ async function writeInstallMetadata(targetDir, pluginKind, installMode, packageM
32485
33183
  installMode,
32486
33184
  installedAt: (/* @__PURE__ */ new Date()).toISOString()
32487
33185
  };
32488
- await writeFile10(
33186
+ await writeFile11(
32489
33187
  getInstallMarkerPath(targetDir),
32490
33188
  `${JSON.stringify(metadata, null, 2)}
32491
33189
  `,
@@ -32493,15 +33191,15 @@ async function writeInstallMetadata(targetDir, pluginKind, installMode, packageM
32493
33191
  );
32494
33192
  }
32495
33193
  async function installCopy(paths, pluginKind) {
32496
- await ensureDir(dirname15(paths.targetDir));
33194
+ await ensureDir(dirname16(paths.targetDir));
32497
33195
  await cp3(paths.sourceDir, paths.targetDir, { recursive: true });
32498
33196
  const packageManifest = await readPackageManifest(paths.packageRoot);
32499
33197
  await writeInstallMetadata(paths.targetDir, pluginKind, "copy", packageManifest);
32500
33198
  }
32501
33199
  async function installLink(paths) {
32502
- await ensureDir(dirname15(paths.targetDir));
33200
+ await ensureDir(dirname16(paths.targetDir));
32503
33201
  await rm6(paths.targetDir, { recursive: true, force: true });
32504
- await ensureDir(dirname15(paths.targetDir));
33202
+ await ensureDir(dirname16(paths.targetDir));
32505
33203
  await symlink(resolve64(paths.sourceDir), paths.targetDir, "dir");
32506
33204
  }
32507
33205
  async function removeInstallMarker(targetDir) {
@@ -32513,7 +33211,7 @@ async function removeInstallMarker(targetDir) {
32513
33211
  }
32514
33212
  function normalizeAbsoluteInstallPath(pathValue, label) {
32515
33213
  const expanded = expandHome(pathValue.trim());
32516
- if (!isAbsolute7(expanded)) {
33214
+ if (!isAbsolute8(expanded)) {
32517
33215
  throw new Error(`${label} must be an absolute path.`);
32518
33216
  }
32519
33217
  return resolve64(expanded);
@@ -32556,7 +33254,7 @@ async function readClaudeMarketplaceFile(manifestPath) {
32556
33254
  };
32557
33255
  }
32558
33256
  async function writeClaudeMarketplaceFile(manifestPath, marketplace) {
32559
- await ensureDir(dirname15(manifestPath));
33257
+ await ensureDir(dirname16(manifestPath));
32560
33258
  if (Array.isArray(marketplace.plugins)) {
32561
33259
  marketplace.plugins = [...marketplace.plugins].sort((a, b) => {
32562
33260
  const an = a?.name ?? "";
@@ -32566,10 +33264,10 @@ async function writeClaudeMarketplaceFile(manifestPath, marketplace) {
32566
33264
  }
32567
33265
  if (await fileExists(manifestPath)) {
32568
33266
  try {
32569
- const prev = await readFile41(manifestPath, "utf-8");
33267
+ const prev = await readFile43(manifestPath, "utf-8");
32570
33268
  JSON.parse(prev);
32571
33269
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
32572
- await writeFile10(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
33270
+ await writeFile11(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
32573
33271
  } catch {
32574
33272
  throw new Error(
32575
33273
  `Refusing to overwrite ${manifestPath}: existing file is not valid JSON. Inspect and remove or repair it manually before re-running.`
@@ -32577,7 +33275,7 @@ async function writeClaudeMarketplaceFile(manifestPath, marketplace) {
32577
33275
  }
32578
33276
  }
32579
33277
  const tmpPath = `${manifestPath}.tmp`;
32580
- await writeFile10(tmpPath, `${JSON.stringify(marketplace, null, 2)}
33278
+ await writeFile11(tmpPath, `${JSON.stringify(marketplace, null, 2)}
32581
33279
  `, "utf-8");
32582
33280
  await rename9(tmpPath, manifestPath);
32583
33281
  }
@@ -32639,7 +33337,7 @@ async function listClaudeMarketplaceCandidates() {
32639
33337
  const [knownMarketplaces, activeMarketplaceNames, entries] = await Promise.all([
32640
33338
  readKnownClaudeMarketplaceRecords(),
32641
33339
  readInstalledClaudeMarketplaceNames(),
32642
- readdir25(rootDir, { withFileTypes: true })
33340
+ readdir26(rootDir, { withFileTypes: true })
32643
33341
  ]);
32644
33342
  const candidates = [];
32645
33343
  const seen = /* @__PURE__ */ new Set();
@@ -32714,7 +33412,7 @@ async function registerKnownClaudeMarketplace(name, rootDir) {
32714
33412
  const manifestPath = getClaudeKnownMarketplacesPath();
32715
33413
  let existing = {};
32716
33414
  if (await fileExists(manifestPath)) {
32717
- const raw2 = await readFile41(manifestPath, "utf-8");
33415
+ const raw2 = await readFile43(manifestPath, "utf-8");
32718
33416
  try {
32719
33417
  const parsed = JSON.parse(raw2);
32720
33418
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
@@ -32739,14 +33437,14 @@ async function registerKnownClaudeMarketplace(name, rootDir) {
32739
33437
  };
32740
33438
  existing[name].lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
32741
33439
  existing[name].autoUpdate = true;
32742
- await ensureDir(dirname15(manifestPath));
33440
+ await ensureDir(dirname16(manifestPath));
32743
33441
  if (await fileExists(manifestPath)) {
32744
- const prev = await readFile41(manifestPath, "utf-8");
33442
+ const prev = await readFile43(manifestPath, "utf-8");
32745
33443
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
32746
- await writeFile10(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
33444
+ await writeFile11(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
32747
33445
  }
32748
33446
  const tmpPath = `${manifestPath}.tmp`;
32749
- await writeFile10(tmpPath, `${JSON.stringify(existing, null, 2)}
33447
+ await writeFile11(tmpPath, `${JSON.stringify(existing, null, 2)}
32750
33448
  `, "utf-8");
32751
33449
  await rename9(tmpPath, manifestPath);
32752
33450
  return { added: !had, updated: had };
@@ -32755,11 +33453,11 @@ async function ensureKnownClaudeMarketplaceForRoot(options) {
32755
33453
  return registerKnownClaudeMarketplace(options.name, options.rootDir);
32756
33454
  }
32757
33455
  async function setSyntaurPluginEnabled(options) {
32758
- const settingsPath = resolve64(homedir8(), ".claude", "settings.json");
33456
+ const settingsPath = resolve64(homedir10(), ".claude", "settings.json");
32759
33457
  const key = `syntaur@${options.marketplaceName}`;
32760
33458
  let parsed = {};
32761
33459
  if (await fileExists(settingsPath)) {
32762
- const raw2 = await readFile41(settingsPath, "utf-8");
33460
+ const raw2 = await readFile43(settingsPath, "utf-8");
32763
33461
  try {
32764
33462
  parsed = JSON.parse(raw2);
32765
33463
  } catch {
@@ -32775,14 +33473,14 @@ async function setSyntaurPluginEnabled(options) {
32775
33473
  }
32776
33474
  enabledPlugins[key] = options.enabled;
32777
33475
  parsed.enabledPlugins = enabledPlugins;
32778
- await ensureDir(dirname15(settingsPath));
33476
+ await ensureDir(dirname16(settingsPath));
32779
33477
  if (await fileExists(settingsPath)) {
32780
33478
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
32781
- const prev = await readFile41(settingsPath, "utf-8");
32782
- await writeFile10(`${settingsPath}.bak-${stamp}`, prev, "utf-8");
33479
+ const prev = await readFile43(settingsPath, "utf-8");
33480
+ await writeFile11(`${settingsPath}.bak-${stamp}`, prev, "utf-8");
32783
33481
  }
32784
33482
  const tmpPath = `${settingsPath}.tmp`;
32785
- await writeFile10(tmpPath, `${JSON.stringify(parsed, null, 2)}
33483
+ await writeFile11(tmpPath, `${JSON.stringify(parsed, null, 2)}
32786
33484
  `, "utf-8");
32787
33485
  await rename9(tmpPath, settingsPath);
32788
33486
  return { key, previous, current: options.enabled, changed: true };
@@ -32818,17 +33516,17 @@ async function ensureClaudeUserMarketplace() {
32818
33516
  }
32819
33517
  async function detectClaudeMarketplaceForTarget(targetDir) {
32820
33518
  const normalizedTargetDir = normalizeAbsoluteInstallPath(targetDir, "Claude plugin target");
32821
- const pluginsDir = dirname15(normalizedTargetDir);
32822
- if (basename8(pluginsDir) !== "plugins") {
33519
+ const pluginsDir = dirname16(normalizedTargetDir);
33520
+ if (basename9(pluginsDir) !== "plugins") {
32823
33521
  return null;
32824
33522
  }
32825
- const rootDir = dirname15(pluginsDir);
33523
+ const rootDir = dirname16(pluginsDir);
32826
33524
  const manifestPath = resolve64(rootDir, ".claude-plugin", "marketplace.json");
32827
33525
  if (!await fileExists(manifestPath)) {
32828
33526
  return null;
32829
33527
  }
32830
33528
  const marketplace = await readClaudeMarketplaceFile(manifestPath);
32831
- const name = typeof marketplace.name === "string" && marketplace.name.trim() !== "" ? marketplace.name : basename8(rootDir);
33529
+ const name = typeof marketplace.name === "string" && marketplace.name.trim() !== "" ? marketplace.name : basename9(rootDir);
32832
33530
  return {
32833
33531
  name,
32834
33532
  rootDir,
@@ -32988,7 +33686,7 @@ async function installManagedPlugin(options) {
32988
33686
  };
32989
33687
  }
32990
33688
  function buildMarketplaceSourcePath(pluginTargetDir, marketplacePath) {
32991
- const relPath = relative2(dirname15(marketplacePath), pluginTargetDir).replaceAll("\\", "/");
33689
+ const relPath = relative2(dirname16(marketplacePath), pluginTargetDir).replaceAll("\\", "/");
32992
33690
  if (relPath === "") {
32993
33691
  return ".";
32994
33692
  }
@@ -33016,7 +33714,7 @@ async function readMarketplaceFile(marketplacePath) {
33016
33714
  plugins: []
33017
33715
  };
33018
33716
  }
33019
- const raw2 = await readFile41(marketplacePath, "utf-8");
33717
+ const raw2 = await readFile43(marketplacePath, "utf-8");
33020
33718
  const parsed = JSON.parse(raw2);
33021
33719
  return {
33022
33720
  name: parsed.name ?? "local",
@@ -33025,8 +33723,8 @@ async function readMarketplaceFile(marketplacePath) {
33025
33723
  };
33026
33724
  }
33027
33725
  async function writeMarketplaceFile(marketplacePath, marketplace) {
33028
- await ensureDir(dirname15(marketplacePath));
33029
- await writeFile10(marketplacePath, `${JSON.stringify(marketplace, null, 2)}
33726
+ await ensureDir(dirname16(marketplacePath));
33727
+ await writeFile11(marketplacePath, `${JSON.stringify(marketplace, null, 2)}
33030
33728
  `, "utf-8");
33031
33729
  }
33032
33730
  async function hasAnySyntaurMarketplaceEntry(marketplacePath) {
@@ -33258,24 +33956,24 @@ async function textPrompt(question, defaultValue) {
33258
33956
 
33259
33957
  // src/utils/install-skills.ts
33260
33958
  init_fs();
33261
- import { readFile as readFile43, readdir as readdir26, mkdir as mkdir7, copyFile, rm as rm7, lstat as lstat2 } from "fs/promises";
33262
- import { resolve as resolve66, relative as relative3, join as join12 } from "path";
33263
- import { homedir as homedir10 } from "os";
33959
+ import { readFile as readFile45, readdir as readdir27, mkdir as mkdir8, copyFile, rm as rm7, lstat as lstat2 } from "fs/promises";
33960
+ import { resolve as resolve66, relative as relative3, join as join14 } from "path";
33961
+ import { homedir as homedir12 } from "os";
33264
33962
 
33265
33963
  // src/utils/plugin-state.ts
33266
33964
  init_fs();
33267
- import { readFile as readFile42 } from "fs/promises";
33965
+ import { readFile as readFile44 } from "fs/promises";
33268
33966
  import { resolve as resolve65 } from "path";
33269
- import { homedir as homedir9 } from "os";
33967
+ import { homedir as homedir11 } from "os";
33270
33968
  function settingsPathFor(agent) {
33271
- if (agent === "claude") return resolve65(homedir9(), ".claude", "settings.json");
33969
+ if (agent === "claude") return resolve65(homedir11(), ".claude", "settings.json");
33272
33970
  return null;
33273
33971
  }
33274
33972
  async function readJsonOrNull(path) {
33275
33973
  if (!path) return null;
33276
33974
  if (!await fileExists(path)) return null;
33277
33975
  try {
33278
- const raw2 = await readFile42(path, "utf-8");
33976
+ const raw2 = await readFile44(path, "utf-8");
33279
33977
  return JSON.parse(raw2);
33280
33978
  } catch {
33281
33979
  return null;
@@ -33328,15 +34026,15 @@ async function getSkillsDir() {
33328
34026
  return resolve66(packageRoot, "skills");
33329
34027
  }
33330
34028
  function defaultSkillTargetDir(target) {
33331
- if (target === "claude") return resolve66(homedir10(), ".claude", "skills");
33332
- return resolve66(homedir10(), ".codex", "skills");
34029
+ if (target === "claude") return resolve66(homedir12(), ".claude", "skills");
34030
+ return resolve66(homedir12(), ".codex", "skills");
33333
34031
  }
33334
34032
  async function walkFiles(root) {
33335
34033
  const out = [];
33336
34034
  async function walk(dir) {
33337
- const entries = await readdir26(dir, { withFileTypes: true });
34035
+ const entries = await readdir27(dir, { withFileTypes: true });
33338
34036
  for (const entry of entries) {
33339
- const full = join12(dir, entry.name);
34037
+ const full = join14(dir, entry.name);
33340
34038
  if (entry.isDirectory()) {
33341
34039
  await walk(full);
33342
34040
  } else if (entry.isFile()) {
@@ -33349,7 +34047,7 @@ async function walkFiles(root) {
33349
34047
  }
33350
34048
  async function filesEqual(a, b) {
33351
34049
  try {
33352
- const [ba, bb] = await Promise.all([readFile43(a), readFile43(b)]);
34050
+ const [ba, bb] = await Promise.all([readFile45(a), readFile45(b)]);
33353
34051
  if (ba.length !== bb.length) return false;
33354
34052
  return ba.equals(bb);
33355
34053
  } catch {
@@ -33357,11 +34055,11 @@ async function filesEqual(a, b) {
33357
34055
  }
33358
34056
  }
33359
34057
  async function copyDir(srcDir, destDir) {
33360
- await mkdir7(destDir, { recursive: true });
33361
- const entries = await readdir26(srcDir, { withFileTypes: true });
34058
+ await mkdir8(destDir, { recursive: true });
34059
+ const entries = await readdir27(srcDir, { withFileTypes: true });
33362
34060
  for (const entry of entries) {
33363
- const src = join12(srcDir, entry.name);
33364
- const dest = join12(destDir, entry.name);
34061
+ const src = join14(srcDir, entry.name);
34062
+ const dest = join14(destDir, entry.name);
33365
34063
  if (entry.isDirectory()) {
33366
34064
  await copyDir(src, dest);
33367
34065
  } else if (entry.isFile()) {
@@ -33374,7 +34072,7 @@ async function skillMatches(srcDir, destDir) {
33374
34072
  const srcFiles = await walkFiles(srcDir);
33375
34073
  for (const srcFile of srcFiles) {
33376
34074
  const rel = relative3(srcDir, srcFile);
33377
- const destFile = join12(destDir, rel);
34075
+ const destFile = join14(destDir, rel);
33378
34076
  if (!await filesEqual(srcFile, destFile)) return false;
33379
34077
  }
33380
34078
  const destFiles = await walkFiles(destDir);
@@ -33383,8 +34081,8 @@ async function skillMatches(srcDir, destDir) {
33383
34081
  }
33384
34082
  async function isSymlink(path) {
33385
34083
  try {
33386
- const stat17 = await lstat2(path);
33387
- return stat17.isSymbolicLink();
34084
+ const stat18 = await lstat2(path);
34085
+ return stat18.isSymbolicLink();
33388
34086
  } catch {
33389
34087
  return false;
33390
34088
  }
@@ -33412,12 +34110,12 @@ async function installSkillDir(srcDir, destDir, skillName, force) {
33412
34110
  return { skill: skillName, status: "differs-preserved", targetPath: destDir };
33413
34111
  }
33414
34112
  async function discoverSkillNames(sourceDir) {
33415
- const entries = await readdir26(sourceDir, { withFileTypes: true });
34113
+ const entries = await readdir27(sourceDir, { withFileTypes: true });
33416
34114
  const names = [];
33417
34115
  for (const entry of entries) {
33418
34116
  if (!entry.isDirectory()) continue;
33419
34117
  if (entry.name.startsWith(".")) continue;
33420
- if (await fileExists(join12(sourceDir, entry.name, "SKILL.md"))) {
34118
+ if (await fileExists(join14(sourceDir, entry.name, "SKILL.md"))) {
33421
34119
  names.push(entry.name);
33422
34120
  }
33423
34121
  }
@@ -33442,10 +34140,10 @@ async function installSkillsWithReport(options) {
33442
34140
  }
33443
34141
  const skillNames = await discoverSkillNames(source);
33444
34142
  const results = [];
33445
- await mkdir7(targetRoot, { recursive: true });
34143
+ await mkdir8(targetRoot, { recursive: true });
33446
34144
  for (const skill of skillNames) {
33447
- const srcDir = join12(source, skill);
33448
- const destDir = join12(targetRoot, skill);
34145
+ const srcDir = join14(source, skill);
34146
+ const destDir = join14(targetRoot, skill);
33449
34147
  results.push(await installSkillDir(srcDir, destDir, skill, force));
33450
34148
  }
33451
34149
  return { results };
@@ -33459,11 +34157,11 @@ async function installSkillsToDir(options) {
33459
34157
  }
33460
34158
  const force = options.force ?? false;
33461
34159
  const skillNames = await discoverSkillNames(source);
33462
- await mkdir7(options.targetDir, { recursive: true });
34160
+ await mkdir8(options.targetDir, { recursive: true });
33463
34161
  const results = [];
33464
34162
  for (const skill of skillNames) {
33465
- const srcDir = join12(source, skill);
33466
- const destDir = join12(options.targetDir, skill);
34163
+ const srcDir = join14(source, skill);
34164
+ const destDir = join14(options.targetDir, skill);
33467
34165
  results.push(await installSkillDir(srcDir, destDir, skill, force));
33468
34166
  }
33469
34167
  return results;
@@ -33484,12 +34182,12 @@ async function uninstallSkills(options) {
33484
34182
  }
33485
34183
  const removed = [];
33486
34184
  for (const skill of known) {
33487
- const destDir = join12(targetRoot, skill);
34185
+ const destDir = join14(targetRoot, skill);
33488
34186
  if (!await fileExists(destDir)) continue;
33489
34187
  if (await isSymlink(destDir)) continue;
33490
- const skillMd = join12(destDir, "SKILL.md");
34188
+ const skillMd = join14(destDir, "SKILL.md");
33491
34189
  if (!await fileExists(skillMd)) continue;
33492
- const content = await readFile43(skillMd, "utf-8").catch(() => "");
34190
+ const content = await readFile45(skillMd, "utf-8").catch(() => "");
33493
34191
  const match = content.match(/^name:\s*(\S+)\s*$/m);
33494
34192
  if (!match || match[1] !== skill) continue;
33495
34193
  await rm7(destDir, { recursive: true, force: true });
@@ -33684,20 +34382,20 @@ import { realpathSync as realpathSync3 } from "fs";
33684
34382
  init_paths();
33685
34383
  init_fs();
33686
34384
  import { fileURLToPath as fileURLToPath6 } from "url";
33687
- import { readFile as readFile45 } from "fs/promises";
33688
- import { dirname as dirname17, join as join14, resolve as resolve67 } from "path";
34385
+ import { readFile as readFile47 } from "fs/promises";
34386
+ import { dirname as dirname18, join as join16, resolve as resolve67 } from "path";
33689
34387
  import { spawn as spawn6 } from "child_process";
33690
34388
  import { createInterface as createInterface2 } from "readline/promises";
33691
34389
 
33692
34390
  // src/utils/version.ts
33693
34391
  import { fileURLToPath as fileURLToPath5 } from "url";
33694
- import { readFile as readFile44 } from "fs/promises";
33695
- import { dirname as dirname16, join as join13 } from "path";
34392
+ import { readFile as readFile46 } from "fs/promises";
34393
+ import { dirname as dirname17, join as join15 } from "path";
33696
34394
  async function readPackageVersion(scriptUrl) {
33697
34395
  try {
33698
34396
  const scriptPath = fileURLToPath5(scriptUrl);
33699
- const pkgRoot = dirname16(dirname16(scriptPath));
33700
- const raw2 = await readFile44(join13(pkgRoot, "package.json"), "utf-8");
34397
+ const pkgRoot = dirname17(dirname17(scriptPath));
34398
+ const raw2 = await readFile46(join15(pkgRoot, "package.json"), "utf-8");
33701
34399
  const parsed = JSON.parse(raw2);
33702
34400
  return typeof parsed.version === "string" ? parsed.version : null;
33703
34401
  } catch {
@@ -33727,7 +34425,7 @@ function isRunningViaNpx(scriptUrl) {
33727
34425
  async function readState() {
33728
34426
  if (!await fileExists(STATE_FILE)) return null;
33729
34427
  try {
33730
- const raw2 = await readFile45(STATE_FILE, "utf-8");
34428
+ const raw2 = await readFile47(STATE_FILE, "utf-8");
33731
34429
  return JSON.parse(raw2);
33732
34430
  } catch {
33733
34431
  return null;
@@ -33738,10 +34436,10 @@ async function writeState(state) {
33738
34436
  `);
33739
34437
  }
33740
34438
  async function resolveNpmBin() {
33741
- const nodeDir = dirname17(process.execPath);
34439
+ const nodeDir = dirname18(process.execPath);
33742
34440
  const isWin = process.platform === "win32";
33743
34441
  const npmName = isWin ? "npm.cmd" : "npm";
33744
- const nearNode = join14(nodeDir, npmName);
34442
+ const nearNode = join16(nodeDir, npmName);
33745
34443
  if (await fileExists(nearNode)) {
33746
34444
  return { cmd: nearNode, shell: false };
33747
34445
  }
@@ -33784,9 +34482,9 @@ async function readGlobalVersion() {
33784
34482
  });
33785
34483
  if (!rootPath) return null;
33786
34484
  try {
33787
- const manifestPath = join14(rootPath, "syntaur", "package.json");
34485
+ const manifestPath = join16(rootPath, "syntaur", "package.json");
33788
34486
  if (!await fileExists(manifestPath)) return null;
33789
- const raw2 = await readFile45(manifestPath, "utf-8");
34487
+ const raw2 = await readFile47(manifestPath, "utf-8");
33790
34488
  const parsed = JSON.parse(raw2);
33791
34489
  return typeof parsed.version === "string" ? parsed.version : null;
33792
34490
  } catch {
@@ -33905,8 +34603,8 @@ async function maybePromptInstall(scriptUrl) {
33905
34603
 
33906
34604
  // src/commands/update.ts
33907
34605
  import { existsSync as existsSync5 } from "fs";
33908
- import { join as join15 } from "path";
33909
- import { homedir as homedir11 } from "os";
34606
+ import { join as join17 } from "path";
34607
+ import { homedir as homedir13 } from "os";
33910
34608
  var PACKAGE_MANAGERS = ["npm", "pnpm", "yarn", "bun"];
33911
34609
  var LOCAL_MSG = "Running from a dev/linked checkout \u2014 `syntaur update` won't touch a linked install. Pull + rebuild in your repo, then `syntaur install-plugin --force` to refresh skills.";
33912
34610
  var NPX_MSG = "Running via npx \u2014 there's no durable global install to update. Install durably first: `npm i -g syntaur`.";
@@ -33947,12 +34645,12 @@ var defaultRunner = (cmd, args, opts) => new Promise((resolvePromise) => {
33947
34645
  child.on("close", (code) => resolvePromise({ code: code ?? -1, stdout, stderr }));
33948
34646
  });
33949
34647
  function bunGlobalNodeModulesDir(env) {
33950
- const globalDir = env.BUN_INSTALL_GLOBAL_DIR ?? join15(env.BUN_INSTALL ?? join15(homedir11(), ".bun"), "install", "global");
33951
- return join15(globalDir, "node_modules");
34648
+ const globalDir = env.BUN_INSTALL_GLOBAL_DIR ?? join17(env.BUN_INSTALL ?? join17(homedir13(), ".bun"), "install", "global");
34649
+ return join17(globalDir, "node_modules");
33952
34650
  }
33953
34651
  async function defaultResolveFreshBin(pm, runner, env) {
33954
34652
  const binFromPkgRoot = (pkgRoot) => {
33955
- const entry = join15(pkgRoot, "syntaur", "bin", "syntaur.js");
34653
+ const entry = join17(pkgRoot, "syntaur", "bin", "syntaur.js");
33956
34654
  return existsSync5(entry) ? { cmd: process.execPath, baseArgs: [entry] } : null;
33957
34655
  };
33958
34656
  try {
@@ -33964,7 +34662,7 @@ async function defaultResolveFreshBin(pm, runner, env) {
33964
34662
  if (pm === "yarn") {
33965
34663
  const res = await runner("yarn", ["global", "dir"], { env, captureStdout: true });
33966
34664
  const dir = res.stdout.trim();
33967
- return dir ? binFromPkgRoot(join15(dir, "node_modules")) : null;
34665
+ return dir ? binFromPkgRoot(join17(dir, "node_modules")) : null;
33968
34666
  }
33969
34667
  return binFromPkgRoot(bunGlobalNodeModulesDir(env));
33970
34668
  } catch {
@@ -34144,16 +34842,16 @@ async function refreshPluginSkills(options, pm, runner, getManagedDir, resolveFr
34144
34842
  // src/commands/install-statusline.ts
34145
34843
  init_paths();
34146
34844
  init_fs();
34147
- import { readFile as readFile47, writeFile as writeFile12, copyFile as copyFile2, rm as rm8, stat as stat8, symlink as symlink2, unlink as unlink11, lstat as lstat3 } from "fs/promises";
34148
- import { resolve as resolve69, dirname as dirname19 } from "path";
34149
- import { homedir as homedir12 } from "os";
34845
+ import { readFile as readFile49, writeFile as writeFile13, copyFile as copyFile2, rm as rm8, stat as stat9, symlink as symlink2, unlink as unlink11, lstat as lstat3 } from "fs/promises";
34846
+ import { resolve as resolve69, dirname as dirname20 } from "path";
34847
+ import { homedir as homedir14 } from "os";
34150
34848
  import { fileURLToPath as fileURLToPath8 } from "url";
34151
34849
 
34152
34850
  // src/commands/configure-statusline.ts
34153
34851
  init_paths();
34154
34852
  init_fs();
34155
- import { readFile as readFile46, writeFile as writeFile11 } from "fs/promises";
34156
- import { resolve as resolve68, dirname as dirname18 } from "path";
34853
+ import { readFile as readFile48, writeFile as writeFile12 } from "fs/promises";
34854
+ import { resolve as resolve68, dirname as dirname19 } from "path";
34157
34855
  import { spawnSync as spawnSync5 } from "child_process";
34158
34856
  import { checkbox, input as input2, confirm } from "@inquirer/prompts";
34159
34857
  var AVAILABLE_SEGMENTS = [
@@ -34179,7 +34877,7 @@ function getConfigPath(installRoot) {
34179
34877
  async function readConfig2(path) {
34180
34878
  if (!await fileExists(path)) return null;
34181
34879
  try {
34182
- const raw2 = await readFile46(path, "utf-8");
34880
+ const raw2 = await readFile48(path, "utf-8");
34183
34881
  const parsed = JSON.parse(raw2);
34184
34882
  if (!parsed || typeof parsed !== "object") return null;
34185
34883
  const segments = Array.isArray(parsed.segments) ? parsed.segments.filter(isSegmentName) : [];
@@ -34274,7 +34972,7 @@ function renderPreview(config, statuslineScript, cwd) {
34274
34972
  env: {
34275
34973
  ...process.env,
34276
34974
  // Force the child to pick up the freshly-written config from install root.
34277
- HOME: dirname18(dirname18(statuslineScript))
34975
+ HOME: dirname19(dirname19(statuslineScript))
34278
34976
  }
34279
34977
  });
34280
34978
  if (res.status !== 0) return null;
@@ -34325,8 +35023,8 @@ async function configureStatuslineCommand(options = {}) {
34325
35023
  console.log("(preview mode \u2014 config NOT written)");
34326
35024
  return;
34327
35025
  }
34328
- await ensureDir(dirname18(configPath2));
34329
- await writeFile11(configPath2, JSON.stringify(config, null, 2) + "\n", "utf-8");
35026
+ await ensureDir(dirname19(configPath2));
35027
+ await writeFile12(configPath2, JSON.stringify(config, null, 2) + "\n", "utf-8");
34330
35028
  console.log("Wrote statusline config:");
34331
35029
  console.log(` path: ${configPath2}`);
34332
35030
  console.log(` segments: ${config.segments.join(", ")}`);
@@ -34352,22 +35050,22 @@ async function configureStatuslineCommand(options = {}) {
34352
35050
  async function writeDefaultConfigIfMissing(installRoot) {
34353
35051
  const path = getConfigPath(installRoot);
34354
35052
  if (await fileExists(path)) return;
34355
- await ensureDir(dirname18(path));
35053
+ await ensureDir(dirname19(path));
34356
35054
  const defaultConfig = {
34357
35055
  segments: ["git", "assignment", "session"],
34358
35056
  separator: " \xB7 "
34359
35057
  };
34360
- await writeFile11(path, JSON.stringify(defaultConfig, null, 2) + "\n", "utf-8");
35058
+ await writeFile12(path, JSON.stringify(defaultConfig, null, 2) + "\n", "utf-8");
34361
35059
  }
34362
35060
 
34363
35061
  // src/commands/install-statusline.ts
34364
35062
  function getPackageStatuslineSource() {
34365
- const here = dirname19(fileURLToPath8(import.meta.url));
35063
+ const here = dirname20(fileURLToPath8(import.meta.url));
34366
35064
  return resolve69(here, "..", "statusline", "statusline.sh");
34367
35065
  }
34368
35066
  async function readSettingsJson(settingsPath) {
34369
35067
  if (!await fileExists(settingsPath)) return {};
34370
- const raw2 = await readFile47(settingsPath, "utf-8");
35068
+ const raw2 = await readFile49(settingsPath, "utf-8");
34371
35069
  if (raw2.trim() === "") return {};
34372
35070
  try {
34373
35071
  const parsed = JSON.parse(raw2);
@@ -34379,8 +35077,8 @@ async function readSettingsJson(settingsPath) {
34379
35077
  }
34380
35078
  }
34381
35079
  async function writeSettingsJson(settingsPath, data) {
34382
- await ensureDir(dirname19(settingsPath));
34383
- await writeFile12(settingsPath, JSON.stringify(data, null, 2) + "\n", "utf-8");
35080
+ await ensureDir(dirname20(settingsPath));
35081
+ await writeFile13(settingsPath, JSON.stringify(data, null, 2) + "\n", "utf-8");
34384
35082
  }
34385
35083
  async function resolveMode(mode, existingCommand, ourCommand) {
34386
35084
  if (mode !== "ask") return mode;
@@ -34414,8 +35112,8 @@ function extractExistingCommand(settings) {
34414
35112
  };
34415
35113
  }
34416
35114
  async function backupSettings(settingsSnapshot, backupPath) {
34417
- await ensureDir(dirname19(backupPath));
34418
- await writeFile12(
35115
+ await ensureDir(dirname20(backupPath));
35116
+ await writeFile13(
34419
35117
  backupPath,
34420
35118
  JSON.stringify(
34421
35119
  {
@@ -34431,7 +35129,7 @@ async function backupSettings(settingsSnapshot, backupPath) {
34431
35129
  );
34432
35130
  }
34433
35131
  async function installScript(sourceScript, destScript, link) {
34434
- await ensureDir(dirname19(destScript));
35132
+ await ensureDir(dirname20(destScript));
34435
35133
  try {
34436
35134
  const s = await lstat3(destScript);
34437
35135
  if (s.isSymbolicLink() || s.isFile()) {
@@ -34447,7 +35145,7 @@ async function installScript(sourceScript, destScript, link) {
34447
35145
  }
34448
35146
  async function installStatuslineCommand(options = {}) {
34449
35147
  const mode = options.mode ?? "ask";
34450
- const settingsPath = options.settingsPath ?? resolve69(homedir12(), ".claude", "settings.json");
35148
+ const settingsPath = options.settingsPath ?? resolve69(homedir14(), ".claude", "settings.json");
34451
35149
  const installRoot = options.installRoot ?? syntaurRoot();
34452
35150
  const sourceScript = options.sourceScript ?? getPackageStatuslineSource();
34453
35151
  const destScript = resolve69(installRoot, "statusline.sh");
@@ -34494,13 +35192,13 @@ async function installStatuslineCommand(options = {}) {
34494
35192
  # Executes the previously configured statusLine command.
34495
35193
  exec ${existingCommand}
34496
35194
  `;
34497
- await writeFile12(wrapperPath, wrapperBody, "utf-8");
35195
+ await writeFile13(wrapperPath, wrapperBody, "utf-8");
34498
35196
  await chmodExec(wrapperPath);
34499
35197
  wrapTarget = wrapperPath;
34500
35198
  }
34501
35199
  }
34502
- await ensureDir(dirname19(confPath));
34503
- await writeFile12(
35200
+ await ensureDir(dirname20(confPath));
35201
+ await writeFile13(
34504
35202
  confPath,
34505
35203
  wrapTarget ? `# Wrap target \u2014 the command below is invoked with the same stdin; its
34506
35204
  # stdout becomes the leading segment of the statusline. Remove this
@@ -34537,13 +35235,13 @@ function parseWrapCommand(command) {
34537
35235
  async function chmodExec(path) {
34538
35236
  const fs = await import("fs/promises");
34539
35237
  try {
34540
- const s = await stat8(path);
35238
+ const s = await stat9(path);
34541
35239
  await fs.chmod(path, s.mode | 73);
34542
35240
  } catch {
34543
35241
  }
34544
35242
  }
34545
35243
  async function uninstallStatuslineCommand(options = {}) {
34546
- const settingsPath = options.settingsPath ?? resolve69(homedir12(), ".claude", "settings.json");
35244
+ const settingsPath = options.settingsPath ?? resolve69(homedir14(), ".claude", "settings.json");
34547
35245
  const installRoot = options.installRoot ?? syntaurRoot();
34548
35246
  const destScript = resolve69(installRoot, "statusline.sh");
34549
35247
  const confPath = resolve69(installRoot, "statusline.conf");
@@ -34555,7 +35253,7 @@ async function uninstallStatuslineCommand(options = {}) {
34555
35253
  let restored = null;
34556
35254
  if (await fileExists(backupPath)) {
34557
35255
  try {
34558
- const raw2 = await readFile47(backupPath, "utf-8");
35256
+ const raw2 = await readFile49(backupPath, "utf-8");
34559
35257
  const parsed = JSON.parse(raw2);
34560
35258
  const prev = parsed?.previousStatusLine;
34561
35259
  if (prev && typeof prev === "object" && typeof prev.command === "string") {
@@ -34736,8 +35434,8 @@ init_config2();
34736
35434
  // src/commands/cross-agent-install.ts
34737
35435
  init_fs();
34738
35436
  import { spawnSync as spawnSync6 } from "child_process";
34739
- import { dirname as dirname20, join as join16, resolve as resolve71 } from "path";
34740
- import { cp as cp4, mkdir as mkdir9 } from "fs/promises";
35437
+ import { dirname as dirname21, join as join18, resolve as resolve71 } from "path";
35438
+ import { cp as cp4, mkdir as mkdir10 } from "fs/promises";
34741
35439
 
34742
35440
  // src/commands/setup-adapter.ts
34743
35441
  init_paths();
@@ -34847,7 +35545,7 @@ async function installTier3Plugin(t, opts = {}) {
34847
35545
  console.log(`${prefix}Tier 3 (${t.id}): ${plugin.source} -> ${installDir}`);
34848
35546
  return "dry-run";
34849
35547
  }
34850
- if (await fileExists(join16(installDir, plugin.entry)) && !opts.force) {
35548
+ if (await fileExists(join18(installDir, plugin.entry)) && !opts.force) {
34851
35549
  console.log(
34852
35550
  `Tier 3 (${t.id}): already installed at ${installDir} (use --force to overwrite).`
34853
35551
  );
@@ -34855,7 +35553,7 @@ async function installTier3Plugin(t, opts = {}) {
34855
35553
  }
34856
35554
  try {
34857
35555
  const sourceDir = resolve71(await findPackageRoot(plugin.source), plugin.source);
34858
- await mkdir9(dirname20(installDir), { recursive: true });
35556
+ await mkdir10(dirname21(installDir), { recursive: true });
34859
35557
  await cp4(sourceDir, installDir, { recursive: true, force: true });
34860
35558
  console.log(`Tier 3 (${t.id}): installed ${plugin.kind} -> ${installDir}`);
34861
35559
  return "installed";
@@ -35225,7 +35923,7 @@ init_cwd();
35225
35923
  init_session_db();
35226
35924
  init_agent_sessions();
35227
35925
  import { resolve as resolve73 } from "path";
35228
- import { readFile as readFile48 } from "fs/promises";
35926
+ import { readFile as readFile50 } from "fs/promises";
35229
35927
  async function trackSessionCommand(options, deps = {}) {
35230
35928
  if (!options.agent) {
35231
35929
  throw new Error("--agent <name> is required.");
@@ -35242,7 +35940,7 @@ async function trackSessionCommand(options, deps = {}) {
35242
35940
  const cwd = process.cwd();
35243
35941
  let legacyHint;
35244
35942
  try {
35245
- const raw2 = await readFile48(resolve73(cwd, ".syntaur", "context.json"), "utf-8");
35943
+ const raw2 = await readFile50(resolve73(cwd, ".syntaur", "context.json"), "utf-8");
35246
35944
  const parsed = JSON.parse(raw2);
35247
35945
  if (typeof parsed.sessionId === "string") legacyHint = parsed.sessionId;
35248
35946
  } catch {
@@ -35406,8 +36104,8 @@ function formatInstallUrlHandlerError(err2) {
35406
36104
  init_config2();
35407
36105
  init_paths();
35408
36106
  init_fs();
35409
- import { resolve as resolve75, isAbsolute as isAbsolute8 } from "path";
35410
- import { readFile as readFile49 } from "fs/promises";
36107
+ import { resolve as resolve75, isAbsolute as isAbsolute9 } from "path";
36108
+ import { readFile as readFile51 } from "fs/promises";
35411
36109
  import { select, confirm as confirm2, input as input3 } from "@inquirer/prompts";
35412
36110
  async function browseCommand(options) {
35413
36111
  const config = await readConfig();
@@ -35486,7 +36184,7 @@ async function ensureWorktree(opts) {
35486
36184
  if (!await fileExists(assignmentPath)) {
35487
36185
  return void 0;
35488
36186
  }
35489
- const content = await readFile49(assignmentPath, "utf-8");
36187
+ const content = await readFile51(assignmentPath, "utf-8");
35490
36188
  const { parseAssignmentFrontmatter: parseAssignmentFrontmatter2 } = await Promise.resolve().then(() => (init_frontmatter(), frontmatter_exports));
35491
36189
  const fm = parseAssignmentFrontmatter2(content);
35492
36190
  const { workspace } = fm;
@@ -35556,7 +36254,7 @@ async function ensureWorktree(opts) {
35556
36254
  async function runCreate(opts) {
35557
36255
  const { createWorktreeAndRecord: createWorktreeAndRecord2, GitWorktreeError: GitWorktreeError2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
35558
36256
  const expandedWorktree = expandHome(opts.worktreePath);
35559
- const absWorktree = isAbsolute8(expandedWorktree) ? expandedWorktree : resolve75(expandedWorktree);
36257
+ const absWorktree = isAbsolute9(expandedWorktree) ? expandedWorktree : resolve75(expandedWorktree);
35560
36258
  try {
35561
36259
  await createWorktreeAndRecord2({
35562
36260
  assignmentPath: opts.assignmentPath,
@@ -35620,7 +36318,7 @@ init_paths();
35620
36318
  init_fs();
35621
36319
  init_parser();
35622
36320
  init_config2();
35623
- import { readdir as readdir27, readFile as readFile50 } from "fs/promises";
36321
+ import { readdir as readdir28, readFile as readFile52 } from "fs/promises";
35624
36322
  import { resolve as resolve77 } from "path";
35625
36323
  async function listPlaybooksCommand(options = {}) {
35626
36324
  const dir = playbooksDir();
@@ -35630,14 +36328,14 @@ async function listPlaybooksCommand(options = {}) {
35630
36328
  }
35631
36329
  const config = await readConfig();
35632
36330
  const disabledSet = new Set(config.playbooks.disabled);
35633
- const entries = await readdir27(dir, { withFileTypes: true });
36331
+ const entries = await readdir28(dir, { withFileTypes: true });
35634
36332
  const mdFiles = entries.filter(
35635
36333
  (e) => e.isFile() && e.name.endsWith(".md") && !e.name.startsWith("_") && e.name !== "manifest.md"
35636
36334
  );
35637
36335
  const rows = [];
35638
36336
  for (const entry of mdFiles) {
35639
36337
  const filePath = resolve77(dir, entry.name);
35640
- const raw2 = await readFile50(filePath, "utf-8");
36338
+ const raw2 = await readFile52(filePath, "utf-8");
35641
36339
  const parsed = parsePlaybook(raw2);
35642
36340
  const slug = parsed.slug || entry.name.replace(/\.md$/, "");
35643
36341
  const disabled = disabledSet.has(slug);
@@ -35760,13 +36458,13 @@ init_fs();
35760
36458
  init_config2();
35761
36459
  init_slug();
35762
36460
  import { Command as Command2 } from "commander";
35763
- import { readFile as readFile52 } from "fs/promises";
36461
+ import { readFile as readFile54 } from "fs/promises";
35764
36462
  import { resolve as resolve79 } from "path";
35765
36463
 
35766
36464
  // src/commands/bundle.ts
35767
36465
  init_paths();
35768
36466
  import { Command } from "commander";
35769
- import { mkdir as mkdir10, readFile as readFile51, readdir as readdir28, rm as rm9, writeFile as writeFile13 } from "fs/promises";
36467
+ import { mkdir as mkdir11, readFile as readFile53, readdir as readdir29, rm as rm9, writeFile as writeFile14 } from "fs/promises";
35770
36468
  import { resolve as resolve78 } from "path";
35771
36469
  init_parser2();
35772
36470
  init_fs();
@@ -36059,7 +36757,7 @@ bundleCommand.command("plan").description("Create or open the bundle's shared pl
36059
36757
  }
36060
36758
  const planDir = bundlePlanDir(sc.todosPath, sc.scopeId, id);
36061
36759
  await ensureDir(planDir);
36062
- const existing = (await readdir28(planDir).catch(() => [])).filter((f) => /^plan(?:-v\d+)?\.md$/.test(f));
36760
+ const existing = (await readdir29(planDir).catch(() => [])).filter((f) => /^plan(?:-v\d+)?\.md$/.test(f));
36063
36761
  const { target } = pickNextPlanFile(planDir, existing);
36064
36762
  const checklist = await readChecklist(sc.todosPath, sc.checklistKey);
36065
36763
  if (!await fileExists(target)) {
@@ -36128,8 +36826,8 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
36128
36826
  }
36129
36827
  const bundlesFilePath = bundlesPath(sc.todosPath);
36130
36828
  const checklistFilePath = checklistPath(sc.todosPath, sc.checklistKey);
36131
- const bundlesSnapshot = await fileExists(bundlesFilePath) ? await readFile51(bundlesFilePath, "utf-8") : null;
36132
- const checklistSnapshot = await fileExists(checklistFilePath) ? await readFile51(checklistFilePath, "utf-8") : null;
36829
+ const bundlesSnapshot = await fileExists(bundlesFilePath) ? await readFile53(bundlesFilePath, "utf-8") : null;
36830
+ const checklistSnapshot = await fileExists(checklistFilePath) ? await readFile53(checklistFilePath, "utf-8") : null;
36133
36831
  const record = async () => {
36134
36832
  bundle.branch = options.branch;
36135
36833
  bundle.worktreePath = worktreePath;
@@ -36146,7 +36844,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
36146
36844
  await writeBundles(sc.todosPath, bundles);
36147
36845
  await writeChecklist(sc.todosPath, checklist);
36148
36846
  const ctxDir = resolve78(worktreePath, ".syntaur");
36149
- await mkdir10(ctxDir, { recursive: true });
36847
+ await mkdir11(ctxDir, { recursive: true });
36150
36848
  const payload = {
36151
36849
  bundleId: bundle.id,
36152
36850
  bundleSlug: bundle.slug,
@@ -36159,7 +36857,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
36159
36857
  repository,
36160
36858
  boundAt: nowISO()
36161
36859
  };
36162
- await writeFile13(resolve78(ctxDir, "context.json"), JSON.stringify(payload, null, 2) + "\n");
36860
+ await writeFile14(resolve78(ctxDir, "context.json"), JSON.stringify(payload, null, 2) + "\n");
36163
36861
  } catch (err2) {
36164
36862
  try {
36165
36863
  if (bundlesSnapshot === null) {
@@ -36685,7 +37383,7 @@ todoCommand.command("archive").description("Archive completed todos and their lo
36685
37383
  await ensureDir(resolve79(todosPath, "archive"));
36686
37384
  let archContent = "";
36687
37385
  if (await fileExists(archFile)) {
36688
- archContent = await readFile52(archFile, "utf-8");
37386
+ archContent = await readFile54(archFile, "utf-8");
36689
37387
  archContent = archContent.trimEnd() + "\n\n";
36690
37388
  } else {
36691
37389
  archContent = `---
@@ -36863,12 +37561,12 @@ function describeScope(scope) {
36863
37561
  }
36864
37562
  async function injectPromotedTodos(assignmentDir, todos, scopeLabel) {
36865
37563
  const { resolve: resolvePath2 } = await import("path");
36866
- const { readFile: readFile82 } = await import("fs/promises");
37564
+ const { readFile: readFile85 } = await import("fs/promises");
36867
37565
  const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
36868
37566
  const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
36869
37567
  const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
36870
37568
  const assignmentMdPath2 = resolvePath2(assignmentDir, "assignment.md");
36871
- let content = await readFile82(assignmentMdPath2, "utf-8");
37569
+ let content = await readFile85(assignmentMdPath2, "utf-8");
36872
37570
  content = appendTodosToAssignmentBody2(
36873
37571
  content,
36874
37572
  todos.map((t) => ({
@@ -36913,8 +37611,8 @@ todoCommand.command("plan").description("Create or open a plan directory for a t
36913
37611
  }
36914
37612
  const planDir = todoPlanDir(todosPath, workspace, id);
36915
37613
  await ensureDir(planDir);
36916
- const { readdir: readdir41 } = await import("fs/promises");
36917
- const existingFiles = (await readdir41(planDir).catch(() => [])).filter(
37614
+ const { readdir: readdir42 } = await import("fs/promises");
37615
+ const existingFiles = (await readdir42(planDir).catch(() => [])).filter(
36918
37616
  (f) => /^plan(?:-v\d+)?\.md$/.test(f)
36919
37617
  );
36920
37618
  let target;
@@ -37004,9 +37702,9 @@ async function moveTodo(id, options) {
37004
37702
  if (await fileExists(newPlanDir)) {
37005
37703
  throw new Error(`Plan directory already exists at target: ${newPlanDir}; refusing to move.`);
37006
37704
  }
37007
- const { rename: rename11, mkdir: mkdir13 } = await import("fs/promises");
37008
- const { dirname: dirname30 } = await import("path");
37009
- await mkdir13(dirname30(newPlanDir), { recursive: true });
37705
+ const { rename: rename11, mkdir: mkdir14 } = await import("fs/promises");
37706
+ const { dirname: dirname31 } = await import("path");
37707
+ await mkdir14(dirname31(newPlanDir), { recursive: true });
37010
37708
  await rename11(item.planDir, newPlanDir);
37011
37709
  item.planDir = newPlanDir;
37012
37710
  }
@@ -37123,13 +37821,13 @@ backupCommand.command("config").description("Show or update backup configuration
37123
37821
 
37124
37822
  // src/commands/doctor.ts
37125
37823
  import { Command as Command4 } from "commander";
37126
- import { readFile as readFile64 } from "fs/promises";
37127
- import { isAbsolute as isAbsolute11, resolve as resolve93 } from "path";
37824
+ import { readFile as readFile66 } from "fs/promises";
37825
+ import { isAbsolute as isAbsolute12, resolve as resolve93 } from "path";
37128
37826
 
37129
37827
  // src/utils/doctor/index.ts
37130
37828
  import { fileURLToPath as fileURLToPath12 } from "url";
37131
- import { readFile as readFile63 } from "fs/promises";
37132
- import { dirname as dirname25, join as join22 } from "path";
37829
+ import { readFile as readFile65 } from "fs/promises";
37830
+ import { dirname as dirname26, join as join24 } from "path";
37133
37831
 
37134
37832
  // src/utils/doctor/context.ts
37135
37833
  init_config2();
@@ -37174,10 +37872,10 @@ function closeCheckContext(ctx) {
37174
37872
  // src/utils/doctor/checks/env.ts
37175
37873
  init_fs();
37176
37874
  init_paths();
37177
- import { resolve as resolve81, isAbsolute as isAbsolute9 } from "path";
37178
- import { readFile as readFile53, stat as stat9 } from "fs/promises";
37875
+ import { resolve as resolve81, isAbsolute as isAbsolute10 } from "path";
37876
+ import { readFile as readFile55, stat as stat10 } from "fs/promises";
37179
37877
  import { fileURLToPath as fileURLToPath10 } from "url";
37180
- import { dirname as dirname22, join as join18 } from "path";
37878
+ import { dirname as dirname23, join as join20 } from "path";
37181
37879
  var CATEGORY = "env";
37182
37880
  var syntaurRootExists = {
37183
37881
  id: "env.syntaur-root-exists",
@@ -37185,7 +37883,7 @@ var syntaurRootExists = {
37185
37883
  title: "~/.syntaur/ directory exists",
37186
37884
  async run(ctx) {
37187
37885
  try {
37188
- const s = await stat9(ctx.syntaurRoot);
37886
+ const s = await stat10(ctx.syntaurRoot);
37189
37887
  if (!s.isDirectory()) {
37190
37888
  return err(this, `${ctx.syntaurRoot} exists but is not a directory`, [
37191
37889
  ctx.syntaurRoot
@@ -37232,7 +37930,7 @@ var configValid = {
37232
37930
  autoFixable: false
37233
37931
  };
37234
37932
  }
37235
- const content = await readFile53(configPath2, "utf-8");
37933
+ const content = await readFile55(configPath2, "utf-8");
37236
37934
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
37237
37935
  if (!fmMatch || fmMatch[1].trim() === "") {
37238
37936
  return {
@@ -37269,7 +37967,7 @@ var configValid = {
37269
37967
  };
37270
37968
  }
37271
37969
  const expanded = expandHome(rawProjectDir);
37272
- if (!isAbsolute9(expanded)) {
37970
+ if (!isAbsolute10(expanded)) {
37273
37971
  return {
37274
37972
  id: this.id,
37275
37973
  category: this.category,
@@ -37508,14 +38206,14 @@ async function readLocalVersion() {
37508
38206
  async function readLocalPkg() {
37509
38207
  try {
37510
38208
  const here = fileURLToPath10(import.meta.url);
37511
- let dir = dirname22(here);
38209
+ let dir = dirname23(here);
37512
38210
  for (let i = 0; i < 6; i++) {
37513
- const candidate = join18(dir, "package.json");
38211
+ const candidate = join20(dir, "package.json");
37514
38212
  try {
37515
- const text = await readFile53(candidate, "utf-8");
38213
+ const text = await readFile55(candidate, "utf-8");
37516
38214
  return JSON.parse(text);
37517
38215
  } catch {
37518
- dir = dirname22(dir);
38216
+ dir = dirname23(dir);
37519
38217
  }
37520
38218
  }
37521
38219
  return null;
@@ -37565,7 +38263,7 @@ function versionGte(a, b) {
37565
38263
  // src/utils/doctor/checks/structure.ts
37566
38264
  init_fs();
37567
38265
  import { resolve as resolve82 } from "path";
37568
- import { readdir as readdir29, stat as stat10 } from "fs/promises";
38266
+ import { readdir as readdir30, stat as stat11 } from "fs/promises";
37569
38267
  var CATEGORY2 = "structure";
37570
38268
  var KNOWN_TOP_LEVEL = /* @__PURE__ */ new Set([
37571
38269
  "projects",
@@ -37645,7 +38343,7 @@ var todosDirValid = {
37645
38343
  autoFixable: false
37646
38344
  };
37647
38345
  }
37648
- const s = await stat10(p);
38346
+ const s = await stat11(p);
37649
38347
  if (!s.isDirectory()) {
37650
38348
  return {
37651
38349
  id: this.id,
@@ -37676,7 +38374,7 @@ var serversDirValid = {
37676
38374
  autoFixable: false
37677
38375
  };
37678
38376
  }
37679
- const s = await stat10(p);
38377
+ const s = await stat11(p);
37680
38378
  if (!s.isDirectory()) {
37681
38379
  return {
37682
38380
  id: this.id,
@@ -37696,7 +38394,7 @@ var knownFilesRecognized = {
37696
38394
  category: CATEGORY2,
37697
38395
  title: "No unexpected top-level entries under ~/.syntaur/",
37698
38396
  async run(ctx) {
37699
- const entries = await readdir29(ctx.syntaurRoot, { withFileTypes: true });
38397
+ const entries = await readdir30(ctx.syntaurRoot, { withFileTypes: true });
37700
38398
  const unexpected = [];
37701
38399
  for (const e of entries) {
37702
38400
  if (e.name.startsWith(".")) continue;
@@ -37740,7 +38438,7 @@ function pass2(check) {
37740
38438
  // src/utils/doctor/checks/project.ts
37741
38439
  init_fs();
37742
38440
  import { resolve as resolve83 } from "path";
37743
- import { readdir as readdir30, stat as stat11 } from "fs/promises";
38441
+ import { readdir as readdir31, stat as stat12 } from "fs/promises";
37744
38442
  var CATEGORY3 = "project";
37745
38443
  var REQUIRED_PROJECT_FILES = [
37746
38444
  "project.md",
@@ -37764,7 +38462,7 @@ var PROJECT_MARKERS = ["project.md", "manifest.md", "assignments"];
37764
38462
  async function listProjects2(ctx) {
37765
38463
  const dir = ctx.config.defaultProjectDir;
37766
38464
  if (!await fileExists(dir)) return [];
37767
- const entries = await readdir30(dir, { withFileTypes: true });
38465
+ const entries = await readdir31(dir, { withFileTypes: true });
37768
38466
  const result = [];
37769
38467
  for (const e of entries) {
37770
38468
  if (!e.isDirectory()) continue;
@@ -37826,7 +38524,7 @@ var manifestStale = {
37826
38524
  for (const projectDir of projects) {
37827
38525
  const manifestPath = resolve83(projectDir, "manifest.md");
37828
38526
  if (!await fileExists(manifestPath)) continue;
37829
- const manifestMtime = (await stat11(manifestPath)).mtimeMs;
38527
+ const manifestMtime = (await stat12(manifestPath)).mtimeMs;
37830
38528
  const newestAssignment = await newestAssignmentMtime(projectDir);
37831
38529
  if (newestAssignment === 0) continue;
37832
38530
  if (newestAssignment > manifestMtime) {
@@ -37858,7 +38556,7 @@ var orphanFiles = {
37858
38556
  const projects = await listProjects2(ctx);
37859
38557
  const results = [];
37860
38558
  for (const projectDir of projects) {
37861
- const entries = await readdir30(projectDir, { withFileTypes: true });
38559
+ const entries = await readdir31(projectDir, { withFileTypes: true });
37862
38560
  const orphans = [];
37863
38561
  for (const e of entries) {
37864
38562
  if (e.name.startsWith(".")) continue;
@@ -37888,7 +38586,7 @@ async function newestAssignmentMtime(projectDir) {
37888
38586
  let newest = 0;
37889
38587
  let entries;
37890
38588
  try {
37891
- entries = await readdir30(assignmentsRoot, { withFileTypes: true });
38589
+ entries = await readdir31(assignmentsRoot, { withFileTypes: true });
37892
38590
  } catch {
37893
38591
  return 0;
37894
38592
  }
@@ -37896,7 +38594,7 @@ async function newestAssignmentMtime(projectDir) {
37896
38594
  if (!e.isDirectory()) continue;
37897
38595
  const assignmentMd = resolve83(assignmentsRoot, e.name, "assignment.md");
37898
38596
  try {
37899
- const s = await stat11(assignmentMd);
38597
+ const s = await stat12(assignmentMd);
37900
38598
  if (s.mtimeMs > newest) newest = s.mtimeMs;
37901
38599
  } catch {
37902
38600
  }
@@ -37920,7 +38618,7 @@ init_types();
37920
38618
  init_paths();
37921
38619
  init_assignment_walk();
37922
38620
  import { resolve as resolve84 } from "path";
37923
- import { readFile as readFile54, readdir as readdir31 } from "fs/promises";
38621
+ import { readFile as readFile56, readdir as readdir32 } from "fs/promises";
37924
38622
  var CATEGORY4 = "assignment";
37925
38623
  var STATUSES_REQUIRING_HANDOFF = /* @__PURE__ */ new Set(["review", "completed"]);
37926
38624
  var PRE_WORKSPACE_STATUSES = /* @__PURE__ */ new Set([
@@ -38268,7 +38966,7 @@ var draftMissingObjective = {
38268
38966
  if (parsed.status !== "draft") continue;
38269
38967
  let raw2;
38270
38968
  try {
38271
- raw2 = await readFile54(path, "utf-8");
38969
+ raw2 = await readFile56(path, "utf-8");
38272
38970
  } catch {
38273
38971
  continue;
38274
38972
  }
@@ -38305,12 +39003,12 @@ var readyToImplementMissingPlan = {
38305
39003
  const parsed = await parseSafe4(path);
38306
39004
  if (!parsed) continue;
38307
39005
  if (parsed.status !== "ready_to_implement") continue;
38308
- const entries = await readdir31(a.assignmentDir).catch(() => []);
39006
+ const entries = await readdir32(a.assignmentDir).catch(() => []);
38309
39007
  const planFiles = entries.filter((f) => /^plan(?:-v\d+)?\.md$/i.test(f));
38310
39008
  let hasPlanContent = false;
38311
39009
  for (const f of planFiles) {
38312
39010
  try {
38313
- const c2 = await readFile54(resolve84(a.assignmentDir, f), "utf-8");
39011
+ const c2 = await readFile56(resolve84(a.assignmentDir, f), "utf-8");
38314
39012
  if (c2.trim().length > 0) {
38315
39013
  hasPlanContent = true;
38316
39014
  break;
@@ -38353,7 +39051,7 @@ var assignmentChecks = [
38353
39051
  ];
38354
39052
  async function parseSafe4(path) {
38355
39053
  try {
38356
- const content = await readFile54(path, "utf-8");
39054
+ const content = await readFile56(path, "utf-8");
38357
39055
  return parseAssignmentFull(content);
38358
39056
  } catch {
38359
39057
  return null;
@@ -38515,9 +39213,9 @@ function skipped(check, reason) {
38515
39213
 
38516
39214
  // src/utils/doctor/checks/integrations.ts
38517
39215
  init_fs();
38518
- import { resolve as resolve86, dirname as dirname23, basename as basename9 } from "path";
38519
- import { readdir as readdir32, readFile as readFile55 } from "fs/promises";
38520
- import { homedir as homedir14 } from "os";
39216
+ import { resolve as resolve86, dirname as dirname24, basename as basename10 } from "path";
39217
+ import { readdir as readdir33, readFile as readFile57 } from "fs/promises";
39218
+ import { homedir as homedir16 } from "os";
38521
39219
  var CATEGORY6 = "integrations";
38522
39220
  var claudePluginLinked = {
38523
39221
  id: "integrations.claude-plugin-linked",
@@ -38579,7 +39277,7 @@ var backupConfigured = {
38579
39277
  if (ctx.config.backup?.repo) return pass6(this);
38580
39278
  const projectsDir2 = ctx.config.defaultProjectDir;
38581
39279
  if (!await fileExists(projectsDir2)) return skipped2(this, "no projects dir");
38582
- const entries = await readdir32(projectsDir2, { withFileTypes: true });
39280
+ const entries = await readdir33(projectsDir2, { withFileTypes: true });
38583
39281
  const hasProjects = entries.some((e) => e.isDirectory() && !e.name.startsWith(".") && !e.name.startsWith("_"));
38584
39282
  if (!hasProjects) return skipped2(this, "no projects yet");
38585
39283
  return {
@@ -38598,10 +39296,10 @@ var backupConfigured = {
38598
39296
  }
38599
39297
  };
38600
39298
  async function readKnownMarketplaces() {
38601
- const path = resolve86(homedir14(), ".claude", "plugins", "known_marketplaces.json");
39299
+ const path = resolve86(homedir16(), ".claude", "plugins", "known_marketplaces.json");
38602
39300
  if (!await fileExists(path)) return {};
38603
39301
  try {
38604
- const raw2 = await readFile55(path, "utf-8");
39302
+ const raw2 = await readFile57(path, "utf-8");
38605
39303
  return JSON.parse(raw2);
38606
39304
  } catch {
38607
39305
  return {};
@@ -38617,8 +39315,8 @@ var claudeMarketplaceRegistered = {
38617
39315
  if (!await fileExists(dir)) {
38618
39316
  return skipped2(this, "claudePluginDir does not exist (run install-plugin)");
38619
39317
  }
38620
- const pluginsParent = dirname23(dir);
38621
- if (basename9(pluginsParent) !== "plugins") {
39318
+ const pluginsParent = dirname24(dir);
39319
+ if (basename10(pluginsParent) !== "plugins") {
38622
39320
  return {
38623
39321
  id: this.id,
38624
39322
  category: this.category,
@@ -38634,7 +39332,7 @@ var claudeMarketplaceRegistered = {
38634
39332
  autoFixable: false
38635
39333
  };
38636
39334
  }
38637
- const marketplaceRoot = dirname23(pluginsParent);
39335
+ const marketplaceRoot = dirname24(pluginsParent);
38638
39336
  const marketplaceManifest = resolve86(marketplaceRoot, ".claude-plugin", "marketplace.json");
38639
39337
  if (!await fileExists(marketplaceManifest)) {
38640
39338
  return {
@@ -38654,7 +39352,7 @@ var claudeMarketplaceRegistered = {
38654
39352
  }
38655
39353
  let parsed = {};
38656
39354
  try {
38657
- parsed = JSON.parse(await readFile55(marketplaceManifest, "utf-8"));
39355
+ parsed = JSON.parse(await readFile57(marketplaceManifest, "utf-8"));
38658
39356
  } catch {
38659
39357
  return {
38660
39358
  id: this.id,
@@ -38666,7 +39364,7 @@ var claudeMarketplaceRegistered = {
38666
39364
  autoFixable: false
38667
39365
  };
38668
39366
  }
38669
- const marketplaceName = parsed.name ?? basename9(marketplaceRoot);
39367
+ const marketplaceName = parsed.name ?? basename10(marketplaceRoot);
38670
39368
  const hasSyntaurEntry = (parsed.plugins ?? []).some((p) => p?.name === "syntaur");
38671
39369
  const known = await readKnownMarketplaces();
38672
39370
  const registered = known[marketplaceName]?.installLocation === marketplaceRoot || Object.values(known).some((v) => v.installLocation === marketplaceRoot);
@@ -38686,7 +39384,7 @@ var claudeMarketplaceRegistered = {
38686
39384
  title: this.title,
38687
39385
  status: "error",
38688
39386
  detail: issues.join("; "),
38689
- affected: [marketplaceManifest, resolve86(homedir14(), ".claude", "plugins", "known_marketplaces.json")],
39387
+ affected: [marketplaceManifest, resolve86(homedir16(), ".claude", "plugins", "known_marketplaces.json")],
38690
39388
  remediation: {
38691
39389
  kind: "manual",
38692
39390
  suggestion: "Re-run install-plugin to ensure both files are in sync.",
@@ -38727,7 +39425,7 @@ init_fs();
38727
39425
  init_parser();
38728
39426
  init_types();
38729
39427
  import { resolve as resolve87 } from "path";
38730
- import { readFile as readFile56 } from "fs/promises";
39428
+ import { readFile as readFile58 } from "fs/promises";
38731
39429
  var CATEGORY7 = "workspace";
38732
39430
  var ASSIGNMENT_FIELDS2 = ["projectSlug", "assignmentSlug", "projectDir", "assignmentDir"];
38733
39431
  var BUNDLE_FIELDS = ["bundleId", "bundleScope", "bundleScopeId"];
@@ -38759,7 +39457,7 @@ async function loadContext(ctx) {
38759
39457
  return { data: null, path, exists: false, parseError: null };
38760
39458
  }
38761
39459
  try {
38762
- const raw2 = await readFile56(path, "utf-8");
39460
+ const raw2 = await readFile58(path, "utf-8");
38763
39461
  return { data: JSON.parse(raw2), path, exists: true, parseError: null };
38764
39462
  } catch (err2) {
38765
39463
  return {
@@ -38871,7 +39569,7 @@ var contextTerminal = {
38871
39569
  const assignmentMd = resolve87(data.assignmentDir, "assignment.md");
38872
39570
  if (!await fileExists(assignmentMd)) return skipped3(this, "assignment file missing");
38873
39571
  try {
38874
- const content = await readFile56(assignmentMd, "utf-8");
39572
+ const content = await readFile58(assignmentMd, "utf-8");
38875
39573
  const parsed = parseAssignmentFull(content);
38876
39574
  const terminal = terminalStatuses2(ctx);
38877
39575
  if (terminal.has(parsed.status)) {
@@ -38925,8 +39623,8 @@ function skipped3(check, reason) {
38925
39623
 
38926
39624
  // src/utils/doctor/checks/agents.ts
38927
39625
  init_config2();
38928
- import { isAbsolute as isAbsolute10 } from "path";
38929
- import { access as access2, constants as fsConstants } from "fs/promises";
39626
+ import { isAbsolute as isAbsolute11 } from "path";
39627
+ import { access as access5, constants as fsConstants } from "fs/promises";
38930
39628
  import { spawnSync as spawnSync8 } from "child_process";
38931
39629
  var CATEGORY8 = "agents";
38932
39630
  var agentsResolvable = {
@@ -38971,9 +39669,9 @@ async function checkAgent(agent) {
38971
39669
  autoFixable: false
38972
39670
  };
38973
39671
  }
38974
- if (isAbsolute10(agent.command)) {
39672
+ if (isAbsolute11(agent.command)) {
38975
39673
  try {
38976
- await access2(agent.command, fsConstants.X_OK);
39674
+ await access5(agent.command, fsConstants.X_OK);
38977
39675
  return { ...base, status: "pass", autoFixable: false };
38978
39676
  } catch (err2) {
38979
39677
  const code = err2.code;
@@ -39017,7 +39715,7 @@ var agentChecks = [agentsResolvable];
39017
39715
  // src/utils/doctor/checks/terminal.ts
39018
39716
  init_config2();
39019
39717
  import { spawnSync as spawnSync9 } from "child_process";
39020
- import { readFile as readFile57 } from "fs/promises";
39718
+ import { readFile as readFile59 } from "fs/promises";
39021
39719
  import { resolve as resolve88 } from "path";
39022
39720
  init_paths();
39023
39721
  init_fs();
@@ -39025,7 +39723,7 @@ var CATEGORY9 = "terminal";
39025
39723
  async function readRawTerminalKey() {
39026
39724
  const configPath2 = resolve88(syntaurRoot(), "config.md");
39027
39725
  if (!await fileExists(configPath2)) return null;
39028
- const content = await readFile57(configPath2, "utf-8");
39726
+ const content = await readFile59(configPath2, "utf-8");
39029
39727
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
39030
39728
  if (!fmMatch) return null;
39031
39729
  const line = fmMatch[1].split("\n").find((l) => /^terminal:\s*/.test(l));
@@ -39175,13 +39873,13 @@ var terminalChecks = [
39175
39873
 
39176
39874
  // src/utils/doctor/checks/skills.ts
39177
39875
  init_fs();
39178
- import { resolve as resolve89, join as join19 } from "path";
39179
- import { readdir as readdir33, readFile as readFile58, lstat as lstat4 } from "fs/promises";
39180
- import { homedir as homedir15 } from "os";
39876
+ import { resolve as resolve89, join as join21 } from "path";
39877
+ import { readdir as readdir34, readFile as readFile60, lstat as lstat4 } from "fs/promises";
39878
+ import { homedir as homedir17 } from "os";
39181
39879
  var CATEGORY10 = "skills";
39182
39880
  var skillTargets = [
39183
- { agent: "claude", dir: resolve89(homedir15(), ".claude", "skills"), label: "~/.claude/skills" },
39184
- { agent: "codex", dir: resolve89(homedir15(), ".codex", "skills"), label: "~/.codex/skills" }
39881
+ { agent: "claude", dir: resolve89(homedir17(), ".claude", "skills"), label: "~/.claude/skills" },
39882
+ { agent: "codex", dir: resolve89(homedir17(), ".codex", "skills"), label: "~/.codex/skills" }
39185
39883
  ];
39186
39884
  var skillsDedupCheck = {
39187
39885
  id: "skills.dedup",
@@ -39196,21 +39894,21 @@ var skillsDedupCheck = {
39196
39894
  const present = [];
39197
39895
  let entries;
39198
39896
  try {
39199
- entries = await readdir33(dir, { withFileTypes: true });
39897
+ entries = await readdir34(dir, { withFileTypes: true });
39200
39898
  } catch {
39201
39899
  continue;
39202
39900
  }
39203
39901
  for (const entry of entries) {
39204
39902
  if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
39205
39903
  if (!KNOWN_SKILLS.includes(entry.name)) continue;
39206
- const skillMd = join19(dir, entry.name, "SKILL.md");
39904
+ const skillMd = join21(dir, entry.name, "SKILL.md");
39207
39905
  if (!await fileExists(skillMd)) continue;
39208
- const content = await readFile58(skillMd, "utf-8").catch(() => "");
39906
+ const content = await readFile60(skillMd, "utf-8").catch(() => "");
39209
39907
  const match = content.match(/^name:\s*(\S+)\s*$/m);
39210
39908
  if (!match || match[1] !== entry.name) continue;
39211
39909
  let isSymlink2 = false;
39212
39910
  try {
39213
- isSymlink2 = (await lstat4(join19(dir, entry.name))).isSymbolicLink();
39911
+ isSymlink2 = (await lstat4(join21(dir, entry.name))).isSymbolicLink();
39214
39912
  } catch {
39215
39913
  }
39216
39914
  present.push({ name: entry.name, isSymlink: isSymlink2 });
@@ -39222,7 +39920,7 @@ var skillsDedupCheck = {
39222
39920
  findings.push(
39223
39921
  `${label}: ${nonSymlink.length} syntaur skill(s) installed globally while the syntaur plugin is enabled (${agent}) \u2014 duplicate registrations`
39224
39922
  );
39225
- for (const p of nonSymlink) affected.push(join19(dir, p.name));
39923
+ for (const p of nonSymlink) affected.push(join21(dir, p.name));
39226
39924
  }
39227
39925
  }
39228
39926
  }
@@ -39255,12 +39953,12 @@ var skillsChecks = [skillsDedupCheck];
39255
39953
 
39256
39954
  // src/utils/doctor/checks/cross-agent.ts
39257
39955
  init_fs();
39258
- import { join as join20, resolve as resolve90 } from "path";
39259
- import { readFile as readFile60 } from "fs/promises";
39956
+ import { join as join22, resolve as resolve90 } from "path";
39957
+ import { readFile as readFile62 } from "fs/promises";
39260
39958
 
39261
39959
  // src/utils/skill-frontmatter.ts
39262
39960
  import { createHash as createHash4 } from "crypto";
39263
- import { readFile as readFile59 } from "fs/promises";
39961
+ import { readFile as readFile61 } from "fs/promises";
39264
39962
  function stripQuotes(raw2) {
39265
39963
  const t = raw2.trim();
39266
39964
  if (t.length >= 2 && (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'"))) {
@@ -39304,7 +40002,7 @@ function readSkillIdentity(skillMdText) {
39304
40002
  return { name, hasDescription };
39305
40003
  }
39306
40004
  async function sha256File(path) {
39307
- return createHash4("sha256").update(await readFile59(path)).digest("hex");
40005
+ return createHash4("sha256").update(await readFile61(path)).digest("hex");
39308
40006
  }
39309
40007
 
39310
40008
  // src/utils/doctor/checks/cross-agent.ts
@@ -39314,14 +40012,14 @@ async function checkTargetSkillsIntegrity(installedDir, canonicalSkillsDir, know
39314
40012
  const problems = [];
39315
40013
  let valid = 0;
39316
40014
  for (const skill of knownSkills) {
39317
- const installedPath = join20(installedDir, skill, "SKILL.md");
40015
+ const installedPath = join22(installedDir, skill, "SKILL.md");
39318
40016
  if (!await fileExists(installedPath)) {
39319
40017
  problems.push({ skill, kind: "missing" });
39320
40018
  continue;
39321
40019
  }
39322
40020
  let text;
39323
40021
  try {
39324
- text = await readFile60(installedPath, "utf-8");
40022
+ text = await readFile62(installedPath, "utf-8");
39325
40023
  } catch {
39326
40024
  problems.push({ skill, kind: "invalid-frontmatter" });
39327
40025
  continue;
@@ -39332,7 +40030,7 @@ async function checkTargetSkillsIntegrity(installedDir, canonicalSkillsDir, know
39332
40030
  continue;
39333
40031
  }
39334
40032
  valid++;
39335
- const canonicalPath2 = join20(canonicalSkillsDir, skill, "SKILL.md");
40033
+ const canonicalPath2 = join22(canonicalSkillsDir, skill, "SKILL.md");
39336
40034
  if (await fileExists(canonicalPath2)) {
39337
40035
  const [installedHash, canonicalHash] = await Promise.all([
39338
40036
  sha256File(installedPath),
@@ -39407,7 +40105,7 @@ var crossAgentSkillsCheck = {
39407
40105
  }
39408
40106
  if (t.tier3) {
39409
40107
  const installDir = t.tier3.installDir();
39410
- const installed2 = await fileExists(join20(installDir, t.tier3.entry));
40108
+ const installed2 = await fileExists(join22(installDir, t.tier3.entry));
39411
40109
  lines.push(
39412
40110
  `${t.displayName}: Tier-3 ${t.tier3.kind} ${installed2 ? "installed" : "absent"} (${installDir})`
39413
40111
  );
@@ -39475,7 +40173,7 @@ var crossAgentChecks = [crossAgentSkillsCheck];
39475
40173
  init_fs();
39476
40174
  init_paths();
39477
40175
  import { resolve as resolve91 } from "path";
39478
- import { readdir as readdir34 } from "fs/promises";
40176
+ import { readdir as readdir35 } from "fs/promises";
39479
40177
  import { spawnSync as spawnSync10 } from "child_process";
39480
40178
  init_parser2();
39481
40179
  var CATEGORY12 = "bundles";
@@ -39483,7 +40181,7 @@ async function listScopes(ctx) {
39483
40181
  const out = [];
39484
40182
  const td = todosDir();
39485
40183
  if (await fileExists(td)) {
39486
- const entries = await readdir34(td).catch(() => []);
40184
+ const entries = await readdir35(td).catch(() => []);
39487
40185
  for (const f of entries) {
39488
40186
  if (typeof f !== "string") continue;
39489
40187
  if (!f.endsWith(".md") || f.endsWith("-log.md")) continue;
@@ -39499,7 +40197,7 @@ async function listScopes(ctx) {
39499
40197
  }
39500
40198
  }
39501
40199
  if (await fileExists(ctx.config.defaultProjectDir)) {
39502
- const projectEntries = await readdir34(ctx.config.defaultProjectDir, { withFileTypes: true }).catch(() => []);
40200
+ const projectEntries = await readdir35(ctx.config.defaultProjectDir, { withFileTypes: true }).catch(() => []);
39503
40201
  for (const e of projectEntries) {
39504
40202
  if (!e.isDirectory()) continue;
39505
40203
  const slug = e.name;
@@ -39697,21 +40395,21 @@ var bundleChecks = [
39697
40395
  ];
39698
40396
 
39699
40397
  // src/utils/doctor/checks/plugin.ts
39700
- import { readFile as readFile61 } from "fs/promises";
39701
- import { dirname as dirname24, join as join21 } from "path";
40398
+ import { readFile as readFile63 } from "fs/promises";
40399
+ import { dirname as dirname25, join as join23 } from "path";
39702
40400
  import { fileURLToPath as fileURLToPath11 } from "url";
39703
40401
  var CATEGORY13 = "plugin";
39704
40402
  var PLUGIN_KINDS = ["claude", "codex"];
39705
40403
  async function readCliVersion() {
39706
40404
  try {
39707
- let dir = dirname24(fileURLToPath11(import.meta.url));
40405
+ let dir = dirname25(fileURLToPath11(import.meta.url));
39708
40406
  for (let i = 0; i < 8; i += 1) {
39709
40407
  try {
39710
- const parsed = JSON.parse(await readFile61(join21(dir, "package.json"), "utf-8"));
40408
+ const parsed = JSON.parse(await readFile63(join23(dir, "package.json"), "utf-8"));
39711
40409
  if (typeof parsed.version === "string" && parsed.version.length > 0) return parsed.version;
39712
40410
  } catch {
39713
40411
  }
39714
- dir = dirname24(dir);
40412
+ dir = dirname25(dir);
39715
40413
  }
39716
40414
  } catch {
39717
40415
  }
@@ -39818,7 +40516,7 @@ var deriveConfigChecks = [deriveConfigValid];
39818
40516
  // src/utils/doctor/checks/staleness.ts
39819
40517
  init_config2();
39820
40518
  import { resolve as resolve92 } from "path";
39821
- import { readFile as readFile62 } from "fs/promises";
40519
+ import { readFile as readFile64 } from "fs/promises";
39822
40520
  var CATEGORY15 = "staleness";
39823
40521
  var stalenessConfigValid = {
39824
40522
  id: "staleness.valid",
@@ -39827,7 +40525,7 @@ var stalenessConfigValid = {
39827
40525
  async run(ctx) {
39828
40526
  let content;
39829
40527
  try {
39830
- content = await readFile62(resolve92(ctx.syntaurRoot, "config.md"), "utf-8");
40528
+ content = await readFile64(resolve92(ctx.syntaurRoot, "config.md"), "utf-8");
39831
40529
  } catch {
39832
40530
  return {
39833
40531
  id: this.id,
@@ -39977,14 +40675,14 @@ async function finalize(checks) {
39977
40675
  async function readVersion() {
39978
40676
  try {
39979
40677
  const here = fileURLToPath12(import.meta.url);
39980
- let dir = dirname25(here);
40678
+ let dir = dirname26(here);
39981
40679
  for (let i = 0; i < 6; i++) {
39982
40680
  try {
39983
- const raw2 = await readFile63(join22(dir, "package.json"), "utf-8");
40681
+ const raw2 = await readFile65(join24(dir, "package.json"), "utf-8");
39984
40682
  const parsed = JSON.parse(raw2);
39985
40683
  return typeof parsed.version === "string" ? parsed.version : null;
39986
40684
  } catch {
39987
- dir = dirname25(dir);
40685
+ dir = dirname26(dir);
39988
40686
  }
39989
40687
  }
39990
40688
  return null;
@@ -40077,7 +40775,7 @@ var REQUIRED_WORKSPACE_FIELDS = [
40077
40775
  ];
40078
40776
  var ISO_DATE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;
40079
40777
  async function validateAssignmentFile(inputPath, cwd = process.cwd()) {
40080
- const absolute = isAbsolute11(inputPath) ? inputPath : resolve93(cwd, inputPath);
40778
+ const absolute = isAbsolute12(inputPath) ? inputPath : resolve93(cwd, inputPath);
40081
40779
  const errors = [];
40082
40780
  const warnings = [];
40083
40781
  if (!await fileExists(absolute)) {
@@ -40090,7 +40788,7 @@ async function validateAssignmentFile(inputPath, cwd = process.cwd()) {
40090
40788
  }
40091
40789
  let content;
40092
40790
  try {
40093
- content = await readFile64(absolute, "utf-8");
40791
+ content = await readFile66(absolute, "utf-8");
40094
40792
  } catch (err2) {
40095
40793
  return {
40096
40794
  ok: false,
@@ -40218,6 +40916,7 @@ note: ${FIX_NOOP_NOTE}
40218
40916
  init_config2();
40219
40917
  init_paths();
40220
40918
  import { Command as Command5 } from "commander";
40919
+ import { readFile as readFile67 } from "fs/promises";
40221
40920
  var agentsCommand = new Command5("agents").description(
40222
40921
  "Manage configurable agents used by `syntaur browse` and future launch flows"
40223
40922
  );
@@ -40237,6 +40936,8 @@ agentsCommand.command("list").description("List configured agents (or built-in d
40237
40936
  if (agent.launchPrompt) flags.push(`launchPrompt=${truncateForList(agent.launchPrompt)}`);
40238
40937
  if (agent.agentName) flags.push(`agentName=${agent.agentName}`);
40239
40938
  if (agent.workdir) flags.push(`workdir=${truncateForList(agent.workdir)}`);
40939
+ if (agent.runner) flags.push(`runner=${agent.runner}`);
40940
+ if (agent.sourcePath) flags.push(`source=${truncateForList(agent.sourcePath)}`);
40240
40941
  const flagStr = flags.length > 0 ? ` [${flags.join(", ")}]` : "";
40241
40942
  const args = agent.args && agent.args.length > 0 ? ` ${agent.args.join(" ")}` : "";
40242
40943
  console.log(` ${agent.id.padEnd(12)} ${agent.label.padEnd(20)} ${agent.command}${args}${flagStr}`);
@@ -40266,6 +40967,48 @@ agentsCommand.command("add").description("Add a new agent to ~/.syntaur/config.m
40266
40967
  reportAndExit(error);
40267
40968
  }
40268
40969
  });
40970
+ async function readInstructions(spec) {
40971
+ if (!spec) return "";
40972
+ if (spec.startsWith("@")) return readFile67(expandHome(spec.slice(1)), "utf-8");
40973
+ return spec;
40974
+ }
40975
+ agentsCommand.command("new").description("Author a runner-native agent def on disk and register it").requiredOption("--name <name>", "Display name").requiredOption("--type <runner>", "Runner: claude | pi | codex").option("--model <model>", "Model (claude agent frontmatter)").option("--description <text>", "One-line description").option("--instructions <text|@file>", "System prompt / instructions body, or @path to read from a file").option("--location <path>", "claude: agents dir (default ~/.claude/agents); directory: parent dir to scaffold under").option("--dry-run", "Author the def but do not register it").action(async (options) => {
40976
+ try {
40977
+ const runner = options.type;
40978
+ if (runner !== "claude" && runner !== "pi" && runner !== "codex") {
40979
+ throw new AgentConfigError(`invalid --type "${options.type}" \u2014 must be claude, pi, or codex`);
40980
+ }
40981
+ const instructions = await readInstructions(options.instructions);
40982
+ const authored = await authorAgentDef({
40983
+ name: options.name,
40984
+ runner,
40985
+ model: options.model,
40986
+ description: options.description,
40987
+ instructions,
40988
+ location: options.location
40989
+ });
40990
+ console.log(`Authored ${runner} def at ${authored.path}`);
40991
+ if (options.dryRun) {
40992
+ console.log("(dry-run: not registered)");
40993
+ return;
40994
+ }
40995
+ const config = await readConfig();
40996
+ const base = getAgents(config);
40997
+ const agent = buildRegisteredAgent({
40998
+ name: options.name,
40999
+ runner,
41000
+ sourceKind: authored.sourceKind,
41001
+ sourcePath: authored.path,
41002
+ sourceRepo: authored.sourceRepo,
41003
+ description: options.description,
41004
+ existingIds: base.map((a) => a.id)
41005
+ });
41006
+ await writeAgentsConfig([...base, agent]);
41007
+ console.log(`Registered agent "${agent.id}" (${runner}).`);
41008
+ } catch (error) {
41009
+ reportAndExit(error);
41010
+ }
41011
+ });
40269
41012
  agentsCommand.command("remove <id>").description("Remove an agent from ~/.syntaur/config.md").option("--dry-run", "Validate and print the proposed config without writing").action(async (id, options) => {
40270
41013
  try {
40271
41014
  const mutation = {
@@ -40505,7 +41248,7 @@ init_frontmatter();
40505
41248
  init_event_emit();
40506
41249
  init_templates();
40507
41250
  import { resolve as resolve94 } from "path";
40508
- import { readFile as readFile65 } from "fs/promises";
41251
+ import { readFile as readFile68 } from "fs/promises";
40509
41252
  function shortId() {
40510
41253
  return generateId().split("-")[0];
40511
41254
  }
@@ -40554,7 +41297,7 @@ async function commentCommand(target, text, options = {}) {
40554
41297
  let currentContent;
40555
41298
  let currentCount = 0;
40556
41299
  if (await fileExists(commentsPath)) {
40557
- currentContent = await readFile65(commentsPath, "utf-8");
41300
+ currentContent = await readFile68(commentsPath, "utf-8");
40558
41301
  const countMatch = currentContent.match(/^entryCount:\s*(\d+)/m);
40559
41302
  if (countMatch) currentCount = parseInt(countMatch[1], 10);
40560
41303
  } else {
@@ -40584,7 +41327,7 @@ ${entry}`;
40584
41327
  try {
40585
41328
  const assignmentMd = resolve94(assignmentDir, "assignment.md");
40586
41329
  if (await fileExists(assignmentMd)) {
40587
- const fm = parseAssignmentFrontmatter(await readFile65(assignmentMd, "utf-8"));
41330
+ const fm = parseAssignmentFrontmatter(await readFile68(assignmentMd, "utf-8"));
40588
41331
  emitEvent({
40589
41332
  assignmentId: fm.id,
40590
41333
  projectSlug,
@@ -40608,8 +41351,8 @@ ${entry}`;
40608
41351
  }
40609
41352
 
40610
41353
  // src/commands/capture.ts
40611
- import { resolve as resolve97, relative as relative4, dirname as dirname26 } from "path";
40612
- import { copyFile as copyFile3, mkdir as mkdir12, realpath as realpath2, rm as rm14, stat as stat14, writeFile as writeFile15 } from "fs/promises";
41354
+ import { resolve as resolve97, relative as relative4, dirname as dirname27 } from "path";
41355
+ import { copyFile as copyFile3, mkdir as mkdir13, realpath as realpath2, rm as rm14, stat as stat15, writeFile as writeFile16 } from "fs/promises";
40613
41356
  import { existsSync as existsSync7 } from "fs";
40614
41357
  init_session_id();
40615
41358
  init_session_db();
@@ -40618,9 +41361,9 @@ init_fs();
40618
41361
 
40619
41362
  // src/utils/screencapture.ts
40620
41363
  import { spawn as spawn8 } from "child_process";
40621
- import { mkdtemp as mkdtemp2, rm as rm10, stat as stat12 } from "fs/promises";
41364
+ import { mkdtemp as mkdtemp2, rm as rm10, stat as stat13 } from "fs/promises";
40622
41365
  import { tmpdir as tmpdir3 } from "os";
40623
- import { join as join23 } from "path";
41366
+ import { join as join25 } from "path";
40624
41367
  function argsFor(mode, pngPath) {
40625
41368
  switch (mode) {
40626
41369
  case "interactive":
@@ -40653,8 +41396,8 @@ async function captureScreenshot(mode) {
40653
41396
  "screencapture is only available on macOS. Use --file <path> to attach an existing image."
40654
41397
  );
40655
41398
  }
40656
- const tmpDir = await mkdtemp2(join23(tmpdir3(), "syntaur-screenshot-"));
40657
- const pngPath = join23(tmpDir, "shot.png");
41399
+ const tmpDir = await mkdtemp2(join25(tmpdir3(), "syntaur-screenshot-"));
41400
+ const pngPath = join25(tmpDir, "shot.png");
40658
41401
  const cleanup = async () => {
40659
41402
  await rm10(tmpDir, { recursive: true, force: true }).catch(() => {
40660
41403
  });
@@ -40676,7 +41419,7 @@ async function captureScreenshot(mode) {
40676
41419
  }
40677
41420
  let size = 0;
40678
41421
  try {
40679
- size = (await stat12(pngPath)).size;
41422
+ size = (await stat13(pngPath)).size;
40680
41423
  } catch {
40681
41424
  throw new Error("screencapture exited 0 but produced no image.");
40682
41425
  }
@@ -40692,9 +41435,9 @@ async function captureScreenshot(mode) {
40692
41435
 
40693
41436
  // src/utils/asciinema.ts
40694
41437
  import { spawn as spawn9 } from "child_process";
40695
- import { mkdtemp as mkdtemp3, readFile as readFile66, rm as rm11 } from "fs/promises";
41438
+ import { mkdtemp as mkdtemp3, readFile as readFile69, rm as rm11 } from "fs/promises";
40696
41439
  import { tmpdir as tmpdir4 } from "os";
40697
- import { join as join24 } from "path";
41440
+ import { join as join26 } from "path";
40698
41441
  var SAFE_RE = /^[A-Za-z0-9_@%+=:,./-]+$/;
40699
41442
  function shellQuote2(s) {
40700
41443
  if (s.length === 0) return `''`;
@@ -40731,8 +41474,8 @@ function runAsciinema(args, stdio) {
40731
41474
  });
40732
41475
  }
40733
41476
  async function captureAsciinema(opts) {
40734
- const tmpDir = await mkdtemp3(join24(tmpdir4(), "syntaur-asciinema-"));
40735
- const castPath = join24(tmpDir, "session.cast");
41477
+ const tmpDir = await mkdtemp3(join26(tmpdir4(), "syntaur-asciinema-"));
41478
+ const castPath = join26(tmpDir, "session.cast");
40736
41479
  const cleanup = async () => {
40737
41480
  await rm11(tmpDir, { recursive: true, force: true }).catch(() => {
40738
41481
  });
@@ -40755,7 +41498,7 @@ async function captureAsciinema(opts) {
40755
41498
  }
40756
41499
  throw err2;
40757
41500
  }
40758
- const text = await readFile66(castPath, "utf8").catch(() => null);
41501
+ const text = await readFile69(castPath, "utf8").catch(() => null);
40759
41502
  if (text === null) {
40760
41503
  throw new Error(
40761
41504
  `asciinema produced no cast file at ${castPath} (exit ${exitCode}). Try running 'asciinema rec ${castPath}' directly to diagnose.`
@@ -40783,9 +41526,9 @@ async function captureAsciinema(opts) {
40783
41526
  // src/utils/recording.ts
40784
41527
  init_paths();
40785
41528
  import { spawn as spawn10 } from "child_process";
40786
- import { mkdir as mkdir11, mkdtemp as mkdtemp4, open as open6, readFile as readFile67, rm as rm12, stat as stat13, unlink as unlink12, writeFile as writeFile14 } from "fs/promises";
41529
+ import { mkdir as mkdir12, mkdtemp as mkdtemp4, open as open6, readFile as readFile70, rm as rm12, stat as stat14, unlink as unlink12, writeFile as writeFile15 } from "fs/promises";
40787
41530
  import { tmpdir as tmpdir5 } from "os";
40788
- import { join as join25, resolve as resolve95 } from "path";
41531
+ import { join as join27, resolve as resolve95 } from "path";
40789
41532
  import { setTimeout as sleep } from "timers/promises";
40790
41533
  function sigintPollIntervalMs() {
40791
41534
  const raw2 = process.env.SYNTAUR_RECORDING_POLL_INTERVAL_MS;
@@ -40857,7 +41600,7 @@ async function acquirePidfile(pidfile) {
40857
41600
  } catch (err2) {
40858
41601
  if (err2.code !== "EEXIST") throw err2;
40859
41602
  if (attempt === 1) throw err2;
40860
- const existing = (await readFile67(pidfile, "utf-8").catch(() => "")).trim();
41603
+ const existing = (await readFile70(pidfile, "utf-8").catch(() => "")).trim();
40861
41604
  if (existing.startsWith(STARTING_SENTINEL_PREFIX)) {
40862
41605
  const parentPidRaw = existing.slice(STARTING_SENTINEL_PREFIX.length);
40863
41606
  const parentPid = Number.parseInt(parentPidRaw, 10);
@@ -40899,7 +41642,7 @@ async function startRecording(input4) {
40899
41642
  );
40900
41643
  }
40901
41644
  const root = syntaurRoot();
40902
- await mkdir11(root, { recursive: true });
41645
+ await mkdir12(root, { recursive: true });
40903
41646
  const pidfile = pidfilePath();
40904
41647
  const log = logPath2();
40905
41648
  const sidecar = sidecarPath();
@@ -40910,8 +41653,8 @@ async function startRecording(input4) {
40910
41653
  let acquiredPid = null;
40911
41654
  try {
40912
41655
  logHandle = await open6(log, "w");
40913
- tmpDir = await mkdtemp4(join25(tmpdir5(), "syntaur-recording-"));
40914
- const mp4Path = join25(tmpDir, "recording.mp4");
41656
+ tmpDir = await mkdtemp4(join27(tmpdir5(), "syntaur-recording-"));
41657
+ const mp4Path = join27(tmpDir, "recording.mp4");
40915
41658
  let child;
40916
41659
  try {
40917
41660
  child = spawn10("ffmpeg", ffmpegArgs(input4.device, input4.fps, mp4Path), {
@@ -40954,12 +41697,12 @@ async function startRecording(input4) {
40954
41697
  const pid = await pidReady;
40955
41698
  acquiredPid = pid;
40956
41699
  child.unref();
40957
- await writeFile14(pidfile, String(pid));
41700
+ await writeFile15(pidfile, String(pid));
40958
41701
  await logHandle.close();
40959
41702
  logHandle = null;
40960
41703
  if (warmupMs > 0) await sleep(warmupMs);
40961
41704
  if (!await isProcessAlive(pid)) {
40962
- const tail = await readFile67(log, "utf-8").then((s) => s.split("\n").slice(-20).join("\n")).catch(() => "");
41705
+ const tail = await readFile70(log, "utf-8").then((s) => s.split("\n").slice(-20).join("\n")).catch(() => "");
40963
41706
  acquiredPid = null;
40964
41707
  throw new Error(
40965
41708
  `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}
@@ -40982,7 +41725,7 @@ ${tail}`
40982
41725
  device: input4.device,
40983
41726
  fps: input4.fps
40984
41727
  };
40985
- await writeFile14(sidecar, JSON.stringify(sidecarData, null, 2));
41728
+ await writeFile15(sidecar, JSON.stringify(sidecarData, null, 2));
40986
41729
  return {
40987
41730
  pid,
40988
41731
  logPath: log,
@@ -41016,7 +41759,7 @@ ${tail}`
41016
41759
  async function stopRecording() {
41017
41760
  const pidfile = pidfilePath();
41018
41761
  const sidecar = sidecarPath();
41019
- const pidRaw = await readFile67(pidfile, "utf-8").catch(() => null);
41762
+ const pidRaw = await readFile70(pidfile, "utf-8").catch(() => null);
41020
41763
  if (pidRaw === null) {
41021
41764
  throw new Error(
41022
41765
  `No active recording found (no pidfile at ${pidfile}). Did you run --start?`
@@ -41026,7 +41769,7 @@ async function stopRecording() {
41026
41769
  if (!Number.isInteger(pid) || pid <= 0) {
41027
41770
  throw new Error(`Pidfile at ${pidfile} is corrupt (got "${pidRaw}").`);
41028
41771
  }
41029
- const sidecarRaw = await readFile67(sidecar, "utf-8").catch(() => null);
41772
+ const sidecarRaw = await readFile70(sidecar, "utf-8").catch(() => null);
41030
41773
  if (sidecarRaw === null) {
41031
41774
  throw new Error(
41032
41775
  `No recording sidecar at ${sidecar}. The recording state is inconsistent \u2014 delete ${pidfile} and re-run --start.`
@@ -41071,7 +41814,7 @@ async function stopRecording() {
41071
41814
  if (alive) {
41072
41815
  throw new Error(`ffmpeg (PID ${pid}) refused to die after SIGKILL`);
41073
41816
  }
41074
- const st = await stat13(sidecarData.mp4Path).catch(() => null);
41817
+ const st = await stat14(sidecarData.mp4Path).catch(() => null);
41075
41818
  if (st === null || st.size === 0) {
41076
41819
  await unlink12(pidfile).catch(() => {
41077
41820
  });
@@ -41159,9 +41902,9 @@ function listArtifactsByAssignment(assignmentId) {
41159
41902
 
41160
41903
  // src/utils/transcribers/elevenlabs.ts
41161
41904
  import { spawn as spawn11 } from "child_process";
41162
- import { mkdtemp as mkdtemp5, readFile as readFile68, rm as rm13 } from "fs/promises";
41905
+ import { mkdtemp as mkdtemp5, readFile as readFile71, rm as rm13 } from "fs/promises";
41163
41906
  import { tmpdir as tmpdir6 } from "os";
41164
- import { join as join26 } from "path";
41907
+ import { join as join28 } from "path";
41165
41908
  var SCRIBE_URL = "https://api.elevenlabs.io/v1/speech-to-text";
41166
41909
  var NO_AUDIO_MARKERS = [
41167
41910
  "Stream map '0:a:0' matches no streams",
@@ -41223,7 +41966,7 @@ async function extractAudio(videoAbsPath, wavOut) {
41223
41966
  throw new TranscribeFfmpegError(`ffmpeg failed (exit ${result.code}): ${tail}`);
41224
41967
  }
41225
41968
  async function callScribe(wavPath, apiKey, opts) {
41226
- const audio = await readFile68(wavPath);
41969
+ const audio = await readFile71(wavPath);
41227
41970
  const form = new FormData();
41228
41971
  form.set("file", new Blob([new Uint8Array(audio)], { type: "audio/wav" }), "audio.wav");
41229
41972
  form.set("model_id", "scribe_v1");
@@ -41251,8 +41994,8 @@ var elevenLabsScribe = {
41251
41994
  "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."
41252
41995
  );
41253
41996
  }
41254
- const tmp = await mkdtemp5(join26(tmpdir6(), "syntaur-transcribe-"));
41255
- const wav = join26(tmp, "audio.wav");
41997
+ const tmp = await mkdtemp5(join28(tmpdir6(), "syntaur-transcribe-"));
41998
+ const wav = join28(tmp, "audio.wav");
41256
41999
  try {
41257
42000
  await extractAudio(videoAbsPath, wav);
41258
42001
  return await callScribe(wav, apiKey, opts);
@@ -41538,7 +42281,7 @@ async function captureCommand(target, options = {}) {
41538
42281
  criterionIndex = sidecar.criterionIndex;
41539
42282
  stopNote = sidecar.note;
41540
42283
  resolvedSource = mp4Path;
41541
- const mp4TmpDir = dirname26(mp4Path);
42284
+ const mp4TmpDir = dirname27(mp4Path);
41542
42285
  shelloutCleanup = async () => {
41543
42286
  await rm14(mp4TmpDir, { recursive: true, force: true }).catch(() => {
41544
42287
  });
@@ -41559,7 +42302,7 @@ async function captureCommand(target, options = {}) {
41559
42302
  `--file is unreadable: ${options.file} (${e instanceof Error ? e.message : String(e)})`
41560
42303
  );
41561
42304
  }
41562
- const st = await stat14(real);
42305
+ const st = await stat15(real);
41563
42306
  if (!st.isFile()) {
41564
42307
  throw new Error(`--file is not a regular file: ${options.file}`);
41565
42308
  }
@@ -41589,7 +42332,7 @@ async function captureCommand(target, options = {}) {
41589
42332
  initProofDb();
41590
42333
  const subdir = criterionIndex === null ? "untagged" : String(criterionIndex);
41591
42334
  const destDir = resolve97(proofDir(resolved.assignmentDir), subdir);
41592
- if (resolvedSource) await mkdir12(destDir, { recursive: true });
42335
+ if (resolvedSource) await mkdir13(destDir, { recursive: true });
41593
42336
  const ext = resolvedSource ? extensionForKind(kind) : null;
41594
42337
  let id = null;
41595
42338
  let relativeFilePath = null;
@@ -41650,7 +42393,7 @@ async function captureCommand(target, options = {}) {
41650
42393
  try {
41651
42394
  const json = await getTranscriber().transcribe(absPath);
41652
42395
  const md = renderMarkdown(groupIntoPhrases(json.words ?? []));
41653
- await writeFile15(sidecarPath2, md, "utf8");
42396
+ await writeFile16(sidecarPath2, md, "utf8");
41654
42397
  console.log(`transcript: ${sidecarPath2}`);
41655
42398
  } catch (err2) {
41656
42399
  if (err2 instanceof TranscribeFfmpegMissingError) {
@@ -41696,8 +42439,8 @@ async function captureCommand(target, options = {}) {
41696
42439
 
41697
42440
  // src/commands/proof.ts
41698
42441
  import { Command as Command6 } from "commander";
41699
- import { readFile as readFile69, writeFile as writeFile16, rename as rename10, stat as stat15 } from "fs/promises";
41700
- import { resolve as resolve98, relative as relative5, isAbsolute as isAbsolute12, dirname as dirname27 } from "path";
42442
+ import { readFile as readFile72, writeFile as writeFile17, rename as rename10, stat as stat16 } from "fs/promises";
42443
+ import { resolve as resolve98, relative as relative5, isAbsolute as isAbsolute13, dirname as dirname28 } from "path";
41701
42444
  import { randomBytes as randomBytes4 } from "crypto";
41702
42445
 
41703
42446
  // src/utils/acceptance-criteria-parse.ts
@@ -41941,7 +42684,7 @@ async function readAssignmentMeta(assignmentDir) {
41941
42684
  if (!await fileExists(path)) {
41942
42685
  return { title: "", body: "" };
41943
42686
  }
41944
- const content = await readFile69(path, "utf-8");
42687
+ const content = await readFile72(path, "utf-8");
41945
42688
  const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
41946
42689
  let title = "";
41947
42690
  if (fmMatch) {
@@ -41955,12 +42698,12 @@ async function readAssignmentMeta(assignmentDir) {
41955
42698
  }
41956
42699
  async function atomicWrite(destPath, content) {
41957
42700
  const tmp = `${destPath}.${randomBytes4(4).toString("hex")}.tmp`;
41958
- await writeFile16(tmp, content, "utf-8");
42701
+ await writeFile17(tmp, content, "utf-8");
41959
42702
  await rename10(tmp, destPath);
41960
42703
  }
41961
42704
  function isWithin(root, target) {
41962
42705
  const rel = relative5(root, target);
41963
- return rel === "" || !rel.startsWith("..") && !isAbsolute12(rel);
42706
+ return rel === "" || !rel.startsWith("..") && !isAbsolute13(rel);
41964
42707
  }
41965
42708
  function groupArtifacts(rows, criterionCount) {
41966
42709
  const artifactsByCriterion = /* @__PURE__ */ new Map();
@@ -41997,13 +42740,13 @@ async function loadInlineFiles(rows, assignmentDir) {
41997
42740
  out.set(r.file_path, null);
41998
42741
  continue;
41999
42742
  }
42000
- const st = await stat15(abs);
42743
+ const st = await stat16(abs);
42001
42744
  if (st.size > INLINE_TEXT_LIMIT_BYTES) {
42002
42745
  out.set(r.file_path, null);
42003
42746
  continue;
42004
42747
  }
42005
42748
  try {
42006
- out.set(r.file_path, await readFile69(abs, "utf-8"));
42749
+ out.set(r.file_path, await readFile72(abs, "utf-8"));
42007
42750
  } catch {
42008
42751
  out.set(r.file_path, null);
42009
42752
  }
@@ -42016,13 +42759,13 @@ async function loadTranscriptSidecars(rows, assignmentDir) {
42016
42759
  for (const r of rows) {
42017
42760
  if (r.kind !== "video" || !r.file_path) continue;
42018
42761
  const videoAbs = resolve98(assignmentDir, r.file_path);
42019
- const sidecar = resolve98(dirname27(videoAbs), `${r.id}.transcript.md`);
42762
+ const sidecar = resolve98(dirname28(videoAbs), `${r.id}.transcript.md`);
42020
42763
  if (!isWithin(proofRoot, sidecar)) continue;
42021
42764
  if (!await fileExists(sidecar)) continue;
42022
- const st = await stat15(sidecar);
42765
+ const st = await stat16(sidecar);
42023
42766
  if (st.size > INLINE_TEXT_LIMIT_BYTES) continue;
42024
42767
  try {
42025
- out.set(r.id, await readFile69(sidecar, "utf-8"));
42768
+ out.set(r.id, await readFile72(sidecar, "utf-8"));
42026
42769
  } catch {
42027
42770
  }
42028
42771
  }
@@ -42918,7 +43661,7 @@ init_timestamp();
42918
43661
  init_assignment_resolver();
42919
43662
  init_assignment_todos();
42920
43663
  import { resolve as resolve100 } from "path";
42921
- import { readFile as readFile70 } from "fs/promises";
43664
+ import { readFile as readFile73 } from "fs/promises";
42922
43665
  async function requestCommand(target, text, options = {}) {
42923
43666
  if (!text || !text.trim()) {
42924
43667
  throw new Error("Request text cannot be empty.");
@@ -42949,7 +43692,7 @@ async function requestCommand(target, text, options = {}) {
42949
43692
  throw new Error(`assignment.md not found at ${assignmentMdPath2}`);
42950
43693
  }
42951
43694
  const source = options.from ?? process.env.SYNTAUR_ASSIGNMENT ?? "unknown";
42952
- let content = await readFile70(assignmentMdPath2, "utf-8");
43695
+ let content = await readFile73(assignmentMdPath2, "utf-8");
42953
43696
  content = appendTodosToAssignmentBody(content, [
42954
43697
  { description: `${text.trim()} (from: ${source})` }
42955
43698
  ]);
@@ -42964,7 +43707,7 @@ init_paths();
42964
43707
  init_config2();
42965
43708
  init_recompute();
42966
43709
  import { Command as Command10 } from "commander";
42967
- import { readFile as readFile71, readdir as readdir35 } from "fs/promises";
43710
+ import { readFile as readFile74, readdir as readdir36 } from "fs/promises";
42968
43711
  import { resolve as resolve101 } from "path";
42969
43712
  init_session_id();
42970
43713
  async function resolveAssignmentDir(opts) {
@@ -42991,7 +43734,7 @@ async function resolveAssignmentDir(opts) {
42991
43734
  var PLAN_PATTERN = /^plan(?:-v(\d+))?\.md$/;
42992
43735
  async function listPlanFiles(assignmentDir) {
42993
43736
  if (!await fileExists(assignmentDir)) return [];
42994
- const entries = await readdir35(assignmentDir, { withFileTypes: true });
43737
+ const entries = await readdir36(assignmentDir, { withFileTypes: true });
42995
43738
  const out = [];
42996
43739
  for (const e of entries) {
42997
43740
  if (!e.isFile()) continue;
@@ -43186,7 +43929,7 @@ async function runPlanCreate(options) {
43186
43929
  "plan.md already exists. Use --force to overwrite, or `syntaur plan version` to create the next version."
43187
43930
  );
43188
43931
  }
43189
- const assignmentMd = await readFile71(assignmentMdPath2, "utf-8");
43932
+ const assignmentMd = await readFile74(assignmentMdPath2, "utf-8");
43190
43933
  const slugMatch = assignmentMd.match(/^slug:\s*(.+?)\s*$/m);
43191
43934
  const slug = slugMatch ? slugMatch[1].trim() : assignmentDir.split("/").pop() ?? "";
43192
43935
  await writeFileForce(planPath, buildInitialPlanStub(slug));
@@ -43223,11 +43966,11 @@ async function runPlanVersion(options) {
43223
43966
  if (await fileExists(newPath) && !options.force) {
43224
43967
  throw new Error(`${next.fileName} already exists. Use --force to overwrite.`);
43225
43968
  }
43226
- const assignmentMd = await readFile71(assignmentMdPath2, "utf-8");
43969
+ const assignmentMd = await readFile74(assignmentMdPath2, "utf-8");
43227
43970
  const slugMatch = assignmentMd.match(/^slug:\s*(.+?)\s*$/m);
43228
43971
  const slug = slugMatch ? slugMatch[1].trim() : assignmentDir.split("/").pop() ?? "";
43229
43972
  const oldPlanPath = resolve101(assignmentDir, current.fileName);
43230
- const oldPlanContent = await readFile71(oldPlanPath, "utf-8");
43973
+ const oldPlanContent = await readFile74(oldPlanPath, "utf-8");
43231
43974
  const oldBody = oldPlanContent.replace(/^---[\s\S]*?\n---\n?/, "");
43232
43975
  const carriedTodos = extractUncheckedTodos(oldBody);
43233
43976
  const stub = buildNewPlanStub({
@@ -43298,7 +44041,7 @@ init_cwd();
43298
44041
  init_session_db();
43299
44042
  init_agent_sessions();
43300
44043
  import { Command as Command11 } from "commander";
43301
- import { readFile as readFile72, readdir as readdir36, stat as stat16 } from "fs/promises";
44044
+ import { readFile as readFile75, readdir as readdir37, stat as stat17 } from "fs/promises";
43302
44045
  import { resolve as resolve102 } from "path";
43303
44046
  init_engagement_db();
43304
44047
  init_parser();
@@ -43306,7 +44049,7 @@ async function readContext(cwd) {
43306
44049
  const path = resolve102(cwd, ".syntaur", "context.json");
43307
44050
  if (!await fileExists(path)) return null;
43308
44051
  try {
43309
- const raw2 = await readFile72(path, "utf-8");
44052
+ const raw2 = await readFile75(path, "utf-8");
43310
44053
  return JSON.parse(raw2);
43311
44054
  } catch {
43312
44055
  return null;
@@ -43315,13 +44058,13 @@ async function readContext(cwd) {
43315
44058
  async function findLatestSessionSummary(assignmentDir) {
43316
44059
  const sessionsRoot = resolve102(assignmentDir, "sessions");
43317
44060
  if (!await fileExists(sessionsRoot)) return null;
43318
- const entries = await readdir36(sessionsRoot, { withFileTypes: true });
44061
+ const entries = await readdir37(sessionsRoot, { withFileTypes: true });
43319
44062
  let best = null;
43320
44063
  for (const entry of entries) {
43321
44064
  if (!entry.isDirectory()) continue;
43322
44065
  const summaryPath = resolve102(sessionsRoot, entry.name, "summary.md");
43323
44066
  if (!await fileExists(summaryPath)) continue;
43324
- const st = await stat16(summaryPath);
44067
+ const st = await stat17(summaryPath);
43325
44068
  if (best === null || st.mtime.getTime() > best.mtime.getTime()) {
43326
44069
  best = { sessionId: entry.name, path: summaryPath, mtime: st.mtime };
43327
44070
  }
@@ -43331,7 +44074,7 @@ async function findLatestSessionSummary(assignmentDir) {
43331
44074
  async function findOpenHandoff(assignmentDir) {
43332
44075
  const handoffPath = resolve102(assignmentDir, "handoff.md");
43333
44076
  if (!await fileExists(handoffPath)) return null;
43334
- const content = await readFile72(handoffPath, "utf-8");
44077
+ const content = await readFile75(handoffPath, "utf-8");
43335
44078
  const body = content.replace(/^---[\s\S]*?\n---\n?/, "").trim();
43336
44079
  if (body.length === 0) return null;
43337
44080
  if (/^<!--[\s\S]*-->$/.test(body)) return null;
@@ -43341,7 +44084,7 @@ async function readAssignmentTitle(assignmentDir) {
43341
44084
  const path = resolve102(assignmentDir, "assignment.md");
43342
44085
  if (!await fileExists(path)) return null;
43343
44086
  try {
43344
- const content = await readFile72(path, "utf-8");
44087
+ const content = await readFile75(path, "utf-8");
43345
44088
  const [fm] = extractFrontmatter(content);
43346
44089
  return getField(fm, "title");
43347
44090
  } catch {
@@ -43558,13 +44301,13 @@ async function runSessionSave(options, cwd = process.cwd(), body) {
43558
44301
  const now = nowTimestamp();
43559
44302
  let created = now;
43560
44303
  if (await fileExists(summaryPath)) {
43561
- const existing = await readFile72(summaryPath, "utf-8");
44304
+ const existing = await readFile75(summaryPath, "utf-8");
43562
44305
  created = extractCreated(existing) ?? now;
43563
44306
  }
43564
44307
  let sectionBody2 = body;
43565
44308
  if (sectionBody2 === void 0) {
43566
44309
  if (options.fromFile) {
43567
- sectionBody2 = await readFile72(resolve102(cwd, options.fromFile), "utf-8");
44310
+ sectionBody2 = await readFile75(resolve102(cwd, options.fromFile), "utf-8");
43568
44311
  } else {
43569
44312
  sectionBody2 = await readStdin();
43570
44313
  }
@@ -43792,7 +44535,7 @@ sessionCommand.command("boundary").description(
43792
44535
  // src/commands/worktree.ts
43793
44536
  init_git_worktree();
43794
44537
  import { Command as Command12 } from "commander";
43795
- import { readFile as readFile73 } from "fs/promises";
44538
+ import { readFile as readFile76 } from "fs/promises";
43796
44539
  import { resolve as resolve103 } from "path";
43797
44540
  init_fs();
43798
44541
  init_paths();
@@ -43882,7 +44625,7 @@ async function runWorktreeRemove(options, cwd = process.cwd()) {
43882
44625
  if (!await fileExists(assignmentPath)) {
43883
44626
  throw new Error(`Assignment file not found: ${assignmentPath}`);
43884
44627
  }
43885
- const original = await readFile73(assignmentPath, "utf-8");
44628
+ const original = await readFile76(assignmentPath, "utf-8");
43886
44629
  const fm = parseAssignmentFrontmatter(original);
43887
44630
  const repository = options.repository ?? fm.workspace.repository ?? void 0;
43888
44631
  const worktreePath = fm.workspace.worktreePath ?? void 0;
@@ -43948,7 +44691,7 @@ async function runWorktreeGc(options, cwd = process.cwd()) {
43948
44691
  const owners = /* @__PURE__ */ new Map();
43949
44692
  for (const entry of walk.withAssignmentMd) {
43950
44693
  try {
43951
- const content = await readFile73(resolve103(entry.assignmentDir, "assignment.md"), "utf-8");
44694
+ const content = await readFile76(resolve103(entry.assignmentDir, "assignment.md"), "utf-8");
43952
44695
  const fm = parseAssignmentFrontmatter(content);
43953
44696
  const wp = fm.workspace?.worktreePath;
43954
44697
  if (!wp) continue;
@@ -44189,7 +44932,7 @@ worktreeCommand.command("gc").description(
44189
44932
  // src/commands/open.ts
44190
44933
  init_fs();
44191
44934
  import { Command as Command13 } from "commander";
44192
- import { readFile as readFile74 } from "fs/promises";
44935
+ import { readFile as readFile77 } from "fs/promises";
44193
44936
  import { resolve as resolve104 } from "path";
44194
44937
  init_frontmatter();
44195
44938
  init_config2();
@@ -44255,7 +44998,7 @@ async function runOpen(assignmentArg, options) {
44255
44998
  remediation: "check the assignment slug or --id"
44256
44999
  });
44257
45000
  }
44258
- const fm = parseAssignmentFrontmatter(await readFile74(assignmentPath, "utf-8"));
45001
+ const fm = parseAssignmentFrontmatter(await readFile77(assignmentPath, "utf-8"));
44259
45002
  const worktreePath = fm.workspace?.worktreePath;
44260
45003
  if (!worktreePath) {
44261
45004
  throw new SyntaurError("No worktree recorded for this assignment.", {
@@ -44321,12 +45064,12 @@ init_fs();
44321
45064
  init_slug();
44322
45065
  import { Command as Command14 } from "commander";
44323
45066
  import { resolve as resolve106 } from "path";
44324
- import { readFile as readFile76, readdir as readdir38, rm as rm15 } from "fs/promises";
45067
+ import { readFile as readFile79, readdir as readdir39, rm as rm15 } from "fs/promises";
44325
45068
 
44326
45069
  // src/utils/project-indexes.ts
44327
45070
  init_parser();
44328
45071
  init_fs();
44329
- import { readdir as readdir37, readFile as readFile75 } from "fs/promises";
45072
+ import { readdir as readdir38, readFile as readFile78 } from "fs/promises";
44330
45073
  import { resolve as resolve105 } from "path";
44331
45074
  function nowIso3() {
44332
45075
  return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
@@ -44336,7 +45079,7 @@ function readProjectSlug(projectDir) {
44336
45079
  }
44337
45080
  async function listSlugFiles(dir) {
44338
45081
  if (!await fileExists(dir)) return [];
44339
- const entries = await readdir37(dir, { withFileTypes: true });
45082
+ const entries = await readdir38(dir, { withFileTypes: true });
44340
45083
  return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && !e.name.startsWith("_")).map((e) => e.name).sort();
44341
45084
  }
44342
45085
  function escapeCell(value) {
@@ -44362,7 +45105,7 @@ async function rebuildResourcesIndex(projectDir) {
44362
45105
  lines.push("| Name | Category | Source | Related Assignments | Updated |");
44363
45106
  lines.push("|------|----------|--------|---------------------|---------|");
44364
45107
  for (const fileName of files) {
44365
- const content = await readFile75(resolve105(dir, fileName), "utf-8");
45108
+ const content = await readFile78(resolve105(dir, fileName), "utf-8");
44366
45109
  const parsed = parseResource(content);
44367
45110
  const slugBase = fileName.replace(/\.md$/, "");
44368
45111
  const name = parsed.name || slugBase;
@@ -44393,7 +45136,7 @@ async function rebuildMemoriesIndex(projectDir) {
44393
45136
  lines.push("| Name | Source | Scope | Source Assignment | Updated |");
44394
45137
  lines.push("|------|--------|-------|-------------------|---------|");
44395
45138
  for (const fileName of files) {
44396
- const content = await readFile75(resolve105(dir, fileName), "utf-8");
45139
+ const content = await readFile78(resolve105(dir, fileName), "utf-8");
44397
45140
  const parsed = parseMemory(content);
44398
45141
  const slugBase = fileName.replace(/\.md$/, "");
44399
45142
  const name = parsed.name || slugBase;
@@ -44500,7 +45243,7 @@ async function runResourceAdd(options) {
44500
45243
  async function listResourceSlugs(projectDir) {
44501
45244
  const dir = resolve106(projectDir, "resources");
44502
45245
  if (!await fileExists(dir)) return [];
44503
- const entries = await readdir38(dir, { withFileTypes: true });
45246
+ const entries = await readdir39(dir, { withFileTypes: true });
44504
45247
  return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && e.name !== "_index.md").map((e) => e.name.slice(0, -3)).sort();
44505
45248
  }
44506
45249
  async function runResourceList(project) {
@@ -44508,7 +45251,7 @@ async function runResourceList(project) {
44508
45251
  const slugs = await listResourceSlugs(projectDir);
44509
45252
  const out = [];
44510
45253
  for (const slug of slugs) {
44511
- const parsed = parseResource(await readFile76(resolve106(projectDir, "resources", `${slug}.md`), "utf-8"));
45254
+ const parsed = parseResource(await readFile79(resolve106(projectDir, "resources", `${slug}.md`), "utf-8"));
44512
45255
  out.push({ slug, name: parsed.name, category: parsed.category, source: parsed.source, updated: parsed.updated });
44513
45256
  }
44514
45257
  return out;
@@ -44517,7 +45260,7 @@ async function runResourceShow(project, slug) {
44517
45260
  const projectDir = await resolveProjectDir(project);
44518
45261
  const filePath = resolve106(projectDir, "resources", `${slug}.md`);
44519
45262
  if (!await fileExists(filePath)) throw new Error(`Resource "${slug}" not found in project "${project}".`);
44520
- const parsed = parseResource(await readFile76(filePath, "utf-8"));
45263
+ const parsed = parseResource(await readFile79(filePath, "utf-8"));
44521
45264
  return {
44522
45265
  slug,
44523
45266
  name: parsed.name,
@@ -44538,7 +45281,7 @@ async function runResourceUpdate(slug, options) {
44538
45281
  if (options.name === void 0 && options.source === void 0 && options.category === void 0 && options.relatedAssignments === void 0) {
44539
45282
  throw new Error("Provide at least one of --name, --source, --category, --related-assignments.");
44540
45283
  }
44541
- const original = await readFile76(filePath, "utf-8");
45284
+ const original = await readFile79(filePath, "utf-8");
44542
45285
  const content = editResourceFrontmatter(original, {
44543
45286
  name: options.name,
44544
45287
  category: options.category,
@@ -44635,7 +45378,7 @@ init_fs();
44635
45378
  init_slug();
44636
45379
  import { Command as Command15 } from "commander";
44637
45380
  import { resolve as resolve107 } from "path";
44638
- import { readFile as readFile77, readdir as readdir39, rm as rm16 } from "fs/promises";
45381
+ import { readFile as readFile80, readdir as readdir40, rm as rm16 } from "fs/promises";
44639
45382
  init_parser();
44640
45383
  function nowIso5() {
44641
45384
  return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
@@ -44733,7 +45476,7 @@ async function runMemoryAdd(options) {
44733
45476
  async function listMemorySlugs(projectDir) {
44734
45477
  const dir = resolve107(projectDir, "memories");
44735
45478
  if (!await fileExists(dir)) return [];
44736
- const entries = await readdir39(dir, { withFileTypes: true });
45479
+ const entries = await readdir40(dir, { withFileTypes: true });
44737
45480
  return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && e.name !== "_index.md").map((e) => e.name.slice(0, -3)).sort();
44738
45481
  }
44739
45482
  async function runMemoryList(project) {
@@ -44741,7 +45484,7 @@ async function runMemoryList(project) {
44741
45484
  const slugs = await listMemorySlugs(projectDir);
44742
45485
  const out = [];
44743
45486
  for (const slug of slugs) {
44744
- const parsed = parseMemory(await readFile77(resolve107(projectDir, "memories", `${slug}.md`), "utf-8"));
45487
+ const parsed = parseMemory(await readFile80(resolve107(projectDir, "memories", `${slug}.md`), "utf-8"));
44745
45488
  out.push({ slug, name: parsed.name, scope: parsed.scope, source: parsed.source, updated: parsed.updated });
44746
45489
  }
44747
45490
  return out;
@@ -44750,7 +45493,7 @@ async function runMemoryShow(project, slug) {
44750
45493
  const projectDir = await resolveProjectDir2(project);
44751
45494
  const filePath = resolve107(projectDir, "memories", `${slug}.md`);
44752
45495
  if (!await fileExists(filePath)) throw new Error(`Memory "${slug}" not found in project "${project}".`);
44753
- const parsed = parseMemory(await readFile77(filePath, "utf-8"));
45496
+ const parsed = parseMemory(await readFile80(filePath, "utf-8"));
44754
45497
  return {
44755
45498
  slug,
44756
45499
  name: parsed.name,
@@ -44774,7 +45517,7 @@ async function runMemoryUpdate(slug, options) {
44774
45517
  "Provide at least one of --name, --source, --scope, --source-assignment, --related-assignments."
44775
45518
  );
44776
45519
  }
44777
- const original = await readFile77(filePath, "utf-8");
45520
+ const original = await readFile80(filePath, "utf-8");
44778
45521
  const content = editMemoryFrontmatter(original, {
44779
45522
  name: options.name,
44780
45523
  source: options.source,
@@ -44877,8 +45620,8 @@ init_derive();
44877
45620
  init_recompute();
44878
45621
  init_query();
44879
45622
  import { Command as Command16 } from "commander";
44880
- import { readFile as readFile78 } from "fs/promises";
44881
- import { dirname as dirname29, resolve as resolve108 } from "path";
45623
+ import { readFile as readFile81 } from "fs/promises";
45624
+ import { dirname as dirname30, resolve as resolve108 } from "path";
44882
45625
  var AGE_PATTERN = /^(\d+)([dhwm])$/i;
44883
45626
  function parseAgeToCutoff(age) {
44884
45627
  const match = age.match(AGE_PATTERN);
@@ -44911,7 +45654,7 @@ async function loadTags(item) {
44911
45654
  const path = assignmentMdPath(item);
44912
45655
  if (!await fileExists(path)) return [];
44913
45656
  try {
44914
- const content = await readFile78(path, "utf-8");
45657
+ const content = await readFile81(path, "utf-8");
44915
45658
  return parseAssignmentFrontmatter(content).tags;
44916
45659
  } catch {
44917
45660
  return [];
@@ -44975,10 +45718,10 @@ async function loadQueryItem(item, terminalStatuses3, now, declarations) {
44975
45718
  const path = assignmentMdPath(item);
44976
45719
  if (!await fileExists(path)) return null;
44977
45720
  try {
44978
- const content = await readFile78(path, "utf-8");
45721
+ const content = await readFile81(path, "utf-8");
44979
45722
  const fm = parseAssignmentFrontmatter(content);
44980
45723
  const body = content.replace(/^---\n[\s\S]*?\n---/, "");
44981
- const assignmentDir = dirname29(path);
45724
+ const assignmentDir = dirname30(path);
44982
45725
  const projectDir = item.projectSlug ? resolve108(defaultProjectDir(), item.projectSlug) : null;
44983
45726
  const facts = await computeFacts({ assignmentDir, frontmatter: fm, body, projectDir, terminalStatuses: terminalStatuses3, declarations });
44984
45727
  const history = fm.statusHistory;
@@ -45754,7 +46497,7 @@ init_fs();
45754
46497
  init_timestamp();
45755
46498
  init_frontmatter();
45756
46499
  import { Command as Command21 } from "commander";
45757
- import { readFile as readFile79 } from "fs/promises";
46500
+ import { readFile as readFile82 } from "fs/promises";
45758
46501
  import { resolve as resolve109 } from "path";
45759
46502
  function renameAssignmentStatusRefs(content, id, newId, now) {
45760
46503
  const fm = parseAssignmentFrontmatter(content);
@@ -45781,7 +46524,7 @@ function configPath() {
45781
46524
  async function readStatusBlock() {
45782
46525
  const p = configPath();
45783
46526
  if (!await fileExists(p)) return null;
45784
- const content = await readFile79(p, "utf-8");
46527
+ const content = await readFile82(p, "utf-8");
45785
46528
  return parseStatusConfig(content);
45786
46529
  }
45787
46530
  async function requireStatusBlock() {
@@ -46065,7 +46808,7 @@ async function runStatusRename(id, opts) {
46065
46808
  printBlockDiff(before, after);
46066
46809
  const now2 = nowTimestamp();
46067
46810
  for (const a of affected) {
46068
- const original = await readFile79(a.path, "utf-8");
46811
+ const original = await readFile82(a.path, "utf-8");
46069
46812
  const rewritten = renameAssignmentStatusRefs(original, id, newId, now2);
46070
46813
  console.log(`
46071
46814
  --- ${a.display}/assignment.md`);
@@ -46076,9 +46819,9 @@ async function runStatusRename(id, opts) {
46076
46819
  }
46077
46820
  const cfgPath = configPath();
46078
46821
  const buffers = /* @__PURE__ */ new Map();
46079
- buffers.set(cfgPath, await fileExists(cfgPath) ? await readFile79(cfgPath, "utf-8") : "");
46822
+ buffers.set(cfgPath, await fileExists(cfgPath) ? await readFile82(cfgPath, "utf-8") : "");
46080
46823
  for (const a of affected) {
46081
- buffers.set(a.path, await readFile79(a.path, "utf-8"));
46824
+ buffers.set(a.path, await readFile82(a.path, "utf-8"));
46082
46825
  }
46083
46826
  const now = nowTimestamp();
46084
46827
  try {
@@ -46280,7 +47023,7 @@ init_config2();
46280
47023
  init_timestamp();
46281
47024
  init_frontmatter();
46282
47025
  import { Command as Command22 } from "commander";
46283
- import { readFile as readFile80 } from "fs/promises";
47026
+ import { readFile as readFile83 } from "fs/promises";
46284
47027
  import { resolve as resolve110 } from "path";
46285
47028
  init_session_id();
46286
47029
  async function resolveAssignmentPath3(opts) {
@@ -46336,7 +47079,7 @@ async function runWorkspaceSet(options, cwd = process.cwd()) {
46336
47079
  ${pre.errors.map((e) => ` - ${e}`).join("\n")}`
46337
47080
  );
46338
47081
  }
46339
- const original = await readFile80(path, "utf-8");
47082
+ const original = await readFile83(path, "utf-8");
46340
47083
  let next = updateAssignmentWorkspace(original, partial);
46341
47084
  next = updateAssignmentFile(next, { updated: nowTimestamp() });
46342
47085
  await writeFileForce(path, next);
@@ -46373,7 +47116,7 @@ init_config2();
46373
47116
  init_timestamp();
46374
47117
  init_templates();
46375
47118
  import { Command as Command23 } from "commander";
46376
- import { readFile as readFile81 } from "fs/promises";
47119
+ import { readFile as readFile84 } from "fs/promises";
46377
47120
  import { resolve as resolve111 } from "path";
46378
47121
  init_session_id();
46379
47122
  async function resolveAssignmentDir2(opts) {
@@ -46457,7 +47200,7 @@ async function runProgressLog(text, options, cwd = process.cwd()) {
46457
47200
  }
46458
47201
  const path = resolve111(dir, "progress.md");
46459
47202
  const now = nowTimestamp();
46460
- const content = await fileExists(path) ? await readFile81(path, "utf-8") : renderProgress({ assignment: slug, timestamp: now });
47203
+ const content = await fileExists(path) ? await readFile84(path, "utf-8") : renderProgress({ assignment: slug, timestamp: now });
46461
47204
  const next = appendProgressEntry(content, text, now);
46462
47205
  await writeFileForce(path, next);
46463
47206
  return path;
@@ -46477,10 +47220,10 @@ progressCommand.command("log").description("Append a timestamped entry to the as
46477
47220
 
46478
47221
  // src/cli-default-command.ts
46479
47222
  init_config2();
46480
- import { readdir as readdir40 } from "fs/promises";
47223
+ import { readdir as readdir41 } from "fs/promises";
46481
47224
  async function hasAnyProjectContent(projectsDir2) {
46482
47225
  try {
46483
- const entries = await readdir40(projectsDir2, { withFileTypes: true });
47226
+ const entries = await readdir41(projectsDir2, { withFileTypes: true });
46484
47227
  return entries.some((entry) => entry.isDirectory());
46485
47228
  } catch {
46486
47229
  return false;