syntaur 0.24.0 → 0.25.1

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.
@@ -388,9 +388,10 @@ __export(fs_exports, {
388
388
  ensureDir: () => ensureDir,
389
389
  fileExists: () => fileExists,
390
390
  writeFileForce: () => writeFileForce,
391
+ writeFileReport: () => writeFileReport,
391
392
  writeFileSafe: () => writeFileSafe
392
393
  });
393
- import { mkdir, writeFile, access, rename } from "fs/promises";
394
+ import { mkdir, writeFile, readFile, access, rename } from "fs/promises";
394
395
  import { dirname, join } from "path";
395
396
  async function ensureDir(dir) {
396
397
  await mkdir(dir, { recursive: true });
@@ -421,6 +422,22 @@ async function writeFileForce(filePath, content) {
421
422
  await writeFile(tempPath, content, "utf-8");
422
423
  await rename(tempPath, filePath);
423
424
  }
425
+ async function writeFileReport(filePath, content, options = {}) {
426
+ if (!await fileExists(filePath)) {
427
+ await ensureDir(dirname(filePath));
428
+ await writeFile(filePath, content, "utf-8");
429
+ return "written";
430
+ }
431
+ const current = await readFile(filePath, "utf-8").catch(() => null);
432
+ if (current === content) {
433
+ return "already-current";
434
+ }
435
+ if (!options.force) {
436
+ return "differs-preserved";
437
+ }
438
+ await writeFileForce(filePath, content);
439
+ return "overwritten";
440
+ }
424
441
  var init_fs = __esm({
425
442
  "src/utils/fs.ts"() {
426
443
  "use strict";
@@ -762,7 +779,7 @@ __export(parser_exports, {
762
779
  writeChecklist: () => writeChecklist
763
780
  });
764
781
  import { randomBytes } from "crypto";
765
- import { readFile } from "fs/promises";
782
+ import { readFile as readFile2 } from "fs/promises";
766
783
  import { resolve as resolve2 } from "path";
767
784
  function generateShortId() {
768
785
  return randomBytes(2).toString("hex");
@@ -1059,7 +1076,7 @@ async function readChecklist(todosDir2, workspace) {
1059
1076
  if (!await fileExists(path)) {
1060
1077
  return { workspace, archiveInterval: "weekly", items: [] };
1061
1078
  }
1062
- const content = await readFile(path, "utf-8");
1079
+ const content = await readFile2(path, "utf-8");
1063
1080
  return parseChecklist(content);
1064
1081
  }
1065
1082
  async function writeChecklist(todosDir2, checklist) {
@@ -1072,7 +1089,7 @@ async function readLog(todosDir2, workspace) {
1072
1089
  if (!await fileExists(path)) {
1073
1090
  return { workspace, entries: [] };
1074
1091
  }
1075
- const content = await readFile(path, "utf-8");
1092
+ const content = await readFile2(path, "utf-8");
1076
1093
  return parseLog(content);
1077
1094
  }
1078
1095
  async function appendLogEntry(todosDir2, workspace, entry) {
@@ -1080,7 +1097,7 @@ async function appendLogEntry(todosDir2, workspace, entry) {
1080
1097
  const path = logPath(todosDir2, workspace);
1081
1098
  let content;
1082
1099
  if (await fileExists(path)) {
1083
- content = await readFile(path, "utf-8");
1100
+ content = await readFile2(path, "utf-8");
1084
1101
  content = content.trimEnd() + "\n\n" + serializeLogEntry(entry) + "\n";
1085
1102
  } else {
1086
1103
  const fm = `---
@@ -1248,7 +1265,7 @@ var init_linked_todos = __esm({
1248
1265
 
1249
1266
  // src/lifecycle/transitions.ts
1250
1267
  import { resolve as resolve4 } from "path";
1251
- import { readFile as readFile2 } from "fs/promises";
1268
+ import { readFile as readFile3 } from "fs/promises";
1252
1269
  function linkedAssignmentRef(frontmatter) {
1253
1270
  return frontmatter.project ? `${frontmatter.project}/${frontmatter.slug}` : frontmatter.id;
1254
1271
  }
@@ -1268,7 +1285,7 @@ async function readAssignment(filePath) {
1268
1285
  if (!await fileExists(filePath)) {
1269
1286
  throw new Error(`Assignment file not found: ${filePath}`);
1270
1287
  }
1271
- const content = await readFile2(filePath, "utf-8");
1288
+ const content = await readFile3(filePath, "utf-8");
1272
1289
  const frontmatter = parseAssignmentFrontmatter(content);
1273
1290
  return { content, frontmatter };
1274
1291
  }
@@ -1281,7 +1298,7 @@ async function checkDependencies(projectDir, dependsOn, terminalStatuses) {
1281
1298
  unmet.push(`${depSlug} (file not found)`);
1282
1299
  continue;
1283
1300
  }
1284
- const depContent = await readFile2(depPath, "utf-8");
1301
+ const depContent = await readFile3(depPath, "utf-8");
1285
1302
  const depFrontmatter = parseAssignmentFrontmatter(depContent);
1286
1303
  if (!terminals.has(depFrontmatter.status)) {
1287
1304
  unmet.push(`${depSlug} (status: ${depFrontmatter.status})`);
@@ -1431,7 +1448,7 @@ var init_config = __esm({
1431
1448
  });
1432
1449
 
1433
1450
  // src/utils/fs-migration.ts
1434
- import { readdir as readdir2, readFile as readFile3, rename as rename2, writeFile as writeFile2 } from "fs/promises";
1451
+ import { readdir as readdir2, readFile as readFile4, rename as rename2, writeFile as writeFile2 } from "fs/promises";
1435
1452
  import { resolve as resolve5 } from "path";
1436
1453
  async function migrateLegacyProjectFiles(projectsDir) {
1437
1454
  const result = {
@@ -1500,7 +1517,7 @@ async function migrateLegacyArchivedProjects(projectsDir) {
1500
1517
  const projectMd = resolve5(projectsDir, entry.name, "project.md");
1501
1518
  try {
1502
1519
  if (!await fileExists(projectMd)) continue;
1503
- const content = await readFile3(projectMd, "utf-8");
1520
+ const content = await readFile4(projectMd, "utf-8");
1504
1521
  if (readFrontmatterField(content, "statusOverride") !== "archived") continue;
1505
1522
  let next = setFrontmatterField(content, "archived", true);
1506
1523
  if (readFrontmatterField(content, "archivedAt") === null) {
@@ -1525,7 +1542,7 @@ async function migrateLegacyConfig(configPath) {
1525
1542
  if (!await fileExists(configPath)) return result;
1526
1543
  let content;
1527
1544
  try {
1528
- content = await readFile3(configPath, "utf-8");
1545
+ content = await readFile4(configPath, "utf-8");
1529
1546
  } catch {
1530
1547
  return result;
1531
1548
  }
@@ -1782,7 +1799,7 @@ __export(config_exports, {
1782
1799
  writeTerminalConfig: () => writeTerminalConfig,
1783
1800
  writeThemeConfig: () => writeThemeConfig
1784
1801
  });
1785
- import { readFile as readFile4 } from "fs/promises";
1802
+ import { readFile as readFile5 } from "fs/promises";
1786
1803
  import { spawnSync } from "child_process";
1787
1804
  import { resolve as resolve6, isAbsolute } from "path";
1788
1805
  function parseAgentCommand(value, agentId) {
@@ -1910,6 +1927,18 @@ function parseFrontmatter(content) {
1910
1927
  }
1911
1928
  return result;
1912
1929
  }
1930
+ function parseInstalledAgents(fm) {
1931
+ const prefix = "integrations.installedAgents.";
1932
+ const installedAgents = {};
1933
+ for (const [key, value] of Object.entries(fm)) {
1934
+ if (!key.startsWith(prefix)) continue;
1935
+ const id = key.slice(prefix.length);
1936
+ if (!id) continue;
1937
+ const scope = value === "project" ? "project" : "global";
1938
+ installedAgents[id] = { scope };
1939
+ }
1940
+ return Object.keys(installedAgents).length > 0 ? { installedAgents } : {};
1941
+ }
1913
1942
  function parseStatusConfig(content) {
1914
1943
  const match = content.match(/^---\n([\s\S]*?)\n---/);
1915
1944
  if (!match) return null;
@@ -2039,6 +2068,11 @@ function serializeIntegrationConfig(integrations) {
2039
2068
  if (integrations.codexMarketplacePath) {
2040
2069
  lines.push(` codexMarketplacePath: ${integrations.codexMarketplacePath}`);
2041
2070
  }
2071
+ if (integrations.installedAgents) {
2072
+ for (const [id, rec] of Object.entries(integrations.installedAgents)) {
2073
+ lines.push(` installedAgents.${id}: ${rec.scope}`);
2074
+ }
2075
+ }
2042
2076
  if (lines.length === 0) {
2043
2077
  return null;
2044
2078
  }
@@ -2107,7 +2141,7 @@ async function updatePlaybooksConfig(playbooks) {
2107
2141
  disabled: Array.from(new Set(playbooks.disabled ?? current.disabled))
2108
2142
  };
2109
2143
  const playbooksBlock = serializePlaybooksConfig(nextPlaybooks);
2110
- const existing = await fileExists(configPath) ? await readFile4(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
2144
+ const existing = await fileExists(configPath) ? await readFile5(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
2111
2145
  const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
2112
2146
  if (!fmMatch) {
2113
2147
  const bodyBlock = playbooksBlock ? `${playbooksBlock}
@@ -2159,7 +2193,7 @@ function serializeThemeConfig(theme) {
2159
2193
  async function writeThemeConfig(theme) {
2160
2194
  const configPath = resolve6(syntaurRoot(), "config.md");
2161
2195
  const themeBlock = serializeThemeConfig(theme);
2162
- const existing = await fileExists(configPath) ? await readFile4(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
2196
+ const existing = await fileExists(configPath) ? await readFile5(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
2163
2197
  const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
2164
2198
  if (!fmMatch) {
2165
2199
  const content = `---
@@ -2185,7 +2219,7 @@ ${normalizedFm}
2185
2219
  async function deleteThemeConfig() {
2186
2220
  const configPath = resolve6(syntaurRoot(), "config.md");
2187
2221
  if (!await fileExists(configPath)) return;
2188
- const existing = await readFile4(configPath, "utf-8");
2222
+ const existing = await readFile5(configPath, "utf-8");
2189
2223
  const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
2190
2224
  if (!fmMatch) return;
2191
2225
  const fmBlock = fmMatch[2];
@@ -2205,7 +2239,7 @@ function stripTopLevelScalar(fmBlock, key) {
2205
2239
  async function writeTerminalConfig(terminal) {
2206
2240
  const configPath = resolve6(syntaurRoot(), "config.md");
2207
2241
  const terminalLine = `terminal: ${terminal}`;
2208
- const existing = await fileExists(configPath) ? await readFile4(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
2242
+ const existing = await fileExists(configPath) ? await readFile5(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
2209
2243
  const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
2210
2244
  if (!fmMatch) {
2211
2245
  const content = `---
@@ -2231,7 +2265,7 @@ ${normalizedFm}
2231
2265
  async function deleteTerminalConfig() {
2232
2266
  const configPath = resolve6(syntaurRoot(), "config.md");
2233
2267
  if (!await fileExists(configPath)) return;
2234
- const existing = await readFile4(configPath, "utf-8");
2268
+ const existing = await readFile5(configPath, "utf-8");
2235
2269
  const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
2236
2270
  if (!fmMatch) return;
2237
2271
  const fmBlock = fmMatch[2];
@@ -2300,7 +2334,7 @@ async function writeHotkeyBindingsConfig(cfg) {
2300
2334
  }
2301
2335
  const configPath = resolve6(syntaurRoot(), "config.md");
2302
2336
  const block = serializeHotkeyBindingsConfig({ bindings: cleaned });
2303
- const existing = await fileExists(configPath) ? await readFile4(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
2337
+ const existing = await fileExists(configPath) ? await readFile5(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
2304
2338
  const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
2305
2339
  if (!fmMatch) {
2306
2340
  const content = `---
@@ -2326,7 +2360,7 @@ ${normalizedFm}
2326
2360
  async function deleteHotkeyBindingsConfig() {
2327
2361
  const configPath = resolve6(syntaurRoot(), "config.md");
2328
2362
  if (!await fileExists(configPath)) return;
2329
- const existing = await readFile4(configPath, "utf-8");
2363
+ const existing = await readFile5(configPath, "utf-8");
2330
2364
  const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
2331
2365
  if (!fmMatch) return;
2332
2366
  const fmBlock = fmMatch[2];
@@ -2643,7 +2677,7 @@ async function writeAgentsConfig(agents) {
2643
2677
  validateAgentList(agents);
2644
2678
  const configPath = resolve6(syntaurRoot(), "config.md");
2645
2679
  const agentsBlock = serializeAgentsConfig(agents);
2646
- const existing = await fileExists(configPath) ? await readFile4(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
2680
+ const existing = await fileExists(configPath) ? await readFile5(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
2647
2681
  const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
2648
2682
  if (!fmMatch) {
2649
2683
  const content = `---
@@ -2668,7 +2702,7 @@ ${newFm}
2668
2702
  async function deleteAgentsConfig() {
2669
2703
  const configPath = resolve6(syntaurRoot(), "config.md");
2670
2704
  if (!await fileExists(configPath)) return;
2671
- const existing = await readFile4(configPath, "utf-8");
2705
+ const existing = await readFile5(configPath, "utf-8");
2672
2706
  const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
2673
2707
  if (!fmMatch) return;
2674
2708
  const fmBlock = fmMatch[2];
@@ -2692,7 +2726,7 @@ ${statusBlock}
2692
2726
  await writeFileForce(configPath, content);
2693
2727
  return;
2694
2728
  }
2695
- const existing = await readFile4(configPath, "utf-8");
2729
+ const existing = await readFile5(configPath, "utf-8");
2696
2730
  const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
2697
2731
  if (!fmMatch) {
2698
2732
  const content = `---
@@ -2736,7 +2770,7 @@ ${statusBlock}
2736
2770
  async function deleteStatusConfig() {
2737
2771
  const configPath = resolve6(syntaurRoot(), "config.md");
2738
2772
  if (!await fileExists(configPath)) return;
2739
- const existing = await readFile4(configPath, "utf-8");
2773
+ const existing = await readFile5(configPath, "utf-8");
2740
2774
  const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
2741
2775
  if (!fmMatch) return;
2742
2776
  const fmBlock = fmMatch[2];
@@ -2754,7 +2788,7 @@ async function updateIntegrationConfig(integrations) {
2754
2788
  ...integrations
2755
2789
  };
2756
2790
  const integrationBlock = serializeIntegrationConfig(nextIntegrations);
2757
- const existing = await fileExists(configPath) ? await readFile4(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
2791
+ const existing = await fileExists(configPath) ? await readFile5(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
2758
2792
  const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
2759
2793
  if (!fmMatch) {
2760
2794
  const content = `---
@@ -2784,7 +2818,7 @@ async function updateOnboardingConfig(onboarding) {
2784
2818
  ...onboarding
2785
2819
  };
2786
2820
  const onboardingBlock = serializeOnboardingConfig(nextOnboarding);
2787
- const existing = await fileExists(configPath) ? await readFile4(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
2821
+ const existing = await fileExists(configPath) ? await readFile5(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
2788
2822
  const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
2789
2823
  if (!fmMatch) {
2790
2824
  const content = `---
@@ -2818,7 +2852,7 @@ async function updateBackupConfig(backup) {
2818
2852
  ...backup
2819
2853
  };
2820
2854
  const backupBlock = serializeBackupConfig(nextBackup);
2821
- const existing = await fileExists(configPath) ? await readFile4(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
2855
+ const existing = await fileExists(configPath) ? await readFile5(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
2822
2856
  const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
2823
2857
  if (!fmMatch) {
2824
2858
  const content = `---
@@ -2850,7 +2884,7 @@ async function readConfig() {
2850
2884
  migratedConfigPaths.add(configPath);
2851
2885
  await migrateLegacyConfig(configPath);
2852
2886
  }
2853
- const content = await readFile4(configPath, "utf-8");
2887
+ const content = await readFile5(configPath, "utf-8");
2854
2888
  const fm = parseFrontmatter(content);
2855
2889
  if (Object.keys(fm).length === 0) {
2856
2890
  console.warn("Warning: ~/.syntaur/config.md has malformed frontmatter, using defaults");
@@ -2889,7 +2923,8 @@ async function readConfig() {
2889
2923
  codexMarketplacePath: parseOptionalAbsolutePath(
2890
2924
  fm["integrations.codexMarketplacePath"],
2891
2925
  "integrations.codexMarketplacePath"
2892
- )
2926
+ ),
2927
+ ...parseInstalledAgents(fm)
2893
2928
  },
2894
2929
  backup: fm["backup.repo"] || fm["backup.categories"] ? {
2895
2930
  repo: fm["backup.repo"] && fm["backup.repo"] !== "null" ? fm["backup.repo"] : null,
@@ -3054,7 +3089,7 @@ var init_slug = __esm({
3054
3089
 
3055
3090
  // src/utils/playbooks.ts
3056
3091
  import { resolve as resolve7 } from "path";
3057
- import { readdir as readdir3, readFile as readFile5, unlink } from "fs/promises";
3092
+ import { readdir as readdir3, readFile as readFile6, unlink } from "fs/promises";
3058
3093
  function escapeRegExp(value) {
3059
3094
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3060
3095
  }
@@ -3080,7 +3115,7 @@ async function resolvePlaybookSlug(playbooksDir2, slug) {
3080
3115
  for (const entry of entries) {
3081
3116
  if (!isVisiblePlaybookFile(entry.name, entry.isFile())) continue;
3082
3117
  const filePath = resolve7(playbooksDir2, entry.name);
3083
- const raw = await readFile5(filePath, "utf-8");
3118
+ const raw = await readFile6(filePath, "utf-8");
3084
3119
  const parsed = parsePlaybook(raw);
3085
3120
  const canonical = parsed.slug || entry.name.replace(/\.md$/, "");
3086
3121
  if (canonical === slug) {
@@ -3128,7 +3163,7 @@ async function rebuildPlaybookManifest(playbooksDir2) {
3128
3163
  const rows = [];
3129
3164
  for (const entry of entries) {
3130
3165
  if (!isVisiblePlaybookFile(entry.name, entry.isFile())) continue;
3131
- const raw = await readFile5(resolve7(playbooksDir2, entry.name), "utf-8");
3166
+ const raw = await readFile6(resolve7(playbooksDir2, entry.name), "utf-8");
3132
3167
  const parsed = parsePlaybook(raw);
3133
3168
  const slug = parsed.slug || entry.name.replace(/\.md$/, "");
3134
3169
  if (disabledSet.has(slug)) continue;
@@ -3206,7 +3241,7 @@ async function renamePlaybook(playbooksDir2, oldSlug, newSlug) {
3206
3241
  );
3207
3242
  }
3208
3243
  }
3209
- const raw = await readFile5(oldPath, "utf-8");
3244
+ const raw = await readFile6(oldPath, "utf-8");
3210
3245
  let next = setFrontmatterField2(raw, "slug", newSlug);
3211
3246
  next = setFrontmatterField2(next, "updated", `"${nowTimestamp()}"`);
3212
3247
  await writeFileForce(newPath, next);
@@ -3243,7 +3278,7 @@ var init_playbooks = __esm({
3243
3278
 
3244
3279
  // src/utils/assignment-resolver.ts
3245
3280
  import { resolve as resolve8 } from "path";
3246
- import { readdir as readdir4, readFile as readFile6 } from "fs/promises";
3281
+ import { readdir as readdir4, readFile as readFile7 } from "fs/promises";
3247
3282
  async function resolveAssignmentById(projectsDir, assignmentsDir2, id) {
3248
3283
  let standaloneMatch = null;
3249
3284
  let projectMatch = null;
@@ -3252,7 +3287,7 @@ async function resolveAssignmentById(projectsDir, assignmentsDir2, id) {
3252
3287
  if (await fileExists(standalonePath)) {
3253
3288
  let workspaceGroup = null;
3254
3289
  try {
3255
- const content = await readFile6(standalonePath, "utf-8");
3290
+ const content = await readFile7(standalonePath, "utf-8");
3256
3291
  const [fm] = extractFrontmatter2(content);
3257
3292
  workspaceGroup = getField(fm, "workspaceGroup");
3258
3293
  } catch {
@@ -3280,7 +3315,7 @@ async function resolveAssignmentById(projectsDir, assignmentsDir2, id) {
3280
3315
  const aPath = resolve8(assignmentsPath, a.name, "assignment.md");
3281
3316
  if (!await fileExists(aPath)) continue;
3282
3317
  try {
3283
- const content = await readFile6(aPath, "utf-8");
3318
+ const content = await readFile7(aPath, "utf-8");
3284
3319
  const [fm] = extractFrontmatter2(content);
3285
3320
  const fileId = getField(fm, "id");
3286
3321
  if (fileId === id) {
@@ -3932,8 +3967,8 @@ async function migrateFromMarkdown(projectsDir) {
3932
3967
  return allSessions.length;
3933
3968
  }
3934
3969
  async function parseMarkdownSessionsIndex(filePath, projectSlug) {
3935
- const { readFile: readFile20 } = await import("fs/promises");
3936
- const raw = await readFile20(filePath, "utf-8");
3970
+ const { readFile: readFile21 } = await import("fs/promises");
3971
+ const raw = await readFile21(filePath, "utf-8");
3937
3972
  const sessions = [];
3938
3973
  const lines = raw.split("\n");
3939
3974
  let inTable = false;
@@ -4003,7 +4038,7 @@ CREATE INDEX IF NOT EXISTS idx_sessions_assignment ON sessions(project_slug, ass
4003
4038
  });
4004
4039
 
4005
4040
  // src/dashboard/agent-sessions.ts
4006
- import { readFile as readFile7 } from "fs/promises";
4041
+ import { readFile as readFile8 } from "fs/promises";
4007
4042
  import { resolve as resolve10 } from "path";
4008
4043
  function rowToSession(row) {
4009
4044
  return {
@@ -4091,7 +4126,7 @@ async function deleteSessions(sessionIds) {
4091
4126
  }
4092
4127
  async function readAssignmentStatusFromPath(assignmentMdPath) {
4093
4128
  if (!await fileExists(assignmentMdPath)) return null;
4094
- const raw = await readFile7(assignmentMdPath, "utf-8");
4129
+ const raw = await readFile8(assignmentMdPath, "utf-8");
4095
4130
  const match = raw.match(/^status:\s*(.+)$/m);
4096
4131
  return match ? match[1].trim() : null;
4097
4132
  }
@@ -4176,7 +4211,7 @@ var init_overviewCopy = __esm({
4176
4211
  });
4177
4212
 
4178
4213
  // src/dashboard/servers.ts
4179
- import { readdir as readdir6, readFile as readFile8, unlink as unlink2 } from "fs/promises";
4214
+ import { readdir as readdir6, readFile as readFile9, unlink as unlink2 } from "fs/promises";
4180
4215
  import { resolve as resolve11 } from "path";
4181
4216
  function sanitizeSessionName(name) {
4182
4217
  return name.replace(/[^a-zA-Z0-9_-]/g, "-");
@@ -4236,7 +4271,7 @@ async function listSessionFiles(dir) {
4236
4271
  async function readSessionFile(dir, name) {
4237
4272
  const filePath = resolve11(dir, `${sanitizeSessionName(name)}.md`);
4238
4273
  if (!await fileExists(filePath)) return null;
4239
- const raw = await readFile8(filePath, "utf-8");
4274
+ const raw = await readFile9(filePath, "utf-8");
4240
4275
  const [frontmatter] = extractFrontmatter2(raw);
4241
4276
  if (!frontmatter) return null;
4242
4277
  const session = getField(frontmatter, "session") ?? name;
@@ -4809,7 +4844,7 @@ var init_scanner = __esm({
4809
4844
  });
4810
4845
 
4811
4846
  // src/dashboard/api.ts
4812
- import { readdir as readdir7, readFile as readFile9, writeFile as writeFile3 } from "fs/promises";
4847
+ import { readdir as readdir7, readFile as readFile10, writeFile as writeFile3 } from "fs/promises";
4813
4848
  import { resolve as resolve13, dirname as dirname2, basename } from "path";
4814
4849
  function clearFrontmatterField(content, key) {
4815
4850
  const fieldRegex = new RegExp(`^(${escapeRegExp2(key)}:)\\s*.*$`, "m");
@@ -4897,7 +4932,7 @@ async function computeStandaloneRecords(assignmentsDir2) {
4897
4932
  const assignmentMdPath = resolve13(assignmentDir, "assignment.md");
4898
4933
  if (!await fileExists(assignmentMdPath)) continue;
4899
4934
  try {
4900
- const content = await readFile9(assignmentMdPath, "utf-8");
4935
+ const content = await readFile10(assignmentMdPath, "utf-8");
4901
4936
  const record = parseAssignmentFull(content);
4902
4937
  records.push({ assignmentDir, id: entry.name, record });
4903
4938
  } catch {
@@ -4973,7 +5008,7 @@ async function listProjects(projectsDir) {
4973
5008
  async function readWorkspaceRegistry(projectsDir) {
4974
5009
  const registryPath = resolve13(dirname2(projectsDir), "workspaces.json");
4975
5010
  try {
4976
- const raw = await readFile9(registryPath, "utf-8");
5011
+ const raw = await readFile10(registryPath, "utf-8");
4977
5012
  const parsed = JSON.parse(raw);
4978
5013
  return Array.isArray(parsed) ? parsed.filter((w) => typeof w === "string") : [];
4979
5014
  } catch {
@@ -5062,7 +5097,7 @@ async function deleteWorkspace(projectsDir, name, opts = {}) {
5062
5097
  const timestamp = nowTimestamp();
5063
5098
  for (const slug of projectsReferencing) {
5064
5099
  const path = resolve13(projectsDir, slug, "project.md");
5065
- const raw = await readFile9(path, "utf-8");
5100
+ const raw = await readFile10(path, "utf-8");
5066
5101
  let next = clearFrontmatterField(raw, "workspace");
5067
5102
  next = setUpdatedField(next, timestamp);
5068
5103
  await writeFileForce(path, next);
@@ -5071,7 +5106,7 @@ async function deleteWorkspace(projectsDir, name, opts = {}) {
5071
5106
  for (const id of standalonesReferencing) {
5072
5107
  if (!opts.assignmentsDir) break;
5073
5108
  const path = resolve13(opts.assignmentsDir, id, "assignment.md");
5074
- const raw = await readFile9(path, "utf-8");
5109
+ const raw = await readFile10(path, "utf-8");
5075
5110
  let next = clearFrontmatterField(raw, "workspaceGroup");
5076
5111
  next = setUpdatedField(next, timestamp);
5077
5112
  await writeFileForce(path, next);
@@ -5308,7 +5343,7 @@ async function getEditableDocument(projectsDir, documentType, projectSlug, assig
5308
5343
  if (!filePath || !await fileExists(filePath)) {
5309
5344
  return null;
5310
5345
  }
5311
- const content = await readFile9(filePath, "utf-8");
5346
+ const content = await readFile10(filePath, "utf-8");
5312
5347
  const title = getEditableDocumentTitle(documentType, projectSlug, assignmentSlug);
5313
5348
  return {
5314
5349
  documentType,
@@ -5334,7 +5369,7 @@ async function getEditableDocumentById(projectsDir, assignmentsDir2, documentTyp
5334
5369
  if (!fileName) return null;
5335
5370
  const filePath = resolve13(resolved.assignmentDir, fileName);
5336
5371
  if (!await fileExists(filePath)) return null;
5337
- const content = await readFile9(filePath, "utf-8");
5372
+ const content = await readFile10(filePath, "utf-8");
5338
5373
  const label = resolved.id;
5339
5374
  const title = documentType === "assignment" ? `Edit Assignment: ${label}` : documentType === "plan" ? `Edit Plan: ${label}` : documentType === "scratchpad" ? `Edit Scratchpad: ${label}` : documentType === "handoff" ? `Append Handoff: ${label}` : `Append Decision: ${label}`;
5340
5375
  return {
@@ -5353,7 +5388,7 @@ async function getProjectDetail(projectsDir, slug) {
5353
5388
  if (!await fileExists(projectMdPath)) {
5354
5389
  return null;
5355
5390
  }
5356
- const projectContent = await readFile9(projectMdPath, "utf-8");
5391
+ const projectContent = await readFile10(projectMdPath, "utf-8");
5357
5392
  const project = parseProject(projectContent);
5358
5393
  const assignments = await listAssignmentRecords(projectPath);
5359
5394
  const rollup = await buildProjectRollup(projectPath, project, assignments);
@@ -5390,18 +5425,18 @@ async function getAssignmentDetail(projectsDir, projectSlug, assignmentSlug) {
5390
5425
  if (!await fileExists(assignmentMdPath)) {
5391
5426
  return null;
5392
5427
  }
5393
- const assignmentContent = await readFile9(assignmentMdPath, "utf-8");
5428
+ const assignmentContent = await readFile10(assignmentMdPath, "utf-8");
5394
5429
  const assignment = parseAssignmentFull(assignmentContent);
5395
5430
  let projectWorkspace = null;
5396
5431
  const projectMdPath = resolve13(projectsDir, projectSlug, "project.md");
5397
5432
  if (await fileExists(projectMdPath)) {
5398
- const projectContent = await readFile9(projectMdPath, "utf-8");
5433
+ const projectContent = await readFile10(projectMdPath, "utf-8");
5399
5434
  projectWorkspace = parseProject(projectContent).workspace;
5400
5435
  }
5401
5436
  let plan = null;
5402
5437
  const planPath = resolve13(assignmentDir, "plan.md");
5403
5438
  if (await fileExists(planPath)) {
5404
- const planContent = await readFile9(planPath, "utf-8");
5439
+ const planContent = await readFile10(planPath, "utf-8");
5405
5440
  const parsed = parsePlan(planContent);
5406
5441
  plan = {
5407
5442
  status: parsed.status,
@@ -5412,7 +5447,7 @@ async function getAssignmentDetail(projectsDir, projectSlug, assignmentSlug) {
5412
5447
  let scratchpad = null;
5413
5448
  const scratchpadPath = resolve13(assignmentDir, "scratchpad.md");
5414
5449
  if (await fileExists(scratchpadPath)) {
5415
- const scratchpadContent = await readFile9(scratchpadPath, "utf-8");
5450
+ const scratchpadContent = await readFile10(scratchpadPath, "utf-8");
5416
5451
  const parsed = parseScratchpad(scratchpadContent);
5417
5452
  scratchpad = {
5418
5453
  updated: parsed.updated,
@@ -5422,7 +5457,7 @@ async function getAssignmentDetail(projectsDir, projectSlug, assignmentSlug) {
5422
5457
  let handoff = null;
5423
5458
  const handoffPath = resolve13(assignmentDir, "handoff.md");
5424
5459
  if (await fileExists(handoffPath)) {
5425
- const handoffContent = await readFile9(handoffPath, "utf-8");
5460
+ const handoffContent = await readFile10(handoffPath, "utf-8");
5426
5461
  const parsed = parseHandoff(handoffContent);
5427
5462
  handoff = {
5428
5463
  updated: parsed.updated,
@@ -5433,7 +5468,7 @@ async function getAssignmentDetail(projectsDir, projectSlug, assignmentSlug) {
5433
5468
  let decisionRecord = null;
5434
5469
  const decisionRecordPath = resolve13(assignmentDir, "decision-record.md");
5435
5470
  if (await fileExists(decisionRecordPath)) {
5436
- const decisionRecordContent = await readFile9(decisionRecordPath, "utf-8");
5471
+ const decisionRecordContent = await readFile10(decisionRecordPath, "utf-8");
5437
5472
  const parsed = parseDecisionRecord(decisionRecordContent);
5438
5473
  decisionRecord = {
5439
5474
  updated: parsed.updated,
@@ -5444,7 +5479,7 @@ async function getAssignmentDetail(projectsDir, projectSlug, assignmentSlug) {
5444
5479
  let progress = null;
5445
5480
  const progressPath = resolve13(assignmentDir, "progress.md");
5446
5481
  if (await fileExists(progressPath)) {
5447
- const progressContent = await readFile9(progressPath, "utf-8");
5482
+ const progressContent = await readFile10(progressPath, "utf-8");
5448
5483
  const parsed = parseProgress(progressContent);
5449
5484
  progress = {
5450
5485
  updated: parsed.updated,
@@ -5455,7 +5490,7 @@ async function getAssignmentDetail(projectsDir, projectSlug, assignmentSlug) {
5455
5490
  let comments = null;
5456
5491
  const commentsPath = resolve13(assignmentDir, "comments.md");
5457
5492
  if (await fileExists(commentsPath)) {
5458
- const commentsContent = await readFile9(commentsPath, "utf-8");
5493
+ const commentsContent = await readFile10(commentsPath, "utf-8");
5459
5494
  const parsed = parseComments(commentsContent);
5460
5495
  comments = {
5461
5496
  updated: parsed.updated,
@@ -5609,7 +5644,7 @@ async function countMentionsInAssignment(sourceDir, target) {
5609
5644
  const bodies = [];
5610
5645
  const assignmentMd = resolve13(sourceDir, "assignment.md");
5611
5646
  if (await fileExists(assignmentMd)) {
5612
- const content = await readFile9(assignmentMd, "utf-8");
5647
+ const content = await readFile10(assignmentMd, "utf-8");
5613
5648
  const todosMatch = content.match(/^## Todos\s*$([\s\S]*?)(?=^## |$(?![\r\n]))/m);
5614
5649
  if (todosMatch) bodies.push(todosMatch[1]);
5615
5650
  }
@@ -5617,7 +5652,7 @@ async function countMentionsInAssignment(sourceDir, target) {
5617
5652
  const path = resolve13(sourceDir, filename);
5618
5653
  if (await fileExists(path)) {
5619
5654
  try {
5620
- bodies.push(await readFile9(path, "utf-8"));
5655
+ bodies.push(await readFile10(path, "utf-8"));
5621
5656
  } catch {
5622
5657
  }
5623
5658
  }
@@ -5677,42 +5712,42 @@ async function buildStandaloneAssignmentDetail(resolved) {
5677
5712
  const assignmentDir = resolved.assignmentDir;
5678
5713
  const assignmentMdPath = resolve13(assignmentDir, "assignment.md");
5679
5714
  if (!await fileExists(assignmentMdPath)) return null;
5680
- const assignmentContent = await readFile9(assignmentMdPath, "utf-8");
5715
+ const assignmentContent = await readFile10(assignmentMdPath, "utf-8");
5681
5716
  const assignment = parseAssignmentFull(assignmentContent);
5682
5717
  let plan = null;
5683
5718
  const planPath = resolve13(assignmentDir, "plan.md");
5684
5719
  if (await fileExists(planPath)) {
5685
- const parsed = parsePlan(await readFile9(planPath, "utf-8"));
5720
+ const parsed = parsePlan(await readFile10(planPath, "utf-8"));
5686
5721
  plan = { status: parsed.status, updated: parsed.updated, body: parsed.body };
5687
5722
  }
5688
5723
  let scratchpad = null;
5689
5724
  const scratchpadPath = resolve13(assignmentDir, "scratchpad.md");
5690
5725
  if (await fileExists(scratchpadPath)) {
5691
- const parsed = parseScratchpad(await readFile9(scratchpadPath, "utf-8"));
5726
+ const parsed = parseScratchpad(await readFile10(scratchpadPath, "utf-8"));
5692
5727
  scratchpad = { updated: parsed.updated, body: parsed.body };
5693
5728
  }
5694
5729
  let handoff = null;
5695
5730
  const handoffPath = resolve13(assignmentDir, "handoff.md");
5696
5731
  if (await fileExists(handoffPath)) {
5697
- const parsed = parseHandoff(await readFile9(handoffPath, "utf-8"));
5732
+ const parsed = parseHandoff(await readFile10(handoffPath, "utf-8"));
5698
5733
  handoff = { updated: parsed.updated, handoffCount: parsed.handoffCount, body: parsed.body };
5699
5734
  }
5700
5735
  let decisionRecord = null;
5701
5736
  const decisionRecordPath = resolve13(assignmentDir, "decision-record.md");
5702
5737
  if (await fileExists(decisionRecordPath)) {
5703
- const parsed = parseDecisionRecord(await readFile9(decisionRecordPath, "utf-8"));
5738
+ const parsed = parseDecisionRecord(await readFile10(decisionRecordPath, "utf-8"));
5704
5739
  decisionRecord = { updated: parsed.updated, decisionCount: parsed.decisionCount, body: parsed.body };
5705
5740
  }
5706
5741
  let progress = null;
5707
5742
  const progressPath = resolve13(assignmentDir, "progress.md");
5708
5743
  if (await fileExists(progressPath)) {
5709
- const parsed = parseProgress(await readFile9(progressPath, "utf-8"));
5744
+ const parsed = parseProgress(await readFile10(progressPath, "utf-8"));
5710
5745
  progress = { updated: parsed.updated, entryCount: parsed.entryCount, entries: parsed.entries };
5711
5746
  }
5712
5747
  let comments = null;
5713
5748
  const commentsPath = resolve13(assignmentDir, "comments.md");
5714
5749
  if (await fileExists(commentsPath)) {
5715
- const parsed = parseComments(await readFile9(commentsPath, "utf-8"));
5750
+ const parsed = parseComments(await readFile10(commentsPath, "utf-8"));
5716
5751
  comments = { updated: parsed.updated, entryCount: parsed.entryCount, entries: parsed.entries };
5717
5752
  }
5718
5753
  const detail = {
@@ -5778,7 +5813,7 @@ async function computeProjectRecords(projectsDir, traces) {
5778
5813
  return null;
5779
5814
  }
5780
5815
  const t0 = traces ? performance.now() : 0;
5781
- const projectContent = await readFile9(projectMdPath, "utf-8");
5816
+ const projectContent = await readFile10(projectMdPath, "utf-8");
5782
5817
  const project = parseProject(projectContent);
5783
5818
  if (traces) accumulatePhase(traces, "parse-project-md", performance.now() - t0);
5784
5819
  const t1 = traces ? performance.now() : 0;
@@ -5832,7 +5867,7 @@ async function listAssignmentRecords(projectPath, traces) {
5832
5867
  return null;
5833
5868
  }
5834
5869
  const t0 = traces ? performance.now() : 0;
5835
- const content = await readFile9(assignmentMd, "utf-8");
5870
+ const content = await readFile10(assignmentMd, "utf-8");
5836
5871
  const parsed = parseAssignmentFull(content);
5837
5872
  if (traces) accumulatePhase(traces, "read-assignment-md", performance.now() - t0);
5838
5873
  return parsed;
@@ -5854,7 +5889,7 @@ async function listResources(projectPath) {
5854
5889
  continue;
5855
5890
  }
5856
5891
  const filePath = resolve13(resourcesDir, entry.name);
5857
- const content = await readFile9(filePath, "utf-8");
5892
+ const content = await readFile10(filePath, "utf-8");
5858
5893
  const parsed = parseResource(content);
5859
5894
  results.push({
5860
5895
  name: parsed.name,
@@ -5880,7 +5915,7 @@ async function listMemories(projectPath) {
5880
5915
  continue;
5881
5916
  }
5882
5917
  const filePath = resolve13(memoriesDir, entry.name);
5883
- const content = await readFile9(filePath, "utf-8");
5918
+ const content = await readFile10(filePath, "utf-8");
5884
5919
  const parsed = parseMemory(content);
5885
5920
  results.push({
5886
5921
  name: parsed.name,
@@ -5943,7 +5978,7 @@ async function getMemoryDetail(projectsDir, projectSlug, itemSlug) {
5943
5978
  if (!projectRecord) return null;
5944
5979
  const filePath = resolve13(projectRecord.projectPath, "memories", `${itemSlug}.md`);
5945
5980
  if (!await fileExists(filePath)) return null;
5946
- const content = await readFile9(filePath, "utf-8");
5981
+ const content = await readFile10(filePath, "utf-8");
5947
5982
  const parsed = parseMemory(content);
5948
5983
  return {
5949
5984
  name: parsed.name,
@@ -5969,7 +6004,7 @@ async function getResourceDetail(projectsDir, projectSlug, itemSlug) {
5969
6004
  if (!projectRecord) return null;
5970
6005
  const filePath = resolve13(projectRecord.projectPath, "resources", `${itemSlug}.md`);
5971
6006
  if (!await fileExists(filePath)) return null;
5972
- const content = await readFile9(filePath, "utf-8");
6007
+ const content = await readFile10(filePath, "utf-8");
5973
6008
  const parsed = parseResource(content);
5974
6009
  return {
5975
6010
  name: parsed.name,
@@ -5987,7 +6022,7 @@ async function getResourceDetail(projectsDir, projectSlug, itemSlug) {
5987
6022
  async function loadDependencyGraph(projectPath, assignments) {
5988
6023
  const statusPath = resolve13(projectPath, "_status.md");
5989
6024
  if (await fileExists(statusPath)) {
5990
- const statusContent = await readFile9(statusPath, "utf-8");
6025
+ const statusContent = await readFile10(statusPath, "utf-8");
5991
6026
  const parsed = parseStatus(statusContent);
5992
6027
  const derivedGraph = extractMermaidGraph(parsed.body);
5993
6028
  if (derivedGraph) {
@@ -6154,7 +6189,7 @@ async function getUnmetDependencies(projectPath, dependsOn, terminalStatuses, de
6154
6189
  unmet.push(`${dependency} (missing)`);
6155
6190
  continue;
6156
6191
  }
6157
- const content = await readFile9(dependencyPath, "utf-8");
6192
+ const content = await readFile10(dependencyPath, "utf-8");
6158
6193
  const parsed = parseAssignmentFull(content);
6159
6194
  if (!terminals.has(parsed.status)) {
6160
6195
  unmet.push(`${dependency} (${parsed.status})`);
@@ -6449,7 +6484,7 @@ async function countOpenQuestions(projectPath, assignmentSlug) {
6449
6484
  return 0;
6450
6485
  }
6451
6486
  try {
6452
- const content = await readFile9(commentsPath, "utf-8");
6487
+ const content = await readFile10(commentsPath, "utf-8");
6453
6488
  const parsed = parseComments(content);
6454
6489
  return parsed.entries.filter(
6455
6490
  (e) => e.type === "question" && e.resolved !== true
@@ -6522,7 +6557,7 @@ async function listPlaybooks(playbooksDir2) {
6522
6557
  for (const entry of entries) {
6523
6558
  if (!entry.isFile() || !entry.name.endsWith(".md") || entry.name.startsWith("_") || entry.name === "manifest.md") continue;
6524
6559
  const filePath = resolve13(playbooksDir2, entry.name);
6525
- const raw = await readFile9(filePath, "utf-8");
6560
+ const raw = await readFile10(filePath, "utf-8");
6526
6561
  const parsed = parsePlaybook(raw);
6527
6562
  const slug = parsed.slug || entry.name.replace(/\.md$/, "");
6528
6563
  playbooks.push({
@@ -7201,7 +7236,7 @@ function mergePatch(current, patch) {
7201
7236
  // src/utils/view-prefs.ts
7202
7237
  init_paths();
7203
7238
  init_fs();
7204
- import { readFile as readFile10, rename as rename3, unlink as unlink3 } from "fs/promises";
7239
+ import { readFile as readFile11, rename as rename3, unlink as unlink3 } from "fs/promises";
7205
7240
  import { resolve as resolve14 } from "path";
7206
7241
  function corruptFilePath() {
7207
7242
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
@@ -7224,7 +7259,7 @@ async function readViewPrefsFile() {
7224
7259
  }
7225
7260
  let raw;
7226
7261
  try {
7227
- raw = await readFile10(path, "utf-8");
7262
+ raw = await readFile11(path, "utf-8");
7228
7263
  } catch {
7229
7264
  return { ...DEFAULT_VIEW_PREFS_FILE };
7230
7265
  }
@@ -7407,7 +7442,7 @@ function isDashboardSlot(value) {
7407
7442
  // src/utils/saved-views.ts
7408
7443
  init_paths();
7409
7444
  init_fs();
7410
- import { readFile as readFile11, rename as rename4, unlink as unlink4 } from "fs/promises";
7445
+ import { readFile as readFile12, rename as rename4, unlink as unlink4 } from "fs/promises";
7411
7446
  import { randomUUID } from "crypto";
7412
7447
  import { resolve as resolve15 } from "path";
7413
7448
  function corruptFilePath2() {
@@ -7437,7 +7472,7 @@ async function readSavedViewsFile() {
7437
7472
  }
7438
7473
  let raw;
7439
7474
  try {
7440
- raw = await readFile11(path, "utf-8");
7475
+ raw = await readFile12(path, "utf-8");
7441
7476
  } catch {
7442
7477
  return cloneDefault();
7443
7478
  }
@@ -7753,7 +7788,7 @@ init_lifecycle();
7753
7788
  init_slug();
7754
7789
  import { Router as Router2 } from "express";
7755
7790
  import { resolve as resolve18, basename as basename3, isAbsolute as isAbsolute2 } from "path";
7756
- import { rm, readFile as readFile14, open as fsOpen, stat as fsStat, realpath as fsRealpath } from "fs/promises";
7791
+ import { rm, readFile as readFile15, open as fsOpen, stat as fsStat, realpath as fsRealpath } from "fs/promises";
7757
7792
  import { spawnSync as spawnSync3 } from "child_process";
7758
7793
 
7759
7794
  // src/utils/uuid.ts
@@ -7770,7 +7805,7 @@ init_fs();
7770
7805
  init_frontmatter();
7771
7806
  init_fs();
7772
7807
  import { spawn } from "child_process";
7773
- import { readFile as readFile12 } from "fs/promises";
7808
+ import { readFile as readFile13 } from "fs/promises";
7774
7809
  function run(command, args, cwd) {
7775
7810
  return new Promise((resolvePromise) => {
7776
7811
  const child = spawn(command, args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
@@ -7854,7 +7889,7 @@ async function createWorktreeAndRecord(opts) {
7854
7889
  const { assignmentPath, repository, branch, worktreePath, parentBranch } = opts;
7855
7890
  await createWorktree({ repository, branch, worktreePath, parentBranch });
7856
7891
  try {
7857
- const content = await readFile12(assignmentPath, "utf-8");
7892
+ const content = await readFile13(assignmentPath, "utf-8");
7858
7893
  const updated = updateAssignmentWorkspace(content, {
7859
7894
  repository,
7860
7895
  worktreePath,
@@ -7967,7 +8002,7 @@ function validateBranchName(name) {
7967
8002
  // src/dashboard/repository-candidates.ts
7968
8003
  init_fs();
7969
8004
  init_parser();
7970
- import { readdir as readdir8, readFile as readFile13 } from "fs/promises";
8005
+ import { readdir as readdir8, readFile as readFile14 } from "fs/promises";
7971
8006
  import { resolve as resolve17 } from "path";
7972
8007
  function toSourceAssignment(parsed, fallbackId) {
7973
8008
  const repository = parsed.workspace.repository?.trim();
@@ -7987,7 +8022,7 @@ async function getProjectRepositoryCandidates(projectsDir, projectSlug) {
7987
8022
  const out = [];
7988
8023
  const projectPath = resolve17(projectsDir, projectSlug, "project.md");
7989
8024
  if (await fileExists(projectPath)) {
7990
- const project = parseProject(await readFile13(projectPath, "utf-8"));
8025
+ const project = parseProject(await readFile14(projectPath, "utf-8"));
7991
8026
  for (const raw of project.repositories) {
7992
8027
  const path = raw.trim();
7993
8028
  if (!path) continue;
@@ -8004,7 +8039,7 @@ async function getProjectRepositoryCandidates(projectsDir, projectSlug) {
8004
8039
  if (!entry.isDirectory()) continue;
8005
8040
  const assignmentMd = resolve17(assignmentsDir2, entry.name, "assignment.md");
8006
8041
  if (!await fileExists(assignmentMd)) continue;
8007
- const parsed = parseAssignmentFull(await readFile13(assignmentMd, "utf-8"));
8042
+ const parsed = parseAssignmentFull(await readFile14(assignmentMd, "utf-8"));
8008
8043
  const repo = parsed.workspace.repository?.trim();
8009
8044
  if (!repo) continue;
8010
8045
  const abs = resolve17(repo);
@@ -8027,7 +8062,7 @@ async function getStandaloneRepositoryCandidates(assignmentsDir2, excludeAssignm
8027
8062
  if (entry.name === excludeAssignmentId) continue;
8028
8063
  const assignmentMd = resolve17(assignmentsDir2, entry.name, "assignment.md");
8029
8064
  if (!await fileExists(assignmentMd)) continue;
8030
- const parsed = parseAssignmentFull(await readFile13(assignmentMd, "utf-8"));
8065
+ const parsed = parseAssignmentFull(await readFile14(assignmentMd, "utf-8"));
8031
8066
  const repo = parsed.workspace.repository?.trim();
8032
8067
  if (!repo) continue;
8033
8068
  const abs = resolve17(repo);
@@ -8048,7 +8083,7 @@ async function getProjectSourceAssignments(projectsDir, projectSlug, excludeSlug
8048
8083
  if (entry.name === excludeSlug) continue;
8049
8084
  const assignmentMd = resolve17(assignmentsDir2, entry.name, "assignment.md");
8050
8085
  if (!await fileExists(assignmentMd)) continue;
8051
- const parsed = parseAssignmentFull(await readFile13(assignmentMd, "utf-8"));
8086
+ const parsed = parseAssignmentFull(await readFile14(assignmentMd, "utf-8"));
8052
8087
  const source = toSourceAssignment(parsed, entry.name);
8053
8088
  if (!source) continue;
8054
8089
  if (seen.has(entry.name)) continue;
@@ -8067,7 +8102,7 @@ async function getStandaloneSourceAssignments(assignmentsDir2, excludeAssignment
8067
8102
  if (entry.name === excludeAssignmentId) continue;
8068
8103
  const assignmentMd = resolve17(assignmentsDir2, entry.name, "assignment.md");
8069
8104
  if (!await fileExists(assignmentMd)) continue;
8070
- const parsed = parseAssignmentFull(await readFile13(assignmentMd, "utf-8"));
8105
+ const parsed = parseAssignmentFull(await readFile14(assignmentMd, "utf-8"));
8071
8106
  const source = toSourceAssignment(parsed, entry.name);
8072
8107
  if (!source) continue;
8073
8108
  if (seen.has(entry.name)) continue;
@@ -8642,7 +8677,7 @@ async function readCurrentDocument(filePath) {
8642
8677
  if (!await fileExists(filePath)) {
8643
8678
  return null;
8644
8679
  }
8645
- return readFile14(filePath, "utf-8");
8680
+ return readFile15(filePath, "utf-8");
8646
8681
  }
8647
8682
  var worktreeInFlight = /* @__PURE__ */ new Set();
8648
8683
  async function assertRepoRoot(repoInput) {
@@ -8696,7 +8731,7 @@ async function handleWorktreeCreate(req, res, ctx) {
8696
8731
  }
8697
8732
  worktreeInFlight.add(ctx.assignmentPath);
8698
8733
  try {
8699
- const parsed = parseAssignmentFull(await readFile14(ctx.assignmentPath, "utf-8"));
8734
+ const parsed = parseAssignmentFull(await readFile15(ctx.assignmentPath, "utf-8"));
8700
8735
  if (parsed.workspace.worktreePath) {
8701
8736
  res.status(409).json({ error: "Worktree already configured for this assignment" });
8702
8737
  return;
@@ -9066,7 +9101,7 @@ ${body.startsWith("\n") ? body.slice(1) : body}${body.endsWith("\n") ? "" : "\n"
9066
9101
  }
9067
9102
  const nextContentRaw = requireContent(req, res);
9068
9103
  if (!nextContentRaw) return;
9069
- const currentContent = await readFile14(filePath, "utf-8");
9104
+ const currentContent = await readFile15(filePath, "utf-8");
9070
9105
  const frontmatterBlock = extractFrontmatterBlock(currentContent);
9071
9106
  if (!frontmatterBlock) {
9072
9107
  res.status(500).json({ error: `${kind} file is malformed (no frontmatter)` });
@@ -9517,7 +9552,7 @@ ${nextBody}${nextBody.endsWith("\n") ? "" : "\n"}`;
9517
9552
  let currentContent;
9518
9553
  let currentCount = 0;
9519
9554
  if (await fileExists(commentsPath)) {
9520
- currentContent = await readFile14(commentsPath, "utf-8");
9555
+ currentContent = await readFile15(commentsPath, "utf-8");
9521
9556
  const countMatch = currentContent.match(/^entryCount:\s*(\d+)/m);
9522
9557
  if (countMatch) currentCount = parseInt(countMatch[1], 10);
9523
9558
  } else {
@@ -9574,7 +9609,7 @@ ${entry}`;
9574
9609
  res.status(400).json({ error: "resolved (boolean) is required" });
9575
9610
  return;
9576
9611
  }
9577
- const content = await readFile14(commentsPath, "utf-8");
9612
+ const content = await readFile15(commentsPath, "utf-8");
9578
9613
  const parsed = parseComments(content);
9579
9614
  const target = parsed.entries.find((e) => e.id === commentId);
9580
9615
  if (!target) {
@@ -9621,7 +9656,7 @@ ${entry}`;
9621
9656
  });
9622
9657
  return;
9623
9658
  }
9624
- let content = await readFile14(projectPath, "utf-8");
9659
+ let content = await readFile15(projectPath, "utf-8");
9625
9660
  content = setTopLevelField(content, "workspace", workspace ?? null);
9626
9661
  content = setTopLevelField(content, "updated", nowTimestamp());
9627
9662
  await writeFileForce(projectPath, content);
@@ -9658,7 +9693,7 @@ ${entry}`;
9658
9693
  return;
9659
9694
  }
9660
9695
  const assignmentPath = resolve18(resolved.assignmentDir, "assignment.md");
9661
- let content = await readFile14(assignmentPath, "utf-8");
9696
+ let content = await readFile15(assignmentPath, "utf-8");
9662
9697
  content = setTopLevelField(content, "workspaceGroup", workspaceGroup ?? null);
9663
9698
  content = setTopLevelField(content, "updated", nowTimestamp());
9664
9699
  await writeFileForce(assignmentPath, content);
@@ -9875,7 +9910,7 @@ ${entry}`;
9875
9910
  return;
9876
9911
  }
9877
9912
  const assignmentPath = resolve18(resolved.assignmentDir, "assignment.md");
9878
- const parsedForSlug = parseAssignmentFull(await readFile14(assignmentPath, "utf-8"));
9913
+ const parsedForSlug = parseAssignmentFull(await readFile15(assignmentPath, "utf-8"));
9879
9914
  const assignmentSlugForBranch = parsedForSlug.slug || resolved.id;
9880
9915
  await handleWorktreeCreate(req, res, {
9881
9916
  assignmentPath,
@@ -9904,7 +9939,7 @@ ${entry}`;
9904
9939
  res.status(400).json({ error: `Invalid status. Must be one of: ${validStatuses.join(", ")}, or null to clear.` });
9905
9940
  return;
9906
9941
  }
9907
- let content = await readFile14(projectPath, "utf-8");
9942
+ let content = await readFile15(projectPath, "utf-8");
9908
9943
  content = setTopLevelField(content, "statusOverride", status ?? null);
9909
9944
  content = setTopLevelField(content, "updated", nowTimestamp());
9910
9945
  await writeFileForce(projectPath, content);
@@ -9937,7 +9972,7 @@ ${entry}`;
9937
9972
  res.status(400).json({ error: `Invalid status. Must be one of: ${validStatuses.join(", ")}.` });
9938
9973
  return;
9939
9974
  }
9940
- let content = await readFile14(assignmentPath, "utf-8");
9975
+ let content = await readFile15(assignmentPath, "utf-8");
9941
9976
  content = setTopLevelField(content, "status", status);
9942
9977
  content = setTopLevelField(content, "updated", nowTimestamp());
9943
9978
  if (status !== "blocked") {
@@ -9963,7 +9998,7 @@ ${entry}`;
9963
9998
  res.status(404).json({ error: `Project "${projectSlug}" not found` });
9964
9999
  return;
9965
10000
  }
9966
- const content = await readFile14(projectPath, "utf-8");
10001
+ const content = await readFile15(projectPath, "utf-8");
9967
10002
  await writeFileForce(projectPath, applyArchiveFields(content, true, archiveReason(req.body)));
9968
10003
  const project = await getProjectDetail(projectsDir, projectSlug);
9969
10004
  res.json({ project });
@@ -9980,7 +10015,7 @@ ${entry}`;
9980
10015
  res.status(404).json({ error: `Project "${projectSlug}" not found` });
9981
10016
  return;
9982
10017
  }
9983
- const content = await readFile14(projectPath, "utf-8");
10018
+ const content = await readFile15(projectPath, "utf-8");
9984
10019
  await writeFileForce(projectPath, applyArchiveFields(content, false, null));
9985
10020
  const project = await getProjectDetail(projectsDir, projectSlug);
9986
10021
  res.json({ project });
@@ -9997,7 +10032,7 @@ ${entry}`;
9997
10032
  res.status(404).json({ error: "Assignment not found" });
9998
10033
  return;
9999
10034
  }
10000
- const content = await readFile14(assignmentPath, "utf-8");
10035
+ const content = await readFile15(assignmentPath, "utf-8");
10001
10036
  await writeFileForce(assignmentPath, applyArchiveFields(content, archived, archived ? archiveReason(req.body) : null));
10002
10037
  const assignment = await getAssignmentDetail(projectsDir, projectSlug, assignmentSlug);
10003
10038
  res.json({ assignment });
@@ -10030,7 +10065,7 @@ ${entry}`;
10030
10065
  return;
10031
10066
  }
10032
10067
  const assignmentPath = resolve18(resolved.assignmentDir, "assignment.md");
10033
- const content = await readFile14(assignmentPath, "utf-8");
10068
+ const content = await readFile15(assignmentPath, "utf-8");
10034
10069
  await writeFileForce(assignmentPath, applyArchiveFields(content, archived, archived ? archiveReason(req.body) : null));
10035
10070
  const assignment = await getAssignmentDetailById(projectsDir, assignmentsDir2, id);
10036
10071
  res.json({ assignment });
@@ -10071,7 +10106,7 @@ ${entry}`;
10071
10106
  res.status(400).json({ error: validation.error });
10072
10107
  return;
10073
10108
  }
10074
- let content = await readFile14(assignmentPath, "utf-8");
10109
+ let content = await readFile15(assignmentPath, "utf-8");
10075
10110
  content = setTopLevelField(content, "assignee", validation.value);
10076
10111
  content = setTopLevelField(content, "updated", nowTimestamp());
10077
10112
  await writeFileForce(assignmentPath, content);
@@ -10102,7 +10137,7 @@ ${entry}`;
10102
10137
  res.status(400).json({ error: validation.error });
10103
10138
  return;
10104
10139
  }
10105
- let content = await readFile14(assignmentPath, "utf-8");
10140
+ let content = await readFile15(assignmentPath, "utf-8");
10106
10141
  content = setTopLevelField(content, "title", validation.value);
10107
10142
  content = setTopLevelField(content, "updated", nowTimestamp());
10108
10143
  await writeFileForce(assignmentPath, content);
@@ -10620,7 +10655,7 @@ ${entry}`;
10620
10655
  res.status(400).json({ error: `Invalid status. Must be one of: ${validStatuses.join(", ")}.` });
10621
10656
  return;
10622
10657
  }
10623
- let content = await readFile14(assignmentPath, "utf-8");
10658
+ let content = await readFile15(assignmentPath, "utf-8");
10624
10659
  content = setTopLevelField(content, "status", status);
10625
10660
  content = setTopLevelField(content, "updated", nowTimestamp());
10626
10661
  if (status !== "blocked") {
@@ -10656,7 +10691,7 @@ ${entry}`;
10656
10691
  res.status(400).json({ error: validation.error });
10657
10692
  return;
10658
10693
  }
10659
- let content = await readFile14(assignmentPath, "utf-8");
10694
+ let content = await readFile15(assignmentPath, "utf-8");
10660
10695
  content = setTopLevelField(content, "assignee", validation.value);
10661
10696
  content = setTopLevelField(content, "updated", nowTimestamp());
10662
10697
  await writeFileForce(assignmentPath, content);
@@ -10689,7 +10724,7 @@ ${entry}`;
10689
10724
  res.status(400).json({ error: validation.error });
10690
10725
  return;
10691
10726
  }
10692
- let content = await readFile14(assignmentPath, "utf-8");
10727
+ let content = await readFile15(assignmentPath, "utf-8");
10693
10728
  content = setTopLevelField(content, "title", validation.value);
10694
10729
  content = setTopLevelField(content, "updated", nowTimestamp());
10695
10730
  await writeFileForce(assignmentPath, content);
@@ -10826,7 +10861,7 @@ async function appendCommentTo(assignmentDir, assignmentRef, req, res, reloadDet
10826
10861
  let currentContent;
10827
10862
  let currentCount = 0;
10828
10863
  if (await fileExists(commentsPath)) {
10829
- currentContent = await readFile14(commentsPath, "utf-8");
10864
+ currentContent = await readFile15(commentsPath, "utf-8");
10830
10865
  const countMatch = currentContent.match(/^entryCount:\s*(\d+)/m);
10831
10866
  if (countMatch) currentCount = parseInt(countMatch[1], 10);
10832
10867
  } else {
@@ -10866,7 +10901,7 @@ async function toggleCommentResolvedAt(assignmentDir, commentId, req, res, reloa
10866
10901
  res.status(400).json({ error: "resolved (boolean) is required" });
10867
10902
  return;
10868
10903
  }
10869
- const content = await readFile14(commentsPath, "utf-8");
10904
+ const content = await readFile15(commentsPath, "utf-8");
10870
10905
  const parsed = parseComments(content);
10871
10906
  const target = parsed.entries.find((e) => e.id === commentId);
10872
10907
  if (!target) {
@@ -11694,7 +11729,7 @@ import { Router as Router8 } from "express";
11694
11729
 
11695
11730
  // src/utils/status-config-resolution.ts
11696
11731
  init_frontmatter();
11697
- import { readFile as readFile15, writeFile as writeFile4, rm as rm2 } from "fs/promises";
11732
+ import { readFile as readFile16, writeFile as writeFile4, rm as rm2 } from "fs/promises";
11698
11733
  import { dirname as dirname4 } from "path";
11699
11734
 
11700
11735
  // src/utils/assignment-walk.ts
@@ -11777,7 +11812,7 @@ async function scanAssignmentsByStatus(projectsDir, standaloneDir, ids) {
11777
11812
  const assignmentPath = `${entry.assignmentDir}/assignment.md`;
11778
11813
  let content;
11779
11814
  try {
11780
- content = await readFile15(assignmentPath, "utf-8");
11815
+ content = await readFile16(assignmentPath, "utf-8");
11781
11816
  } catch (err) {
11782
11817
  const code = err?.code;
11783
11818
  if (code === "ENOENT") {
@@ -11840,7 +11875,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
11840
11875
  const list = affected.get(r.id) ?? [];
11841
11876
  for (const a of list) {
11842
11877
  try {
11843
- const content = await readFile15(a.path, "utf-8");
11878
+ const content = await readFile16(a.path, "utf-8");
11844
11879
  buffer.set(a.path, content);
11845
11880
  } catch (err) {
11846
11881
  const code = err?.code;
@@ -11868,7 +11903,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
11868
11903
  for (const a of list) {
11869
11904
  let current;
11870
11905
  try {
11871
- current = await readFile15(a.path, "utf-8");
11906
+ current = await readFile16(a.path, "utf-8");
11872
11907
  } catch (err) {
11873
11908
  const code = err?.code;
11874
11909
  if (code === "ENOENT") {
@@ -11917,7 +11952,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
11917
11952
  const list = affected.get(r.id) ?? [];
11918
11953
  for (const a of list) {
11919
11954
  try {
11920
- const current = await readFile15(a.path, "utf-8");
11955
+ const current = await readFile16(a.path, "utf-8");
11921
11956
  const fm = parseAssignmentFrontmatter(current);
11922
11957
  if (fm.status !== r.id) {
11923
11958
  console.warn(
@@ -12792,7 +12827,7 @@ init_timestamp();
12792
12827
  init_fs();
12793
12828
  import { Router as Router11 } from "express";
12794
12829
  import { resolve as resolve23 } from "path";
12795
- import { readFile as readFile16 } from "fs/promises";
12830
+ import { readFile as readFile17 } from "fs/promises";
12796
12831
  init_playbooks();
12797
12832
  function statusForPlaybookError(code) {
12798
12833
  switch (code) {
@@ -12875,7 +12910,7 @@ function createPlaybooksRouter(playbooksDir2) {
12875
12910
  return;
12876
12911
  }
12877
12912
  const filePath = resolve23(playbooksDir2, resolved.filename);
12878
- const content = await readFile16(filePath, "utf-8");
12913
+ const content = await readFile17(filePath, "utf-8");
12879
12914
  res.json({
12880
12915
  documentType: "playbook",
12881
12916
  title: `Edit Playbook: ${resolved.slug}`,
@@ -13562,7 +13597,7 @@ function createTodosRouter(todosDir2, broadcast, projectsDir) {
13562
13597
  try {
13563
13598
  const { archivePath: archivePath2 } = await Promise.resolve().then(() => (init_parser2(), parser_exports));
13564
13599
  const { resolve: resolve29 } = await import("path");
13565
- const { readFile: readFile20 } = await import("fs/promises");
13600
+ const { readFile: readFile21 } = await import("fs/promises");
13566
13601
  const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
13567
13602
  const workspace = getWorkspaceParam(req.params.workspace);
13568
13603
  const checklist = await readChecklist(todosDir2, workspace);
@@ -13581,7 +13616,7 @@ function createTodosRouter(todosDir2, broadcast, projectsDir) {
13581
13616
  await ensureDir(resolve29(todosDir2, "archive"));
13582
13617
  let archContent = "";
13583
13618
  if (await fileExists(archFile)) {
13584
- archContent = await readFile20(archFile, "utf-8");
13619
+ archContent = await readFile21(archFile, "utf-8");
13585
13620
  archContent = archContent.trimEnd() + "\n\n";
13586
13621
  } else {
13587
13622
  archContent = `---
@@ -13863,7 +13898,7 @@ workspace: ${workspace}
13863
13898
  const { readConfig: readConfig2 } = await Promise.resolve().then(() => (init_config2(), config_exports));
13864
13899
  const { assignmentsDir: assignmentsDirFn } = await Promise.resolve().then(() => (init_paths(), paths_exports));
13865
13900
  const { fileExists: fileExists2, writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
13866
- const { readFile: readFile20 } = await import("fs/promises");
13901
+ const { readFile: readFile21 } = await import("fs/promises");
13867
13902
  const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
13868
13903
  const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
13869
13904
  let assignmentRef;
@@ -13884,7 +13919,7 @@ workspace: ${workspace}
13884
13919
  }
13885
13920
  const assignmentMdPath = resolvePath2(assignmentDir, "assignment.md");
13886
13921
  if (!await fileExists2(assignmentMdPath)) return { error: `Target assignment not found: ${assignmentMdPath}` };
13887
- let content = await readFile20(assignmentMdPath, "utf-8");
13922
+ let content = await readFile21(assignmentMdPath, "utf-8");
13888
13923
  content = appendTodosToAssignmentBody2(
13889
13924
  content,
13890
13925
  items.map((it) => ({
@@ -14072,7 +14107,7 @@ init_fs();
14072
14107
  init_paths();
14073
14108
  init_slug();
14074
14109
  import { Router as Router13 } from "express";
14075
- import { mkdir as mkdir3, readFile as readFile17, rename as rename6 } from "fs/promises";
14110
+ import { mkdir as mkdir3, readFile as readFile18, rename as rename6 } from "fs/promises";
14076
14111
  import { resolve as resolve25, dirname as dirname6 } from "path";
14077
14112
  init_api();
14078
14113
  var WORKSPACE_REGEX2 = /^[a-z0-9_][a-z0-9-]*$/;
@@ -14296,7 +14331,7 @@ function createProjectTodosRouter(projectsDir, broadcast, workspaceTodosDir) {
14296
14331
  const archFile = archivePath(todosDir2, slug, checklist.archiveInterval);
14297
14332
  let archContent = "";
14298
14333
  if (await fileExists(archFile)) {
14299
- archContent = await readFile17(archFile, "utf-8");
14334
+ archContent = await readFile18(archFile, "utf-8");
14300
14335
  archContent = archContent.trimEnd() + "\n\n";
14301
14336
  } else {
14302
14337
  archContent = `---
@@ -14753,7 +14788,7 @@ workspace: ${slug}
14753
14788
  }
14754
14789
  const assignmentMdPath = resolve25(assignmentDir, "assignment.md");
14755
14790
  if (!await fileExists(assignmentMdPath)) return { error: `Target assignment not found: ${assignmentMdPath}` };
14756
- let content = await readFile17(assignmentMdPath, "utf-8");
14791
+ let content = await readFile18(assignmentMdPath, "utf-8");
14757
14792
  content = appendTodosToAssignmentBody2(
14758
14793
  content,
14759
14794
  items.map((it) => ({
@@ -14957,7 +14992,7 @@ init_fs();
14957
14992
  init_paths();
14958
14993
  init_parser2();
14959
14994
  import { randomBytes as randomBytes2 } from "crypto";
14960
- import { readFile as readFile18 } from "fs/promises";
14995
+ import { readFile as readFile19 } from "fs/promises";
14961
14996
  var BUNDLE_ID_REGEX = /^[a-f0-9]{4}$/;
14962
14997
  var SCOPE_VALUES = /* @__PURE__ */ new Set(["workspace", "project", "global"]);
14963
14998
  var SCOPE_ID_REGEX = /^[a-z0-9_][a-z0-9_-]*$/;
@@ -15024,7 +15059,7 @@ function parseBundles(content) {
15024
15059
  async function readBundles(todosDir2) {
15025
15060
  const path = bundlesPath(todosDir2);
15026
15061
  if (!await fileExists(path)) return [];
15027
- const content = await readFile18(path, "utf-8");
15062
+ const content = await readFile19(path, "utf-8");
15028
15063
  return parseBundles(content).bundles;
15029
15064
  }
15030
15065
 
@@ -15197,7 +15232,7 @@ init_fs();
15197
15232
  init_config2();
15198
15233
  import { execFile as execFile2 } from "child_process";
15199
15234
  import { promisify as promisify2 } from "util";
15200
- import { cp, mkdtemp, rm as rm3, readFile as readFile19, writeFile as writeFile5, unlink as unlink5, stat, open as open2, rename as rename7 } from "fs/promises";
15235
+ import { cp, mkdtemp, rm as rm3, readFile as readFile20, writeFile as writeFile5, unlink as unlink5, stat, open as open2, rename as rename7 } from "fs/promises";
15201
15236
  import { resolve as resolve27, join as join3 } from "path";
15202
15237
  import { tmpdir } from "os";
15203
15238
  var exec2 = promisify2(execFile2);
@@ -15258,7 +15293,7 @@ async function acquireLock() {
15258
15293
  return lockPath;
15259
15294
  } catch (err) {
15260
15295
  if (err.code === "EEXIST") {
15261
- const pid = await readFile19(lockPath, "utf-8").catch(() => "");
15296
+ const pid = await readFile20(lockPath, "utf-8").catch(() => "");
15262
15297
  throw new Error(
15263
15298
  `Backup operation already in progress (lock file at ${lockPath}, pid ${pid.trim() || "unknown"}). If stale, delete the file and retry.`
15264
15299
  );
@@ -15305,7 +15340,7 @@ function resolveCategoriesStrict(csv) {
15305
15340
  return parseCategoriesStrict(parts);
15306
15341
  }
15307
15342
  async function readSanitizedConfig(configPath) {
15308
- const content = await readFile19(configPath, "utf-8");
15343
+ const content = await readFile20(configPath, "utf-8");
15309
15344
  return content.replace(/^(\s*lastBackup:\s*).*$/m, "$1null").replace(/^(\s*lastRestore:\s*).*$/m, "$1null");
15310
15345
  }
15311
15346
  async function backupToGithub(overrides) {