syntaur 0.32.0 → 0.33.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.
package/dist/index.js CHANGED
@@ -2760,9 +2760,9 @@ function normalizeAgentsFromConfig(agents) {
2760
2760
  validateAgentList(normalized);
2761
2761
  return normalized;
2762
2762
  } catch (err2) {
2763
- const msg = err2 instanceof Error ? err2.message : String(err2);
2763
+ const msg2 = err2 instanceof Error ? err2.message : String(err2);
2764
2764
  console.warn(
2765
- `Warning: ~/.syntaur/config.md agents block is invalid (${msg}) \u2014 using built-in defaults`
2765
+ `Warning: ~/.syntaur/config.md agents block is invalid (${msg2}) \u2014 using built-in defaults`
2766
2766
  );
2767
2767
  return null;
2768
2768
  }
@@ -3152,8 +3152,8 @@ async function readConfig() {
3152
3152
  try {
3153
3153
  return parseTerminalConfig(fm["terminal"]);
3154
3154
  } catch (err2) {
3155
- const msg = err2 instanceof TerminalConfigError ? err2.message : String(err2);
3156
- console.warn(`Warning: ${msg} \u2014 falling back to default`);
3155
+ const msg2 = err2 instanceof TerminalConfigError ? err2.message : String(err2);
3156
+ console.warn(`Warning: ${msg2} \u2014 falling back to default`);
3157
3157
  return null;
3158
3158
  }
3159
3159
  })(),
@@ -5382,8 +5382,8 @@ async function migrateFromMarkdown(projectsDir2) {
5382
5382
  return allSessions.length;
5383
5383
  }
5384
5384
  async function parseMarkdownSessionsIndex(filePath, projectSlug) {
5385
- const { readFile: readFile63 } = await import("fs/promises");
5386
- const raw2 = await readFile63(filePath, "utf-8");
5385
+ const { readFile: readFile64 } = await import("fs/promises");
5386
+ const raw2 = await readFile64(filePath, "utf-8");
5387
5387
  const sessions = [];
5388
5388
  const lines = raw2.split("\n");
5389
5389
  let inTable = false;
@@ -5819,8 +5819,8 @@ function scanKey(serversDir2, projectsDir2, assignmentsDir2) {
5819
5819
  return `${serversDir2}\0${projectsDir2}\0${assignmentsDir2 ?? ""}`;
5820
5820
  }
5821
5821
  function delay(ms) {
5822
- return new Promise((resolve86) => {
5823
- const timer2 = setTimeout(resolve86, ms);
5822
+ return new Promise((resolve87) => {
5823
+ const timer2 = setTimeout(resolve87, ms);
5824
5824
  if (typeof timer2.unref === "function") {
5825
5825
  timer2.unref();
5826
5826
  }
@@ -8802,7 +8802,7 @@ import {
8802
8802
  unlinkSync
8803
8803
  } from "fs";
8804
8804
  import { fileURLToPath as fileURLToPath9, pathToFileURL } from "url";
8805
- import { dirname as dirname17, resolve as resolve50, join as join9 } from "path";
8805
+ import { dirname as dirname18, resolve as resolve51, join as join10 } from "path";
8806
8806
  import { homedir as homedir9, tmpdir as tmpdir2 } from "os";
8807
8807
  import { spawnSync as spawnSync7 } from "child_process";
8808
8808
  function syntaurRootMjs() {
@@ -8810,7 +8810,7 @@ function syntaurRootMjs() {
8810
8810
  if (override && override.length > 0) {
8811
8811
  return override;
8812
8812
  }
8813
- return join9(homedir9(), ".syntaur");
8813
+ return join10(homedir9(), ".syntaur");
8814
8814
  }
8815
8815
  async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
8816
8816
  const { throwOnFailure } = options;
@@ -8824,38 +8824,38 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
8824
8824
  }
8825
8825
  const stateRoot = syntaurRootMjs();
8826
8826
  mkdirSync2(stateRoot, { recursive: true });
8827
- const lockPath = resolve50(stateRoot, "install-url-handler.lock");
8827
+ const lockPath = resolve51(stateRoot, "install-url-handler.lock");
8828
8828
  let lockFd;
8829
8829
  try {
8830
8830
  lockFd = openSync(lockPath, "wx");
8831
8831
  } catch (err2) {
8832
8832
  if (err2 && err2.code === "EEXIST") {
8833
- const msg = `Another syntaur:// handler registration is in progress (lock at ${lockPath}). Wait for it to finish or remove the stale lock.`;
8833
+ const msg2 = `Another syntaur:// handler registration is in progress (lock at ${lockPath}). Wait for it to finish or remove the stale lock.`;
8834
8834
  if (throwOnFailure) {
8835
- throw new Error(msg);
8835
+ throw new Error(msg2);
8836
8836
  }
8837
- console.warn(`syntaur: skipping macOS URL-handler registration (${msg})`);
8837
+ console.warn(`syntaur: skipping macOS URL-handler registration (${msg2})`);
8838
8838
  return { bundlePath: "" };
8839
8839
  }
8840
8840
  throw err2;
8841
8841
  }
8842
8842
  try {
8843
- const pkgRoot = resolve50(dirname17(fileURLToPath9(import.meta.url)), "..");
8844
- const cliBin = realpathSync3(resolve50(pkgRoot, "bin/syntaur.js"));
8843
+ const pkgRoot = resolve51(dirname18(fileURLToPath9(import.meta.url)), "..");
8844
+ const cliBin = realpathSync3(resolve51(pkgRoot, "bin/syntaur.js"));
8845
8845
  const nodeBin = process.execPath;
8846
- const bundleParent = join9(
8846
+ const bundleParent = join10(
8847
8847
  homedir9(),
8848
8848
  "Library",
8849
8849
  "Application Support",
8850
8850
  "Syntaur"
8851
8851
  );
8852
- const bundlePath = join9(bundleParent, "syntaur-url.app");
8852
+ const bundlePath = join10(bundleParent, "syntaur-url.app");
8853
8853
  mkdirSync2(bundleParent, { recursive: true });
8854
8854
  if (existsSync5(bundlePath)) {
8855
8855
  rmSync(bundlePath, { recursive: true, force: true });
8856
8856
  }
8857
8857
  const installedTerminals = detectInstalledTerminals();
8858
- const scriptPath = join9(
8858
+ const scriptPath = join10(
8859
8859
  tmpdir2(),
8860
8860
  `syntaur-url-handler-${process.pid}.applescript`
8861
8861
  );
@@ -8874,7 +8874,7 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
8874
8874
  `osacompile exited with code ${compile.status}: ${compile.stderr || compile.stdout}`
8875
8875
  );
8876
8876
  }
8877
- const infoPlistPath = join9(bundlePath, "Contents", "Info.plist");
8877
+ const infoPlistPath = join10(bundlePath, "Contents", "Info.plist");
8878
8878
  if (!existsSync5(infoPlistPath)) {
8879
8879
  throw new Error(`osacompile did not produce ${infoPlistPath}`);
8880
8880
  }
@@ -8914,23 +8914,23 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
8914
8914
  { stdio: "pipe", encoding: "utf-8" }
8915
8915
  );
8916
8916
  if (sign.status !== 0) {
8917
- const msg = `codesign returned ${sign.status} while re-signing ${bundlePath}: ${sign.stderr || sign.stdout || "(no output)"}`;
8917
+ const msg2 = `codesign returned ${sign.status} while re-signing ${bundlePath}: ${sign.stderr || sign.stdout || "(no output)"}`;
8918
8918
  if (throwOnFailure) {
8919
- throw new Error(msg);
8919
+ throw new Error(msg2);
8920
8920
  }
8921
- console.warn(`syntaur: ${msg} \u2014 macOS may deny Automation permission.`);
8921
+ console.warn(`syntaur: ${msg2} \u2014 macOS may deny Automation permission.`);
8922
8922
  }
8923
8923
  const ls = spawnSync7(LSREGISTER, ["-f", bundlePath], {
8924
8924
  stdio: "pipe",
8925
8925
  encoding: "utf-8"
8926
8926
  });
8927
8927
  if (ls.status !== 0) {
8928
- const msg = `lsregister returned ${ls.status} while registering ${bundlePath}: ${ls.stderr || ls.stdout || "(no output)"}`;
8928
+ const msg2 = `lsregister returned ${ls.status} while registering ${bundlePath}: ${ls.stderr || ls.stdout || "(no output)"}`;
8929
8929
  if (throwOnFailure) {
8930
- throw new Error(msg);
8930
+ throw new Error(msg2);
8931
8931
  }
8932
8932
  console.warn(
8933
- `syntaur: ${msg} \u2014 \`open syntaur://...\` may not route through the CLI handler until you run \`${LSREGISTER} -f ${bundlePath}\` manually.`
8933
+ `syntaur: ${msg2} \u2014 \`open syntaur://...\` may not route through the CLI handler until you run \`${LSREGISTER} -f ${bundlePath}\` manually.`
8934
8934
  );
8935
8935
  }
8936
8936
  try {
@@ -8953,8 +8953,8 @@ async function main() {
8953
8953
  try {
8954
8954
  await registerMacosUrlHandler({ throwOnFailure: false });
8955
8955
  } catch (err2) {
8956
- const msg = err2 instanceof Error ? err2.message : String(err2);
8957
- console.warn(`syntaur: skipping macOS URL-handler registration (${msg})`);
8956
+ const msg2 = err2 instanceof Error ? err2.message : String(err2);
8957
+ console.warn(`syntaur: skipping macOS URL-handler registration (${msg2})`);
8958
8958
  }
8959
8959
  }
8960
8960
  function detectInstalledTerminals() {
@@ -8969,7 +8969,7 @@ function detectInstalledTerminals() {
8969
8969
  ghostty: "Ghostty.app",
8970
8970
  warp: "Warp.app"
8971
8971
  };
8972
- const appDirs = ["/Applications", join9(homedir9(), "Applications")];
8972
+ const appDirs = ["/Applications", join10(homedir9(), "Applications")];
8973
8973
  for (const [id, bundleId] of Object.entries(bundleIds)) {
8974
8974
  const r = spawnSync7(
8975
8975
  "mdfind",
@@ -8981,7 +8981,7 @@ function detectInstalledTerminals() {
8981
8981
  continue;
8982
8982
  }
8983
8983
  const name = bundleNames[id];
8984
- if (name && appDirs.some((dir) => existsSync5(join9(dir, name)))) {
8984
+ if (name && appDirs.some((dir) => existsSync5(join10(dir, name)))) {
8985
8985
  installed.add(id);
8986
8986
  }
8987
8987
  }
@@ -16160,12 +16160,12 @@ function createPlaybooksRouter(playbooksDir3) {
16160
16160
  const result = await setPlaybookEnabled(playbooksDir3, req.params.slug, true);
16161
16161
  res.json({ slug: result.slug, enabled: result.enabled, changed: result.changed });
16162
16162
  } catch (error) {
16163
- const msg = error instanceof Error ? error.message : "Failed to enable playbook";
16164
- if (msg.startsWith("Playbook ")) {
16165
- res.status(404).json({ error: msg });
16163
+ const msg2 = error instanceof Error ? error.message : "Failed to enable playbook";
16164
+ if (msg2.startsWith("Playbook ")) {
16165
+ res.status(404).json({ error: msg2 });
16166
16166
  return;
16167
16167
  }
16168
- res.status(500).json({ error: msg });
16168
+ res.status(500).json({ error: msg2 });
16169
16169
  }
16170
16170
  });
16171
16171
  router.post("/:slug/disable", async (req, res) => {
@@ -16173,12 +16173,12 @@ function createPlaybooksRouter(playbooksDir3) {
16173
16173
  const result = await setPlaybookEnabled(playbooksDir3, req.params.slug, false);
16174
16174
  res.json({ slug: result.slug, enabled: result.enabled, changed: result.changed });
16175
16175
  } catch (error) {
16176
- const msg = error instanceof Error ? error.message : "Failed to disable playbook";
16177
- if (msg.startsWith("Playbook ")) {
16178
- res.status(404).json({ error: msg });
16176
+ const msg2 = error instanceof Error ? error.message : "Failed to disable playbook";
16177
+ if (msg2.startsWith("Playbook ")) {
16178
+ res.status(404).json({ error: msg2 });
16179
16179
  return;
16180
16180
  }
16181
- res.status(500).json({ error: msg });
16181
+ res.status(500).json({ error: msg2 });
16182
16182
  }
16183
16183
  });
16184
16184
  router.get("/:slug", async (req, res) => {
@@ -16916,8 +16916,8 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
16916
16916
  router.post("/:workspace/archive", async (req, res) => {
16917
16917
  try {
16918
16918
  const { archivePath: archivePath2 } = await Promise.resolve().then(() => (init_parser2(), parser_exports));
16919
- const { resolve: resolve86 } = await import("path");
16920
- const { readFile: readFile63 } = await import("fs/promises");
16919
+ const { resolve: resolve87 } = await import("path");
16920
+ const { readFile: readFile64 } = await import("fs/promises");
16921
16921
  const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
16922
16922
  const workspace = getWorkspaceParam(req.params.workspace);
16923
16923
  const outcome = await wsLock(workspace, async () => {
@@ -16933,10 +16933,10 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
16933
16933
  (e) => e.itemIds.every((id) => completedIds.has(id))
16934
16934
  );
16935
16935
  const archFile = archivePath2(todosDir2, workspace, checklist.archiveInterval);
16936
- await ensureDir(resolve86(todosDir2, "archive"));
16936
+ await ensureDir(resolve87(todosDir2, "archive"));
16937
16937
  let archContent = "";
16938
16938
  if (await fileExists(archFile)) {
16939
- archContent = await readFile63(archFile, "utf-8");
16939
+ archContent = await readFile64(archFile, "utf-8");
16940
16940
  archContent = archContent.trimEnd() + "\n\n";
16941
16941
  } else {
16942
16942
  archContent = `---
@@ -17225,7 +17225,7 @@ workspace: ${workspace}
17225
17225
  const { readConfig: readConfig3 } = await Promise.resolve().then(() => (init_config2(), config_exports));
17226
17226
  const { assignmentsDir: assignmentsDirFn } = await Promise.resolve().then(() => (init_paths(), paths_exports));
17227
17227
  const { fileExists: fileExists2, writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
17228
- const { readFile: readFile63 } = await import("fs/promises");
17228
+ const { readFile: readFile64 } = await import("fs/promises");
17229
17229
  const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
17230
17230
  const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
17231
17231
  let assignmentRef;
@@ -17246,7 +17246,7 @@ workspace: ${workspace}
17246
17246
  }
17247
17247
  const assignmentMdPath2 = resolvePath2(assignmentDir, "assignment.md");
17248
17248
  if (!await fileExists2(assignmentMdPath2)) return { error: `Target assignment not found: ${assignmentMdPath2}` };
17249
- let content = await readFile63(assignmentMdPath2, "utf-8");
17249
+ let content = await readFile64(assignmentMdPath2, "utf-8");
17250
17250
  content = appendTodosToAssignmentBody2(
17251
17251
  content,
17252
17252
  items.map((it) => ({
@@ -18920,8 +18920,8 @@ async function restoreFromGithub(overrides) {
18920
18920
  await safeRestoreCategory(localPath, repoSrcPath, isFile);
18921
18921
  restored.push(category);
18922
18922
  } catch (error) {
18923
- const msg = error instanceof Error ? error.message : String(error);
18924
- console.error(`Failed to restore "${category}": ${msg}`);
18923
+ const msg2 = error instanceof Error ? error.message : String(error);
18924
+ console.error(`Failed to restore "${category}": ${msg2}`);
18925
18925
  failed.push(category);
18926
18926
  }
18927
18927
  }
@@ -22083,13 +22083,13 @@ async function executeLaunchPlan(plan, spawnFn = realSpawn) {
22083
22083
  env: plan.env
22084
22084
  });
22085
22085
  } catch (err2) {
22086
- const msg = err2 instanceof Error ? err2.message : String(err2);
22086
+ const msg2 = err2 instanceof Error ? err2.message : String(err2);
22087
22087
  throw new TerminalNotFoundError(
22088
22088
  plan.terminal,
22089
- `Spawn failed: ${msg}. Verify the terminal is installed and on PATH.`
22089
+ `Spawn failed: ${msg2}. Verify the terminal is installed and on PATH.`
22090
22090
  );
22091
22091
  }
22092
- await new Promise((resolve86, reject) => {
22092
+ await new Promise((resolve87, reject) => {
22093
22093
  let settled = false;
22094
22094
  let stderr = "";
22095
22095
  const finishOk = () => {
@@ -22099,7 +22099,7 @@ async function executeLaunchPlan(plan, spawnFn = realSpawn) {
22099
22099
  child.unref();
22100
22100
  } catch {
22101
22101
  }
22102
- resolve86();
22102
+ resolve87();
22103
22103
  };
22104
22104
  const finishErr = (remediation) => {
22105
22105
  if (settled) return;
@@ -22270,7 +22270,7 @@ function normalizeSlashes(p) {
22270
22270
  }
22271
22271
  function detectInstallKind(scriptUrl, opts = {}) {
22272
22272
  const realpath3 = opts.realpath ?? realpathSync.native;
22273
- const readFile63 = opts.readFile ?? ((p) => readFileSync(p, "utf-8"));
22273
+ const readFile64 = opts.readFile ?? ((p) => readFileSync(p, "utf-8"));
22274
22274
  const ua = opts.envUserAgent !== void 0 ? opts.envUserAgent : process.env.npm_config_user_agent ?? "";
22275
22275
  const resolved = resolveScriptPath(scriptUrl, realpath3);
22276
22276
  if (resolved === null) {
@@ -22291,7 +22291,7 @@ function detectInstallKind(scriptUrl, opts = {}) {
22291
22291
  const pkgJsonPath = join5(dir, "package.json");
22292
22292
  let raw2;
22293
22293
  try {
22294
- raw2 = readFile63(pkgJsonPath);
22294
+ raw2 = readFile64(pkgJsonPath);
22295
22295
  } catch {
22296
22296
  const parent2 = dirname12(dir);
22297
22297
  if (parent2 === dir) break;
@@ -23428,36 +23428,267 @@ init_config2();
23428
23428
  // src/commands/cross-agent-install.ts
23429
23429
  init_fs();
23430
23430
  import { spawnSync as spawnSync6 } from "child_process";
23431
- import { resolve as resolve47 } from "path";
23432
- import { readFile as readFile31 } from "fs/promises";
23431
+ import { dirname as dirname17, join as join9, resolve as resolve48 } from "path";
23432
+ import { cp as cp4, mkdir as mkdir8, readFile as readFile32 } from "fs/promises";
23433
23433
 
23434
23434
  // src/commands/setup-adapter.ts
23435
23435
  init_paths();
23436
23436
  init_fs();
23437
23437
  init_config2();
23438
23438
  init_slug();
23439
- import { resolve as resolve46 } from "path";
23439
+ import { resolve as resolve47 } from "path";
23440
23440
 
23441
23441
  // src/targets/registry.ts
23442
23442
  init_fs();
23443
23443
  import { homedir as homedir8 } from "os";
23444
+ import { resolve as resolve46 } from "path";
23445
+
23446
+ // src/targets/user-descriptors.ts
23447
+ init_fs();
23448
+ init_paths();
23444
23449
  import { resolve as resolve45 } from "path";
23450
+ import { readFile as readFile31, readdir as readdir17 } from "fs/promises";
23451
+
23452
+ // src/targets/renderers.ts
23453
+ init_cursor_rules();
23454
+ init_codex_agents();
23455
+ init_opencode_config();
23456
+ init_hermes_soul();
23457
+ var RENDERERS = {
23458
+ codexAgents: (ctx) => renderCodexAgents(ctx),
23459
+ cursorProtocol: () => renderCursorProtocol(),
23460
+ cursorAssignment: (ctx) => renderCursorAssignment(ctx),
23461
+ openCodeConfig: (ctx) => renderOpenCodeConfig({ projectDir: ctx.projectDir }),
23462
+ hermesSoul: (ctx) => renderHermesSoul(ctx)
23463
+ };
23464
+
23465
+ // src/targets/user-descriptors.ts
23466
+ function userTargetsDir() {
23467
+ return resolve45(syntaurRoot(), "targets");
23468
+ }
23469
+ var ID_RE = /^[a-z0-9][a-z0-9_-]*$/;
23470
+ var VALID_RENDERER_KEYS = new Set(Object.keys(RENDERERS));
23471
+ var ALLOWED_TOP_KEYS = /* @__PURE__ */ new Set([
23472
+ "id",
23473
+ "displayName",
23474
+ "skillsShAgentId",
23475
+ "detect",
23476
+ "skillsDir",
23477
+ "instructions"
23478
+ ]);
23479
+ function msg(err2) {
23480
+ return err2 instanceof Error ? err2.message : String(err2);
23481
+ }
23482
+ function expandHomeAndEnv(p) {
23483
+ const envExpanded = p.replace(
23484
+ /\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Za-z_][A-Za-z0-9_]*)/g,
23485
+ (_m, braced, bare) => {
23486
+ const name = braced ?? bare ?? "";
23487
+ const v = process.env[name];
23488
+ return v ?? "";
23489
+ }
23490
+ );
23491
+ return resolve45(expandHome(envExpanded));
23492
+ }
23493
+ function compileDetect(spec) {
23494
+ switch (spec.kind) {
23495
+ case "pathExists": {
23496
+ const p = expandHomeAndEnv(spec.path);
23497
+ return () => fileExists(p);
23498
+ }
23499
+ case "anyPathExists": {
23500
+ const ps = spec.paths.map(expandHomeAndEnv);
23501
+ return async () => {
23502
+ for (const p of ps) {
23503
+ if (await fileExists(p)) return true;
23504
+ }
23505
+ return false;
23506
+ };
23507
+ }
23508
+ case "envSet": {
23509
+ const env = spec.env;
23510
+ return async () => {
23511
+ const v = process.env[env];
23512
+ return typeof v === "string" && v.length > 0;
23513
+ };
23514
+ }
23515
+ }
23516
+ }
23517
+ function isPlainObject(v) {
23518
+ return typeof v === "object" && v !== null && !Array.isArray(v);
23519
+ }
23520
+ function validateDetect(detect, errors) {
23521
+ if (!isPlainObject(detect)) {
23522
+ errors.push("detect must be an object");
23523
+ return;
23524
+ }
23525
+ switch (detect.kind) {
23526
+ case "pathExists":
23527
+ if (typeof detect.path !== "string" || detect.path.length === 0)
23528
+ errors.push('detect.path must be a non-empty string for kind "pathExists"');
23529
+ break;
23530
+ case "anyPathExists":
23531
+ if (!Array.isArray(detect.paths) || detect.paths.length === 0 || !detect.paths.every((p) => typeof p === "string" && p.length > 0))
23532
+ errors.push('detect.paths must be a non-empty string[] for kind "anyPathExists"');
23533
+ break;
23534
+ case "envSet":
23535
+ if (typeof detect.env !== "string" || detect.env.length === 0)
23536
+ errors.push('detect.env must be a non-empty string for kind "envSet"');
23537
+ break;
23538
+ default:
23539
+ errors.push(
23540
+ `detect.kind must be one of pathExists|anyPathExists|envSet (got ${JSON.stringify(detect.kind)})`
23541
+ );
23542
+ }
23543
+ }
23544
+ function validateInstructions(instructions, errors) {
23545
+ if (!isPlainObject(instructions)) {
23546
+ errors.push("instructions must be an object");
23547
+ return;
23548
+ }
23549
+ if (!Array.isArray(instructions.files) || instructions.files.length === 0) {
23550
+ errors.push("instructions.files must be a non-empty array");
23551
+ return;
23552
+ }
23553
+ instructions.files.forEach((f, i) => {
23554
+ if (!isPlainObject(f)) {
23555
+ errors.push(`instructions.files[${i}] must be an object`);
23556
+ return;
23557
+ }
23558
+ if (typeof f.path !== "string" || f.path.length === 0)
23559
+ errors.push(`instructions.files[${i}].path must be a non-empty string`);
23560
+ if (typeof f.renderer !== "string" || !VALID_RENDERER_KEYS.has(f.renderer))
23561
+ errors.push(
23562
+ `instructions.files[${i}].renderer ${JSON.stringify(f.renderer)} is not a known renderer (valid: ${[...VALID_RENDERER_KEYS].join(", ")})`
23563
+ );
23564
+ });
23565
+ }
23566
+ function validateUserDescriptor(data, builtinIds) {
23567
+ const errors = [];
23568
+ if (!isPlainObject(data)) {
23569
+ return { ok: false, errors: ["descriptor must be a JSON object"] };
23570
+ }
23571
+ for (const k of Object.keys(data)) {
23572
+ if (!ALLOWED_TOP_KEYS.has(k)) errors.push(`unknown field "${k}"`);
23573
+ }
23574
+ if (typeof data.id !== "string" || data.id.length === 0) {
23575
+ errors.push("id is required and must be a non-empty string");
23576
+ } else if (!ID_RE.test(data.id)) {
23577
+ errors.push(`id "${data.id}" must match ${ID_RE.source}`);
23578
+ } else if (builtinIds.has(data.id)) {
23579
+ errors.push(
23580
+ `id "${data.id}" collides with a built-in agent (built-ins cannot be overridden)`
23581
+ );
23582
+ }
23583
+ if (typeof data.displayName !== "string" || data.displayName.trim().length === 0) {
23584
+ errors.push("displayName is required and must be a non-empty string");
23585
+ }
23586
+ if (data.skillsShAgentId !== void 0 && (typeof data.skillsShAgentId !== "string" || data.skillsShAgentId.length === 0)) {
23587
+ errors.push("skillsShAgentId must be a non-empty string when present");
23588
+ }
23589
+ if (data.detect === void 0) {
23590
+ errors.push("detect is required");
23591
+ } else {
23592
+ validateDetect(data.detect, errors);
23593
+ }
23594
+ if (data.skillsDir !== void 0) {
23595
+ if (!isPlainObject(data.skillsDir)) {
23596
+ errors.push("skillsDir must be an object");
23597
+ } else {
23598
+ for (const k of Object.keys(data.skillsDir)) {
23599
+ if (k !== "project" && k !== "global") errors.push(`skillsDir.${k} is not a valid key`);
23600
+ }
23601
+ if (data.skillsDir.project !== void 0 && typeof data.skillsDir.project !== "string")
23602
+ errors.push("skillsDir.project must be a string");
23603
+ if (data.skillsDir.global !== void 0 && typeof data.skillsDir.global !== "string")
23604
+ errors.push("skillsDir.global must be a string");
23605
+ }
23606
+ }
23607
+ if (data.instructions !== void 0) {
23608
+ validateInstructions(data.instructions, errors);
23609
+ }
23610
+ if (errors.length > 0) return { ok: false, errors };
23611
+ return { ok: true, value: data };
23612
+ }
23613
+ function compileDescriptor(desc) {
23614
+ const target = {
23615
+ id: desc.id,
23616
+ displayName: desc.displayName,
23617
+ detect: compileDetect(desc.detect)
23618
+ };
23619
+ if (desc.skillsShAgentId) target.skillsShAgentId = desc.skillsShAgentId;
23620
+ if (desc.skillsDir) {
23621
+ const skillsDir = {};
23622
+ if (desc.skillsDir.global) skillsDir.global = expandHomeAndEnv(desc.skillsDir.global);
23623
+ if (desc.skillsDir.project) skillsDir.project = desc.skillsDir.project;
23624
+ target.skillsDir = skillsDir;
23625
+ }
23626
+ if (desc.instructions) target.instructions = desc.instructions;
23627
+ return target;
23628
+ }
23629
+ async function loadUserDescriptors(opts = {}) {
23630
+ const dir = opts.dir ?? userTargetsDir();
23631
+ const builtinIds = opts.builtinIds ?? /* @__PURE__ */ new Set();
23632
+ const warnings = [];
23633
+ if (!await fileExists(dir)) return { targets: [], warnings };
23634
+ let files;
23635
+ try {
23636
+ files = (await readdir17(dir)).filter((f) => f.endsWith(".json")).sort();
23637
+ } catch (err2) {
23638
+ return { targets: [], warnings: [`could not read ${dir}: ${msg(err2)}`] };
23639
+ }
23640
+ const targets = [];
23641
+ const seen = /* @__PURE__ */ new Set();
23642
+ for (const file of files) {
23643
+ const full = resolve45(dir, file);
23644
+ let raw2;
23645
+ try {
23646
+ raw2 = await readFile31(full, "utf-8");
23647
+ } catch (err2) {
23648
+ warnings.push(`skipped ${file}: ${msg(err2)}`);
23649
+ continue;
23650
+ }
23651
+ let parsed;
23652
+ try {
23653
+ parsed = JSON.parse(raw2);
23654
+ } catch (err2) {
23655
+ warnings.push(`skipped ${file}: invalid JSON: ${msg(err2)}`);
23656
+ continue;
23657
+ }
23658
+ const result = validateUserDescriptor(parsed, builtinIds);
23659
+ if (!result.ok) {
23660
+ warnings.push(`skipped ${file}: ${result.errors.join("; ")}`);
23661
+ continue;
23662
+ }
23663
+ if (seen.has(result.value.id)) {
23664
+ warnings.push(
23665
+ `skipped ${file}: duplicate id "${result.value.id}" (already loaded from an earlier file)`
23666
+ );
23667
+ continue;
23668
+ }
23669
+ seen.add(result.value.id);
23670
+ targets.push(compileDescriptor(result.value));
23671
+ }
23672
+ return { targets, warnings };
23673
+ }
23674
+
23675
+ // src/targets/registry.ts
23445
23676
  function home(...segments) {
23446
- return resolve45(homedir8(), ...segments);
23677
+ return resolve46(homedir8(), ...segments);
23447
23678
  }
23448
23679
  function hermesHome() {
23449
23680
  const env = process.env.HERMES_HOME;
23450
- return env && env.length > 0 ? resolve45(env) : home(".hermes");
23681
+ return env && env.length > 0 ? resolve46(env) : home(".hermes");
23451
23682
  }
23452
23683
  function hermesSkillsDir() {
23453
- return resolve45(hermesHome(), "skills");
23684
+ return resolve46(hermesHome(), "skills");
23454
23685
  }
23455
23686
  function isHermesHomeCustom() {
23456
23687
  return hermesHome() !== home(".hermes");
23457
23688
  }
23458
23689
  function codexHome() {
23459
23690
  const env = process.env.CODEX_HOME;
23460
- return env && env.length > 0 ? resolve45(env) : home(".codex");
23691
+ return env && env.length > 0 ? resolve46(env) : home(".codex");
23461
23692
  }
23462
23693
  var detectDir = (dir) => () => fileExists(dir);
23463
23694
  var AGENT_TARGETS = [
@@ -23481,7 +23712,7 @@ var AGENT_TARGETS = [
23481
23712
  skillsShAgentId: "codex",
23482
23713
  nativePlugin: "codex",
23483
23714
  detect: detectDir(codexHome()),
23484
- skillsDir: { global: resolve45(codexHome(), "skills") },
23715
+ skillsDir: { global: resolve46(codexHome(), "skills") },
23485
23716
  instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] }
23486
23717
  },
23487
23718
  {
@@ -23513,7 +23744,13 @@ var AGENT_TARGETS = [
23513
23744
  skillsShAgentId: "pi",
23514
23745
  detect: detectDir(home(".pi")),
23515
23746
  skillsDir: { global: home(".pi", "agent", "skills") },
23516
- instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] }
23747
+ instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] },
23748
+ tier3: {
23749
+ kind: "pi-extension",
23750
+ source: "platforms/pi/extensions/syntaur",
23751
+ installDir: () => home(".pi", "agent", "extensions", "syntaur"),
23752
+ entry: "index.ts"
23753
+ }
23517
23754
  },
23518
23755
  {
23519
23756
  id: "openclaw",
@@ -23521,7 +23758,15 @@ var AGENT_TARGETS = [
23521
23758
  skillsShAgentId: "openclaw",
23522
23759
  detect: detectDir(home(".openclaw")),
23523
23760
  skillsDir: { global: home(".openclaw", "skills") },
23524
- instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] }
23761
+ instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] },
23762
+ // OpenClaw runs on pi-coding-agent (design memo), so it reuses the pi
23763
+ // extension SOURCE; only the install dir differs.
23764
+ tier3: {
23765
+ kind: "pi-extension",
23766
+ source: "platforms/pi/extensions/syntaur",
23767
+ installDir: () => home(".openclaw", "extensions", "syntaur"),
23768
+ entry: "index.ts"
23769
+ }
23525
23770
  },
23526
23771
  {
23527
23772
  id: "hermes",
@@ -23529,42 +23774,34 @@ var AGENT_TARGETS = [
23529
23774
  skillsShAgentId: "hermes-agent",
23530
23775
  detect: () => fileExists(hermesHome()),
23531
23776
  skillsDir: { global: hermesSkillsDir() },
23532
- instructions: { files: [{ path: "SOUL.md", renderer: "hermesSoul" }] }
23777
+ instructions: { files: [{ path: "SOUL.md", renderer: "hermesSoul" }] },
23778
+ tier3: {
23779
+ kind: "hermes-plugin",
23780
+ source: "platforms/hermes/plugins/syntaur",
23781
+ installDir: () => resolve46(hermesHome(), "plugins", "syntaur"),
23782
+ entry: "plugin.yaml"
23783
+ }
23533
23784
  }
23534
23785
  ];
23535
23786
  var AGENT_TARGETS_BY_ID = Object.fromEntries(
23536
23787
  AGENT_TARGETS.map((t) => [t.id, t])
23537
23788
  );
23538
- function getAgentTarget(id) {
23539
- return AGENT_TARGETS_BY_ID[id];
23540
- }
23541
- function agentTargetIds() {
23542
- return AGENT_TARGETS.map((t) => t.id);
23543
- }
23544
- function adapterTargets() {
23545
- return AGENT_TARGETS.filter((t) => t.instructions !== void 0);
23789
+ async function resolveAgentTargets() {
23790
+ const { targets: user, warnings } = await loadUserDescriptors({
23791
+ builtinIds: new Set(AGENT_TARGETS.map((t) => t.id))
23792
+ });
23793
+ return { targets: [...AGENT_TARGETS, ...user], warnings };
23546
23794
  }
23547
23795
 
23548
- // src/targets/renderers.ts
23549
- init_cursor_rules();
23550
- init_codex_agents();
23551
- init_opencode_config();
23552
- init_hermes_soul();
23553
- var RENDERERS = {
23554
- codexAgents: (ctx) => renderCodexAgents(ctx),
23555
- cursorProtocol: () => renderCursorProtocol(),
23556
- cursorAssignment: (ctx) => renderCursorAssignment(ctx),
23557
- openCodeConfig: (ctx) => renderOpenCodeConfig({ projectDir: ctx.projectDir }),
23558
- hermesSoul: (ctx) => renderHermesSoul(ctx)
23559
- };
23560
-
23561
23796
  // src/commands/setup-adapter.ts
23562
23797
  async function setupAdapterCommand(framework, options) {
23563
- const target = getAgentTarget(framework);
23798
+ const { targets: known, warnings } = await resolveAgentTargets();
23799
+ const target = known.find((t) => t.id === framework);
23564
23800
  if (!target || !target.instructions) {
23565
- const supported = adapterTargets().map((t) => t.id).join(", ");
23801
+ const supported = known.filter((t) => t.instructions !== void 0).map((t) => t.id).join(", ");
23802
+ const warn2 = warnings.length ? ` (descriptor warnings: ${warnings.join("; ")})` : "";
23566
23803
  throw new Error(
23567
- `Unsupported framework "${framework}". Supported: ${supported}`
23804
+ `Unsupported framework "${framework}". Supported: ${supported}.${warn2}`
23568
23805
  );
23569
23806
  }
23570
23807
  if (!options.project) {
@@ -23585,13 +23822,13 @@ async function setupAdapterCommand(framework, options) {
23585
23822
  }
23586
23823
  const config = await readConfig();
23587
23824
  const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
23588
- const projectDir = resolve46(baseDir, options.project);
23589
- const assignmentDir = resolve46(projectDir, "assignments", options.assignment);
23590
- const projectMdPath = resolve46(projectDir, "project.md");
23825
+ const projectDir = resolve47(baseDir, options.project);
23826
+ const assignmentDir = resolve47(projectDir, "assignments", options.assignment);
23827
+ const projectMdPath = resolve47(projectDir, "project.md");
23591
23828
  if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
23592
23829
  throw new Error(`Project "${options.project}" not found at ${projectDir}.`);
23593
23830
  }
23594
- const assignmentMdPath2 = resolve46(assignmentDir, "assignment.md");
23831
+ const assignmentMdPath2 = resolve47(assignmentDir, "assignment.md");
23595
23832
  if (!await fileExists(assignmentDir) || !await fileExists(assignmentMdPath2)) {
23596
23833
  throw new Error(
23597
23834
  `Assignment "${options.assignment}" not found at ${assignmentDir}.`
@@ -23608,7 +23845,7 @@ async function setupAdapterCommand(framework, options) {
23608
23845
  const upToDateFiles = [];
23609
23846
  const skippedFiles = [];
23610
23847
  for (const file of target.instructions.files) {
23611
- const filePath = resolve46(cwd, file.path);
23848
+ const filePath = resolve47(cwd, file.path);
23612
23849
  const content = RENDERERS[file.renderer](rendererParams);
23613
23850
  const status = await writeFileReport(filePath, content, {
23614
23851
  force: options.force
@@ -23647,6 +23884,33 @@ async function setupAdapterCommand(framework, options) {
23647
23884
  // src/commands/cross-agent-install.ts
23648
23885
  init_config2();
23649
23886
  var DEFAULT_SKILLS_SOURCE = "prong-horn/syntaur";
23887
+ async function installTier3Plugin(t, opts = {}) {
23888
+ if (!t.tier3) return "none";
23889
+ const plugin = t.tier3;
23890
+ const installDir = plugin.installDir();
23891
+ const prefix = opts.prefix ?? "";
23892
+ if (opts.dryRun) {
23893
+ console.log(`${prefix}Tier 3 (${t.id}): ${plugin.source} -> ${installDir}`);
23894
+ return "dry-run";
23895
+ }
23896
+ if (await fileExists(join9(installDir, plugin.entry)) && !opts.force) {
23897
+ console.log(
23898
+ `Tier 3 (${t.id}): already installed at ${installDir} (use --force to overwrite).`
23899
+ );
23900
+ return "already-present";
23901
+ }
23902
+ try {
23903
+ const sourceDir = resolve48(await findPackageRoot(plugin.source), plugin.source);
23904
+ await mkdir8(dirname17(installDir), { recursive: true });
23905
+ await cp4(sourceDir, installDir, { recursive: true, force: true });
23906
+ console.log(`Tier 3 (${t.id}): installed ${plugin.kind} -> ${installDir}`);
23907
+ return "installed";
23908
+ } catch (err2) {
23909
+ const msg2 = err2 instanceof Error ? err2.message : String(err2);
23910
+ console.log(`Tier 3 for ${t.id} FAILED: ${msg2}`);
23911
+ return "failed";
23912
+ }
23913
+ }
23650
23914
  function parseTargetIds(options) {
23651
23915
  const raw2 = [options.target, options.agent].filter(Boolean).join(",");
23652
23916
  const ids = raw2.split(",").map((s) => s.trim()).filter(Boolean);
@@ -23661,10 +23925,10 @@ function isNpxAvailable() {
23661
23925
  }
23662
23926
  }
23663
23927
  async function readAssignmentContext() {
23664
- const p = resolve47(process.cwd(), ".syntaur", "context.json");
23928
+ const p = resolve48(process.cwd(), ".syntaur", "context.json");
23665
23929
  if (!await fileExists(p)) return null;
23666
23930
  try {
23667
- return JSON.parse(await readFile31(p, "utf-8"));
23931
+ return JSON.parse(await readFile32(p, "utf-8"));
23668
23932
  } catch {
23669
23933
  return null;
23670
23934
  }
@@ -23674,12 +23938,15 @@ async function crossAgentInstallCommand(options) {
23674
23938
  if (ids.length === 0) {
23675
23939
  throw new Error("No agents specified. Use --target <id> or --agent <id>.");
23676
23940
  }
23941
+ const { targets: known, warnings } = await resolveAgentTargets();
23942
+ for (const w of warnings) console.log(`Warning (user target): ${w}`);
23943
+ const byId = new Map(known.map((t) => [t.id, t]));
23677
23944
  const targets = [];
23678
23945
  for (const id of ids) {
23679
- const t = getAgentTarget(id);
23946
+ const t = byId.get(id);
23680
23947
  if (!t) {
23681
23948
  throw new Error(
23682
- `Unknown agent "${id}". Known agents: ${agentTargetIds().join(", ")}`
23949
+ `Unknown agent "${id}". Known agents: ${known.map((k) => k.id).join(", ")}`
23683
23950
  );
23684
23951
  }
23685
23952
  if (t.nativePlugin) {
@@ -23713,8 +23980,15 @@ async function crossAgentInstallCommand(options) {
23713
23980
  }
23714
23981
  for (const t of targets) {
23715
23982
  const globalDir = t.id === "hermes" ? hermesSkillsDir() : t.skillsDir?.global;
23716
- if (!globalDir) continue;
23717
23983
  const offlineNeeded = !tier1Done;
23984
+ if (!globalDir) {
23985
+ if (offlineNeeded && !dryRun) {
23986
+ console.log(
23987
+ `Warning: skills NOT installed for ${t.displayName} \u2014 Tier-1 (npx skills add) was unavailable/failed and the descriptor has no skillsDir.global for an offline copy.`
23988
+ );
23989
+ }
23990
+ continue;
23991
+ }
23718
23992
  const hermesCustom = t.id === "hermes" && isHermesHomeCustom();
23719
23993
  if (!offlineNeeded && !hermesCustom) continue;
23720
23994
  if (dryRun) {
@@ -23726,15 +24000,15 @@ async function crossAgentInstallCommand(options) {
23726
24000
  await installSkillsToDir({ targetDir: globalDir, force });
23727
24001
  console.log(`Copied skills -> ${globalDir}${reason}`);
23728
24002
  }
23729
- const adapterTargets2 = targets.filter((t) => t.instructions);
23730
- if (adapterTargets2.length > 0) {
24003
+ const adapterTargets = targets.filter((t) => t.instructions);
24004
+ if (adapterTargets.length > 0) {
23731
24005
  const ctx = await readAssignmentContext();
23732
24006
  const haveCtx = Boolean(ctx?.projectSlug && ctx?.assignmentSlug);
23733
- for (const t of adapterTargets2) {
24007
+ for (const t of adapterTargets) {
23734
24008
  if (dryRun) {
23735
24009
  for (const f of t.instructions.files) {
23736
24010
  console.log(
23737
- `${prefix}Tier 2 (${t.id}): ${resolve47(process.cwd(), f.path)}`
24011
+ `${prefix}Tier 2 (${t.id}): ${resolve48(process.cwd(), f.path)}`
23738
24012
  );
23739
24013
  }
23740
24014
  continue;
@@ -23752,11 +24026,21 @@ async function crossAgentInstallCommand(options) {
23752
24026
  force
23753
24027
  });
23754
24028
  } catch (err2) {
23755
- const msg = err2 instanceof Error ? err2.message : String(err2);
23756
- console.log(`Tier 2 for ${t.id} skipped: ${msg}`);
24029
+ const msg2 = err2 instanceof Error ? err2.message : String(err2);
24030
+ console.log(`Tier 2 for ${t.id} skipped: ${msg2}`);
23757
24031
  }
23758
24032
  }
23759
24033
  }
24034
+ const tier3Failures = [];
24035
+ for (const t of targets.filter((x) => x.tier3)) {
24036
+ const result = await installTier3Plugin(t, { dryRun, force, prefix });
24037
+ if (result === "failed") tier3Failures.push(t.displayName);
24038
+ }
24039
+ if (tier3Failures.length > 0) {
24040
+ throw new Error(
24041
+ `Tier-3 enforcement plugin failed to install for: ${tier3Failures.join(", ")}. Enforcement is NOT active for ${tier3Failures.length > 1 ? "those agents" : "that agent"} \u2014 check permissions and re-run \`syntaur setup --target <id> --force\`.`
24042
+ );
24043
+ }
23760
24044
  if (!dryRun) {
23761
24045
  const current = (await readConfig()).integrations.installedAgents ?? {};
23762
24046
  const next = { ...current };
@@ -23881,7 +24165,7 @@ async function setupCommand(options) {
23881
24165
  }
23882
24166
 
23883
24167
  // src/commands/uninstall.ts
23884
- import { resolve as resolve48 } from "path";
24168
+ import { resolve as resolve49 } from "path";
23885
24169
  init_paths();
23886
24170
  function expandTargets(options) {
23887
24171
  if (options.all) {
@@ -23961,7 +24245,7 @@ async function uninstallCommand(options) {
23961
24245
  const configuredProjectDir = await getConfiguredProjectDir();
23962
24246
  await removeSyntaurData();
23963
24247
  console.log(`Removed ${syntaurRoot()}`);
23964
- if (configuredProjectDir && resolve48(configuredProjectDir) !== resolve48(syntaurRoot(), "projects")) {
24248
+ if (configuredProjectDir && resolve49(configuredProjectDir) !== resolve49(syntaurRoot(), "projects")) {
23965
24249
  console.warn(
23966
24250
  `Warning: config.md pointed to an external project directory (${configuredProjectDir}). That directory was not removed automatically.`
23967
24251
  );
@@ -23976,7 +24260,7 @@ async function uninstallCommand(options) {
23976
24260
  init_paths();
23977
24261
  init_fs();
23978
24262
  init_config2();
23979
- import { resolve as resolve49 } from "path";
24263
+ import { resolve as resolve50 } from "path";
23980
24264
  init_git_worktree();
23981
24265
  init_cwd();
23982
24266
  init_session_db();
@@ -23993,7 +24277,7 @@ async function trackSessionCommand(options) {
23993
24277
  if (options.project) {
23994
24278
  const config = await readConfig();
23995
24279
  const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
23996
- const projectDir = resolve49(baseDir, options.project);
24280
+ const projectDir = resolve50(baseDir, options.project);
23997
24281
  if (!await fileExists(projectDir)) {
23998
24282
  throw new Error(
23999
24283
  `Project "${options.project}" not found at ${projectDir}.`
@@ -24127,8 +24411,8 @@ function formatInstallUrlHandlerError(err2) {
24127
24411
  init_config2();
24128
24412
  init_paths();
24129
24413
  init_fs();
24130
- import { resolve as resolve51, isAbsolute as isAbsolute8 } from "path";
24131
- import { readFile as readFile32 } from "fs/promises";
24414
+ import { resolve as resolve52, isAbsolute as isAbsolute8 } from "path";
24415
+ import { readFile as readFile33 } from "fs/promises";
24132
24416
  import { select, confirm as confirm2, input as input3 } from "@inquirer/prompts";
24133
24417
  async function browseCommand(options) {
24134
24418
  const config = await readConfig();
@@ -24197,7 +24481,7 @@ async function pickAgent2(agents) {
24197
24481
  return picked;
24198
24482
  }
24199
24483
  async function ensureWorktree(opts) {
24200
- const assignmentPath = resolve51(
24484
+ const assignmentPath = resolve52(
24201
24485
  opts.projectsDir,
24202
24486
  opts.projectSlug,
24203
24487
  "assignments",
@@ -24207,7 +24491,7 @@ async function ensureWorktree(opts) {
24207
24491
  if (!await fileExists(assignmentPath)) {
24208
24492
  return void 0;
24209
24493
  }
24210
- const content = await readFile32(assignmentPath, "utf-8");
24494
+ const content = await readFile33(assignmentPath, "utf-8");
24211
24495
  const { parseAssignmentFrontmatter: parseAssignmentFrontmatter2 } = await Promise.resolve().then(() => (init_frontmatter(), frontmatter_exports));
24212
24496
  const fm = parseAssignmentFrontmatter2(content);
24213
24497
  const { workspace } = fm;
@@ -24277,7 +24561,7 @@ async function ensureWorktree(opts) {
24277
24561
  async function runCreate(opts) {
24278
24562
  const { createWorktreeAndRecord: createWorktreeAndRecord2, GitWorktreeError: GitWorktreeError2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
24279
24563
  const expandedWorktree = expandHome(opts.worktreePath);
24280
- const absWorktree = isAbsolute8(expandedWorktree) ? expandedWorktree : resolve51(expandedWorktree);
24564
+ const absWorktree = isAbsolute8(expandedWorktree) ? expandedWorktree : resolve52(expandedWorktree);
24281
24565
  try {
24282
24566
  await createWorktreeAndRecord2({
24283
24567
  assignmentPath: opts.assignmentPath,
@@ -24289,11 +24573,11 @@ async function runCreate(opts) {
24289
24573
  console.log(`syntaur: created worktree at ${absWorktree} on branch ${opts.branch}`);
24290
24574
  return absWorktree;
24291
24575
  } catch (err2) {
24292
- const msg = err2 instanceof Error ? err2.message : String(err2);
24576
+ const msg2 = err2 instanceof Error ? err2.message : String(err2);
24293
24577
  if (err2 instanceof GitWorktreeError2) {
24294
- console.error(`syntaur: ${msg}`);
24578
+ console.error(`syntaur: ${msg2}`);
24295
24579
  } else {
24296
- console.error(`syntaur: ${msg}`);
24580
+ console.error(`syntaur: ${msg2}`);
24297
24581
  }
24298
24582
  process.exit(1);
24299
24583
  }
@@ -24306,7 +24590,7 @@ init_paths();
24306
24590
  init_fs();
24307
24591
  init_playbook();
24308
24592
  init_playbooks();
24309
- import { resolve as resolve52 } from "path";
24593
+ import { resolve as resolve53 } from "path";
24310
24594
  async function createPlaybookCommand(name, options) {
24311
24595
  if (!name.trim()) {
24312
24596
  throw new Error("Playbook name cannot be empty.");
@@ -24319,7 +24603,7 @@ async function createPlaybookCommand(name, options) {
24319
24603
  }
24320
24604
  const dir = playbooksDir();
24321
24605
  await ensureDir(dir);
24322
- const filePath = resolve52(dir, `${slug}.md`);
24606
+ const filePath = resolve53(dir, `${slug}.md`);
24323
24607
  if (await fileExists(filePath)) {
24324
24608
  throw new Error(
24325
24609
  `Playbook "${slug}" already exists at ${filePath}
@@ -24341,8 +24625,8 @@ init_paths();
24341
24625
  init_fs();
24342
24626
  init_parser();
24343
24627
  init_config2();
24344
- import { readdir as readdir17, readFile as readFile33 } from "fs/promises";
24345
- import { resolve as resolve53 } from "path";
24628
+ import { readdir as readdir18, readFile as readFile34 } from "fs/promises";
24629
+ import { resolve as resolve54 } from "path";
24346
24630
  async function listPlaybooksCommand(options = {}) {
24347
24631
  const dir = playbooksDir();
24348
24632
  if (!await fileExists(dir)) {
@@ -24351,14 +24635,14 @@ async function listPlaybooksCommand(options = {}) {
24351
24635
  }
24352
24636
  const config = await readConfig();
24353
24637
  const disabledSet = new Set(config.playbooks.disabled);
24354
- const entries = await readdir17(dir, { withFileTypes: true });
24638
+ const entries = await readdir18(dir, { withFileTypes: true });
24355
24639
  const mdFiles = entries.filter(
24356
24640
  (e) => e.isFile() && e.name.endsWith(".md") && !e.name.startsWith("_") && e.name !== "manifest.md"
24357
24641
  );
24358
24642
  const rows = [];
24359
24643
  for (const entry of mdFiles) {
24360
- const filePath = resolve53(dir, entry.name);
24361
- const raw2 = await readFile33(filePath, "utf-8");
24644
+ const filePath = resolve54(dir, entry.name);
24645
+ const raw2 = await readFile34(filePath, "utf-8");
24362
24646
  const parsed = parsePlaybook(raw2);
24363
24647
  const slug = parsed.slug || entry.name.replace(/\.md$/, "");
24364
24648
  const disabled = disabledSet.has(slug);
@@ -24481,14 +24765,14 @@ init_fs();
24481
24765
  init_config2();
24482
24766
  init_slug();
24483
24767
  import { Command as Command2 } from "commander";
24484
- import { readFile as readFile35 } from "fs/promises";
24485
- import { resolve as resolve55 } from "path";
24768
+ import { readFile as readFile36 } from "fs/promises";
24769
+ import { resolve as resolve56 } from "path";
24486
24770
 
24487
24771
  // src/commands/bundle.ts
24488
24772
  init_paths();
24489
24773
  import { Command } from "commander";
24490
- import { mkdir as mkdir8, readFile as readFile34, readdir as readdir18, rm as rm8, writeFile as writeFile13 } from "fs/promises";
24491
- import { resolve as resolve54 } from "path";
24774
+ import { mkdir as mkdir9, readFile as readFile35, readdir as readdir19, rm as rm8, writeFile as writeFile13 } from "fs/promises";
24775
+ import { resolve as resolve55 } from "path";
24492
24776
  init_parser2();
24493
24777
  init_fs();
24494
24778
  init_config2();
@@ -24506,7 +24790,7 @@ async function resolveBundleScope(options) {
24506
24790
  throw new Error(`Invalid project slug: "${options.project}".`);
24507
24791
  }
24508
24792
  const config = await readConfig();
24509
- const projectMd = resolve54(config.defaultProjectDir, options.project, "project.md");
24793
+ const projectMd = resolve55(config.defaultProjectDir, options.project, "project.md");
24510
24794
  if (!await fileExists(projectMd)) {
24511
24795
  throw new Error(`Project "${options.project}" not found.`);
24512
24796
  }
@@ -24576,10 +24860,10 @@ function pickNextPlanFile(planDir, existingFiles) {
24576
24860
  const m = f.match(/^plan-v(\d+)\.md$/);
24577
24861
  if (m) versions.add(parseInt(m[1], 10));
24578
24862
  }
24579
- if (versions.size === 0) return { target: resolve54(planDir, "plan.md"), version: 1 };
24863
+ if (versions.size === 0) return { target: resolve55(planDir, "plan.md"), version: 1 };
24580
24864
  let n = 2;
24581
24865
  while (versions.has(n)) n++;
24582
- return { target: resolve54(planDir, `plan-v${n}.md`), version: n };
24866
+ return { target: resolve55(planDir, `plan-v${n}.md`), version: n };
24583
24867
  }
24584
24868
  function dedupePreserveOrder(ids) {
24585
24869
  const out = [];
@@ -24663,7 +24947,7 @@ bundleCommand.command("new").description("Create a new bundle from 2+ existing t
24663
24947
  if (options.plan) {
24664
24948
  const planDir = bundlePlanDir(sc.todosPath, sc.scopeId, id);
24665
24949
  await ensureDir(planDir);
24666
- const target = resolve54(planDir, "plan.md");
24950
+ const target = resolve55(planDir, "plan.md");
24667
24951
  const memberLines = items.map((it) => `- ${it.description} [t:${it.id}]`).join("\n");
24668
24952
  const stub = [
24669
24953
  "---",
@@ -24780,7 +25064,7 @@ bundleCommand.command("plan").description("Create or open the bundle's shared pl
24780
25064
  }
24781
25065
  const planDir = bundlePlanDir(sc.todosPath, sc.scopeId, id);
24782
25066
  await ensureDir(planDir);
24783
- const existing = (await readdir18(planDir).catch(() => [])).filter((f) => /^plan(?:-v\d+)?\.md$/.test(f));
25067
+ const existing = (await readdir19(planDir).catch(() => [])).filter((f) => /^plan(?:-v\d+)?\.md$/.test(f));
24784
25068
  const { target } = pickNextPlanFile(planDir, existing);
24785
25069
  const checklist = await readChecklist(sc.todosPath, sc.checklistKey);
24786
25070
  if (!await fileExists(target)) {
@@ -24839,7 +25123,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
24839
25123
  }
24840
25124
  const repository = options.repository ?? process.cwd();
24841
25125
  const parentBranch = options.parentBranch ?? "main";
24842
- const worktreePath = options.worktreePath ?? resolve54(repository, ".worktrees", options.branch);
25126
+ const worktreePath = options.worktreePath ?? resolve55(repository, ".worktrees", options.branch);
24843
25127
  const checklist = await readChecklist(sc.todosPath, sc.checklistKey);
24844
25128
  for (const memberId of bundle.todoIds) {
24845
25129
  const item = checklist.items.find((i) => i.id === memberId);
@@ -24849,8 +25133,8 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
24849
25133
  }
24850
25134
  const bundlesFilePath = bundlesPath(sc.todosPath);
24851
25135
  const checklistFilePath = checklistPath(sc.todosPath, sc.checklistKey);
24852
- const bundlesSnapshot = await fileExists(bundlesFilePath) ? await readFile34(bundlesFilePath, "utf-8") : null;
24853
- const checklistSnapshot = await fileExists(checklistFilePath) ? await readFile34(checklistFilePath, "utf-8") : null;
25136
+ const bundlesSnapshot = await fileExists(bundlesFilePath) ? await readFile35(bundlesFilePath, "utf-8") : null;
25137
+ const checklistSnapshot = await fileExists(checklistFilePath) ? await readFile35(checklistFilePath, "utf-8") : null;
24854
25138
  const record = async () => {
24855
25139
  bundle.branch = options.branch;
24856
25140
  bundle.worktreePath = worktreePath;
@@ -24866,8 +25150,8 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
24866
25150
  try {
24867
25151
  await writeBundles(sc.todosPath, bundles);
24868
25152
  await writeChecklist(sc.todosPath, checklist);
24869
- const ctxDir = resolve54(worktreePath, ".syntaur");
24870
- await mkdir8(ctxDir, { recursive: true });
25153
+ const ctxDir = resolve55(worktreePath, ".syntaur");
25154
+ await mkdir9(ctxDir, { recursive: true });
24871
25155
  const payload = {
24872
25156
  bundleId: bundle.id,
24873
25157
  bundleSlug: bundle.slug,
@@ -24880,7 +25164,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
24880
25164
  repository,
24881
25165
  boundAt: nowISO()
24882
25166
  };
24883
- await writeFile13(resolve54(ctxDir, "context.json"), JSON.stringify(payload, null, 2) + "\n");
25167
+ await writeFile13(resolve55(ctxDir, "context.json"), JSON.stringify(payload, null, 2) + "\n");
24884
25168
  } catch (err2) {
24885
25169
  try {
24886
25170
  if (bundlesSnapshot === null) {
@@ -25070,7 +25354,7 @@ async function resolveScope(options) {
25070
25354
  throw new Error(`Invalid project slug: "${options.project}".`);
25071
25355
  }
25072
25356
  const config = await readConfig();
25073
- const projectMd = resolve55(config.defaultProjectDir, options.project, "project.md");
25357
+ const projectMd = resolve56(config.defaultProjectDir, options.project, "project.md");
25074
25358
  if (!await fileExists(projectMd)) {
25075
25359
  throw new Error(`Project "${options.project}" not found.`);
25076
25360
  }
@@ -25393,10 +25677,10 @@ todoCommand.command("archive").description("Archive completed todos and their lo
25393
25677
  (e) => e.itemIds.every((id) => completedIds.has(id))
25394
25678
  );
25395
25679
  const archFile = archivePath(todosPath, workspace, checklist.archiveInterval);
25396
- await ensureDir(resolve55(todosPath, "archive"));
25680
+ await ensureDir(resolve56(todosPath, "archive"));
25397
25681
  let archContent = "";
25398
25682
  if (await fileExists(archFile)) {
25399
- archContent = await readFile35(archFile, "utf-8");
25683
+ archContent = await readFile36(archFile, "utf-8");
25400
25684
  archContent = archContent.trimEnd() + "\n\n";
25401
25685
  } else {
25402
25686
  archContent = `---
@@ -25573,12 +25857,12 @@ function describeScope(scope) {
25573
25857
  }
25574
25858
  async function injectPromotedTodos(assignmentDir, todos, scopeLabel) {
25575
25859
  const { resolve: resolvePath2 } = await import("path");
25576
- const { readFile: readFile63 } = await import("fs/promises");
25860
+ const { readFile: readFile64 } = await import("fs/promises");
25577
25861
  const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
25578
25862
  const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
25579
25863
  const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
25580
25864
  const assignmentMdPath2 = resolvePath2(assignmentDir, "assignment.md");
25581
- let content = await readFile63(assignmentMdPath2, "utf-8");
25865
+ let content = await readFile64(assignmentMdPath2, "utf-8");
25582
25866
  content = appendTodosToAssignmentBody2(
25583
25867
  content,
25584
25868
  todos.map((t) => ({
@@ -25623,13 +25907,13 @@ todoCommand.command("plan").description("Create or open a plan directory for a t
25623
25907
  }
25624
25908
  const planDir = todoPlanDir(todosPath, workspace, id);
25625
25909
  await ensureDir(planDir);
25626
- const { readdir: readdir32 } = await import("fs/promises");
25627
- const existingFiles = (await readdir32(planDir).catch(() => [])).filter(
25910
+ const { readdir: readdir33 } = await import("fs/promises");
25911
+ const existingFiles = (await readdir33(planDir).catch(() => [])).filter(
25628
25912
  (f) => /^plan(?:-v\d+)?\.md$/.test(f)
25629
25913
  );
25630
25914
  let target;
25631
25915
  if (existingFiles.length === 0) {
25632
- target = resolve55(planDir, "plan.md");
25916
+ target = resolve56(planDir, "plan.md");
25633
25917
  } else {
25634
25918
  const versions = /* @__PURE__ */ new Set();
25635
25919
  for (const f of existingFiles) {
@@ -25639,7 +25923,7 @@ todoCommand.command("plan").description("Create or open a plan directory for a t
25639
25923
  }
25640
25924
  let n = 2;
25641
25925
  while (versions.has(n)) n++;
25642
- target = resolve55(planDir, `plan-v${n}.md`);
25926
+ target = resolve56(planDir, `plan-v${n}.md`);
25643
25927
  }
25644
25928
  if (!await fileExists(target)) {
25645
25929
  const stub = `---
@@ -25709,9 +25993,9 @@ async function moveTodo(id, options) {
25709
25993
  if (await fileExists(newPlanDir)) {
25710
25994
  throw new Error(`Plan directory already exists at target: ${newPlanDir}; refusing to move.`);
25711
25995
  }
25712
- const { rename: rename11, mkdir: mkdir11 } = await import("fs/promises");
25713
- const { dirname: dirname23 } = await import("path");
25714
- await mkdir11(dirname23(newPlanDir), { recursive: true });
25996
+ const { rename: rename11, mkdir: mkdir12 } = await import("fs/promises");
25997
+ const { dirname: dirname24 } = await import("path");
25998
+ await mkdir12(dirname24(newPlanDir), { recursive: true });
25715
25999
  await rename11(item.planDir, newPlanDir);
25716
26000
  item.planDir = newPlanDir;
25717
26001
  }
@@ -25828,24 +26112,24 @@ backupCommand.command("config").description("Show or update backup configuration
25828
26112
 
25829
26113
  // src/commands/doctor.ts
25830
26114
  import { Command as Command4 } from "commander";
25831
- import { readFile as readFile45 } from "fs/promises";
25832
- import { isAbsolute as isAbsolute11, resolve as resolve68 } from "path";
26115
+ import { readFile as readFile46 } from "fs/promises";
26116
+ import { isAbsolute as isAbsolute11, resolve as resolve69 } from "path";
25833
26117
 
25834
26118
  // src/utils/doctor/index.ts
25835
26119
  import { fileURLToPath as fileURLToPath11 } from "url";
25836
- import { readFile as readFile44 } from "fs/promises";
25837
- import { dirname as dirname20, join as join13 } from "path";
26120
+ import { readFile as readFile45 } from "fs/promises";
26121
+ import { dirname as dirname21, join as join14 } from "path";
25838
26122
 
25839
26123
  // src/utils/doctor/context.ts
25840
26124
  init_config2();
25841
26125
  init_paths();
25842
26126
  init_fs();
25843
26127
  import Database4 from "better-sqlite3";
25844
- import { resolve as resolve56 } from "path";
26128
+ import { resolve as resolve57 } from "path";
25845
26129
  async function buildCheckContext(cwd = process.cwd()) {
25846
26130
  const config = await readConfig();
25847
26131
  const root = syntaurRoot();
25848
- const dbPath = resolve56(root, "syntaur.db");
26132
+ const dbPath = resolve57(root, "syntaur.db");
25849
26133
  let db5 = null;
25850
26134
  let dbError = null;
25851
26135
  if (await fileExists(dbPath)) {
@@ -25879,10 +26163,10 @@ function closeCheckContext(ctx) {
25879
26163
  // src/utils/doctor/checks/env.ts
25880
26164
  init_fs();
25881
26165
  init_paths();
25882
- import { resolve as resolve57, isAbsolute as isAbsolute9 } from "path";
25883
- import { readFile as readFile36, stat as stat4 } from "fs/promises";
26166
+ import { resolve as resolve58, isAbsolute as isAbsolute9 } from "path";
26167
+ import { readFile as readFile37, stat as stat4 } from "fs/promises";
25884
26168
  import { fileURLToPath as fileURLToPath10 } from "url";
25885
- import { dirname as dirname18, join as join10 } from "path";
26169
+ import { dirname as dirname19, join as join11 } from "path";
25886
26170
  var CATEGORY = "env";
25887
26171
  var syntaurRootExists = {
25888
26172
  id: "env.syntaur-root-exists",
@@ -25920,7 +26204,7 @@ var configValid = {
25920
26204
  category: CATEGORY,
25921
26205
  title: "~/.syntaur/config.md is valid",
25922
26206
  async run(ctx) {
25923
- const configPath2 = resolve57(ctx.syntaurRoot, "config.md");
26207
+ const configPath2 = resolve58(ctx.syntaurRoot, "config.md");
25924
26208
  if (!await fileExists(configPath2)) {
25925
26209
  return {
25926
26210
  id: this.id,
@@ -25937,7 +26221,7 @@ var configValid = {
25937
26221
  autoFixable: false
25938
26222
  };
25939
26223
  }
25940
- const content = await readFile36(configPath2, "utf-8");
26224
+ const content = await readFile37(configPath2, "utf-8");
25941
26225
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
25942
26226
  if (!fmMatch || fmMatch[1].trim() === "") {
25943
26227
  return {
@@ -26213,14 +26497,14 @@ async function readLocalVersion() {
26213
26497
  async function readLocalPkg() {
26214
26498
  try {
26215
26499
  const here = fileURLToPath10(import.meta.url);
26216
- let dir = dirname18(here);
26500
+ let dir = dirname19(here);
26217
26501
  for (let i = 0; i < 6; i++) {
26218
- const candidate = join10(dir, "package.json");
26502
+ const candidate = join11(dir, "package.json");
26219
26503
  try {
26220
- const text = await readFile36(candidate, "utf-8");
26504
+ const text = await readFile37(candidate, "utf-8");
26221
26505
  return JSON.parse(text);
26222
26506
  } catch {
26223
- dir = dirname18(dir);
26507
+ dir = dirname19(dir);
26224
26508
  }
26225
26509
  }
26226
26510
  return null;
@@ -26269,8 +26553,8 @@ function versionGte(a, b) {
26269
26553
 
26270
26554
  // src/utils/doctor/checks/structure.ts
26271
26555
  init_fs();
26272
- import { resolve as resolve58 } from "path";
26273
- import { readdir as readdir19, stat as stat5 } from "fs/promises";
26556
+ import { resolve as resolve59 } from "path";
26557
+ import { readdir as readdir20, stat as stat5 } from "fs/promises";
26274
26558
  var CATEGORY2 = "structure";
26275
26559
  var KNOWN_TOP_LEVEL = /* @__PURE__ */ new Set([
26276
26560
  "projects",
@@ -26289,7 +26573,7 @@ var projectsDir = {
26289
26573
  category: CATEGORY2,
26290
26574
  title: "projects/ directory exists",
26291
26575
  async run(ctx) {
26292
- const p = resolve58(ctx.syntaurRoot, "projects");
26576
+ const p = resolve59(ctx.syntaurRoot, "projects");
26293
26577
  if (!await fileExists(p)) {
26294
26578
  return {
26295
26579
  id: this.id,
@@ -26314,7 +26598,7 @@ var playbooksDir2 = {
26314
26598
  category: CATEGORY2,
26315
26599
  title: "playbooks/ directory exists",
26316
26600
  async run(ctx) {
26317
- const p = resolve58(ctx.syntaurRoot, "playbooks");
26601
+ const p = resolve59(ctx.syntaurRoot, "playbooks");
26318
26602
  if (!await fileExists(p)) {
26319
26603
  return {
26320
26604
  id: this.id,
@@ -26339,7 +26623,7 @@ var todosDirValid = {
26339
26623
  category: CATEGORY2,
26340
26624
  title: "todos/ directory is readable (if present)",
26341
26625
  async run(ctx) {
26342
- const p = resolve58(ctx.syntaurRoot, "todos");
26626
+ const p = resolve59(ctx.syntaurRoot, "todos");
26343
26627
  if (!await fileExists(p)) {
26344
26628
  return {
26345
26629
  id: this.id,
@@ -26370,7 +26654,7 @@ var serversDirValid = {
26370
26654
  category: CATEGORY2,
26371
26655
  title: "servers/ directory is readable (if present)",
26372
26656
  async run(ctx) {
26373
- const p = resolve58(ctx.syntaurRoot, "servers");
26657
+ const p = resolve59(ctx.syntaurRoot, "servers");
26374
26658
  if (!await fileExists(p)) {
26375
26659
  return {
26376
26660
  id: this.id,
@@ -26401,7 +26685,7 @@ var knownFilesRecognized = {
26401
26685
  category: CATEGORY2,
26402
26686
  title: "No unexpected top-level entries under ~/.syntaur/",
26403
26687
  async run(ctx) {
26404
- const entries = await readdir19(ctx.syntaurRoot, { withFileTypes: true });
26688
+ const entries = await readdir20(ctx.syntaurRoot, { withFileTypes: true });
26405
26689
  const unexpected = [];
26406
26690
  for (const e of entries) {
26407
26691
  if (e.name.startsWith(".")) continue;
@@ -26415,7 +26699,7 @@ var knownFilesRecognized = {
26415
26699
  title: this.title,
26416
26700
  status: "warn",
26417
26701
  detail: `unexpected top-level entries: ${unexpected.join(", ")}`,
26418
- affected: unexpected.map((n) => resolve58(ctx.syntaurRoot, n)),
26702
+ affected: unexpected.map((n) => resolve59(ctx.syntaurRoot, n)),
26419
26703
  remediation: {
26420
26704
  kind: "manual",
26421
26705
  suggestion: "Review these entries \u2014 they may be leftover state from older versions",
@@ -26444,8 +26728,8 @@ function pass2(check) {
26444
26728
 
26445
26729
  // src/utils/doctor/checks/project.ts
26446
26730
  init_fs();
26447
- import { resolve as resolve59 } from "path";
26448
- import { readdir as readdir20, stat as stat6 } from "fs/promises";
26731
+ import { resolve as resolve60 } from "path";
26732
+ import { readdir as readdir21, stat as stat6 } from "fs/promises";
26449
26733
  var CATEGORY3 = "project";
26450
26734
  var REQUIRED_PROJECT_FILES = [
26451
26735
  "project.md",
@@ -26469,15 +26753,15 @@ var PROJECT_MARKERS = ["project.md", "manifest.md", "assignments"];
26469
26753
  async function listProjects2(ctx) {
26470
26754
  const dir = ctx.config.defaultProjectDir;
26471
26755
  if (!await fileExists(dir)) return [];
26472
- const entries = await readdir20(dir, { withFileTypes: true });
26756
+ const entries = await readdir21(dir, { withFileTypes: true });
26473
26757
  const result = [];
26474
26758
  for (const e of entries) {
26475
26759
  if (!e.isDirectory()) continue;
26476
26760
  if (e.name.startsWith(".") || e.name.startsWith("_")) continue;
26477
- const projectDir = resolve59(dir, e.name);
26761
+ const projectDir = resolve60(dir, e.name);
26478
26762
  let looksLikeProject = false;
26479
26763
  for (const marker of PROJECT_MARKERS) {
26480
- if (await fileExists(resolve59(projectDir, marker))) {
26764
+ if (await fileExists(resolve60(projectDir, marker))) {
26481
26765
  looksLikeProject = true;
26482
26766
  break;
26483
26767
  }
@@ -26496,7 +26780,7 @@ var requiredFiles = {
26496
26780
  for (const projectDir of projects) {
26497
26781
  const missing = [];
26498
26782
  for (const rel of REQUIRED_PROJECT_FILES) {
26499
- const p = resolve59(projectDir, rel);
26783
+ const p = resolve60(projectDir, rel);
26500
26784
  if (!await fileExists(p)) missing.push(rel);
26501
26785
  }
26502
26786
  if (missing.length === 0) continue;
@@ -26506,7 +26790,7 @@ var requiredFiles = {
26506
26790
  title: this.title,
26507
26791
  status: "error",
26508
26792
  detail: `project at ${projectDir} is missing: ${missing.join(", ")}`,
26509
- affected: missing.map((m) => resolve59(projectDir, m)),
26793
+ affected: missing.map((m) => resolve60(projectDir, m)),
26510
26794
  remediation: {
26511
26795
  kind: "manual",
26512
26796
  suggestion: "Recreate the missing scaffold files from templates",
@@ -26529,7 +26813,7 @@ var manifestStale = {
26529
26813
  const projects = await listProjects2(ctx);
26530
26814
  const results = [];
26531
26815
  for (const projectDir of projects) {
26532
- const manifestPath = resolve59(projectDir, "manifest.md");
26816
+ const manifestPath = resolve60(projectDir, "manifest.md");
26533
26817
  if (!await fileExists(manifestPath)) continue;
26534
26818
  const manifestMtime = (await stat6(manifestPath)).mtimeMs;
26535
26819
  const newestAssignment = await newestAssignmentMtime(projectDir);
@@ -26563,7 +26847,7 @@ var orphanFiles = {
26563
26847
  const projects = await listProjects2(ctx);
26564
26848
  const results = [];
26565
26849
  for (const projectDir of projects) {
26566
- const entries = await readdir20(projectDir, { withFileTypes: true });
26850
+ const entries = await readdir21(projectDir, { withFileTypes: true });
26567
26851
  const orphans = [];
26568
26852
  for (const e of entries) {
26569
26853
  if (e.name.startsWith(".")) continue;
@@ -26578,7 +26862,7 @@ var orphanFiles = {
26578
26862
  title: this.title,
26579
26863
  status: "warn",
26580
26864
  detail: `project at ${projectDir} has unexpected entries: ${orphans.join(", ")}`,
26581
- affected: orphans.map((o) => resolve59(projectDir, o)),
26865
+ affected: orphans.map((o) => resolve60(projectDir, o)),
26582
26866
  autoFixable: false
26583
26867
  });
26584
26868
  }
@@ -26588,18 +26872,18 @@ var orphanFiles = {
26588
26872
  };
26589
26873
  var projectChecks = [requiredFiles, manifestStale, orphanFiles];
26590
26874
  async function newestAssignmentMtime(projectDir) {
26591
- const assignmentsRoot = resolve59(projectDir, "assignments");
26875
+ const assignmentsRoot = resolve60(projectDir, "assignments");
26592
26876
  if (!await fileExists(assignmentsRoot)) return 0;
26593
26877
  let newest = 0;
26594
26878
  let entries;
26595
26879
  try {
26596
- entries = await readdir20(assignmentsRoot, { withFileTypes: true });
26880
+ entries = await readdir21(assignmentsRoot, { withFileTypes: true });
26597
26881
  } catch {
26598
26882
  return 0;
26599
26883
  }
26600
26884
  for (const e of entries) {
26601
26885
  if (!e.isDirectory()) continue;
26602
- const assignmentMd = resolve59(assignmentsRoot, e.name, "assignment.md");
26886
+ const assignmentMd = resolve60(assignmentsRoot, e.name, "assignment.md");
26603
26887
  try {
26604
26888
  const s = await stat6(assignmentMd);
26605
26889
  if (s.mtimeMs > newest) newest = s.mtimeMs;
@@ -26623,8 +26907,8 @@ init_fs();
26623
26907
  init_parser();
26624
26908
  init_types();
26625
26909
  init_paths();
26626
- import { resolve as resolve60 } from "path";
26627
- import { readFile as readFile37, readdir as readdir21 } from "fs/promises";
26910
+ import { resolve as resolve61 } from "path";
26911
+ import { readFile as readFile38, readdir as readdir22 } from "fs/promises";
26628
26912
  var CATEGORY4 = "assignment";
26629
26913
  var STATUSES_REQUIRING_HANDOFF = /* @__PURE__ */ new Set(["review", "completed"]);
26630
26914
  var PRE_WORKSPACE_STATUSES = /* @__PURE__ */ new Set([
@@ -26718,7 +27002,7 @@ var invalidStatus = {
26718
27002
  const allowed = configuredStatuses(ctx);
26719
27003
  const results = [];
26720
27004
  for (const a of withAssignmentMd) {
26721
- const path = resolve60(a.assignmentDir, "assignment.md");
27005
+ const path = resolve61(a.assignmentDir, "assignment.md");
26722
27006
  const parsed = await parseSafe2(path);
26723
27007
  if (!parsed) continue;
26724
27008
  if (!allowed.has(parsed.status)) {
@@ -26751,7 +27035,7 @@ var workspaceMissing = {
26751
27035
  const terminal = terminalStatuses(ctx);
26752
27036
  const results = [];
26753
27037
  for (const a of withAssignmentMd) {
26754
- const path = resolve60(a.assignmentDir, "assignment.md");
27038
+ const path = resolve61(a.assignmentDir, "assignment.md");
26755
27039
  const parsed = await parseSafe2(path);
26756
27040
  if (!parsed) continue;
26757
27041
  if (terminal.has(parsed.status)) continue;
@@ -26798,12 +27082,12 @@ var requiredFilesByStatus = {
26798
27082
  const { withAssignmentMd } = await listAssignments(ctx);
26799
27083
  const results = [];
26800
27084
  for (const a of withAssignmentMd) {
26801
- const assignmentPath = resolve60(a.assignmentDir, "assignment.md");
27085
+ const assignmentPath = resolve61(a.assignmentDir, "assignment.md");
26802
27086
  const parsed = await parseSafe2(assignmentPath);
26803
27087
  if (!parsed) continue;
26804
27088
  const missing = [];
26805
27089
  if (STATUSES_REQUIRING_HANDOFF.has(parsed.status)) {
26806
- const handoffPath = resolve60(a.assignmentDir, "handoff.md");
27090
+ const handoffPath = resolve61(a.assignmentDir, "handoff.md");
26807
27091
  if (!await fileExists(handoffPath)) missing.push("handoff.md");
26808
27092
  }
26809
27093
  if (missing.length === 0) continue;
@@ -26813,7 +27097,7 @@ var requiredFilesByStatus = {
26813
27097
  title: this.title,
26814
27098
  status: "warn",
26815
27099
  detail: `${a.projectSlug}/${a.assignmentSlug} (status: ${parsed.status}) is missing ${missing.join(", ")}`,
26816
- affected: missing.map((m) => resolve60(a.assignmentDir, m)),
27100
+ affected: missing.map((m) => resolve61(a.assignmentDir, m)),
26817
27101
  remediation: {
26818
27102
  kind: "manual",
26819
27103
  suggestion: `Create the missing ${missing.join(" and ")} files for this assignment`,
@@ -26836,7 +27120,7 @@ var companionFilesScaffolded = {
26836
27120
  for (const a of withAssignmentMd) {
26837
27121
  const missing = [];
26838
27122
  for (const filename of ["progress.md", "comments.md"]) {
26839
- if (!await fileExists(resolve60(a.assignmentDir, filename))) {
27123
+ if (!await fileExists(resolve61(a.assignmentDir, filename))) {
26840
27124
  missing.push(filename);
26841
27125
  }
26842
27126
  }
@@ -26848,7 +27132,7 @@ var companionFilesScaffolded = {
26848
27132
  title: this.title,
26849
27133
  status: "warn",
26850
27134
  detail: `${label} is missing ${missing.join(" and ")} (pre-v2.0 assignment \u2014 not required, but scaffolding them keeps the dashboard and CLIs consistent)`,
26851
- affected: missing.map((m) => resolve60(a.assignmentDir, m)),
27135
+ affected: missing.map((m) => resolve61(a.assignmentDir, m)),
26852
27136
  remediation: {
26853
27137
  kind: "manual",
26854
27138
  suggestion: `Create ${missing.join(" and ")} with the renderProgress/renderComments templates, or re-scaffold via the CLI`,
@@ -26881,7 +27165,7 @@ var typeDefinition = {
26881
27165
  const { withAssignmentMd } = await listAssignments(ctx);
26882
27166
  const results = [];
26883
27167
  for (const a of withAssignmentMd) {
26884
- const path = resolve60(a.assignmentDir, "assignment.md");
27168
+ const path = resolve61(a.assignmentDir, "assignment.md");
26885
27169
  const parsed = await parseSafe2(path);
26886
27170
  if (!parsed) continue;
26887
27171
  if (!parsed.type) continue;
@@ -26915,7 +27199,7 @@ var projectFrontmatterMatchesContainer = {
26915
27199
  const { withAssignmentMd } = await listAssignments(ctx);
26916
27200
  const results = [];
26917
27201
  for (const a of withAssignmentMd) {
26918
- const path = resolve60(a.assignmentDir, "assignment.md");
27202
+ const path = resolve61(a.assignmentDir, "assignment.md");
26919
27203
  const parsed = await parseSafe2(path);
26920
27204
  if (!parsed) continue;
26921
27205
  if (a.standalone) {
@@ -26966,13 +27250,13 @@ var draftMissingObjective = {
26966
27250
  const { withAssignmentMd } = await listAssignments(ctx);
26967
27251
  const results = [];
26968
27252
  for (const a of withAssignmentMd) {
26969
- const path = resolve60(a.assignmentDir, "assignment.md");
27253
+ const path = resolve61(a.assignmentDir, "assignment.md");
26970
27254
  const parsed = await parseSafe2(path);
26971
27255
  if (!parsed) continue;
26972
27256
  if (parsed.status !== "draft") continue;
26973
27257
  let raw2;
26974
27258
  try {
26975
- raw2 = await readFile37(path, "utf-8");
27259
+ raw2 = await readFile38(path, "utf-8");
26976
27260
  } catch {
26977
27261
  continue;
26978
27262
  }
@@ -27005,16 +27289,16 @@ var readyToImplementMissingPlan = {
27005
27289
  const { withAssignmentMd } = await listAssignments(ctx);
27006
27290
  const results = [];
27007
27291
  for (const a of withAssignmentMd) {
27008
- const path = resolve60(a.assignmentDir, "assignment.md");
27292
+ const path = resolve61(a.assignmentDir, "assignment.md");
27009
27293
  const parsed = await parseSafe2(path);
27010
27294
  if (!parsed) continue;
27011
27295
  if (parsed.status !== "ready_to_implement") continue;
27012
- const entries = await readdir21(a.assignmentDir).catch(() => []);
27296
+ const entries = await readdir22(a.assignmentDir).catch(() => []);
27013
27297
  const planFiles = entries.filter((f) => /^plan(?:-v\d+)?\.md$/i.test(f));
27014
27298
  let hasPlanContent = false;
27015
27299
  for (const f of planFiles) {
27016
27300
  try {
27017
- const c2 = await readFile37(resolve60(a.assignmentDir, f), "utf-8");
27301
+ const c2 = await readFile38(resolve61(a.assignmentDir, f), "utf-8");
27018
27302
  if (c2.trim().length > 0) {
27019
27303
  hasPlanContent = true;
27020
27304
  break;
@@ -27030,7 +27314,7 @@ var readyToImplementMissingPlan = {
27030
27314
  title: this.title,
27031
27315
  status: "warn",
27032
27316
  detail: `${label} (status: ready_to_implement) has no plan.md or plan-v<N>.md`,
27033
- affected: [resolve60(a.assignmentDir, "plan.md")],
27317
+ affected: [resolve61(a.assignmentDir, "plan.md")],
27034
27318
  remediation: {
27035
27319
  kind: "manual",
27036
27320
  suggestion: `Write a plan with '/plan-assignment' (or 'syntaur plan'), then re-mark ready_to_implement`,
@@ -27057,7 +27341,7 @@ var assignmentChecks = [
27057
27341
  ];
27058
27342
  async function parseSafe2(path) {
27059
27343
  try {
27060
- const content = await readFile37(path, "utf-8");
27344
+ const content = await readFile38(path, "utf-8");
27061
27345
  return parseAssignmentFull(content);
27062
27346
  } catch {
27063
27347
  return null;
@@ -27076,7 +27360,7 @@ function pass4(check, detail) {
27076
27360
 
27077
27361
  // src/utils/doctor/checks/dashboard.ts
27078
27362
  init_fs();
27079
- import { resolve as resolve61 } from "path";
27363
+ import { resolve as resolve62 } from "path";
27080
27364
  var CATEGORY5 = "dashboard";
27081
27365
  var dbReachable = {
27082
27366
  id: "dashboard.db-reachable",
@@ -27090,7 +27374,7 @@ var dbReachable = {
27090
27374
  title: this.title,
27091
27375
  status: "error",
27092
27376
  detail: `could not open syntaur.db: ${ctx.dbError ?? "unknown error"}`,
27093
- affected: [resolve61(ctx.syntaurRoot, "syntaur.db")],
27377
+ affected: [resolve62(ctx.syntaurRoot, "syntaur.db")],
27094
27378
  remediation: {
27095
27379
  kind: "manual",
27096
27380
  suggestion: "Start the dashboard once (`syntaur dashboard`) to initialize the DB, or restore it from backup",
@@ -27108,7 +27392,7 @@ var dbReachable = {
27108
27392
  title: this.title,
27109
27393
  status: "error",
27110
27394
  detail: 'syntaur.db is missing the expected "sessions" table',
27111
- affected: [resolve61(ctx.syntaurRoot, "syntaur.db")],
27395
+ affected: [resolve62(ctx.syntaurRoot, "syntaur.db")],
27112
27396
  autoFixable: false
27113
27397
  };
27114
27398
  }
@@ -27120,7 +27404,7 @@ var dbReachable = {
27120
27404
  title: this.title,
27121
27405
  status: "error",
27122
27406
  detail: `syntaur.db query failed: ${err2 instanceof Error ? err2.message : String(err2)}`,
27123
- affected: [resolve61(ctx.syntaurRoot, "syntaur.db")],
27407
+ affected: [resolve62(ctx.syntaurRoot, "syntaur.db")],
27124
27408
  autoFixable: false
27125
27409
  };
27126
27410
  }
@@ -27146,7 +27430,7 @@ var ghostSessions = {
27146
27430
  const results = [];
27147
27431
  for (const row of rows) {
27148
27432
  if (!row.project_slug) continue;
27149
- const projectPath = resolve61(projectsDir2, row.project_slug, "project.md");
27433
+ const projectPath = resolve62(projectsDir2, row.project_slug, "project.md");
27150
27434
  if (!await fileExists(projectPath)) {
27151
27435
  results.push({
27152
27436
  id: this.id,
@@ -27165,7 +27449,7 @@ var ghostSessions = {
27165
27449
  continue;
27166
27450
  }
27167
27451
  if (row.assignment_slug) {
27168
- const assignmentPath = resolve61(
27452
+ const assignmentPath = resolve62(
27169
27453
  projectsDir2,
27170
27454
  row.project_slug,
27171
27455
  "assignments",
@@ -27217,8 +27501,8 @@ function skipped(check, reason) {
27217
27501
 
27218
27502
  // src/utils/doctor/checks/integrations.ts
27219
27503
  init_fs();
27220
- import { resolve as resolve62, dirname as dirname19, basename as basename6 } from "path";
27221
- import { readdir as readdir22, readFile as readFile38 } from "fs/promises";
27504
+ import { resolve as resolve63, dirname as dirname20, basename as basename6 } from "path";
27505
+ import { readdir as readdir23, readFile as readFile39 } from "fs/promises";
27222
27506
  import { homedir as homedir10 } from "os";
27223
27507
  var CATEGORY6 = "integrations";
27224
27508
  var claudePluginLinked = {
@@ -27281,7 +27565,7 @@ var backupConfigured = {
27281
27565
  if (ctx.config.backup?.repo) return pass6(this);
27282
27566
  const projectsDir2 = ctx.config.defaultProjectDir;
27283
27567
  if (!await fileExists(projectsDir2)) return skipped2(this, "no projects dir");
27284
- const entries = await readdir22(projectsDir2, { withFileTypes: true });
27568
+ const entries = await readdir23(projectsDir2, { withFileTypes: true });
27285
27569
  const hasProjects = entries.some((e) => e.isDirectory() && !e.name.startsWith(".") && !e.name.startsWith("_"));
27286
27570
  if (!hasProjects) return skipped2(this, "no projects yet");
27287
27571
  return {
@@ -27300,10 +27584,10 @@ var backupConfigured = {
27300
27584
  }
27301
27585
  };
27302
27586
  async function readKnownMarketplaces() {
27303
- const path = resolve62(homedir10(), ".claude", "plugins", "known_marketplaces.json");
27587
+ const path = resolve63(homedir10(), ".claude", "plugins", "known_marketplaces.json");
27304
27588
  if (!await fileExists(path)) return {};
27305
27589
  try {
27306
- const raw2 = await readFile38(path, "utf-8");
27590
+ const raw2 = await readFile39(path, "utf-8");
27307
27591
  return JSON.parse(raw2);
27308
27592
  } catch {
27309
27593
  return {};
@@ -27319,7 +27603,7 @@ var claudeMarketplaceRegistered = {
27319
27603
  if (!await fileExists(dir)) {
27320
27604
  return skipped2(this, "claudePluginDir does not exist (run install-plugin)");
27321
27605
  }
27322
- const pluginsParent = dirname19(dir);
27606
+ const pluginsParent = dirname20(dir);
27323
27607
  if (basename6(pluginsParent) !== "plugins") {
27324
27608
  return {
27325
27609
  id: this.id,
@@ -27336,8 +27620,8 @@ var claudeMarketplaceRegistered = {
27336
27620
  autoFixable: false
27337
27621
  };
27338
27622
  }
27339
- const marketplaceRoot = dirname19(pluginsParent);
27340
- const marketplaceManifest = resolve62(marketplaceRoot, ".claude-plugin", "marketplace.json");
27623
+ const marketplaceRoot = dirname20(pluginsParent);
27624
+ const marketplaceManifest = resolve63(marketplaceRoot, ".claude-plugin", "marketplace.json");
27341
27625
  if (!await fileExists(marketplaceManifest)) {
27342
27626
  return {
27343
27627
  id: this.id,
@@ -27356,7 +27640,7 @@ var claudeMarketplaceRegistered = {
27356
27640
  }
27357
27641
  let parsed = {};
27358
27642
  try {
27359
- parsed = JSON.parse(await readFile38(marketplaceManifest, "utf-8"));
27643
+ parsed = JSON.parse(await readFile39(marketplaceManifest, "utf-8"));
27360
27644
  } catch {
27361
27645
  return {
27362
27646
  id: this.id,
@@ -27388,7 +27672,7 @@ var claudeMarketplaceRegistered = {
27388
27672
  title: this.title,
27389
27673
  status: "error",
27390
27674
  detail: issues.join("; "),
27391
- affected: [marketplaceManifest, resolve62(homedir10(), ".claude", "plugins", "known_marketplaces.json")],
27675
+ affected: [marketplaceManifest, resolve63(homedir10(), ".claude", "plugins", "known_marketplaces.json")],
27392
27676
  remediation: {
27393
27677
  kind: "manual",
27394
27678
  suggestion: "Re-run install-plugin to ensure both files are in sync.",
@@ -27428,8 +27712,8 @@ function skipped2(check, reason) {
27428
27712
  init_fs();
27429
27713
  init_parser();
27430
27714
  init_types();
27431
- import { resolve as resolve63 } from "path";
27432
- import { readFile as readFile39 } from "fs/promises";
27715
+ import { resolve as resolve64 } from "path";
27716
+ import { readFile as readFile40 } from "fs/promises";
27433
27717
  var CATEGORY7 = "workspace";
27434
27718
  var ASSIGNMENT_FIELDS = ["projectSlug", "assignmentSlug", "projectDir", "assignmentDir"];
27435
27719
  var BUNDLE_FIELDS = ["bundleId", "bundleScope", "bundleScopeId"];
@@ -27450,12 +27734,12 @@ function isStandaloneSession(ctx) {
27450
27734
  return !hasAnyAssignmentField(ctx) && !hasAnyBundleField(ctx) && typeof ctx.sessionId === "string" && ctx.sessionId.length > 0;
27451
27735
  }
27452
27736
  async function loadContext(ctx) {
27453
- const path = resolve63(ctx.cwd, ".syntaur", "context.json");
27737
+ const path = resolve64(ctx.cwd, ".syntaur", "context.json");
27454
27738
  if (!await fileExists(path)) {
27455
27739
  return { data: null, path, exists: false, parseError: null };
27456
27740
  }
27457
27741
  try {
27458
- const raw2 = await readFile39(path, "utf-8");
27742
+ const raw2 = await readFile40(path, "utf-8");
27459
27743
  return { data: JSON.parse(raw2), path, exists: true, parseError: null };
27460
27744
  } catch (err2) {
27461
27745
  return {
@@ -27549,7 +27833,7 @@ var contextAssignmentResolves = {
27549
27833
  if (isStandaloneSession(data)) return skipped3(this, "standalone session context \u2014 no assignment to resolve");
27550
27834
  if (isBundleContext(data)) return skipped3(this, "bundle context \u2014 no assignment to resolve");
27551
27835
  if (!data?.assignmentDir) return skipped3(this, "context has no assignmentDir");
27552
- const assignmentMd = resolve63(data.assignmentDir, "assignment.md");
27836
+ const assignmentMd = resolve64(data.assignmentDir, "assignment.md");
27553
27837
  if (!await fileExists(assignmentMd)) {
27554
27838
  return {
27555
27839
  id: this.id,
@@ -27579,10 +27863,10 @@ var contextTerminal = {
27579
27863
  if (isStandaloneSession(data)) return skipped3(this, "standalone session context \u2014 no assignment to check");
27580
27864
  if (isBundleContext(data)) return skipped3(this, "bundle context \u2014 no assignment to check");
27581
27865
  if (!data?.assignmentDir) return skipped3(this, "context has no assignmentDir");
27582
- const assignmentMd = resolve63(data.assignmentDir, "assignment.md");
27866
+ const assignmentMd = resolve64(data.assignmentDir, "assignment.md");
27583
27867
  if (!await fileExists(assignmentMd)) return skipped3(this, "assignment file missing");
27584
27868
  try {
27585
- const content = await readFile39(assignmentMd, "utf-8");
27869
+ const content = await readFile40(assignmentMd, "utf-8");
27586
27870
  const parsed = parseAssignmentFull(content);
27587
27871
  const terminal = terminalStatuses2(ctx);
27588
27872
  if (terminal.has(parsed.status)) {
@@ -27728,15 +28012,15 @@ var agentChecks = [agentsResolvable];
27728
28012
  // src/utils/doctor/checks/terminal.ts
27729
28013
  init_config2();
27730
28014
  import { spawnSync as spawnSync9 } from "child_process";
27731
- import { readFile as readFile40 } from "fs/promises";
27732
- import { resolve as resolve64 } from "path";
28015
+ import { readFile as readFile41 } from "fs/promises";
28016
+ import { resolve as resolve65 } from "path";
27733
28017
  init_paths();
27734
28018
  init_fs();
27735
28019
  var CATEGORY9 = "terminal";
27736
28020
  async function readRawTerminalKey() {
27737
- const configPath2 = resolve64(syntaurRoot(), "config.md");
28021
+ const configPath2 = resolve65(syntaurRoot(), "config.md");
27738
28022
  if (!await fileExists(configPath2)) return null;
27739
- const content = await readFile40(configPath2, "utf-8");
28023
+ const content = await readFile41(configPath2, "utf-8");
27740
28024
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
27741
28025
  if (!fmMatch) return null;
27742
28026
  const line = fmMatch[1].split("\n").find((l) => /^terminal:\s*/.test(l));
@@ -27886,13 +28170,13 @@ var terminalChecks = [
27886
28170
 
27887
28171
  // src/utils/doctor/checks/skills.ts
27888
28172
  init_fs();
27889
- import { resolve as resolve65, join as join11 } from "path";
27890
- import { readdir as readdir23, readFile as readFile41, lstat as lstat4 } from "fs/promises";
28173
+ import { resolve as resolve66, join as join12 } from "path";
28174
+ import { readdir as readdir24, readFile as readFile42, lstat as lstat4 } from "fs/promises";
27891
28175
  import { homedir as homedir11 } from "os";
27892
28176
  var CATEGORY10 = "skills";
27893
28177
  var skillTargets = [
27894
- { agent: "claude", dir: resolve65(homedir11(), ".claude", "skills"), label: "~/.claude/skills" },
27895
- { agent: "codex", dir: resolve65(homedir11(), ".codex", "skills"), label: "~/.codex/skills" }
28178
+ { agent: "claude", dir: resolve66(homedir11(), ".claude", "skills"), label: "~/.claude/skills" },
28179
+ { agent: "codex", dir: resolve66(homedir11(), ".codex", "skills"), label: "~/.codex/skills" }
27896
28180
  ];
27897
28181
  var skillsDedupCheck = {
27898
28182
  id: "skills.dedup",
@@ -27907,21 +28191,21 @@ var skillsDedupCheck = {
27907
28191
  const present = [];
27908
28192
  let entries;
27909
28193
  try {
27910
- entries = await readdir23(dir, { withFileTypes: true });
28194
+ entries = await readdir24(dir, { withFileTypes: true });
27911
28195
  } catch {
27912
28196
  continue;
27913
28197
  }
27914
28198
  for (const entry of entries) {
27915
28199
  if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
27916
28200
  if (!KNOWN_SKILLS.includes(entry.name)) continue;
27917
- const skillMd = join11(dir, entry.name, "SKILL.md");
28201
+ const skillMd = join12(dir, entry.name, "SKILL.md");
27918
28202
  if (!await fileExists(skillMd)) continue;
27919
- const content = await readFile41(skillMd, "utf-8").catch(() => "");
28203
+ const content = await readFile42(skillMd, "utf-8").catch(() => "");
27920
28204
  const match = content.match(/^name:\s*(\S+)\s*$/m);
27921
28205
  if (!match || match[1] !== entry.name) continue;
27922
28206
  let isSymlink2 = false;
27923
28207
  try {
27924
- isSymlink2 = (await lstat4(join11(dir, entry.name))).isSymbolicLink();
28208
+ isSymlink2 = (await lstat4(join12(dir, entry.name))).isSymbolicLink();
27925
28209
  } catch {
27926
28210
  }
27927
28211
  present.push({ name: entry.name, isSymlink: isSymlink2 });
@@ -27933,7 +28217,7 @@ var skillsDedupCheck = {
27933
28217
  findings.push(
27934
28218
  `${label}: ${nonSymlink.length} syntaur skill(s) installed globally while the syntaur plugin is enabled (${agent}) \u2014 duplicate registrations`
27935
28219
  );
27936
- for (const p of nonSymlink) affected.push(join11(dir, p.name));
28220
+ for (const p of nonSymlink) affected.push(join12(dir, p.name));
27937
28221
  }
27938
28222
  }
27939
28223
  }
@@ -27966,12 +28250,12 @@ var skillsChecks = [skillsDedupCheck];
27966
28250
 
27967
28251
  // src/utils/doctor/checks/cross-agent.ts
27968
28252
  init_fs();
27969
- import { join as join12, resolve as resolve66 } from "path";
27970
- import { readFile as readFile43 } from "fs/promises";
28253
+ import { join as join13, resolve as resolve67 } from "path";
28254
+ import { readFile as readFile44 } from "fs/promises";
27971
28255
 
27972
28256
  // src/utils/skill-frontmatter.ts
27973
28257
  import { createHash } from "crypto";
27974
- import { readFile as readFile42 } from "fs/promises";
28258
+ import { readFile as readFile43 } from "fs/promises";
27975
28259
  function stripQuotes(raw2) {
27976
28260
  const t = raw2.trim();
27977
28261
  if (t.length >= 2 && (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'"))) {
@@ -28015,7 +28299,7 @@ function readSkillIdentity(skillMdText) {
28015
28299
  return { name, hasDescription };
28016
28300
  }
28017
28301
  async function sha256File(path) {
28018
- return createHash("sha256").update(await readFile42(path)).digest("hex");
28302
+ return createHash("sha256").update(await readFile43(path)).digest("hex");
28019
28303
  }
28020
28304
 
28021
28305
  // src/utils/doctor/checks/cross-agent.ts
@@ -28024,14 +28308,14 @@ async function checkTargetSkillsIntegrity(installedDir, canonicalSkillsDir, know
28024
28308
  const problems = [];
28025
28309
  let valid = 0;
28026
28310
  for (const skill of knownSkills) {
28027
- const installedPath = join12(installedDir, skill, "SKILL.md");
28311
+ const installedPath = join13(installedDir, skill, "SKILL.md");
28028
28312
  if (!await fileExists(installedPath)) {
28029
28313
  problems.push({ skill, kind: "missing" });
28030
28314
  continue;
28031
28315
  }
28032
28316
  let text;
28033
28317
  try {
28034
- text = await readFile43(installedPath, "utf-8");
28318
+ text = await readFile44(installedPath, "utf-8");
28035
28319
  } catch {
28036
28320
  problems.push({ skill, kind: "invalid-frontmatter" });
28037
28321
  continue;
@@ -28042,7 +28326,7 @@ async function checkTargetSkillsIntegrity(installedDir, canonicalSkillsDir, know
28042
28326
  continue;
28043
28327
  }
28044
28328
  valid++;
28045
- const canonicalPath = join12(canonicalSkillsDir, skill, "SKILL.md");
28329
+ const canonicalPath = join13(canonicalSkillsDir, skill, "SKILL.md");
28046
28330
  if (await fileExists(canonicalPath)) {
28047
28331
  const [installedHash, canonicalHash] = await Promise.all([
28048
28332
  sha256File(installedPath),
@@ -28075,6 +28359,7 @@ var crossAgentSkillsCheck = {
28075
28359
  title: "Cross-agent targets have Syntaur skills + protocol files",
28076
28360
  async run(ctx) {
28077
28361
  const installed = ctx.config.integrations.installedAgents ?? {};
28362
+ const { targets: resolvedTargets, warnings: descriptorWarnings } = await resolveAgentTargets();
28078
28363
  const canonicalSkillsDir = await getSkillsDir();
28079
28364
  let knownSkills;
28080
28365
  try {
@@ -28088,7 +28373,7 @@ var crossAgentSkillsCheck = {
28088
28373
  const problems = [];
28089
28374
  const affected = [];
28090
28375
  let considered = 0;
28091
- for (const t of AGENT_TARGETS) {
28376
+ for (const t of resolvedTargets) {
28092
28377
  if (t.nativePlugin) continue;
28093
28378
  const dir = t.skillsDir?.global;
28094
28379
  if (!dir) continue;
@@ -28107,15 +28392,41 @@ var crossAgentSkillsCheck = {
28107
28392
  }
28108
28393
  if (recorded && t.instructions) {
28109
28394
  for (const f of t.instructions.files) {
28110
- const p = resolve66(ctx.cwd, f.path);
28395
+ const p = resolve67(ctx.cwd, f.path);
28111
28396
  if (!await fileExists(p)) {
28112
28397
  problems.push(`${t.displayName}: missing protocol file ${f.path} in cwd`);
28113
28398
  affected.push(p);
28114
28399
  }
28115
28400
  }
28116
28401
  }
28402
+ if (t.tier3) {
28403
+ const installDir = t.tier3.installDir();
28404
+ const installed2 = await fileExists(join13(installDir, t.tier3.entry));
28405
+ lines.push(
28406
+ `${t.displayName}: Tier-3 ${t.tier3.kind} ${installed2 ? "installed" : "absent"} (${installDir})`
28407
+ );
28408
+ if (recorded && !installed2) {
28409
+ problems.push(`${t.displayName}: Tier-3 ${t.tier3.kind} not installed`);
28410
+ affected.push(installDir);
28411
+ }
28412
+ }
28117
28413
  }
28118
28414
  if (considered === 0) {
28415
+ if (descriptorWarnings.length > 0) {
28416
+ return {
28417
+ id: this.id,
28418
+ category: this.category,
28419
+ title: this.title,
28420
+ status: "warn",
28421
+ detail: `User target descriptor issues: ${descriptorWarnings.join("; ")}`,
28422
+ remediation: {
28423
+ kind: "manual",
28424
+ suggestion: `Fix or remove the offending file(s) in ~/.syntaur/targets/ (see references/user-targets.md).`,
28425
+ command: null
28426
+ },
28427
+ autoFixable: false
28428
+ };
28429
+ }
28119
28430
  return {
28120
28431
  id: this.id,
28121
28432
  category: this.category,
@@ -28125,6 +28436,7 @@ var crossAgentSkillsCheck = {
28125
28436
  autoFixable: false
28126
28437
  };
28127
28438
  }
28439
+ for (const w of descriptorWarnings) problems.push(`user target descriptor: ${w}`);
28128
28440
  if (problems.length > 0) {
28129
28441
  return {
28130
28442
  id: this.id,
@@ -28156,8 +28468,8 @@ var crossAgentChecks = [crossAgentSkillsCheck];
28156
28468
  // src/utils/doctor/checks/bundles.ts
28157
28469
  init_fs();
28158
28470
  init_paths();
28159
- import { resolve as resolve67 } from "path";
28160
- import { readdir as readdir24 } from "fs/promises";
28471
+ import { resolve as resolve68 } from "path";
28472
+ import { readdir as readdir25 } from "fs/promises";
28161
28473
  import { spawnSync as spawnSync10 } from "child_process";
28162
28474
  init_parser2();
28163
28475
  var CATEGORY12 = "bundles";
@@ -28165,7 +28477,7 @@ async function listScopes(ctx) {
28165
28477
  const out = [];
28166
28478
  const td = todosDir();
28167
28479
  if (await fileExists(td)) {
28168
- const entries = await readdir24(td).catch(() => []);
28480
+ const entries = await readdir25(td).catch(() => []);
28169
28481
  for (const f of entries) {
28170
28482
  if (typeof f !== "string") continue;
28171
28483
  if (!f.endsWith(".md") || f.endsWith("-log.md")) continue;
@@ -28181,12 +28493,12 @@ async function listScopes(ctx) {
28181
28493
  }
28182
28494
  }
28183
28495
  if (await fileExists(ctx.config.defaultProjectDir)) {
28184
- const projectEntries = await readdir24(ctx.config.defaultProjectDir, { withFileTypes: true }).catch(() => []);
28496
+ const projectEntries = await readdir25(ctx.config.defaultProjectDir, { withFileTypes: true }).catch(() => []);
28185
28497
  for (const e of projectEntries) {
28186
28498
  if (!e.isDirectory()) continue;
28187
28499
  const slug = e.name;
28188
28500
  if (typeof slug !== "string" || slug.startsWith(".")) continue;
28189
- const projectMd = resolve67(ctx.config.defaultProjectDir, slug, "project.md");
28501
+ const projectMd = resolve68(ctx.config.defaultProjectDir, slug, "project.md");
28190
28502
  if (!await fileExists(projectMd)) continue;
28191
28503
  out.push({
28192
28504
  scopeLabel: `project:${slug}`,
@@ -28475,14 +28787,14 @@ async function finalize(checks) {
28475
28787
  async function readVersion() {
28476
28788
  try {
28477
28789
  const here = fileURLToPath11(import.meta.url);
28478
- let dir = dirname20(here);
28790
+ let dir = dirname21(here);
28479
28791
  for (let i = 0; i < 6; i++) {
28480
28792
  try {
28481
- const raw2 = await readFile44(join13(dir, "package.json"), "utf-8");
28793
+ const raw2 = await readFile45(join14(dir, "package.json"), "utf-8");
28482
28794
  const parsed = JSON.parse(raw2);
28483
28795
  return typeof parsed.version === "string" ? parsed.version : null;
28484
28796
  } catch {
28485
- dir = dirname20(dir);
28797
+ dir = dirname21(dir);
28486
28798
  }
28487
28799
  }
28488
28800
  return null;
@@ -28575,7 +28887,7 @@ var REQUIRED_WORKSPACE_FIELDS = [
28575
28887
  ];
28576
28888
  var ISO_DATE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;
28577
28889
  async function validateAssignmentFile(inputPath, cwd = process.cwd()) {
28578
- const absolute = isAbsolute11(inputPath) ? inputPath : resolve68(cwd, inputPath);
28890
+ const absolute = isAbsolute11(inputPath) ? inputPath : resolve69(cwd, inputPath);
28579
28891
  const errors = [];
28580
28892
  const warnings = [];
28581
28893
  if (!await fileExists(absolute)) {
@@ -28588,7 +28900,7 @@ async function validateAssignmentFile(inputPath, cwd = process.cwd()) {
28588
28900
  }
28589
28901
  let content;
28590
28902
  try {
28591
- content = await readFile45(absolute, "utf-8");
28903
+ content = await readFile46(absolute, "utf-8");
28592
28904
  } catch (err2) {
28593
28905
  return {
28594
28906
  ok: false,
@@ -28654,20 +28966,20 @@ var doctorCommand = new Command4("doctor").description("Diagnose Syntaur state a
28654
28966
  process.exit(result.ok ? 0 : 1);
28655
28967
  }
28656
28968
  if (!await fileExists(syntaurRoot())) {
28657
- const msg = "~/.syntaur/ does not exist. Run `syntaur init` first.";
28969
+ const msg2 = "~/.syntaur/ does not exist. Run `syntaur init` first.";
28658
28970
  if (options.json) {
28659
28971
  process.stdout.write(
28660
28972
  JSON.stringify(
28661
28973
  {
28662
28974
  version: "1.0",
28663
- error: msg
28975
+ error: msg2
28664
28976
  },
28665
28977
  null,
28666
28978
  2
28667
28979
  ) + "\n"
28668
28980
  );
28669
28981
  } else {
28670
- process.stderr.write(msg + "\n");
28982
+ process.stderr.write(msg2 + "\n");
28671
28983
  }
28672
28984
  process.exit(2);
28673
28985
  }
@@ -28686,11 +28998,11 @@ var doctorCommand = new Command4("doctor").description("Diagnose Syntaur state a
28686
28998
  const hasError = report.summary.error > 0;
28687
28999
  process.exit(hasError ? 1 : 0);
28688
29000
  } catch (err2) {
28689
- const msg = err2 instanceof Error ? err2.message : String(err2);
29001
+ const msg2 = err2 instanceof Error ? err2.message : String(err2);
28690
29002
  if (options.json) {
28691
- process.stdout.write(JSON.stringify({ version: "1.0", error: msg }, null, 2) + "\n");
29003
+ process.stdout.write(JSON.stringify({ version: "1.0", error: msg2 }, null, 2) + "\n");
28692
29004
  } else {
28693
- process.stderr.write(`doctor itself failed: ${msg}
29005
+ process.stderr.write(`doctor itself failed: ${msg2}
28694
29006
  `);
28695
29007
  }
28696
29008
  process.exit(2);
@@ -28912,8 +29224,8 @@ init_uuid();
28912
29224
  init_timestamp();
28913
29225
  init_assignment_resolver();
28914
29226
  init_templates();
28915
- import { resolve as resolve69 } from "path";
28916
- import { readFile as readFile46 } from "fs/promises";
29227
+ import { resolve as resolve70 } from "path";
29228
+ import { readFile as readFile47 } from "fs/promises";
28917
29229
  function shortId() {
28918
29230
  return generateId().split("-")[0];
28919
29231
  }
@@ -28943,7 +29255,7 @@ async function commentCommand(target, text, options = {}) {
28943
29255
  if (!isValidSlug(target)) {
28944
29256
  throw new Error(`Invalid assignment slug "${target}".`);
28945
29257
  }
28946
- assignmentDir = resolve69(baseDir, options.project, "assignments", target);
29258
+ assignmentDir = resolve70(baseDir, options.project, "assignments", target);
28947
29259
  assignmentRef = target;
28948
29260
  } else {
28949
29261
  const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), target);
@@ -28953,13 +29265,13 @@ async function commentCommand(target, text, options = {}) {
28953
29265
  assignmentDir = resolved.assignmentDir;
28954
29266
  assignmentRef = resolved.standalone ? resolved.id : resolved.assignmentSlug;
28955
29267
  }
28956
- const commentsPath = resolve69(assignmentDir, "comments.md");
29268
+ const commentsPath = resolve70(assignmentDir, "comments.md");
28957
29269
  const timestamp = nowTimestamp();
28958
29270
  const author = options.author ?? process.env.USER ?? "unknown";
28959
29271
  let currentContent;
28960
29272
  let currentCount = 0;
28961
29273
  if (await fileExists(commentsPath)) {
28962
- currentContent = await readFile46(commentsPath, "utf-8");
29274
+ currentContent = await readFile47(commentsPath, "utf-8");
28963
29275
  const countMatch = currentContent.match(/^entryCount:\s*(\d+)/m);
28964
29276
  if (countMatch) currentCount = parseInt(countMatch[1], 10);
28965
29277
  } else {
@@ -28993,8 +29305,8 @@ ${entry}`;
28993
29305
  }
28994
29306
 
28995
29307
  // src/commands/capture.ts
28996
- import { resolve as resolve73, relative as relative4, dirname as dirname21 } from "path";
28997
- import { copyFile as copyFile3, mkdir as mkdir10, realpath as realpath2, rm as rm13, stat as stat9, writeFile as writeFile15 } from "fs/promises";
29308
+ import { resolve as resolve74, relative as relative4, dirname as dirname22 } from "path";
29309
+ import { copyFile as copyFile3, mkdir as mkdir11, realpath as realpath2, rm as rm13, stat as stat9, writeFile as writeFile15 } from "fs/promises";
28998
29310
  import { existsSync as existsSync6 } from "fs";
28999
29311
 
29000
29312
  // src/utils/assignment-target.ts
@@ -29004,8 +29316,8 @@ init_config2();
29004
29316
  init_slug();
29005
29317
  init_assignment_resolver();
29006
29318
  init_parser();
29007
- import { resolve as resolve70 } from "path";
29008
- import { readFile as readFile47 } from "fs/promises";
29319
+ import { resolve as resolve71 } from "path";
29320
+ import { readFile as readFile48 } from "fs/promises";
29009
29321
  var AssignmentTargetError = class extends Error {
29010
29322
  };
29011
29323
  function classifyContext(ctx) {
@@ -29017,10 +29329,10 @@ function classifyContext(ctx) {
29017
29329
  return "empty";
29018
29330
  }
29019
29331
  async function readAssignmentFrontmatterId(assignmentDir) {
29020
- const path = resolve70(assignmentDir, "assignment.md");
29332
+ const path = resolve71(assignmentDir, "assignment.md");
29021
29333
  if (!await fileExists(path)) return null;
29022
29334
  try {
29023
- const content = await readFile47(path, "utf-8");
29335
+ const content = await readFile48(path, "utf-8");
29024
29336
  const [fm] = extractFrontmatter(content);
29025
29337
  return getField(fm, "id");
29026
29338
  } catch {
@@ -29028,10 +29340,10 @@ async function readAssignmentFrontmatterId(assignmentDir) {
29028
29340
  }
29029
29341
  }
29030
29342
  async function readContextJson(cwd) {
29031
- const path = resolve70(cwd, ".syntaur", "context.json");
29343
+ const path = resolve71(cwd, ".syntaur", "context.json");
29032
29344
  if (!await fileExists(path)) return null;
29033
29345
  try {
29034
- const raw2 = await readFile47(path, "utf-8");
29346
+ const raw2 = await readFile48(path, "utf-8");
29035
29347
  return JSON.parse(raw2);
29036
29348
  } catch {
29037
29349
  return null;
@@ -29052,15 +29364,15 @@ async function resolveAssignmentTarget(input4, opts = {}) {
29052
29364
  if (!isValidSlug(input4)) {
29053
29365
  throw new AssignmentTargetError(`Invalid assignment slug "${input4}".`);
29054
29366
  }
29055
- const projectDir = resolve70(baseDir, opts.project);
29056
- const projectMdPath = resolve70(projectDir, "project.md");
29367
+ const projectDir = resolve71(baseDir, opts.project);
29368
+ const projectMdPath = resolve71(projectDir, "project.md");
29057
29369
  if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
29058
29370
  throw new AssignmentTargetError(
29059
29371
  `Project "${opts.project}" not found at ${projectDir}.`
29060
29372
  );
29061
29373
  }
29062
- const assignmentDir = resolve70(projectDir, "assignments", input4);
29063
- const assignmentMdPath2 = resolve70(assignmentDir, "assignment.md");
29374
+ const assignmentDir = resolve71(projectDir, "assignments", input4);
29375
+ const assignmentMdPath2 = resolve71(assignmentDir, "assignment.md");
29064
29376
  if (!await fileExists(assignmentMdPath2)) {
29065
29377
  throw new AssignmentTargetError(
29066
29378
  `Assignment "${input4}" not found in project "${opts.project}".`
@@ -29099,7 +29411,7 @@ async function resolveAssignmentTarget(input4, opts = {}) {
29099
29411
  }
29100
29412
  if (ctx.assignmentDir) {
29101
29413
  const dir = expandHome(ctx.assignmentDir);
29102
- const assignmentMdPath2 = resolve70(dir, "assignment.md");
29414
+ const assignmentMdPath2 = resolve71(dir, "assignment.md");
29103
29415
  if (!await fileExists(assignmentMdPath2)) {
29104
29416
  throw new AssignmentTargetError(
29105
29417
  `.syntaur/context.json points to a missing assignment dir: ${dir}.`
@@ -29128,8 +29440,8 @@ async function resolveAssignmentTarget(input4, opts = {}) {
29128
29440
  `.syntaur/context.json contains invalid slugs: project="${ctx.projectSlug}" assignment="${ctx.assignmentSlug}".`
29129
29441
  );
29130
29442
  }
29131
- const assignmentDir = resolve70(baseDir, ctx.projectSlug, "assignments", ctx.assignmentSlug);
29132
- const assignmentMdPath2 = resolve70(assignmentDir, "assignment.md");
29443
+ const assignmentDir = resolve71(baseDir, ctx.projectSlug, "assignments", ctx.assignmentSlug);
29444
+ const assignmentMdPath2 = resolve71(assignmentDir, "assignment.md");
29133
29445
  if (!await fileExists(assignmentMdPath2)) {
29134
29446
  throw new AssignmentTargetError(
29135
29447
  `.syntaur/context.json points to a missing assignment: ${assignmentDir}.`
@@ -29158,7 +29470,7 @@ init_fs();
29158
29470
  import { spawn as spawn7 } from "child_process";
29159
29471
  import { mkdtemp as mkdtemp2, rm as rm9, stat as stat7 } from "fs/promises";
29160
29472
  import { tmpdir as tmpdir3 } from "os";
29161
- import { join as join14 } from "path";
29473
+ import { join as join15 } from "path";
29162
29474
  function argsFor(mode, pngPath) {
29163
29475
  switch (mode) {
29164
29476
  case "interactive":
@@ -29191,8 +29503,8 @@ async function captureScreenshot(mode) {
29191
29503
  "screencapture is only available on macOS. Use --file <path> to attach an existing image."
29192
29504
  );
29193
29505
  }
29194
- const tmpDir = await mkdtemp2(join14(tmpdir3(), "syntaur-screenshot-"));
29195
- const pngPath = join14(tmpDir, "shot.png");
29506
+ const tmpDir = await mkdtemp2(join15(tmpdir3(), "syntaur-screenshot-"));
29507
+ const pngPath = join15(tmpDir, "shot.png");
29196
29508
  const cleanup = async () => {
29197
29509
  await rm9(tmpDir, { recursive: true, force: true }).catch(() => {
29198
29510
  });
@@ -29230,9 +29542,9 @@ async function captureScreenshot(mode) {
29230
29542
 
29231
29543
  // src/utils/asciinema.ts
29232
29544
  import { spawn as spawn8 } from "child_process";
29233
- import { mkdtemp as mkdtemp3, readFile as readFile48, rm as rm10 } from "fs/promises";
29545
+ import { mkdtemp as mkdtemp3, readFile as readFile49, rm as rm10 } from "fs/promises";
29234
29546
  import { tmpdir as tmpdir4 } from "os";
29235
- import { join as join15 } from "path";
29547
+ import { join as join16 } from "path";
29236
29548
  var SAFE_RE = /^[A-Za-z0-9_@%+=:,./-]+$/;
29237
29549
  function shellQuote2(s) {
29238
29550
  if (s.length === 0) return `''`;
@@ -29269,8 +29581,8 @@ function runAsciinema(args, stdio) {
29269
29581
  });
29270
29582
  }
29271
29583
  async function captureAsciinema(opts) {
29272
- const tmpDir = await mkdtemp3(join15(tmpdir4(), "syntaur-asciinema-"));
29273
- const castPath = join15(tmpDir, "session.cast");
29584
+ const tmpDir = await mkdtemp3(join16(tmpdir4(), "syntaur-asciinema-"));
29585
+ const castPath = join16(tmpDir, "session.cast");
29274
29586
  const cleanup = async () => {
29275
29587
  await rm10(tmpDir, { recursive: true, force: true }).catch(() => {
29276
29588
  });
@@ -29293,7 +29605,7 @@ async function captureAsciinema(opts) {
29293
29605
  }
29294
29606
  throw err2;
29295
29607
  }
29296
- const text = await readFile48(castPath, "utf8").catch(() => null);
29608
+ const text = await readFile49(castPath, "utf8").catch(() => null);
29297
29609
  if (text === null) {
29298
29610
  throw new Error(
29299
29611
  `asciinema produced no cast file at ${castPath} (exit ${exitCode}). Try running 'asciinema rec ${castPath}' directly to diagnose.`
@@ -29321,9 +29633,9 @@ async function captureAsciinema(opts) {
29321
29633
  // src/utils/recording.ts
29322
29634
  init_paths();
29323
29635
  import { spawn as spawn9 } from "child_process";
29324
- import { mkdir as mkdir9, mkdtemp as mkdtemp4, open as open3, readFile as readFile49, rm as rm11, stat as stat8, unlink as unlink10, writeFile as writeFile14 } from "fs/promises";
29636
+ import { mkdir as mkdir10, mkdtemp as mkdtemp4, open as open3, readFile as readFile50, rm as rm11, stat as stat8, unlink as unlink10, writeFile as writeFile14 } from "fs/promises";
29325
29637
  import { tmpdir as tmpdir5 } from "os";
29326
- import { join as join16, resolve as resolve71 } from "path";
29638
+ import { join as join17, resolve as resolve72 } from "path";
29327
29639
  import { setTimeout as sleep } from "timers/promises";
29328
29640
  function sigintPollIntervalMs() {
29329
29641
  const raw2 = process.env.SYNTAUR_RECORDING_POLL_INTERVAL_MS;
@@ -29344,13 +29656,13 @@ function sigtermWaitMs() {
29344
29656
  return Number.isFinite(parsed) && parsed >= 0 ? parsed : 1e3;
29345
29657
  }
29346
29658
  function pidfilePath() {
29347
- return resolve71(syntaurRoot(), "recording.pid");
29659
+ return resolve72(syntaurRoot(), "recording.pid");
29348
29660
  }
29349
29661
  function logPath2() {
29350
- return resolve71(syntaurRoot(), "recording.log");
29662
+ return resolve72(syntaurRoot(), "recording.log");
29351
29663
  }
29352
29664
  function sidecarPath() {
29353
- return resolve71(syntaurRoot(), "recording.json");
29665
+ return resolve72(syntaurRoot(), "recording.json");
29354
29666
  }
29355
29667
  function ffmpegArgs(device, fps, mp4Path) {
29356
29668
  return [
@@ -29395,7 +29707,7 @@ async function acquirePidfile(pidfile) {
29395
29707
  } catch (err2) {
29396
29708
  if (err2.code !== "EEXIST") throw err2;
29397
29709
  if (attempt === 1) throw err2;
29398
- const existing = (await readFile49(pidfile, "utf-8").catch(() => "")).trim();
29710
+ const existing = (await readFile50(pidfile, "utf-8").catch(() => "")).trim();
29399
29711
  if (existing.startsWith(STARTING_SENTINEL_PREFIX)) {
29400
29712
  const parentPidRaw = existing.slice(STARTING_SENTINEL_PREFIX.length);
29401
29713
  const parentPid = Number.parseInt(parentPidRaw, 10);
@@ -29437,7 +29749,7 @@ async function startRecording(input4) {
29437
29749
  );
29438
29750
  }
29439
29751
  const root = syntaurRoot();
29440
- await mkdir9(root, { recursive: true });
29752
+ await mkdir10(root, { recursive: true });
29441
29753
  const pidfile = pidfilePath();
29442
29754
  const log = logPath2();
29443
29755
  const sidecar = sidecarPath();
@@ -29448,8 +29760,8 @@ async function startRecording(input4) {
29448
29760
  let acquiredPid = null;
29449
29761
  try {
29450
29762
  logHandle = await open3(log, "w");
29451
- tmpDir = await mkdtemp4(join16(tmpdir5(), "syntaur-recording-"));
29452
- const mp4Path = join16(tmpDir, "recording.mp4");
29763
+ tmpDir = await mkdtemp4(join17(tmpdir5(), "syntaur-recording-"));
29764
+ const mp4Path = join17(tmpDir, "recording.mp4");
29453
29765
  let child;
29454
29766
  try {
29455
29767
  child = spawn9("ffmpeg", ffmpegArgs(input4.device, input4.fps, mp4Path), {
@@ -29497,7 +29809,7 @@ async function startRecording(input4) {
29497
29809
  logHandle = null;
29498
29810
  if (warmupMs > 0) await sleep(warmupMs);
29499
29811
  if (!await isProcessAlive(pid)) {
29500
- const tail = await readFile49(log, "utf-8").then((s) => s.split("\n").slice(-20).join("\n")).catch(() => "");
29812
+ const tail = await readFile50(log, "utf-8").then((s) => s.split("\n").slice(-20).join("\n")).catch(() => "");
29501
29813
  acquiredPid = null;
29502
29814
  throw new Error(
29503
29815
  `ffmpeg exited during startup \u2014 likely macOS Screen Recording permission missing. Grant access to your terminal in System Settings \u2192 Privacy & Security \u2192 Screen Recording, then retry. Log: ${log}
@@ -29554,7 +29866,7 @@ ${tail}`
29554
29866
  async function stopRecording() {
29555
29867
  const pidfile = pidfilePath();
29556
29868
  const sidecar = sidecarPath();
29557
- const pidRaw = await readFile49(pidfile, "utf-8").catch(() => null);
29869
+ const pidRaw = await readFile50(pidfile, "utf-8").catch(() => null);
29558
29870
  if (pidRaw === null) {
29559
29871
  throw new Error(
29560
29872
  `No active recording found (no pidfile at ${pidfile}). Did you run --start?`
@@ -29564,7 +29876,7 @@ async function stopRecording() {
29564
29876
  if (!Number.isInteger(pid) || pid <= 0) {
29565
29877
  throw new Error(`Pidfile at ${pidfile} is corrupt (got "${pidRaw}").`);
29566
29878
  }
29567
- const sidecarRaw = await readFile49(sidecar, "utf-8").catch(() => null);
29879
+ const sidecarRaw = await readFile50(sidecar, "utf-8").catch(() => null);
29568
29880
  if (sidecarRaw === null) {
29569
29881
  throw new Error(
29570
29882
  `No recording sidecar at ${sidecar}. The recording state is inconsistent \u2014 delete ${pidfile} and re-run --start.`
@@ -29629,7 +29941,7 @@ async function stopRecording() {
29629
29941
  // src/db/proof-db.ts
29630
29942
  init_paths();
29631
29943
  import Database5 from "better-sqlite3";
29632
- import { resolve as resolve72 } from "path";
29944
+ import { resolve as resolve73 } from "path";
29633
29945
  var db4 = null;
29634
29946
  var PROOF_SCHEMA_VERSION = "1";
29635
29947
  var SCHEMA_SQL4 = `
@@ -29649,7 +29961,7 @@ CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT);
29649
29961
  `;
29650
29962
  function initProofDb(dbPath) {
29651
29963
  if (db4) return db4;
29652
- const finalPath = dbPath ?? resolve72(syntaurRoot(), "syntaur.db");
29964
+ const finalPath = dbPath ?? resolve73(syntaurRoot(), "syntaur.db");
29653
29965
  db4 = new Database5(finalPath);
29654
29966
  db4.pragma("journal_mode = WAL");
29655
29967
  db4.exec(SCHEMA_SQL4);
@@ -29697,9 +30009,9 @@ function listArtifactsByAssignment(assignmentId) {
29697
30009
 
29698
30010
  // src/utils/transcribers/elevenlabs.ts
29699
30011
  import { spawn as spawn10 } from "child_process";
29700
- import { mkdtemp as mkdtemp5, readFile as readFile50, rm as rm12 } from "fs/promises";
30012
+ import { mkdtemp as mkdtemp5, readFile as readFile51, rm as rm12 } from "fs/promises";
29701
30013
  import { tmpdir as tmpdir6 } from "os";
29702
- import { join as join17 } from "path";
30014
+ import { join as join18 } from "path";
29703
30015
  var SCRIBE_URL = "https://api.elevenlabs.io/v1/speech-to-text";
29704
30016
  var NO_AUDIO_MARKERS = [
29705
30017
  "Stream map '0:a:0' matches no streams",
@@ -29761,7 +30073,7 @@ async function extractAudio(videoAbsPath, wavOut) {
29761
30073
  throw new TranscribeFfmpegError(`ffmpeg failed (exit ${result.code}): ${tail}`);
29762
30074
  }
29763
30075
  async function callScribe(wavPath, apiKey, opts) {
29764
- const audio = await readFile50(wavPath);
30076
+ const audio = await readFile51(wavPath);
29765
30077
  const form = new FormData();
29766
30078
  form.set("file", new Blob([new Uint8Array(audio)], { type: "audio/wav" }), "audio.wav");
29767
30079
  form.set("model_id", "scribe_v1");
@@ -29789,8 +30101,8 @@ var elevenLabsScribe = {
29789
30101
  "ELEVENLABS_API_KEY is not set. Export it (e.g. `export ELEVENLABS_API_KEY=\u2026`) and re-run. A config-file slot will land later."
29790
30102
  );
29791
30103
  }
29792
- const tmp = await mkdtemp5(join17(tmpdir6(), "syntaur-transcribe-"));
29793
- const wav = join17(tmp, "audio.wav");
30104
+ const tmp = await mkdtemp5(join18(tmpdir6(), "syntaur-transcribe-"));
30105
+ const wav = join18(tmp, "audio.wav");
29794
30106
  try {
29795
30107
  await extractAudio(videoAbsPath, wav);
29796
30108
  return await callScribe(wav, apiKey, opts);
@@ -30064,7 +30376,7 @@ async function captureCommand(target, options = {}) {
30064
30376
  criterionIndex = sidecar.criterionIndex;
30065
30377
  stopNote = sidecar.note;
30066
30378
  resolvedSource = mp4Path;
30067
- const mp4TmpDir = dirname21(mp4Path);
30379
+ const mp4TmpDir = dirname22(mp4Path);
30068
30380
  shelloutCleanup = async () => {
30069
30381
  await rm13(mp4TmpDir, { recursive: true, force: true }).catch(() => {
30070
30382
  });
@@ -30077,7 +30389,7 @@ async function captureCommand(target, options = {}) {
30077
30389
  });
30078
30390
  }
30079
30391
  if (options.file) {
30080
- const expanded = options.file.startsWith("~/") ? resolve73(process.env.HOME ?? "", options.file.slice(2)) : resolve73(options.file);
30392
+ const expanded = options.file.startsWith("~/") ? resolve74(process.env.HOME ?? "", options.file.slice(2)) : resolve74(options.file);
30081
30393
  if (!await fileExists(expanded)) {
30082
30394
  throw new Error(`--file does not exist: ${options.file}`);
30083
30395
  }
@@ -30118,8 +30430,8 @@ async function captureCommand(target, options = {}) {
30118
30430
  }
30119
30431
  initProofDb();
30120
30432
  const subdir = criterionIndex === null ? "untagged" : String(criterionIndex);
30121
- const destDir = resolve73(proofDir(resolved.assignmentDir), subdir);
30122
- if (resolvedSource) await mkdir10(destDir, { recursive: true });
30433
+ const destDir = resolve74(proofDir(resolved.assignmentDir), subdir);
30434
+ if (resolvedSource) await mkdir11(destDir, { recursive: true });
30123
30435
  const ext = resolvedSource ? extensionForKind(kind) : null;
30124
30436
  let id = null;
30125
30437
  let relativeFilePath = null;
@@ -30127,7 +30439,7 @@ async function captureCommand(target, options = {}) {
30127
30439
  let lastErr = null;
30128
30440
  for (let attempt = 0; attempt < MAX_ID_RETRIES; attempt += 1) {
30129
30441
  const candidate = generateArtifactId();
30130
- const candidateAbsPath = resolvedSource && ext ? resolve73(destDir, `${candidate}.${ext}`) : null;
30442
+ const candidateAbsPath = resolvedSource && ext ? resolve74(destDir, `${candidate}.${ext}`) : null;
30131
30443
  const candidateRel = candidateAbsPath ? relative4(resolved.assignmentDir, candidateAbsPath) : null;
30132
30444
  try {
30133
30445
  insertArtifact({
@@ -30171,7 +30483,7 @@ async function captureCommand(target, options = {}) {
30171
30483
  }
30172
30484
  }
30173
30485
  if (options.transcribe && kind === "video" && absPath && id) {
30174
- const sidecarPath2 = resolve73(destDir, `${id}.transcript.md`);
30486
+ const sidecarPath2 = resolve74(destDir, `${id}.transcript.md`);
30175
30487
  if (existsSync6(sidecarPath2)) {
30176
30488
  console.warn(
30177
30489
  `transcript: ${sidecarPath2} already exists, skipping (delete to re-transcribe)`
@@ -30203,7 +30515,7 @@ async function captureCommand(target, options = {}) {
30203
30515
  const tagSuffix = criterionIndex === null ? "untagged" : `criterion ${criterionIndex}`;
30204
30516
  console.log(`Captured artifact ${id} (${kind}) for ${ref} \u2014 ${tagSuffix}.`);
30205
30517
  if (relativeFilePath) {
30206
- console.log(` file: ${resolve73(resolved.assignmentDir, relativeFilePath)}`);
30518
+ console.log(` file: ${resolve74(resolved.assignmentDir, relativeFilePath)}`);
30207
30519
  }
30208
30520
  } catch (err2) {
30209
30521
  if (options.stop && kind === "video" && shelloutCleanup && resolvedSource) {
@@ -30226,8 +30538,8 @@ async function captureCommand(target, options = {}) {
30226
30538
 
30227
30539
  // src/commands/proof.ts
30228
30540
  import { Command as Command6 } from "commander";
30229
- import { readFile as readFile51, writeFile as writeFile16, rename as rename10, stat as stat10 } from "fs/promises";
30230
- import { resolve as resolve74, relative as relative5, isAbsolute as isAbsolute12, dirname as dirname22 } from "path";
30541
+ import { readFile as readFile52, writeFile as writeFile16, rename as rename10, stat as stat10 } from "fs/promises";
30542
+ import { resolve as resolve75, relative as relative5, isAbsolute as isAbsolute12, dirname as dirname23 } from "path";
30231
30543
  import { randomBytes as randomBytes4 } from "crypto";
30232
30544
 
30233
30545
  // src/utils/acceptance-criteria-parse.ts
@@ -30467,11 +30779,11 @@ function renderProofHtml(params2, inlineFiles = /* @__PURE__ */ new Map(), trans
30467
30779
 
30468
30780
  // src/commands/proof.ts
30469
30781
  async function readAssignmentMeta(assignmentDir) {
30470
- const path = resolve74(assignmentDir, "assignment.md");
30782
+ const path = resolve75(assignmentDir, "assignment.md");
30471
30783
  if (!await fileExists(path)) {
30472
30784
  return { title: "", body: "" };
30473
30785
  }
30474
- const content = await readFile51(path, "utf-8");
30786
+ const content = await readFile52(path, "utf-8");
30475
30787
  const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
30476
30788
  let title = "";
30477
30789
  if (fmMatch) {
@@ -30518,7 +30830,7 @@ async function loadInlineFiles(rows, assignmentDir) {
30518
30830
  for (const r of rows) {
30519
30831
  if (!r.file_path) continue;
30520
30832
  if (r.kind !== "http" && r.kind !== "text") continue;
30521
- const abs = resolve74(assignmentDir, r.file_path);
30833
+ const abs = resolve75(assignmentDir, r.file_path);
30522
30834
  if (!isWithin(proofRoot, abs)) {
30523
30835
  out.set(r.file_path, null);
30524
30836
  continue;
@@ -30533,7 +30845,7 @@ async function loadInlineFiles(rows, assignmentDir) {
30533
30845
  continue;
30534
30846
  }
30535
30847
  try {
30536
- out.set(r.file_path, await readFile51(abs, "utf-8"));
30848
+ out.set(r.file_path, await readFile52(abs, "utf-8"));
30537
30849
  } catch {
30538
30850
  out.set(r.file_path, null);
30539
30851
  }
@@ -30545,14 +30857,14 @@ async function loadTranscriptSidecars(rows, assignmentDir) {
30545
30857
  const proofRoot = proofDir(assignmentDir);
30546
30858
  for (const r of rows) {
30547
30859
  if (r.kind !== "video" || !r.file_path) continue;
30548
- const videoAbs = resolve74(assignmentDir, r.file_path);
30549
- const sidecar = resolve74(dirname22(videoAbs), `${r.id}.transcript.md`);
30860
+ const videoAbs = resolve75(assignmentDir, r.file_path);
30861
+ const sidecar = resolve75(dirname23(videoAbs), `${r.id}.transcript.md`);
30550
30862
  if (!isWithin(proofRoot, sidecar)) continue;
30551
30863
  if (!await fileExists(sidecar)) continue;
30552
30864
  const st = await stat10(sidecar);
30553
30865
  if (st.size > INLINE_TEXT_LIMIT_BYTES) continue;
30554
30866
  try {
30555
- out.set(r.id, await readFile51(sidecar, "utf-8"));
30867
+ out.set(r.id, await readFile52(sidecar, "utf-8"));
30556
30868
  } catch {
30557
30869
  }
30558
30870
  }
@@ -30586,8 +30898,8 @@ async function proofBuildCommand(target, options = {}) {
30586
30898
  };
30587
30899
  const md = renderProofMarkdown(renderParams);
30588
30900
  const html = renderProofHtml(renderParams, inlineFiles, transcriptSidecars);
30589
- const mdPath = resolve74(resolved.assignmentDir, "proof.md");
30590
- const htmlPath = resolve74(resolved.assignmentDir, "proof.html");
30901
+ const mdPath = resolve75(resolved.assignmentDir, "proof.md");
30902
+ const htmlPath = resolve75(resolved.assignmentDir, "proof.html");
30591
30903
  await atomicWrite(mdPath, md);
30592
30904
  await atomicWrite(htmlPath, html);
30593
30905
  console.log(`Wrote ${htmlPath}`);
@@ -31252,7 +31564,7 @@ async function runCcusage(opts = {}) {
31252
31564
  };
31253
31565
  }
31254
31566
  function runOnce(binary, args, env, timeoutMs, maxOutputBytes) {
31255
- return new Promise((resolve86) => {
31567
+ return new Promise((resolve87) => {
31256
31568
  const child = spawn11(binary, args, {
31257
31569
  env: env ?? process.env,
31258
31570
  stdio: ["ignore", "pipe", "pipe"]
@@ -31266,7 +31578,7 @@ function runOnce(binary, args, env, timeoutMs, maxOutputBytes) {
31266
31578
  if (settled) return;
31267
31579
  settled = true;
31268
31580
  clearTimeout(timer2);
31269
- resolve86(result);
31581
+ resolve87(result);
31270
31582
  };
31271
31583
  const timer2 = setTimeout(() => {
31272
31584
  timedOut = true;
@@ -31310,8 +31622,8 @@ function isoToCcusageDate(iso) {
31310
31622
 
31311
31623
  // src/usage/cwd-extractor.ts
31312
31624
  init_paths();
31313
- import { open as open4, readdir as readdir25, stat as stat11 } from "fs/promises";
31314
- import { join as join18 } from "path";
31625
+ import { open as open4, readdir as readdir26, stat as stat11 } from "fs/promises";
31626
+ import { join as join19 } from "path";
31315
31627
  import { homedir as homedir12 } from "os";
31316
31628
  var SCAN_LINE_CAP = 50;
31317
31629
  var TAIL_READ_BYTES = 8 * 1024;
@@ -31386,12 +31698,12 @@ async function* walkClaudeProjects(opts = {}) {
31386
31698
  const dirs = await listDirSafe(root);
31387
31699
  for (const dirent of dirs) {
31388
31700
  if (!dirent.isDirectory) continue;
31389
- const dirPath = join18(root, dirent.name);
31701
+ const dirPath = join19(root, dirent.name);
31390
31702
  const files = await listDirSafe(dirPath);
31391
31703
  let cachedCwd = null;
31392
31704
  for (const f of files) {
31393
31705
  if (!f.isFile || !f.name.endsWith(".jsonl")) continue;
31394
- const filePath = join18(dirPath, f.name);
31706
+ const filePath = join19(dirPath, f.name);
31395
31707
  if (opts.sinceMtimeMs !== void 0) {
31396
31708
  const mtime = await mtimeMs(filePath);
31397
31709
  if (mtime !== null && mtime < opts.sinceMtimeMs) continue;
@@ -31428,12 +31740,12 @@ function resolveCodexSessionsRoot(override) {
31428
31740
  const fromSessionsEnv = process.env.CODEX_SESSIONS_DIR;
31429
31741
  if (fromSessionsEnv && fromSessionsEnv.length > 0) return expandHome(fromSessionsEnv);
31430
31742
  const fromHomeEnv = process.env.CODEX_HOME;
31431
- if (fromHomeEnv && fromHomeEnv.length > 0) return join18(expandHome(fromHomeEnv), "sessions");
31432
- return join18(homedir12(), ".codex", "sessions");
31743
+ if (fromHomeEnv && fromHomeEnv.length > 0) return join19(expandHome(fromHomeEnv), "sessions");
31744
+ return join19(homedir12(), ".codex", "sessions");
31433
31745
  }
31434
31746
  async function listDirSafe(path) {
31435
31747
  try {
31436
- const entries = await readdir25(path, { withFileTypes: true });
31748
+ const entries = await readdir26(path, { withFileTypes: true });
31437
31749
  return entries.map((e) => ({
31438
31750
  name: e.name,
31439
31751
  isFile: e.isFile(),
@@ -31449,7 +31761,7 @@ async function* walkJsonlRecursive(root) {
31449
31761
  const current = stack.pop();
31450
31762
  const entries = await listDirSafe(current);
31451
31763
  for (const e of entries) {
31452
- const full = join18(current, e.name);
31764
+ const full = join19(current, e.name);
31453
31765
  if (e.isDirectory) {
31454
31766
  stack.push(full);
31455
31767
  } else if (e.isFile && e.name.endsWith(".jsonl")) {
@@ -31788,8 +32100,8 @@ init_slug();
31788
32100
  init_timestamp();
31789
32101
  init_assignment_resolver();
31790
32102
  init_assignment_todos();
31791
- import { resolve as resolve75 } from "path";
31792
- import { readFile as readFile52 } from "fs/promises";
32103
+ import { resolve as resolve76 } from "path";
32104
+ import { readFile as readFile53 } from "fs/promises";
31793
32105
  async function requestCommand(target, text, options = {}) {
31794
32106
  if (!text || !text.trim()) {
31795
32107
  throw new Error("Request text cannot be empty.");
@@ -31805,7 +32117,7 @@ async function requestCommand(target, text, options = {}) {
31805
32117
  if (!isValidSlug(target)) {
31806
32118
  throw new Error(`Invalid assignment slug "${target}".`);
31807
32119
  }
31808
- assignmentDir = resolve75(baseDir, options.project, "assignments", target);
32120
+ assignmentDir = resolve76(baseDir, options.project, "assignments", target);
31809
32121
  targetRef = target;
31810
32122
  } else {
31811
32123
  const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), target);
@@ -31815,12 +32127,12 @@ async function requestCommand(target, text, options = {}) {
31815
32127
  assignmentDir = resolved.assignmentDir;
31816
32128
  targetRef = resolved.standalone ? resolved.id : resolved.assignmentSlug;
31817
32129
  }
31818
- const assignmentMdPath2 = resolve75(assignmentDir, "assignment.md");
32130
+ const assignmentMdPath2 = resolve76(assignmentDir, "assignment.md");
31819
32131
  if (!await fileExists(assignmentMdPath2)) {
31820
32132
  throw new Error(`assignment.md not found at ${assignmentMdPath2}`);
31821
32133
  }
31822
32134
  const source = options.from ?? process.env.SYNTAUR_ASSIGNMENT ?? "unknown";
31823
- let content = await readFile52(assignmentMdPath2, "utf-8");
32135
+ let content = await readFile53(assignmentMdPath2, "utf-8");
31824
32136
  content = appendTodosToAssignmentBody(content, [
31825
32137
  { description: `${text.trim()} (from: ${source})` }
31826
32138
  ]);
@@ -31834,13 +32146,13 @@ init_fs();
31834
32146
  init_paths();
31835
32147
  init_config2();
31836
32148
  import { Command as Command9 } from "commander";
31837
- import { readFile as readFile53, readdir as readdir26 } from "fs/promises";
31838
- import { resolve as resolve76 } from "path";
32149
+ import { readFile as readFile54, readdir as readdir27 } from "fs/promises";
32150
+ import { resolve as resolve77 } from "path";
31839
32151
  async function readContextAssignmentDir(cwd) {
31840
- const path = resolve76(cwd, ".syntaur", "context.json");
32152
+ const path = resolve77(cwd, ".syntaur", "context.json");
31841
32153
  if (!await fileExists(path)) return null;
31842
32154
  try {
31843
- const raw2 = await readFile53(path, "utf-8");
32155
+ const raw2 = await readFile54(path, "utf-8");
31844
32156
  const ctx = JSON.parse(raw2);
31845
32157
  if (typeof ctx.assignmentDir === "string" && ctx.assignmentDir.length > 0) {
31846
32158
  return ctx.assignmentDir;
@@ -31854,9 +32166,9 @@ async function resolveAssignmentDir(opts) {
31854
32166
  const cwd = opts.cwd ?? process.cwd();
31855
32167
  if (opts.assignment) {
31856
32168
  if (opts.project) {
31857
- return resolve76((await readConfig()).defaultProjectDir, opts.project, "assignments", opts.assignment);
32169
+ return resolve77((await readConfig()).defaultProjectDir, opts.project, "assignments", opts.assignment);
31858
32170
  }
31859
- return resolve76(assignmentsDir(), opts.assignment);
32171
+ return resolve77(assignmentsDir(), opts.assignment);
31860
32172
  }
31861
32173
  const fromCtx = await readContextAssignmentDir(cwd);
31862
32174
  if (fromCtx) return fromCtx;
@@ -31867,7 +32179,7 @@ async function resolveAssignmentDir(opts) {
31867
32179
  var PLAN_PATTERN = /^plan(?:-v(\d+))?\.md$/;
31868
32180
  async function listPlanFiles(assignmentDir) {
31869
32181
  if (!await fileExists(assignmentDir)) return [];
31870
- const entries = await readdir26(assignmentDir, { withFileTypes: true });
32182
+ const entries = await readdir27(assignmentDir, { withFileTypes: true });
31871
32183
  const out = [];
31872
32184
  for (const e of entries) {
31873
32185
  if (!e.isFile()) continue;
@@ -32052,17 +32364,17 @@ async function runPlanCreate(options) {
32052
32364
  if (!await fileExists(assignmentDir)) {
32053
32365
  throw new Error(`Assignment directory does not exist: ${assignmentDir}`);
32054
32366
  }
32055
- const assignmentMdPath2 = resolve76(assignmentDir, "assignment.md");
32367
+ const assignmentMdPath2 = resolve77(assignmentDir, "assignment.md");
32056
32368
  if (!await fileExists(assignmentMdPath2)) {
32057
32369
  throw new Error(`Missing assignment.md at: ${assignmentMdPath2}`);
32058
32370
  }
32059
- const planPath = resolve76(assignmentDir, "plan.md");
32371
+ const planPath = resolve77(assignmentDir, "plan.md");
32060
32372
  if (await fileExists(planPath) && !options.force) {
32061
32373
  throw new Error(
32062
32374
  "plan.md already exists. Use --force to overwrite, or `syntaur plan version` to create the next version."
32063
32375
  );
32064
32376
  }
32065
- const assignmentMd = await readFile53(assignmentMdPath2, "utf-8");
32377
+ const assignmentMd = await readFile54(assignmentMdPath2, "utf-8");
32066
32378
  const slugMatch = assignmentMd.match(/^slug:\s*(.+?)\s*$/m);
32067
32379
  const slug = slugMatch ? slugMatch[1].trim() : assignmentDir.split("/").pop() ?? "";
32068
32380
  await writeFileForce(planPath, buildInitialPlanStub(slug));
@@ -32082,7 +32394,7 @@ async function runPlanVersion(options) {
32082
32394
  if (!await fileExists(assignmentDir)) {
32083
32395
  throw new Error(`Assignment directory does not exist: ${assignmentDir}`);
32084
32396
  }
32085
- const assignmentMdPath2 = resolve76(assignmentDir, "assignment.md");
32397
+ const assignmentMdPath2 = resolve77(assignmentDir, "assignment.md");
32086
32398
  if (!await fileExists(assignmentMdPath2)) {
32087
32399
  throw new Error(`Missing assignment.md at: ${assignmentMdPath2}`);
32088
32400
  }
@@ -32094,15 +32406,15 @@ async function runPlanVersion(options) {
32094
32406
  }
32095
32407
  const current = planFiles[planFiles.length - 1];
32096
32408
  const next = nextPlanFileName(current.version);
32097
- const newPath = resolve76(assignmentDir, next.fileName);
32409
+ const newPath = resolve77(assignmentDir, next.fileName);
32098
32410
  if (await fileExists(newPath) && !options.force) {
32099
32411
  throw new Error(`${next.fileName} already exists. Use --force to overwrite.`);
32100
32412
  }
32101
- const assignmentMd = await readFile53(assignmentMdPath2, "utf-8");
32413
+ const assignmentMd = await readFile54(assignmentMdPath2, "utf-8");
32102
32414
  const slugMatch = assignmentMd.match(/^slug:\s*(.+?)\s*$/m);
32103
32415
  const slug = slugMatch ? slugMatch[1].trim() : assignmentDir.split("/").pop() ?? "";
32104
- const oldPlanPath = resolve76(assignmentDir, current.fileName);
32105
- const oldPlanContent = await readFile53(oldPlanPath, "utf-8");
32416
+ const oldPlanPath = resolve77(assignmentDir, current.fileName);
32417
+ const oldPlanContent = await readFile54(oldPlanPath, "utf-8");
32106
32418
  const oldBody = oldPlanContent.replace(/^---[\s\S]*?\n---\n?/, "");
32107
32419
  const carriedTodos = extractUncheckedTodos(oldBody);
32108
32420
  const stub = buildNewPlanStub({
@@ -32150,26 +32462,26 @@ init_paths();
32150
32462
  init_config2();
32151
32463
  init_timestamp();
32152
32464
  import { Command as Command10 } from "commander";
32153
- import { readFile as readFile54, readdir as readdir27, stat as stat12 } from "fs/promises";
32154
- import { resolve as resolve77 } from "path";
32465
+ import { readFile as readFile55, readdir as readdir28, stat as stat12 } from "fs/promises";
32466
+ import { resolve as resolve78 } from "path";
32155
32467
  async function readContext(cwd) {
32156
- const path = resolve77(cwd, ".syntaur", "context.json");
32468
+ const path = resolve78(cwd, ".syntaur", "context.json");
32157
32469
  if (!await fileExists(path)) return null;
32158
32470
  try {
32159
- const raw2 = await readFile54(path, "utf-8");
32471
+ const raw2 = await readFile55(path, "utf-8");
32160
32472
  return JSON.parse(raw2);
32161
32473
  } catch {
32162
32474
  return null;
32163
32475
  }
32164
32476
  }
32165
32477
  async function findLatestSessionSummary(assignmentDir) {
32166
- const sessionsRoot = resolve77(assignmentDir, "sessions");
32478
+ const sessionsRoot = resolve78(assignmentDir, "sessions");
32167
32479
  if (!await fileExists(sessionsRoot)) return null;
32168
- const entries = await readdir27(sessionsRoot, { withFileTypes: true });
32480
+ const entries = await readdir28(sessionsRoot, { withFileTypes: true });
32169
32481
  let best = null;
32170
32482
  for (const entry of entries) {
32171
32483
  if (!entry.isDirectory()) continue;
32172
- const summaryPath = resolve77(sessionsRoot, entry.name, "summary.md");
32484
+ const summaryPath = resolve78(sessionsRoot, entry.name, "summary.md");
32173
32485
  if (!await fileExists(summaryPath)) continue;
32174
32486
  const st = await stat12(summaryPath);
32175
32487
  if (best === null || st.mtime.getTime() > best.mtime.getTime()) {
@@ -32179,9 +32491,9 @@ async function findLatestSessionSummary(assignmentDir) {
32179
32491
  return best;
32180
32492
  }
32181
32493
  async function findOpenHandoff(assignmentDir) {
32182
- const handoffPath = resolve77(assignmentDir, "handoff.md");
32494
+ const handoffPath = resolve78(assignmentDir, "handoff.md");
32183
32495
  if (!await fileExists(handoffPath)) return null;
32184
- const content = await readFile54(handoffPath, "utf-8");
32496
+ const content = await readFile55(handoffPath, "utf-8");
32185
32497
  const body = content.replace(/^---[\s\S]*?\n---\n?/, "").trim();
32186
32498
  if (body.length === 0) return null;
32187
32499
  if (/^<!--[\s\S]*-->$/.test(body)) return null;
@@ -32276,7 +32588,7 @@ async function resolveSaveTarget(options, cwd) {
32276
32588
  let slug;
32277
32589
  const ctx = await readContext(cwd);
32278
32590
  if (options.assignment) {
32279
- assignmentDir = options.project ? resolve77((await readConfig()).defaultProjectDir, options.project, "assignments", options.assignment) : resolve77(assignmentsDir(), options.assignment);
32591
+ assignmentDir = options.project ? resolve78((await readConfig()).defaultProjectDir, options.project, "assignments", options.assignment) : resolve78(assignmentsDir(), options.assignment);
32280
32592
  slug = options.assignment;
32281
32593
  } else {
32282
32594
  if (!ctx?.assignmentDir) {
@@ -32329,21 +32641,21 @@ function extractCreated(content) {
32329
32641
  }
32330
32642
  async function runSessionSave(options, cwd = process.cwd(), body) {
32331
32643
  const { assignmentDir, slug, sessionId } = await resolveSaveTarget(options, cwd);
32332
- if (!await fileExists(resolve77(assignmentDir, "assignment.md"))) {
32644
+ if (!await fileExists(resolve78(assignmentDir, "assignment.md"))) {
32333
32645
  throw new Error(`No assignment found at ${assignmentDir} (missing assignment.md).`);
32334
32646
  }
32335
- const sessionDir = resolve77(assignmentDir, "sessions", sessionId);
32336
- const summaryPath = resolve77(sessionDir, "summary.md");
32647
+ const sessionDir = resolve78(assignmentDir, "sessions", sessionId);
32648
+ const summaryPath = resolve78(sessionDir, "summary.md");
32337
32649
  const now = nowTimestamp();
32338
32650
  let created = now;
32339
32651
  if (await fileExists(summaryPath)) {
32340
- const existing = await readFile54(summaryPath, "utf-8");
32652
+ const existing = await readFile55(summaryPath, "utf-8");
32341
32653
  created = extractCreated(existing) ?? now;
32342
32654
  }
32343
32655
  let sectionBody = body;
32344
32656
  if (sectionBody === void 0) {
32345
32657
  if (options.fromFile) {
32346
- sectionBody = await readFile54(resolve77(cwd, options.fromFile), "utf-8");
32658
+ sectionBody = await readFile55(resolve78(cwd, options.fromFile), "utf-8");
32347
32659
  } else {
32348
32660
  sectionBody = await readStdin();
32349
32661
  }
@@ -32391,13 +32703,13 @@ init_config2();
32391
32703
  init_timestamp();
32392
32704
  init_frontmatter();
32393
32705
  import { Command as Command11 } from "commander";
32394
- import { readFile as readFile55 } from "fs/promises";
32395
- import { resolve as resolve78 } from "path";
32706
+ import { readFile as readFile56 } from "fs/promises";
32707
+ import { resolve as resolve79 } from "path";
32396
32708
  async function readContext2(cwd) {
32397
- const path = resolve78(cwd, ".syntaur", "context.json");
32709
+ const path = resolve79(cwd, ".syntaur", "context.json");
32398
32710
  if (!await fileExists(path)) return null;
32399
32711
  try {
32400
- return JSON.parse(await readFile55(path, "utf-8"));
32712
+ return JSON.parse(await readFile56(path, "utf-8"));
32401
32713
  } catch {
32402
32714
  return null;
32403
32715
  }
@@ -32406,12 +32718,12 @@ async function resolveAssignmentPath2(opts) {
32406
32718
  if (opts.assignment) {
32407
32719
  if (opts.project) {
32408
32720
  const projectsDir2 = (await readConfig()).defaultProjectDir;
32409
- return resolve78(projectsDir2, opts.project, "assignments", opts.assignment, "assignment.md");
32721
+ return resolve79(projectsDir2, opts.project, "assignments", opts.assignment, "assignment.md");
32410
32722
  }
32411
- return resolve78(assignmentsDir(), opts.assignment, "assignment.md");
32723
+ return resolve79(assignmentsDir(), opts.assignment, "assignment.md");
32412
32724
  }
32413
32725
  const ctx = await readContext2(opts.cwd);
32414
- if (ctx?.assignmentDir) return resolve78(ctx.assignmentDir, "assignment.md");
32726
+ if (ctx?.assignmentDir) return resolve79(ctx.assignmentDir, "assignment.md");
32415
32727
  throw new Error(
32416
32728
  "No active assignment. Pass --assignment <slug> [--project <slug>] or run from a workspace with .syntaur/context.json."
32417
32729
  );
@@ -32422,7 +32734,7 @@ async function runWorktreeCreate(options, cwd = process.cwd()) {
32422
32734
  }
32423
32735
  const repository = options.repository ?? cwd;
32424
32736
  const parentBranch = options.parentBranch ?? "main";
32425
- const worktreePath = options.worktreePath ?? resolve78(repository, ".worktrees", options.branch);
32737
+ const worktreePath = options.worktreePath ?? resolve79(repository, ".worktrees", options.branch);
32426
32738
  const assignmentPath = await resolveAssignmentPath2({
32427
32739
  assignment: options.assignment,
32428
32740
  project: options.project,
@@ -32452,7 +32764,7 @@ async function runWorktreeRemove(options, cwd = process.cwd()) {
32452
32764
  if (!await fileExists(assignmentPath)) {
32453
32765
  throw new Error(`Assignment file not found: ${assignmentPath}`);
32454
32766
  }
32455
- const original = await readFile55(assignmentPath, "utf-8");
32767
+ const original = await readFile56(assignmentPath, "utf-8");
32456
32768
  const fm = parseAssignmentFrontmatter(original);
32457
32769
  const repository = options.repository ?? fm.workspace.repository ?? void 0;
32458
32770
  const worktreePath = fm.workspace.worktreePath ?? void 0;
@@ -32551,14 +32863,14 @@ init_config2();
32551
32863
  init_fs();
32552
32864
  init_slug();
32553
32865
  import { Command as Command12 } from "commander";
32554
- import { resolve as resolve80 } from "path";
32555
- import { readFile as readFile57, readdir as readdir29, rm as rm14 } from "fs/promises";
32866
+ import { resolve as resolve81 } from "path";
32867
+ import { readFile as readFile58, readdir as readdir30, rm as rm14 } from "fs/promises";
32556
32868
 
32557
32869
  // src/utils/project-indexes.ts
32558
32870
  init_parser();
32559
32871
  init_fs();
32560
- import { readdir as readdir28, readFile as readFile56 } from "fs/promises";
32561
- import { resolve as resolve79 } from "path";
32872
+ import { readdir as readdir29, readFile as readFile57 } from "fs/promises";
32873
+ import { resolve as resolve80 } from "path";
32562
32874
  function nowIso3() {
32563
32875
  return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
32564
32876
  }
@@ -32567,7 +32879,7 @@ function readProjectSlug(projectDir) {
32567
32879
  }
32568
32880
  async function listSlugFiles(dir) {
32569
32881
  if (!await fileExists(dir)) return [];
32570
- const entries = await readdir28(dir, { withFileTypes: true });
32882
+ const entries = await readdir29(dir, { withFileTypes: true });
32571
32883
  return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && !e.name.startsWith("_")).map((e) => e.name).sort();
32572
32884
  }
32573
32885
  function escapeCell(value) {
@@ -32577,7 +32889,7 @@ function joinList(items) {
32577
32889
  return items.length === 0 ? "\u2014" : items.map(escapeCell).join(", ");
32578
32890
  }
32579
32891
  async function rebuildResourcesIndex(projectDir) {
32580
- const dir = resolve79(projectDir, "resources");
32892
+ const dir = resolve80(projectDir, "resources");
32581
32893
  await ensureDir(dir);
32582
32894
  const files = await listSlugFiles(dir);
32583
32895
  const slug = readProjectSlug(projectDir);
@@ -32593,7 +32905,7 @@ async function rebuildResourcesIndex(projectDir) {
32593
32905
  lines.push("| Name | Category | Source | Related Assignments | Updated |");
32594
32906
  lines.push("|------|----------|--------|---------------------|---------|");
32595
32907
  for (const fileName of files) {
32596
- const content = await readFile56(resolve79(dir, fileName), "utf-8");
32908
+ const content = await readFile57(resolve80(dir, fileName), "utf-8");
32597
32909
  const parsed = parseResource(content);
32598
32910
  const slugBase = fileName.replace(/\.md$/, "");
32599
32911
  const name = parsed.name || slugBase;
@@ -32603,12 +32915,12 @@ async function rebuildResourcesIndex(projectDir) {
32603
32915
  );
32604
32916
  }
32605
32917
  lines.push("");
32606
- const indexPath = resolve79(dir, "_index.md");
32918
+ const indexPath = resolve80(dir, "_index.md");
32607
32919
  await writeFileForce(indexPath, lines.join("\n"));
32608
32920
  return { total: files.length, path: indexPath };
32609
32921
  }
32610
32922
  async function rebuildMemoriesIndex(projectDir) {
32611
- const dir = resolve79(projectDir, "memories");
32923
+ const dir = resolve80(projectDir, "memories");
32612
32924
  await ensureDir(dir);
32613
32925
  const files = await listSlugFiles(dir);
32614
32926
  const slug = readProjectSlug(projectDir);
@@ -32624,7 +32936,7 @@ async function rebuildMemoriesIndex(projectDir) {
32624
32936
  lines.push("| Name | Source | Scope | Source Assignment | Updated |");
32625
32937
  lines.push("|------|--------|-------|-------------------|---------|");
32626
32938
  for (const fileName of files) {
32627
- const content = await readFile56(resolve79(dir, fileName), "utf-8");
32939
+ const content = await readFile57(resolve80(dir, fileName), "utf-8");
32628
32940
  const parsed = parseMemory(content);
32629
32941
  const slugBase = fileName.replace(/\.md$/, "");
32630
32942
  const name = parsed.name || slugBase;
@@ -32634,7 +32946,7 @@ async function rebuildMemoriesIndex(projectDir) {
32634
32946
  );
32635
32947
  }
32636
32948
  lines.push("");
32637
- const indexPath = resolve79(dir, "_index.md");
32949
+ const indexPath = resolve80(dir, "_index.md");
32638
32950
  await writeFileForce(indexPath, lines.join("\n"));
32639
32951
  return { total: files.length, path: indexPath };
32640
32952
  }
@@ -32698,8 +33010,8 @@ ${opts.body ?? "<!-- Add notes about this resource here. -->"}
32698
33010
  }
32699
33011
  async function resolveProjectDir(project) {
32700
33012
  if (!isValidSlug(project)) throw new Error(`Invalid project slug: "${project}".`);
32701
- const projectDir = resolve80((await readConfig()).defaultProjectDir, project);
32702
- if (!await fileExists(resolve80(projectDir, "project.md"))) {
33013
+ const projectDir = resolve81((await readConfig()).defaultProjectDir, project);
33014
+ if (!await fileExists(resolve81(projectDir, "project.md"))) {
32703
33015
  throw new Error(`Project "${project}" not found at ${projectDir}.`);
32704
33016
  }
32705
33017
  return projectDir;
@@ -32712,7 +33024,7 @@ async function runResourceAdd(options) {
32712
33024
  if (!isValidSlug(slug)) {
32713
33025
  throw new Error(`Invalid resource slug: "${slug}".`);
32714
33026
  }
32715
- const filePath = resolve80(projectDir, "resources", `${slug}.md`);
33027
+ const filePath = resolve81(projectDir, "resources", `${slug}.md`);
32716
33028
  if (await fileExists(filePath) && !options.force) {
32717
33029
  throw new Error(
32718
33030
  `Resource "${slug}" already exists at ${filePath}. Use --force to overwrite.`
@@ -32729,9 +33041,9 @@ async function runResourceAdd(options) {
32729
33041
  return { filePath, indexPath, total };
32730
33042
  }
32731
33043
  async function listResourceSlugs(projectDir) {
32732
- const dir = resolve80(projectDir, "resources");
33044
+ const dir = resolve81(projectDir, "resources");
32733
33045
  if (!await fileExists(dir)) return [];
32734
- const entries = await readdir29(dir, { withFileTypes: true });
33046
+ const entries = await readdir30(dir, { withFileTypes: true });
32735
33047
  return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && e.name !== "_index.md").map((e) => e.name.slice(0, -3)).sort();
32736
33048
  }
32737
33049
  async function runResourceList(project) {
@@ -32739,16 +33051,16 @@ async function runResourceList(project) {
32739
33051
  const slugs = await listResourceSlugs(projectDir);
32740
33052
  const out = [];
32741
33053
  for (const slug of slugs) {
32742
- const parsed = parseResource(await readFile57(resolve80(projectDir, "resources", `${slug}.md`), "utf-8"));
33054
+ const parsed = parseResource(await readFile58(resolve81(projectDir, "resources", `${slug}.md`), "utf-8"));
32743
33055
  out.push({ slug, name: parsed.name, category: parsed.category, source: parsed.source, updated: parsed.updated });
32744
33056
  }
32745
33057
  return out;
32746
33058
  }
32747
33059
  async function runResourceShow(project, slug) {
32748
33060
  const projectDir = await resolveProjectDir(project);
32749
- const filePath = resolve80(projectDir, "resources", `${slug}.md`);
33061
+ const filePath = resolve81(projectDir, "resources", `${slug}.md`);
32750
33062
  if (!await fileExists(filePath)) throw new Error(`Resource "${slug}" not found in project "${project}".`);
32751
- const parsed = parseResource(await readFile57(filePath, "utf-8"));
33063
+ const parsed = parseResource(await readFile58(filePath, "utf-8"));
32752
33064
  return {
32753
33065
  slug,
32754
33066
  name: parsed.name,
@@ -32762,14 +33074,14 @@ async function runResourceShow(project, slug) {
32762
33074
  }
32763
33075
  async function runResourceUpdate(slug, options) {
32764
33076
  const projectDir = await resolveProjectDir(options.project);
32765
- const filePath = resolve80(projectDir, "resources", `${slug}.md`);
33077
+ const filePath = resolve81(projectDir, "resources", `${slug}.md`);
32766
33078
  if (!await fileExists(filePath)) {
32767
33079
  throw new Error(`Resource "${slug}" not found in project "${options.project}".`);
32768
33080
  }
32769
33081
  if (options.name === void 0 && options.source === void 0 && options.category === void 0 && options.relatedAssignments === void 0) {
32770
33082
  throw new Error("Provide at least one of --name, --source, --category, --related-assignments.");
32771
33083
  }
32772
- const original = await readFile57(filePath, "utf-8");
33084
+ const original = await readFile58(filePath, "utf-8");
32773
33085
  const content = editResourceFrontmatter(original, {
32774
33086
  name: options.name,
32775
33087
  category: options.category,
@@ -32782,7 +33094,7 @@ async function runResourceUpdate(slug, options) {
32782
33094
  }
32783
33095
  async function runResourceRemove(slug, options) {
32784
33096
  const projectDir = await resolveProjectDir(options.project);
32785
- const filePath = resolve80(projectDir, "resources", `${slug}.md`);
33097
+ const filePath = resolve81(projectDir, "resources", `${slug}.md`);
32786
33098
  if (!await fileExists(filePath)) {
32787
33099
  throw new Error(`Resource "${slug}" not found in project "${options.project}".`);
32788
33100
  }
@@ -32865,8 +33177,8 @@ init_config2();
32865
33177
  init_fs();
32866
33178
  init_slug();
32867
33179
  import { Command as Command13 } from "commander";
32868
- import { resolve as resolve81 } from "path";
32869
- import { readFile as readFile58, readdir as readdir30, rm as rm15 } from "fs/promises";
33180
+ import { resolve as resolve82 } from "path";
33181
+ import { readFile as readFile59, readdir as readdir31, rm as rm15 } from "fs/promises";
32870
33182
  init_parser();
32871
33183
  function nowIso5() {
32872
33184
  return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
@@ -32930,8 +33242,8 @@ ${opts.body ?? "<!-- Capture the load-bearing context for this memory here. -->"
32930
33242
  }
32931
33243
  async function resolveProjectDir2(project) {
32932
33244
  if (!isValidSlug(project)) throw new Error(`Invalid project slug: "${project}".`);
32933
- const projectDir = resolve81((await readConfig()).defaultProjectDir, project);
32934
- if (!await fileExists(resolve81(projectDir, "project.md"))) {
33245
+ const projectDir = resolve82((await readConfig()).defaultProjectDir, project);
33246
+ if (!await fileExists(resolve82(projectDir, "project.md"))) {
32935
33247
  throw new Error(`Project "${project}" not found at ${projectDir}.`);
32936
33248
  }
32937
33249
  return projectDir;
@@ -32944,7 +33256,7 @@ async function runMemoryAdd(options) {
32944
33256
  if (!isValidSlug(slug)) {
32945
33257
  throw new Error(`Invalid memory slug: "${slug}".`);
32946
33258
  }
32947
- const filePath = resolve81(projectDir, "memories", `${slug}.md`);
33259
+ const filePath = resolve82(projectDir, "memories", `${slug}.md`);
32948
33260
  if (await fileExists(filePath) && !options.force) {
32949
33261
  throw new Error(
32950
33262
  `Memory "${slug}" already exists at ${filePath}. Use --force to overwrite.`
@@ -32962,9 +33274,9 @@ async function runMemoryAdd(options) {
32962
33274
  return { filePath, indexPath, total };
32963
33275
  }
32964
33276
  async function listMemorySlugs(projectDir) {
32965
- const dir = resolve81(projectDir, "memories");
33277
+ const dir = resolve82(projectDir, "memories");
32966
33278
  if (!await fileExists(dir)) return [];
32967
- const entries = await readdir30(dir, { withFileTypes: true });
33279
+ const entries = await readdir31(dir, { withFileTypes: true });
32968
33280
  return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && e.name !== "_index.md").map((e) => e.name.slice(0, -3)).sort();
32969
33281
  }
32970
33282
  async function runMemoryList(project) {
@@ -32972,16 +33284,16 @@ async function runMemoryList(project) {
32972
33284
  const slugs = await listMemorySlugs(projectDir);
32973
33285
  const out = [];
32974
33286
  for (const slug of slugs) {
32975
- const parsed = parseMemory(await readFile58(resolve81(projectDir, "memories", `${slug}.md`), "utf-8"));
33287
+ const parsed = parseMemory(await readFile59(resolve82(projectDir, "memories", `${slug}.md`), "utf-8"));
32976
33288
  out.push({ slug, name: parsed.name, scope: parsed.scope, source: parsed.source, updated: parsed.updated });
32977
33289
  }
32978
33290
  return out;
32979
33291
  }
32980
33292
  async function runMemoryShow(project, slug) {
32981
33293
  const projectDir = await resolveProjectDir2(project);
32982
- const filePath = resolve81(projectDir, "memories", `${slug}.md`);
33294
+ const filePath = resolve82(projectDir, "memories", `${slug}.md`);
32983
33295
  if (!await fileExists(filePath)) throw new Error(`Memory "${slug}" not found in project "${project}".`);
32984
- const parsed = parseMemory(await readFile58(filePath, "utf-8"));
33296
+ const parsed = parseMemory(await readFile59(filePath, "utf-8"));
32985
33297
  return {
32986
33298
  slug,
32987
33299
  name: parsed.name,
@@ -32996,7 +33308,7 @@ async function runMemoryShow(project, slug) {
32996
33308
  }
32997
33309
  async function runMemoryUpdate(slug, options) {
32998
33310
  const projectDir = await resolveProjectDir2(options.project);
32999
- const filePath = resolve81(projectDir, "memories", `${slug}.md`);
33311
+ const filePath = resolve82(projectDir, "memories", `${slug}.md`);
33000
33312
  if (!await fileExists(filePath)) {
33001
33313
  throw new Error(`Memory "${slug}" not found in project "${options.project}".`);
33002
33314
  }
@@ -33005,7 +33317,7 @@ async function runMemoryUpdate(slug, options) {
33005
33317
  "Provide at least one of --name, --source, --scope, --source-assignment, --related-assignments."
33006
33318
  );
33007
33319
  }
33008
- const original = await readFile58(filePath, "utf-8");
33320
+ const original = await readFile59(filePath, "utf-8");
33009
33321
  const content = editMemoryFrontmatter(original, {
33010
33322
  name: options.name,
33011
33323
  source: options.source,
@@ -33019,7 +33331,7 @@ async function runMemoryUpdate(slug, options) {
33019
33331
  }
33020
33332
  async function runMemoryRemove(slug, options) {
33021
33333
  const projectDir = await resolveProjectDir2(options.project);
33022
- const filePath = resolve81(projectDir, "memories", `${slug}.md`);
33334
+ const filePath = resolve82(projectDir, "memories", `${slug}.md`);
33023
33335
  if (!await fileExists(filePath)) {
33024
33336
  throw new Error(`Memory "${slug}" not found in project "${options.project}".`);
33025
33337
  }
@@ -33104,8 +33416,8 @@ init_paths();
33104
33416
  init_fs();
33105
33417
  init_frontmatter();
33106
33418
  import { Command as Command14 } from "commander";
33107
- import { readFile as readFile59 } from "fs/promises";
33108
- import { resolve as resolve82 } from "path";
33419
+ import { readFile as readFile60 } from "fs/promises";
33420
+ import { resolve as resolve83 } from "path";
33109
33421
  var AGE_PATTERN = /^(\d+)([dhwm])$/i;
33110
33422
  function parseAgeToCutoff(age) {
33111
33423
  const match = age.match(AGE_PATTERN);
@@ -33124,7 +33436,7 @@ function parseAgeToCutoff(age) {
33124
33436
  }
33125
33437
  function assignmentMdPath(item) {
33126
33438
  if (item.projectSlug) {
33127
- return resolve82(
33439
+ return resolve83(
33128
33440
  defaultProjectDir(),
33129
33441
  item.projectSlug,
33130
33442
  "assignments",
@@ -33132,13 +33444,13 @@ function assignmentMdPath(item) {
33132
33444
  "assignment.md"
33133
33445
  );
33134
33446
  }
33135
- return resolve82(assignmentsDir(), item.id, "assignment.md");
33447
+ return resolve83(assignmentsDir(), item.id, "assignment.md");
33136
33448
  }
33137
33449
  async function loadTags(item) {
33138
33450
  const path = assignmentMdPath(item);
33139
33451
  if (!await fileExists(path)) return [];
33140
33452
  try {
33141
- const content = await readFile59(path, "utf-8");
33453
+ const content = await readFile60(path, "utf-8");
33142
33454
  return parseAssignmentFrontmatter(content).tags;
33143
33455
  } catch {
33144
33456
  return [];
@@ -33567,8 +33879,8 @@ init_fs();
33567
33879
  init_timestamp();
33568
33880
  init_frontmatter();
33569
33881
  import { Command as Command16 } from "commander";
33570
- import { readFile as readFile60 } from "fs/promises";
33571
- import { resolve as resolve83 } from "path";
33882
+ import { readFile as readFile61 } from "fs/promises";
33883
+ import { resolve as resolve84 } from "path";
33572
33884
  async function scanDirs() {
33573
33885
  const config = await readConfig();
33574
33886
  return { projectsDir: config.defaultProjectDir, standaloneDir: assignmentsDir() };
@@ -33578,12 +33890,12 @@ function fail3(error) {
33578
33890
  process.exit(1);
33579
33891
  }
33580
33892
  function configPath() {
33581
- return resolve83(syntaurRoot(), "config.md");
33893
+ return resolve84(syntaurRoot(), "config.md");
33582
33894
  }
33583
33895
  async function readStatusBlock() {
33584
33896
  const p = configPath();
33585
33897
  if (!await fileExists(p)) return null;
33586
- const content = await readFile60(p, "utf-8");
33898
+ const content = await readFile61(p, "utf-8");
33587
33899
  return parseStatusConfig(content);
33588
33900
  }
33589
33901
  async function requireStatusBlock() {
@@ -33832,7 +34144,7 @@ async function runStatusRename(id, opts) {
33832
34144
  printBlockDiff(before, after);
33833
34145
  const now2 = nowTimestamp();
33834
34146
  for (const a of affected) {
33835
- const original = await readFile60(a.path, "utf-8");
34147
+ const original = await readFile61(a.path, "utf-8");
33836
34148
  const rewritten = updateAssignmentFile(original, { status: newId, updated: now2 });
33837
34149
  console.log(`
33838
34150
  --- ${a.display}/assignment.md`);
@@ -33843,9 +34155,9 @@ async function runStatusRename(id, opts) {
33843
34155
  }
33844
34156
  const cfgPath = configPath();
33845
34157
  const buffers = /* @__PURE__ */ new Map();
33846
- buffers.set(cfgPath, await fileExists(cfgPath) ? await readFile60(cfgPath, "utf-8") : "");
34158
+ buffers.set(cfgPath, await fileExists(cfgPath) ? await readFile61(cfgPath, "utf-8") : "");
33847
34159
  for (const a of affected) {
33848
- buffers.set(a.path, await readFile60(a.path, "utf-8"));
34160
+ buffers.set(a.path, await readFile61(a.path, "utf-8"));
33849
34161
  }
33850
34162
  const now = nowTimestamp();
33851
34163
  try {
@@ -34025,13 +34337,13 @@ init_config2();
34025
34337
  init_timestamp();
34026
34338
  init_frontmatter();
34027
34339
  import { Command as Command17 } from "commander";
34028
- import { readFile as readFile61 } from "fs/promises";
34029
- import { resolve as resolve84 } from "path";
34340
+ import { readFile as readFile62 } from "fs/promises";
34341
+ import { resolve as resolve85 } from "path";
34030
34342
  async function readContext3(cwd) {
34031
- const path = resolve84(cwd, ".syntaur", "context.json");
34343
+ const path = resolve85(cwd, ".syntaur", "context.json");
34032
34344
  if (!await fileExists(path)) return null;
34033
34345
  try {
34034
- return JSON.parse(await readFile61(path, "utf-8"));
34346
+ return JSON.parse(await readFile62(path, "utf-8"));
34035
34347
  } catch {
34036
34348
  return null;
34037
34349
  }
@@ -34040,12 +34352,12 @@ async function resolveAssignmentPath3(opts) {
34040
34352
  if (opts.assignment) {
34041
34353
  if (opts.project) {
34042
34354
  const projectsDir2 = (await readConfig()).defaultProjectDir;
34043
- return resolve84(projectsDir2, opts.project, "assignments", opts.assignment, "assignment.md");
34355
+ return resolve85(projectsDir2, opts.project, "assignments", opts.assignment, "assignment.md");
34044
34356
  }
34045
- return resolve84(assignmentsDir(), opts.assignment, "assignment.md");
34357
+ return resolve85(assignmentsDir(), opts.assignment, "assignment.md");
34046
34358
  }
34047
34359
  const ctx = await readContext3(opts.cwd);
34048
- if (ctx?.assignmentDir) return resolve84(ctx.assignmentDir, "assignment.md");
34360
+ if (ctx?.assignmentDir) return resolve85(ctx.assignmentDir, "assignment.md");
34049
34361
  throw new Error(
34050
34362
  "No active assignment. Pass --assignment <slug> [--project <slug>] or run from a workspace with .syntaur/context.json."
34051
34363
  );
@@ -34082,7 +34394,7 @@ async function runWorkspaceSet(options, cwd = process.cwd()) {
34082
34394
  ${pre.errors.map((e) => ` - ${e}`).join("\n")}`
34083
34395
  );
34084
34396
  }
34085
- const original = await readFile61(path, "utf-8");
34397
+ const original = await readFile62(path, "utf-8");
34086
34398
  let next = updateAssignmentWorkspace(original, partial);
34087
34399
  next = updateAssignmentFile(next, { updated: nowTimestamp() });
34088
34400
  await writeFileForce(path, next);
@@ -34119,13 +34431,13 @@ init_config2();
34119
34431
  init_timestamp();
34120
34432
  init_templates();
34121
34433
  import { Command as Command18 } from "commander";
34122
- import { readFile as readFile62 } from "fs/promises";
34123
- import { resolve as resolve85 } from "path";
34434
+ import { readFile as readFile63 } from "fs/promises";
34435
+ import { resolve as resolve86 } from "path";
34124
34436
  async function readContext4(cwd) {
34125
- const path = resolve85(cwd, ".syntaur", "context.json");
34437
+ const path = resolve86(cwd, ".syntaur", "context.json");
34126
34438
  if (!await fileExists(path)) return null;
34127
34439
  try {
34128
- return JSON.parse(await readFile62(path, "utf-8"));
34440
+ return JSON.parse(await readFile63(path, "utf-8"));
34129
34441
  } catch {
34130
34442
  return null;
34131
34443
  }
@@ -34135,11 +34447,11 @@ async function resolveAssignmentDir2(opts) {
34135
34447
  if (opts.project) {
34136
34448
  const projectsDir2 = (await readConfig()).defaultProjectDir;
34137
34449
  return {
34138
- dir: resolve85(projectsDir2, opts.project, "assignments", opts.assignment),
34450
+ dir: resolve86(projectsDir2, opts.project, "assignments", opts.assignment),
34139
34451
  slug: opts.assignment
34140
34452
  };
34141
34453
  }
34142
- return { dir: resolve85(assignmentsDir(), opts.assignment), slug: opts.assignment };
34454
+ return { dir: resolve86(assignmentsDir(), opts.assignment), slug: opts.assignment };
34143
34455
  }
34144
34456
  const ctx = await readContext4(opts.cwd);
34145
34457
  if (ctx?.assignmentDir) {
@@ -34201,12 +34513,12 @@ async function runProgressLog(text, options, cwd = process.cwd()) {
34201
34513
  project: options.project,
34202
34514
  cwd
34203
34515
  });
34204
- if (!await fileExists(resolve85(dir, "assignment.md"))) {
34516
+ if (!await fileExists(resolve86(dir, "assignment.md"))) {
34205
34517
  throw new Error(`No assignment found at ${dir} (missing assignment.md).`);
34206
34518
  }
34207
- const path = resolve85(dir, "progress.md");
34519
+ const path = resolve86(dir, "progress.md");
34208
34520
  const now = nowTimestamp();
34209
- const content = await fileExists(path) ? await readFile62(path, "utf-8") : renderProgress({ assignment: slug, timestamp: now });
34521
+ const content = await fileExists(path) ? await readFile63(path, "utf-8") : renderProgress({ assignment: slug, timestamp: now });
34210
34522
  const next = appendProgressEntry(content, text, now);
34211
34523
  await writeFileForce(path, next);
34212
34524
  return path;
@@ -34226,10 +34538,10 @@ progressCommand.command("log").description("Append a timestamped entry to the as
34226
34538
 
34227
34539
  // src/cli-default-command.ts
34228
34540
  init_config2();
34229
- import { readdir as readdir31 } from "fs/promises";
34541
+ import { readdir as readdir32 } from "fs/promises";
34230
34542
  async function hasAnyProjectContent(projectsDir2) {
34231
34543
  try {
34232
- const entries = await readdir31(projectsDir2, { withFileTypes: true });
34544
+ const entries = await readdir32(projectsDir2, { withFileTypes: true });
34233
34545
  return entries.some((entry) => entry.isDirectory());
34234
34546
  } catch {
34235
34547
  return false;
@@ -34531,7 +34843,7 @@ program.command("reopen").description("Reopen a completed or failed assignment")
34531
34843
  process.exit(1);
34532
34844
  }
34533
34845
  });
34534
- program.command("setup").description("Initialize Syntaur and optionally install plugins or launch the dashboard").option("--yes", "Skip interactive prompts and perform only the requested flags").option("--claude", "Install the Claude Code plugin").option("--codex", "Install the Codex plugin").option("--claude-dir <path>", "Install the Claude Code plugin at a specific path").option("--codex-dir <path>", "Install the Codex plugin at a specific path").option("--codex-marketplace-path <path>", "Write the Codex marketplace entry to a specific file").option("--dashboard", "Launch the dashboard after setup").option("--target <id>", "Install Syntaur into a cross-agent target (pi, hermes, openclaw, cursor, opencode); comma-separated for several").option("--agent <id>", "Alias for --target; cross-agent target id(s) to install into").option("--force", "Overwrite existing cross-agent protocol files / skills").option("--dry-run", "Print the cross-agent install actions without writing anything").action(async (options) => {
34846
+ program.command("setup").description("Initialize Syntaur and optionally install plugins or launch the dashboard").option("--yes", "Skip interactive prompts and perform only the requested flags").option("--claude", "Install the Claude Code plugin").option("--codex", "Install the Codex plugin").option("--claude-dir <path>", "Install the Claude Code plugin at a specific path").option("--codex-dir <path>", "Install the Codex plugin at a specific path").option("--codex-marketplace-path <path>", "Write the Codex marketplace entry to a specific file").option("--dashboard", "Launch the dashboard after setup").option("--target <id>", "Install Syntaur into a cross-agent target. Built-in ids: pi, hermes, openclaw, cursor, opencode (plus any user descriptors in ~/.syntaur/targets/). Comma-separated for several").option("--agent <id>", "Alias for --target; cross-agent target id(s) to install into").option("--force", "Overwrite existing cross-agent protocol files / skills").option("--dry-run", "Print the cross-agent install actions without writing anything").action(async (options) => {
34535
34847
  try {
34536
34848
  await setupCommand(options);
34537
34849
  } catch (error) {
@@ -34640,7 +34952,7 @@ program.command("uninstall").description("Remove Syntaur integrations and option
34640
34952
  process.exit(1);
34641
34953
  }
34642
34954
  });
34643
- program.command("setup-adapter").description("Generate adapter instruction files for a framework in the current directory").argument("<framework>", "Target framework (cursor, codex, opencode)").option("--project <slug>", "Target project slug (required)").option("--assignment <slug>", "Target assignment slug (required)").option("--force", "Overwrite existing adapter files").option("--dir <path>", "Override default project directory").action(async (framework, options) => {
34955
+ program.command("setup-adapter").description("Generate adapter instruction files for a framework in the current directory").argument("<framework>", "Target framework: built-in ids cursor, codex, opencode, pi, openclaw, hermes (plus any user descriptor with an instructions adapter in ~/.syntaur/targets/)").option("--project <slug>", "Target project slug (required)").option("--assignment <slug>", "Target assignment slug (required)").option("--force", "Overwrite existing adapter files").option("--dir <path>", "Override default project directory").action(async (framework, options) => {
34644
34956
  try {
34645
34957
  await setupAdapterCommand(framework, options);
34646
34958
  } catch (error) {