@hasna/todos 0.11.90 → 0.11.92

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +7 -2
  2. package/dist/cli/cloud-router.d.ts +57 -25
  3. package/dist/cli/cloud-router.d.ts.map +1 -1
  4. package/dist/cli/commands/agent-commands.d.ts.map +1 -1
  5. package/dist/cli/commands/plan-template-commands.d.ts.map +1 -1
  6. package/dist/cli/commands/project-commands.d.ts.map +1 -1
  7. package/dist/cli/commands/query-commands.d.ts.map +1 -1
  8. package/dist/cli/commands/storage-commands.d.ts.map +1 -1
  9. package/dist/cli/commands/task-commands.d.ts.map +1 -1
  10. package/dist/cli/helpers.d.ts +15 -1
  11. package/dist/cli/helpers.d.ts.map +1 -1
  12. package/dist/cli/index.js +19594 -30654
  13. package/dist/cli/output-redaction.d.ts +5 -0
  14. package/dist/cli/output-redaction.d.ts.map +1 -0
  15. package/dist/cli/stage-a.d.ts +45 -0
  16. package/dist/cli/stage-a.d.ts.map +1 -0
  17. package/dist/contracts.js +196 -97
  18. package/dist/index.js +517 -313
  19. package/dist/lib/package-version.d.ts +1 -1
  20. package/dist/lib/package-version.d.ts.map +1 -1
  21. package/dist/lib/redaction.d.ts.map +1 -1
  22. package/dist/lib/tmux.d.ts.map +1 -1
  23. package/dist/mcp/index.js +837 -6847
  24. package/dist/mcp.js +118 -20
  25. package/dist/registry.js +196 -97
  26. package/dist/release-provenance.json +5 -3
  27. package/dist/sdk/index.js +37 -2
  28. package/dist/sdk/v1.generated.d.ts +72 -3
  29. package/dist/sdk/v1.generated.d.ts.map +1 -1
  30. package/dist/server/index.js +2213 -8136
  31. package/dist/server/openapi.d.ts +366 -2
  32. package/dist/server/openapi.d.ts.map +1 -1
  33. package/dist/server/v1.d.ts.map +1 -1
  34. package/dist/storage.js +112 -14
  35. package/dist/types/index.d.ts +2 -2
  36. package/dist/types/index.d.ts.map +1 -1
  37. package/package.json +9 -6
package/dist/index.js CHANGED
@@ -2427,7 +2427,7 @@ var init_schema = __esm(() => {
2427
2427
  });
2428
2428
 
2429
2429
  // src/db/machines.ts
2430
- import { existsSync as existsSync2 } from "fs";
2430
+ import { existsSync } from "fs";
2431
2431
  import { hostname as osHostname, platform as osPlatform, arch as osArch } from "os";
2432
2432
  import { resolve } from "path";
2433
2433
  import { spawnSync } from "child_process";
@@ -2637,7 +2637,7 @@ function getMachineTopologyDiagnostics(opts = {}, db, at = new Date) {
2637
2637
  message: `${project.name} has ${distinctPaths.length} different machine-local paths`
2638
2638
  });
2639
2639
  }
2640
- if (localRow && !existsSync2(localRow.path)) {
2640
+ if (localRow && !existsSync(localRow.path)) {
2641
2641
  pathIssues.push({
2642
2642
  type: "path_missing",
2643
2643
  project_id: project.id,
@@ -2648,7 +2648,7 @@ function getMachineTopologyDiagnostics(opts = {}, db, at = new Date) {
2648
2648
  message: `Local path does not exist on this machine: ${localRow.path}`
2649
2649
  });
2650
2650
  }
2651
- if (!localRow && project.path && machineById.has(localMachine.id) && !existsSync2(project.path)) {
2651
+ if (!localRow && project.path && machineById.has(localMachine.id) && !existsSync(project.path)) {
2652
2652
  pathIssues.push({
2653
2653
  type: "path_missing",
2654
2654
  project_id: project.id,
@@ -3036,8 +3036,8 @@ __export(exports_database, {
3036
3036
  LOCK_EXPIRY_MINUTES: () => LOCK_EXPIRY_MINUTES
3037
3037
  });
3038
3038
  import { Database } from "bun:sqlite";
3039
- import { existsSync as existsSync3, mkdirSync } from "fs";
3040
- import { dirname as dirname2, join as join2, resolve as resolve2 } from "path";
3039
+ import { existsSync as existsSync2, mkdirSync } from "fs";
3040
+ import { dirname, join, resolve as resolve2 } from "path";
3041
3041
  function isInMemoryDb(path) {
3042
3042
  return path === ":memory:" || path.startsWith("file::memory:");
3043
3043
  }
@@ -3046,12 +3046,12 @@ function findNearestProjectDb(startDir) {
3046
3046
  const stopAt = gitRoot ? resolve2(gitRoot) : resolve2(startDir);
3047
3047
  let dir = resolve2(startDir);
3048
3048
  while (true) {
3049
- const candidate = join2(dir, ".hasna", "todos", "todos.db");
3050
- if (existsSync3(candidate))
3049
+ const candidate = join(dir, ".hasna", "todos", "todos.db");
3050
+ if (existsSync2(candidate))
3051
3051
  return candidate;
3052
3052
  if (dir === stopAt)
3053
3053
  break;
3054
- const parent = dirname2(dir);
3054
+ const parent = dirname(dir);
3055
3055
  if (parent === dir)
3056
3056
  break;
3057
3057
  dir = parent;
@@ -3061,9 +3061,9 @@ function findNearestProjectDb(startDir) {
3061
3061
  function findGitRoot(startDir) {
3062
3062
  let dir = resolve2(startDir);
3063
3063
  while (true) {
3064
- if (existsSync3(join2(dir, ".git")))
3064
+ if (existsSync2(join(dir, ".git")))
3065
3065
  return dir;
3066
- const parent = dirname2(dir);
3066
+ const parent = dirname(dir);
3067
3067
  if (parent === dir)
3068
3068
  break;
3069
3069
  dir = parent;
@@ -3084,11 +3084,11 @@ function getDbPath() {
3084
3084
  if (process.env["TODOS_DB_SCOPE"] === "project") {
3085
3085
  const gitRoot = findGitRoot(cwd);
3086
3086
  if (gitRoot) {
3087
- return join2(gitRoot, ".hasna", "todos", "todos.db");
3087
+ return join(gitRoot, ".hasna", "todos", "todos.db");
3088
3088
  }
3089
3089
  }
3090
3090
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
3091
- return join2(home, ".hasna", "todos", "todos.db");
3091
+ return join(home, ".hasna", "todos", "todos.db");
3092
3092
  }
3093
3093
  function getDatabasePath() {
3094
3094
  return getDbPath();
@@ -3096,8 +3096,8 @@ function getDatabasePath() {
3096
3096
  function ensureDir(filePath) {
3097
3097
  if (isInMemoryDb(filePath))
3098
3098
  return;
3099
- const dir = dirname2(resolve2(filePath));
3100
- if (!existsSync3(dir)) {
3099
+ const dir = dirname(resolve2(filePath));
3100
+ if (!existsSync2(dir)) {
3101
3101
  mkdirSync(dir, { recursive: true });
3102
3102
  }
3103
3103
  }
@@ -3368,26 +3368,26 @@ var init_types = __esm(() => {
3368
3368
  });
3369
3369
 
3370
3370
  // src/lib/sync-utils.ts
3371
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, readdirSync, statSync, writeFileSync } from "fs";
3372
- import { join as join3 } from "path";
3371
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
3372
+ import { join as join2 } from "path";
3373
3373
  function getHomeDir() {
3374
3374
  return process.env["HOME"] || process.env["USERPROFILE"] || "~";
3375
3375
  }
3376
3376
  function getTodosGlobalDir() {
3377
- return join3(getHomeDir(), ".hasna", "todos");
3377
+ return join2(getHomeDir(), ".hasna", "todos");
3378
3378
  }
3379
3379
  function ensureDir2(dir) {
3380
- if (!existsSync4(dir))
3380
+ if (!existsSync3(dir))
3381
3381
  mkdirSync2(dir, { recursive: true });
3382
3382
  }
3383
3383
  function listJsonFiles(dir) {
3384
- if (!existsSync4(dir))
3384
+ if (!existsSync3(dir))
3385
3385
  return [];
3386
3386
  return readdirSync(dir).filter((f) => f.endsWith(".json"));
3387
3387
  }
3388
3388
  function readJsonFile(path) {
3389
3389
  try {
3390
- return JSON.parse(readFileSync2(path, "utf-8"));
3390
+ return JSON.parse(readFileSync(path, "utf-8"));
3391
3391
  } catch {
3392
3392
  return null;
3393
3393
  }
@@ -3397,14 +3397,14 @@ function writeJsonFile(path, data) {
3397
3397
  `);
3398
3398
  }
3399
3399
  function readHighWaterMark(dir) {
3400
- const path = join3(dir, ".highwatermark");
3401
- if (!existsSync4(path))
3400
+ const path = join2(dir, ".highwatermark");
3401
+ if (!existsSync3(path))
3402
3402
  return 1;
3403
- const val = parseInt(readFileSync2(path, "utf-8").trim(), 10);
3403
+ const val = parseInt(readFileSync(path, "utf-8").trim(), 10);
3404
3404
  return isNaN(val) ? 1 : val;
3405
3405
  }
3406
3406
  function writeHighWaterMark(dir, value) {
3407
- writeFileSync(join3(dir, ".highwatermark"), String(value));
3407
+ writeFileSync(join2(dir, ".highwatermark"), String(value));
3408
3408
  }
3409
3409
  function getFileMtimeMs(path) {
3410
3410
  try {
@@ -3430,10 +3430,10 @@ var init_sync_utils = __esm(() => {
3430
3430
  });
3431
3431
 
3432
3432
  // src/lib/config.ts
3433
- import { existsSync as existsSync5 } from "fs";
3434
- import { dirname as dirname3, join as join4 } from "path";
3433
+ import { existsSync as existsSync4 } from "fs";
3434
+ import { dirname as dirname2, join as join3 } from "path";
3435
3435
  function getConfigPath() {
3436
- return join4(getTodosGlobalDir(), "config.json");
3436
+ return join3(getTodosGlobalDir(), "config.json");
3437
3437
  }
3438
3438
  function normalizeAgent(agent) {
3439
3439
  return agent.trim().toLowerCase();
@@ -3441,7 +3441,7 @@ function normalizeAgent(agent) {
3441
3441
  function loadConfig() {
3442
3442
  if (cached)
3443
3443
  return cached;
3444
- if (!existsSync5(getConfigPath())) {
3444
+ if (!existsSync4(getConfigPath())) {
3445
3445
  cached = {};
3446
3446
  return cached;
3447
3447
  }
@@ -3454,7 +3454,7 @@ function loadConfig() {
3454
3454
  }
3455
3455
  function saveConfig(config) {
3456
3456
  const configPath = getConfigPath();
3457
- ensureDir2(dirname3(configPath));
3457
+ ensureDir2(dirname2(configPath));
3458
3458
  writeJsonFile(configPath, config);
3459
3459
  cached = config;
3460
3460
  return config;
@@ -4139,7 +4139,8 @@ var init_redaction = __esm(() => {
4139
4139
  "input_tokens",
4140
4140
  "output_tokens",
4141
4141
  "prompt_tokens",
4142
- "completion_tokens"
4142
+ "completion_tokens",
4143
+ "cost_tokens"
4143
4144
  ]);
4144
4145
  });
4145
4146
 
@@ -4523,7 +4524,7 @@ var init_runner_sandbox = __esm(() => {
4523
4524
  // src/lib/event-hooks.ts
4524
4525
  import { createHash, randomUUID } from "crypto";
4525
4526
  import { appendFileSync, mkdirSync as mkdirSync3 } from "fs";
4526
- import { dirname as dirname4, resolve as resolve6 } from "path";
4527
+ import { dirname as dirname3, resolve as resolve6 } from "path";
4527
4528
  import { createConnection } from "net";
4528
4529
  function safeName(name) {
4529
4530
  const trimmed = name.trim();
@@ -4662,7 +4663,7 @@ async function deliverHook(hook, envelope) {
4662
4663
  output = line.trim();
4663
4664
  } else if (hook.target === "file") {
4664
4665
  const filePath = resolve6(hook.file_path);
4665
- mkdirSync3(dirname4(filePath), { recursive: true });
4666
+ mkdirSync3(dirname3(filePath), { recursive: true });
4666
4667
  appendFileSync(filePath, line);
4667
4668
  } else if (hook.target === "socket") {
4668
4669
  await writeSocket(hook.socket_path, line);
@@ -4781,9 +4782,9 @@ var init_event_hooks = __esm(() => {
4781
4782
 
4782
4783
  // node_modules/.bun/@hasna+events@0.1.11/node_modules/@hasna/events/dist/index.js
4783
4784
  import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
4784
- import { existsSync as existsSync6 } from "fs";
4785
+ import { existsSync as existsSync5 } from "fs";
4785
4786
  import { homedir } from "os";
4786
- import { join as join5 } from "path";
4787
+ import { join as join4 } from "path";
4787
4788
  import { createHmac, timingSafeEqual } from "crypto";
4788
4789
  import { randomUUID as randomUUID2 } from "crypto";
4789
4790
  import { spawn } from "child_process";
@@ -4884,7 +4885,7 @@ function channelMatchesEvent(channel, event) {
4884
4885
  return channel.filters.some((filter) => eventMatchesFilter(event, filter));
4885
4886
  }
4886
4887
  function getEventsDataDir(override) {
4887
- return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join5(homedir(), ".hasna", "events");
4888
+ return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join4(homedir(), ".hasna", "events");
4888
4889
  }
4889
4890
 
4890
4891
  class JsonEventsStore {
@@ -4894,9 +4895,9 @@ class JsonEventsStore {
4894
4895
  deliveriesPath;
4895
4896
  constructor(dataDir = getEventsDataDir()) {
4896
4897
  this.dataDir = dataDir;
4897
- this.channelsPath = join5(dataDir, "channels.json");
4898
- this.eventsPath = join5(dataDir, "events.json");
4899
- this.deliveriesPath = join5(dataDir, "deliveries.json");
4898
+ this.channelsPath = join4(dataDir, "channels.json");
4899
+ this.eventsPath = join4(dataDir, "events.json");
4900
+ this.deliveriesPath = join4(dataDir, "deliveries.json");
4900
4901
  }
4901
4902
  async init() {
4902
4903
  await mkdir(this.dataDir, { recursive: true, mode: 448 });
@@ -4968,7 +4969,7 @@ class JsonEventsStore {
4968
4969
  };
4969
4970
  }
4970
4971
  async ensureArrayFile(path) {
4971
- if (!existsSync6(path)) {
4972
+ if (!existsSync5(path)) {
4972
4973
  await writeFile(path, `[]
4973
4974
  `, { encoding: "utf-8", mode: 384 });
4974
4975
  }
@@ -5741,7 +5742,7 @@ var init_shared_events = __esm(() => {
5741
5742
  });
5742
5743
 
5743
5744
  // src/lib/secret-redaction.ts
5744
- import { readFileSync as readFileSync3, existsSync as existsSync7 } from "fs";
5745
+ import { readFileSync as readFileSync2, existsSync as existsSync6 } from "fs";
5745
5746
  function registerCustomRedactor(fn) {
5746
5747
  customRedactors.push(fn);
5747
5748
  }
@@ -5806,9 +5807,9 @@ function scanAndRedactText(text, options = {}) {
5806
5807
  };
5807
5808
  }
5808
5809
  function scanFileForSecrets(path, options = {}) {
5809
- if (!existsSync7(path))
5810
+ if (!existsSync6(path))
5810
5811
  throw new Error(`File not found: ${path}`);
5811
- const content = readFileSync3(path, "utf8");
5812
+ const content = readFileSync2(path, "utf8");
5812
5813
  return scanAndRedactText(content, options);
5813
5814
  }
5814
5815
  function safeStringify(value, space) {
@@ -9334,8 +9335,8 @@ var init_boards = __esm(() => {
9334
9335
 
9335
9336
  // src/lib/artifact-store.ts
9336
9337
  import { createHash as createHash2 } from "crypto";
9337
- import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync4, rmSync, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
9338
- import { basename, dirname as dirname5, join as join6, resolve as resolve7 } from "path";
9338
+ import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync3, rmSync, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
9339
+ import { basename, dirname as dirname4, join as join5, resolve as resolve7 } from "path";
9339
9340
  import { tmpdir as tmpdir2 } from "os";
9340
9341
  function isInMemoryDb2(path) {
9341
9342
  return path === ":memory:" || path.startsWith("file::memory:");
@@ -9347,15 +9348,15 @@ function artifactStoreRoot() {
9347
9348
  return resolve7(process.env["TODOS_ARTIFACTS_DIR"]);
9348
9349
  const dbPath = getDatabasePath();
9349
9350
  if (isInMemoryDb2(dbPath))
9350
- return join6(tmpdir2(), "hasna-todos-artifacts");
9351
- return join6(dirname5(resolve7(dbPath)), "artifacts");
9351
+ return join5(tmpdir2(), "hasna-todos-artifacts");
9352
+ return join5(dirname4(resolve7(dbPath)), "artifacts");
9352
9353
  }
9353
9354
  function artifactStorePath(relativePath) {
9354
9355
  const normalized = relativePath.replace(/\\/g, "/");
9355
9356
  if (normalized.includes("..") || normalized.startsWith("/") || normalized.length === 0) {
9356
9357
  throw new Error("Invalid artifact store path");
9357
9358
  }
9358
- return join6(artifactStoreRoot(), normalized);
9359
+ return join5(artifactStoreRoot(), normalized);
9359
9360
  }
9360
9361
  function sha256(buffer) {
9361
9362
  return createHash2("sha256").update(buffer).digest("hex");
@@ -9396,12 +9397,12 @@ function mediaTypeFor(path, textLike) {
9396
9397
  }
9397
9398
  function storeArtifactContent(input) {
9398
9399
  const sourcePath = resolve7(input.path);
9399
- if (!existsSync8(sourcePath))
9400
+ if (!existsSync7(sourcePath))
9400
9401
  return null;
9401
9402
  const sourceStat = statSync2(sourcePath);
9402
9403
  if (!sourceStat.isFile())
9403
9404
  throw new Error(`Artifact path is not a file: ${input.path}`);
9404
- const sourceBuffer = readFileSync4(sourcePath);
9405
+ const sourceBuffer = readFileSync3(sourcePath);
9405
9406
  const sourceSha = sha256(sourceBuffer);
9406
9407
  const textLike = isTextLike(sourceBuffer, input.path);
9407
9408
  let storedBuffer = sourceBuffer;
@@ -9413,10 +9414,10 @@ function storeArtifactContent(input) {
9413
9414
  redactionStatus = "redacted";
9414
9415
  }
9415
9416
  const storedSha = sha256(storedBuffer);
9416
- const relativePath = join6("sha256", storedSha.slice(0, 2), storedSha).replace(/\\/g, "/");
9417
+ const relativePath = join5("sha256", storedSha.slice(0, 2), storedSha).replace(/\\/g, "/");
9417
9418
  const destination = artifactStorePath(relativePath);
9418
- if (!existsSync8(destination)) {
9419
- mkdirSync4(dirname5(destination), { recursive: true });
9419
+ if (!existsSync7(destination)) {
9420
+ mkdirSync4(dirname4(destination), { recursive: true });
9420
9421
  writeFileSync2(destination, storedBuffer);
9421
9422
  }
9422
9423
  const createdAt = input.created_at || new Date().toISOString();
@@ -9475,7 +9476,7 @@ function verifyStoredArtifact(input) {
9475
9476
  };
9476
9477
  }
9477
9478
  const storedPath = artifactStorePath(store.relative_path);
9478
- if (!existsSync8(storedPath)) {
9479
+ if (!existsSync7(storedPath)) {
9479
9480
  return {
9480
9481
  id: input.id,
9481
9482
  path: input.path,
@@ -9488,7 +9489,7 @@ function verifyStoredArtifact(input) {
9488
9489
  message: "stored artifact content is missing"
9489
9490
  };
9490
9491
  }
9491
- const buffer = readFileSync4(storedPath);
9492
+ const buffer = readFileSync3(storedPath);
9492
9493
  const actualSha = sha256(buffer);
9493
9494
  const actualSize = buffer.length;
9494
9495
  const ok = actualSha === store.sha256 && actualSize === store.size_bytes;
@@ -9508,7 +9509,7 @@ function exportStoredArtifactContent(input) {
9508
9509
  const report = verifyStoredArtifact(input);
9509
9510
  if (report.status !== "ok" || !report.relative_path || !report.actual_sha256 || report.actual_size_bytes === null)
9510
9511
  return null;
9511
- const content = readFileSync4(artifactStorePath(report.relative_path));
9512
+ const content = readFileSync3(artifactStorePath(report.relative_path));
9512
9513
  return {
9513
9514
  artifact_id: input.id,
9514
9515
  sha256: report.actual_sha256,
@@ -9534,7 +9535,7 @@ function importStoredArtifactContent(content) {
9534
9535
  };
9535
9536
  }
9536
9537
  const destination = artifactStorePath(content.relative_path);
9537
- mkdirSync4(dirname5(destination), { recursive: true });
9538
+ mkdirSync4(dirname4(destination), { recursive: true });
9538
9539
  writeFileSync2(destination, buffer);
9539
9540
  return {
9540
9541
  id: content.artifact_id,
@@ -9555,29 +9556,29 @@ function getArtifactStoreRoot(dbPath) {
9555
9556
  return resolve7(process.env["TODOS_ARTIFACTS_DIR"]);
9556
9557
  const path = dbPath ?? getDatabasePath();
9557
9558
  if (isInMemoryDb2(path))
9558
- return join6(tmpdir2(), "hasna-todos-artifacts");
9559
- return join6(dirname5(resolve7(path)), "artifacts");
9559
+ return join5(tmpdir2(), "hasna-todos-artifacts");
9560
+ return join5(dirname4(resolve7(path)), "artifacts");
9560
9561
  }
9561
9562
  function computeContentHash(path) {
9562
- return sha256(readFileSync4(resolve7(path)));
9563
+ return sha256(readFileSync3(resolve7(path)));
9563
9564
  }
9564
9565
  function storeArtifactFile(input) {
9565
9566
  const sourcePath = resolve7(input.sourcePath);
9566
- if (!existsSync8(sourcePath)) {
9567
+ if (!existsSync7(sourcePath)) {
9567
9568
  throw new Error(`Source file not found: ${input.sourcePath}`);
9568
9569
  }
9569
9570
  if (!statSync2(sourcePath).isFile()) {
9570
9571
  throw new Error(`Source path is not a file: ${input.sourcePath}`);
9571
9572
  }
9572
- const buffer = readFileSync4(sourcePath);
9573
+ const buffer = readFileSync3(sourcePath);
9573
9574
  const contentHash = sha256(buffer);
9574
9575
  const mimeType = mediaTypeFor(sourcePath, isTextLike(buffer, sourcePath));
9575
9576
  const storageMode = input.storageMode ?? "copy";
9576
9577
  let localPath = sourcePath;
9577
9578
  if (storageMode === "copy") {
9578
9579
  const fileName = input.name && input.name.trim().length > 0 ? basename(input.name) : basename(sourcePath);
9579
- const destination = join6(getArtifactStoreRoot(input.dbPath), input.artifactId, fileName);
9580
- mkdirSync4(dirname5(destination), { recursive: true });
9580
+ const destination = join5(getArtifactStoreRoot(input.dbPath), input.artifactId, fileName);
9581
+ mkdirSync4(dirname4(destination), { recursive: true });
9581
9582
  writeFileSync2(destination, buffer);
9582
9583
  localPath = destination;
9583
9584
  }
@@ -9586,11 +9587,11 @@ function storeArtifactFile(input) {
9586
9587
  function deleteStoredArtifactFile(localPath, storageMode, _dbPath2) {
9587
9588
  if (storageMode === "reference")
9588
9589
  return false;
9589
- if (!localPath || !existsSync8(localPath))
9590
+ if (!localPath || !existsSync7(localPath))
9590
9591
  return false;
9591
9592
  rmSync(localPath, { force: true });
9592
9593
  try {
9593
- rmSync(dirname5(localPath), { recursive: false });
9594
+ rmSync(dirname4(localPath), { recursive: false });
9594
9595
  } catch {}
9595
9596
  return true;
9596
9597
  }
@@ -9612,7 +9613,7 @@ function buildArtifactExportManifest(artifacts, dbPath) {
9612
9613
  }
9613
9614
  function writeArtifactExportManifest(manifest, outputPath) {
9614
9615
  const destination = resolve7(outputPath);
9615
- mkdirSync4(dirname5(destination), { recursive: true });
9616
+ mkdirSync4(dirname4(destination), { recursive: true });
9616
9617
  writeFileSync2(destination, `${JSON.stringify(manifest, null, 2)}
9617
9618
  `);
9618
9619
  return destination;
@@ -10857,28 +10858,126 @@ var init_dispatches = __esm(() => {
10857
10858
  init_database();
10858
10859
  init_types();
10859
10860
  });
10860
-
10861
- // src/lib/package-version.ts
10862
- import { existsSync, readFileSync } from "fs";
10863
- import { dirname, join } from "path";
10864
- import { fileURLToPath } from "url";
10865
- function getPackageVersion(fromUrl = import.meta.url) {
10866
- try {
10867
- let dir = dirname(fileURLToPath(fromUrl));
10868
- for (let i = 0;i < 5; i++) {
10869
- const pkgPath = join(dir, "package.json");
10870
- if (existsSync(pkgPath)) {
10871
- return JSON.parse(readFileSync(pkgPath, "utf-8")).version || "0.0.0";
10872
- }
10873
- const parent = dirname(dir);
10874
- if (parent === dir)
10875
- break;
10876
- dir = parent;
10861
+ // package.json
10862
+ var package_default = {
10863
+ name: "@hasna/todos",
10864
+ version: "0.11.92",
10865
+ description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
10866
+ type: "module",
10867
+ main: "dist/index.js",
10868
+ types: "dist/index.d.ts",
10869
+ bin: {
10870
+ todos: "dist/cli/index.js",
10871
+ "todos-mcp": "dist/mcp/index.js",
10872
+ "todos-serve": "dist/server/index.js"
10873
+ },
10874
+ exports: {
10875
+ ".": {
10876
+ types: "./dist/index.d.ts",
10877
+ import: "./dist/index.js"
10878
+ },
10879
+ "./sdk": {
10880
+ types: "./dist/sdk/index.d.ts",
10881
+ import: "./dist/sdk/index.js"
10882
+ },
10883
+ "./mcp": {
10884
+ types: "./dist/mcp.d.ts",
10885
+ import: "./dist/mcp.js"
10886
+ },
10887
+ "./registry": {
10888
+ types: "./dist/registry.d.ts",
10889
+ import: "./dist/registry.js"
10890
+ },
10891
+ "./contracts": {
10892
+ types: "./dist/contracts.d.ts",
10893
+ import: "./dist/contracts.js"
10894
+ },
10895
+ "./storage": {
10896
+ types: "./dist/storage.d.ts",
10897
+ import: "./dist/storage.js"
10877
10898
  }
10878
- } catch {
10879
- return "0.0.0";
10899
+ },
10900
+ workspaces: [
10901
+ "dashboard"
10902
+ ],
10903
+ files: [
10904
+ "dist",
10905
+ "dashboard/dist",
10906
+ "LICENSE",
10907
+ "README.md"
10908
+ ],
10909
+ scripts: {
10910
+ build: "rm -rf dist dashboard/dist && cd dashboard && bun install --frozen-lockfile && bun run build && cd .. && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/sdk/index.ts --outdir dist/sdk --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/index.ts src/mcp.ts src/registry.ts src/contracts.ts src/storage.ts --outdir dist --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && tsc --emitDeclarationOnly --outDir dist",
10911
+ "build:server": "rm -rf dist && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/sdk/index.ts --outdir dist/sdk --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/index.ts src/mcp.ts src/registry.ts src/contracts.ts src/storage.ts --outdir dist --target bun --external '@hasna/contracts' --external '@hasna/contracts/*'",
10912
+ migrate: "bun run src/server/index.ts migrate",
10913
+ "backfill:comment-redaction": "bun run src/server/index.ts redact-comments",
10914
+ "generate:sdk": "bun run scripts/generate-sdk.ts",
10915
+ "build:dashboard": "cd dashboard && bun install --frozen-lockfile && bun run build",
10916
+ typecheck: "tsc --noEmit",
10917
+ test: "bun test",
10918
+ "test:no-cloud": "bun test src/no-cloud-boundary.test.ts src/local-first.test.ts src/lib/public-release-gate.test.ts",
10919
+ "dev:cli": "bun run src/cli/index.tsx",
10920
+ "dev:mcp": "bun run src/mcp/index.ts",
10921
+ "dev:serve": "bun run src/server/index.ts",
10922
+ "verify:release": "bun run scripts/verify-public-release.ts --mode=review",
10923
+ prepublishOnly: "bun run scripts/verify-public-release.ts --mode=publish",
10924
+ postinstall: "mkdir -p $HOME/.hasna/todos $HOME/.hasna/todos/training 2>/dev/null || true"
10925
+ },
10926
+ keywords: [
10927
+ "todos",
10928
+ "tasks",
10929
+ "mcp",
10930
+ "ai",
10931
+ "coding-agent",
10932
+ "claude",
10933
+ "codex",
10934
+ "gemini",
10935
+ "tui",
10936
+ "cli",
10937
+ "dashboard"
10938
+ ],
10939
+ publishConfig: {
10940
+ registry: "https://registry.npmjs.org",
10941
+ access: "public"
10942
+ },
10943
+ repository: {
10944
+ type: "git",
10945
+ url: "https://github.com/hasna/todos.git"
10946
+ },
10947
+ homepage: "https://github.com/hasna/todos",
10948
+ bugs: {
10949
+ url: "https://github.com/hasna/todos/issues"
10950
+ },
10951
+ engines: {
10952
+ bun: ">=1.0.0"
10953
+ },
10954
+ packageManager: "bun@1.3.14",
10955
+ author: "Andrei Hasna <andrei@hasna.com>",
10956
+ license: "Apache-2.0",
10957
+ dependencies: {
10958
+ "@hasna/contracts": "0.5.2",
10959
+ "@hasna/events": "^0.1.11",
10960
+ "@modelcontextprotocol/sdk": "^1.12.1",
10961
+ chalk: "^5.4.1",
10962
+ commander: "^13.1.0",
10963
+ ink: "^5.2.0",
10964
+ react: "^18.3.1",
10965
+ zod: "^3.24.2"
10966
+ },
10967
+ overrides: {
10968
+ "fast-uri": "3.1.2"
10969
+ },
10970
+ devDependencies: {
10971
+ "@types/bun": "^1.2.4",
10972
+ "@types/react": "^18.3.18",
10973
+ "bun-types": "1.3.9",
10974
+ typescript: "^5.7.3"
10880
10975
  }
10881
- return "0.0.0";
10976
+ };
10977
+
10978
+ // src/lib/package-version.ts
10979
+ function getPackageVersion(_fromUrl = import.meta.url) {
10980
+ return package_default.version || "0.0.0";
10882
10981
  }
10883
10982
 
10884
10983
  // src/mcp/token-utils.ts
@@ -13465,7 +13564,7 @@ var TODOS_JSON_CONTRACTS_MANIFEST = createJsonContractsManifest({
13465
13564
  });
13466
13565
  // src/lib/onboarding-fixtures.ts
13467
13566
  import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync3 } from "fs";
13468
- import { join as join7 } from "path";
13567
+ import { join as join6 } from "path";
13469
13568
 
13470
13569
  // src/lib/local-bridge.ts
13471
13570
  init_database();
@@ -14372,7 +14471,7 @@ function writeOnboardingFixtureFiles(directory) {
14372
14471
  mkdirSync5(directory, { recursive: true });
14373
14472
  const files = [];
14374
14473
  for (const fixture of allFixtures()) {
14375
- const path = join7(directory, `${fixture.summary.name}.bridge.json`);
14474
+ const path = join6(directory, `${fixture.summary.name}.bridge.json`);
14376
14475
  writeFileSync3(path, `${JSON.stringify(fixture.bundle, null, 2)}
14377
14476
  `, "utf-8");
14378
14477
  files.push(path);
@@ -14389,8 +14488,8 @@ function importOnboardingFixture(options = {}) {
14389
14488
  // src/lib/local-backups.ts
14390
14489
  init_database();
14391
14490
  import { createHash as createHash3 } from "crypto";
14392
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
14393
- import { dirname as dirname6, resolve as resolve8 } from "path";
14491
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
14492
+ import { dirname as dirname5, resolve as resolve8 } from "path";
14394
14493
  import { mkdirSync as mkdirSync6 } from "fs";
14395
14494
  var TODOS_LOCAL_BACKUP_KIND = "hasna.todos.local-backup";
14396
14495
  var TODOS_LOCAL_BACKUP_SCHEMA_VERSION = 1;
@@ -14498,13 +14597,13 @@ function createLocalBackup(options = {}, db) {
14498
14597
  }
14499
14598
  function writeLocalBackupFile(backup, outputPath) {
14500
14599
  const path = resolve8(outputPath);
14501
- mkdirSync6(dirname6(path), { recursive: true });
14600
+ mkdirSync6(dirname5(path), { recursive: true });
14502
14601
  writeFileSync4(path, `${JSON.stringify(backup, null, 2)}
14503
14602
  `);
14504
14603
  return path;
14505
14604
  }
14506
14605
  function readLocalBackupFile(path) {
14507
- return JSON.parse(readFileSync5(resolve8(path), "utf-8"));
14606
+ return JSON.parse(readFileSync4(resolve8(path), "utf-8"));
14508
14607
  }
14509
14608
  function verifyLocalBackup(value, options = {}, db) {
14510
14609
  const verifiedAt = options.verified_at ?? now();
@@ -15198,7 +15297,7 @@ function renderLocalSnapshotMarkdown(snapshot) {
15198
15297
  }
15199
15298
  // src/lib/sdk-integration-fixtures.ts
15200
15299
  import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync5 } from "fs";
15201
- import { join as join8 } from "path";
15300
+ import { join as join7 } from "path";
15202
15301
 
15203
15302
  // src/cli-mcp-parity.ts
15204
15303
  function source4(version) {
@@ -17154,7 +17253,7 @@ function writeSdkIntegrationFixtures(directory, options = {}) {
17154
17253
  ];
17155
17254
  const written = [];
17156
17255
  for (const [name, payload] of files) {
17157
- const file = join8(directory, name);
17256
+ const file = join7(directory, name);
17158
17257
  writeFileSync5(file, `${JSON.stringify(payload, null, 2)}
17159
17258
  `, "utf-8");
17160
17259
  written.push(file);
@@ -18436,8 +18535,8 @@ function renderLocalAuditLedgerMarkdown(ledger) {
18436
18535
  // src/lib/release-compatibility.ts
18437
18536
  init_migrations();
18438
18537
  init_schema();
18439
- import { readFileSync as readFileSync6 } from "fs";
18440
- import { join as join9, resolve as resolve9 } from "path";
18538
+ import { readFileSync as readFileSync5 } from "fs";
18539
+ import { join as join8, resolve as resolve9 } from "path";
18441
18540
  import { Database as Database2 } from "bun:sqlite";
18442
18541
  var LOCAL_RELEASE_COMPATIBILITY_SCHEMA_VERSION = 1;
18443
18542
  var EXPECTED_PACKAGE_NAME = "@hasna/todos";
@@ -18483,7 +18582,7 @@ function warn(id, message, details) {
18483
18582
  return { id, status: "warning", message, details };
18484
18583
  }
18485
18584
  function readPackageJson(root) {
18486
- return JSON.parse(readFileSync6(join9(root, "package.json"), "utf8"));
18585
+ return JSON.parse(readFileSync5(join8(root, "package.json"), "utf8"));
18487
18586
  }
18488
18587
  function sortedKeys(value) {
18489
18588
  return Object.keys(value ?? {}).sort((left, right) => left.localeCompare(right));
@@ -23970,7 +24069,7 @@ function createPostgresTodosStorageAdapter(options) {
23970
24069
  get: (id) => store.get("plans", id),
23971
24070
  list: async (projectId) => (await store.list("plans")).filter((plan) => projectId === undefined || plan.project_id === projectId).sort((a, b) => a.name.localeCompare(b.name)),
23972
24071
  update: (id, input) => updatePlan2(id, input, store),
23973
- delete: (id, context) => store.delete("plans", id, context)
24072
+ delete: (id, context) => store.deletePlan(id, context)
23974
24073
  },
23975
24074
  agents: {
23976
24075
  register: (input, context) => registerAgent2(input, store, context),
@@ -24254,6 +24353,62 @@ class PostgresJsonRecordStore {
24254
24353
  }
24255
24354
  return value;
24256
24355
  }
24356
+ async completeTask(id, agentId, options) {
24357
+ await this.ensureSchema();
24358
+ const operationTimestamp = new Date().toISOString();
24359
+ const completedAt2 = options?.completed_at ?? operationTimestamp;
24360
+ const evidence = options ? {
24361
+ ...options.files_changed !== undefined ? { files_changed: options.files_changed } : {},
24362
+ ...options.test_results !== undefined ? { test_results: options.test_results } : {},
24363
+ ...options.commit_hash !== undefined ? { commit_hash: options.commit_hash } : {},
24364
+ ...options.notes !== undefined ? { notes: options.notes } : {},
24365
+ ...options.attachment_ids !== undefined ? { attachment_ids: options.attachment_ids } : {}
24366
+ } : {};
24367
+ const hasEvidence = Object.keys(evidence).length > 0;
24368
+ const hasConfidence = options?.confidence !== undefined;
24369
+ const result = await this.options.client.query(`/* todos:complete-task-atomic */ UPDATE ${this.tableName}
24370
+ SET payload = payload || jsonb_build_object(
24371
+ 'status', 'completed',
24372
+ 'assigned_to', CASE
24373
+ WHEN jsonb_typeof(payload->'assigned_to') = 'string' THEN payload->'assigned_to'
24374
+ ELSE COALESCE(to_jsonb($3::text), 'null'::jsonb)
24375
+ END,
24376
+ 'completed_at', $4::text,
24377
+ 'updated_at', $9::text,
24378
+ 'version', COALESCE((payload->>'version')::integer, 0) + 1,
24379
+ 'metadata',
24380
+ (CASE WHEN jsonb_typeof(payload->'metadata') = 'object'
24381
+ THEN payload->'metadata' ELSE '{}'::jsonb END)
24382
+ || CASE WHEN $5::boolean THEN jsonb_build_object(
24383
+ '_evidence',
24384
+ (CASE WHEN jsonb_typeof(payload->'metadata'->'_evidence') = 'object'
24385
+ THEN payload->'metadata'->'_evidence' ELSE '{}'::jsonb END) || $6::jsonb
24386
+ ) ELSE '{}'::jsonb END
24387
+ || CASE WHEN $7::boolean THEN jsonb_build_object(
24388
+ '_completion',
24389
+ (CASE WHEN jsonb_typeof(payload->'metadata'->'_completion') = 'object'
24390
+ THEN payload->'metadata'->'_completion' ELSE '{}'::jsonb END)
24391
+ || jsonb_build_object('confidence', $8::double precision)
24392
+ ) ELSE '{}'::jsonb END
24393
+ ) || CASE WHEN $7::boolean
24394
+ THEN jsonb_build_object('confidence', $8::double precision)
24395
+ ELSE '{}'::jsonb END,
24396
+ updated_at = $9::timestamptz,
24397
+ version = COALESCE(version, 0) + 1
24398
+ WHERE service = $1 AND object_type = 'tasks' AND object_id = $2 AND deleted_at IS NULL
24399
+ RETURNING payload`, [
24400
+ this.service,
24401
+ id,
24402
+ agentId ?? null,
24403
+ completedAt2,
24404
+ hasEvidence,
24405
+ jsonbParam(evidence),
24406
+ hasConfidence,
24407
+ options?.confidence ?? null,
24408
+ operationTimestamp
24409
+ ]);
24410
+ return result.rows[0] ? payloadRecord2(result.rows[0].payload) : null;
24411
+ }
24257
24412
  async renameProject(id, newSlug, name, context = {}) {
24258
24413
  await this.ensureSchema();
24259
24414
  const normalizedSlug = slugifyRaw(newSlug);
@@ -24370,6 +24525,41 @@ class PostgresJsonRecordStore {
24370
24525
  version: numberValue3(existing["version"])
24371
24526
  }, context);
24372
24527
  }
24528
+ async deletePlan(id, context = {}) {
24529
+ await this.ensureSchema();
24530
+ const timestamp2 = new Date().toISOString();
24531
+ const result = await this.options.client.query(`/* todos:delete-plan-atomic */ WITH target AS (
24532
+ SELECT payload FROM ${this.tableName}
24533
+ WHERE service = $1 AND object_type = 'plans' AND object_id = $2 AND deleted_at IS NULL
24534
+ FOR UPDATE
24535
+ ), updated_tasks AS (
24536
+ UPDATE ${this.tableName} r SET
24537
+ payload = jsonb_set(
24538
+ jsonb_set(r.payload, '{plan_id}', 'null'::jsonb, true),
24539
+ '{version}',
24540
+ to_jsonb(COALESCE((r.payload->>'version')::int, 0) + 1),
24541
+ true
24542
+ ) || jsonb_build_object('updated_at', $3::text),
24543
+ updated_at = $3::timestamptz,
24544
+ source_machine_id = COALESCE($4, r.source_machine_id),
24545
+ version = COALESCE(r.version, 0) + 1
24546
+ WHERE r.service = $1 AND r.object_type = 'tasks' AND r.deleted_at IS NULL
24547
+ AND r.payload->>'plan_id' = $2 AND EXISTS (SELECT 1 FROM target)
24548
+ RETURNING 1
24549
+ ), deleted_plan AS (
24550
+ UPDATE ${this.tableName} r SET
24551
+ deleted_at = $3::timestamptz,
24552
+ updated_at = $3::timestamptz,
24553
+ source_machine_id = COALESCE($4, r.source_machine_id),
24554
+ version = COALESCE(r.version, 0) + 1
24555
+ FROM target
24556
+ WHERE r.service = $1 AND r.object_type = 'plans' AND r.object_id = $2 AND r.deleted_at IS NULL
24557
+ RETURNING 1
24558
+ ) SELECT
24559
+ EXISTS (SELECT 1 FROM target) AS found,
24560
+ (SELECT count(*) FROM updated_tasks) AS tasks_updated`, [this.service, id, timestamp2, this.machineId(context)]);
24561
+ return Boolean(result.rows[0]?.found);
24562
+ }
24373
24563
  async tombstone(tombstone, context = {}) {
24374
24564
  await this.ensureSchema();
24375
24565
  const deletedAt = stringValue2(tombstone.deleted_at) ?? new Date().toISOString();
@@ -24523,14 +24713,10 @@ async function startTask2(id, agentId, store) {
24523
24713
  }, store);
24524
24714
  }
24525
24715
  async function completeTask2(id, agentId, options, store) {
24526
- const task2 = await requireRecord("tasks", id, store);
24527
- return patchTask(task2, {
24528
- status: "completed",
24529
- assigned_to: task2.assigned_to ?? agentId ?? null,
24530
- completed_at: options?.completed_at ?? new Date().toISOString(),
24531
- actual_minutes: task2.actual_minutes,
24532
- confidence: options?.confidence ?? task2.confidence
24533
- }, store);
24716
+ const task2 = await store.completeTask(id, agentId, options);
24717
+ if (!task2)
24718
+ throw new Error(`tasks record not found: ${id}`);
24719
+ return task2;
24534
24720
  }
24535
24721
  async function failTask2(id, agentId, reason, options, store) {
24536
24722
  const task2 = await requireRecord("tasks", id, store);
@@ -25104,8 +25290,9 @@ async function resolvePostgresPlanSlug(options) {
25104
25290
  const used = new Set(plans.filter((plan) => plan.project_id === options.projectId && plan.id !== options.excludeId && plan.slug).map((plan) => plan.slug));
25105
25291
  if (options.slug !== undefined) {
25106
25292
  const slug = normalizePlanSlug2(options.slug);
25107
- if (used.has(slug))
25108
- throw new Error(`Plan slug already exists in this scope: ${slug}`);
25293
+ if (used.has(slug)) {
25294
+ throw new ResourceConflictError("PLAN_SLUG_CONFLICT", `Plan slug already exists in this scope: ${slug}`);
25295
+ }
25109
25296
  return slug;
25110
25297
  }
25111
25298
  const base = planSlugBase4(options.name);
@@ -25143,13 +25330,22 @@ function numberValue3(value) {
25143
25330
  return typeof value === "number" && Number.isSafeInteger(value) ? value : null;
25144
25331
  }
25145
25332
  function isPostgresUniqueViolation(error) {
25146
- return typeof error === "object" && error !== null && error.code === "23505";
25333
+ if (typeof error !== "object" || error === null)
25334
+ return false;
25335
+ const candidate = error;
25336
+ const states = [candidate.code, candidate.errno, candidate.sqlState, candidate.sqlstate];
25337
+ if (typeof candidate.cause === "object" && candidate.cause !== null) {
25338
+ const cause = candidate.cause;
25339
+ states.push(cause.code, cause.errno, cause.sqlState, cause.sqlstate);
25340
+ }
25341
+ return states.some((state) => String(state) === "23505");
25147
25342
  }
25148
25343
  function postgresConstraintName(error) {
25149
25344
  if (typeof error !== "object" || error === null)
25150
25345
  return "";
25151
25346
  const candidate = error;
25152
- const constraint = candidate.constraint ?? candidate.constraint_name;
25347
+ const cause = typeof candidate.cause === "object" && candidate.cause !== null ? candidate.cause : undefined;
25348
+ const constraint = candidate.constraint ?? candidate.constraint_name ?? cause?.constraint ?? cause?.constraint_name;
25153
25349
  return typeof constraint === "string" ? constraint : "";
25154
25350
  }
25155
25351
 
@@ -27167,8 +27363,8 @@ init_task_crud();
27167
27363
  init_redaction();
27168
27364
  import { Database as Database3 } from "bun:sqlite";
27169
27365
  import { createHash as createHash10 } from "crypto";
27170
- import { existsSync as existsSync10, readdirSync as readdirSync2, statSync as statSync4 } from "fs";
27171
- import { basename as basename2, dirname as dirname7, join as join10, resolve as resolve10 } from "path";
27366
+ import { existsSync as existsSync9, readdirSync as readdirSync2, statSync as statSync4 } from "fs";
27367
+ import { basename as basename2, dirname as dirname6, join as join9, resolve as resolve10 } from "path";
27172
27368
 
27173
27369
  // src/lib/task-routing.ts
27174
27370
  init_database();
@@ -27176,7 +27372,7 @@ init_projects();
27176
27372
  init_task_crud();
27177
27373
  init_task_lifecycle();
27178
27374
  init_task_lists();
27179
- import { existsSync as existsSync9, statSync as statSync3 } from "fs";
27375
+ import { existsSync as existsSync8, statSync as statSync3 } from "fs";
27180
27376
  var DEFAULT_STALE_IN_PROGRESS_MS = 3 * 24 * 60 * 60 * 1000;
27181
27377
  var TERMINAL_WORKFLOW_STATES = new Set([
27182
27378
  "failed",
@@ -27231,7 +27427,7 @@ function routeConcurrencyKey(task2, project, taskList, projectPath) {
27231
27427
  }
27232
27428
  function directoryExists(path) {
27233
27429
  try {
27234
- return existsSync9(path) && statSync3(path).isDirectory();
27430
+ return existsSync8(path) && statSync3(path).isDirectory();
27235
27431
  } catch {
27236
27432
  return false;
27237
27433
  }
@@ -27432,7 +27628,7 @@ function pointerPatch(previous, input, key) {
27432
27628
 
27433
27629
  // src/lib/task-route-sources.ts
27434
27630
  var TASK_ROUTE_SOURCE_DISCOVERY_SCHEMA_VERSION = "todos.task_route_sources.v1";
27435
- var TODO_STORE_RELATIVE_PATH = join10(".hasna", "todos", "todos.db");
27631
+ var TODO_STORE_RELATIVE_PATH = join9(".hasna", "todos", "todos.db");
27436
27632
  var ROOT_SCAN_MAX_DEPTH = 5;
27437
27633
  var SKIPPED_SCAN_DIRS = new Set([
27438
27634
  ".git",
@@ -27455,9 +27651,9 @@ function sourceStoreId(sourceDbPath) {
27455
27651
  function inferSourceRepoPath(sourceDbPath) {
27456
27652
  const normalized = normalizePath3(sourceDbPath);
27457
27653
  if (normalized.endsWith(TODO_STORE_RELATIVE_PATH)) {
27458
- return dirname7(dirname7(dirname7(normalized)));
27654
+ return dirname6(dirname6(dirname6(normalized)));
27459
27655
  }
27460
- return dirname7(normalized);
27656
+ return dirname6(normalized);
27461
27657
  }
27462
27658
  function createStoreRef(sourceDbPath) {
27463
27659
  const normalized = normalizePath3(sourceDbPath);
@@ -27508,8 +27704,8 @@ function discoverStoresUnderRoot(sourceRoot) {
27508
27704
  const rootPath = normalizePath3(sourceRoot);
27509
27705
  const errors = [];
27510
27706
  const stores = [];
27511
- if (!existsSync10(rootPath)) {
27512
- const ref = createStoreRef(join10(rootPath, TODO_STORE_RELATIVE_PATH));
27707
+ if (!existsSync9(rootPath)) {
27708
+ const ref = createStoreRef(join9(rootPath, TODO_STORE_RELATIVE_PATH));
27513
27709
  errors.push({
27514
27710
  ...ref,
27515
27711
  code: "SOURCE_ROOT_MISSING",
@@ -27521,7 +27717,7 @@ function discoverStoresUnderRoot(sourceRoot) {
27521
27717
  try {
27522
27718
  rootStat = statSync4(rootPath);
27523
27719
  } catch (error) {
27524
- const ref = createStoreRef(join10(rootPath, TODO_STORE_RELATIVE_PATH));
27720
+ const ref = createStoreRef(join9(rootPath, TODO_STORE_RELATIVE_PATH));
27525
27721
  errors.push({
27526
27722
  ...ref,
27527
27723
  code: "SOURCE_ROOT_UNREADABLE",
@@ -27534,8 +27730,8 @@ function discoverStoresUnderRoot(sourceRoot) {
27534
27730
  return { stores, errors };
27535
27731
  }
27536
27732
  function scanDirectory(dir, depth) {
27537
- const candidate = join10(dir, TODO_STORE_RELATIVE_PATH);
27538
- if (existsSync10(candidate)) {
27733
+ const candidate = join9(dir, TODO_STORE_RELATIVE_PATH);
27734
+ if (existsSync9(candidate)) {
27539
27735
  stores.push(createStoreRef(candidate));
27540
27736
  }
27541
27737
  if (depth >= ROOT_SCAN_MAX_DEPTH)
@@ -27555,7 +27751,7 @@ function discoverStoresUnderRoot(sourceRoot) {
27555
27751
  for (const entry2 of entries) {
27556
27752
  if (!entry2.isDirectory() || SKIPPED_SCAN_DIRS.has(entry2.name))
27557
27753
  continue;
27558
- scanDirectory(join10(dir, entry2.name), depth + 1);
27754
+ scanDirectory(join9(dir, entry2.name), depth + 1);
27559
27755
  }
27560
27756
  }
27561
27757
  scanDirectory(rootPath, 0);
@@ -27581,7 +27777,7 @@ function collectStoreRefs(input) {
27581
27777
  };
27582
27778
  }
27583
27779
  function openReadonlyStore(ref) {
27584
- if (!existsSync10(ref.source_db_path)) {
27780
+ if (!existsSync9(ref.source_db_path)) {
27585
27781
  throw Object.assign(new Error(`Store does not exist: ${ref.source_db_path}`), { code: "STORE_MISSING" });
27586
27782
  }
27587
27783
  return new Database3(ref.source_db_path, { readonly: true, create: false });
@@ -27892,8 +28088,8 @@ init_plans();
27892
28088
  init_database();
27893
28089
  init_projects();
27894
28090
  init_tasks();
27895
- import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
27896
- import { join as join11, resolve as resolve11 } from "path";
28091
+ import { existsSync as existsSync10, mkdirSync as mkdirSync8, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "fs";
28092
+ import { join as join10, resolve as resolve11 } from "path";
27897
28093
  var PLAN_MARKDOWN_SCHEMA = "hasna.todos.plan/v1";
27898
28094
  function assertSafePathSegment(value, label) {
27899
28095
  const trimmed = value.trim();
@@ -27955,7 +28151,7 @@ function resolvePlanArtifactPaths(input) {
27955
28151
  const project = resolvePlanArtifactProject(input);
27956
28152
  const projectId = assertSafePathSegment(project.id, "project id");
27957
28153
  const projectRoot = resolve11(project.path);
27958
- const directory = join11(projectRoot, ".hasna", "todos", "plans", projectId);
28154
+ const directory = join10(projectRoot, ".hasna", "todos", "plans", projectId);
27959
28155
  const planId = input.plan_id ? assertSafePathSegment(input.plan_id, "plan id") : null;
27960
28156
  const planSlug = input.plan_slug ? assertSafePathSegment(slugify(input.plan_slug), "plan slug") : null;
27961
28157
  const fileName = planId ? planSlug ? `${planSlug}--${planId.slice(0, 8)}.md` : `${planId}.md` : null;
@@ -27963,7 +28159,7 @@ function resolvePlanArtifactPaths(input) {
27963
28159
  project_id: project.id,
27964
28160
  project_root: projectRoot,
27965
28161
  directory,
27966
- file_path: fileName ? join11(directory, fileName) : directory
28162
+ file_path: fileName ? join10(directory, fileName) : directory
27967
28163
  };
27968
28164
  }
27969
28165
  function resolvePlanArtifactCandidatePaths(plan, db) {
@@ -28129,10 +28325,10 @@ function readPlanArtifact(plan, db) {
28129
28325
  return null;
28130
28326
  const d = db || getDatabase();
28131
28327
  const paths = resolvePlanArtifactCandidatePaths(plan, d);
28132
- const path = existsSync11(paths.primary.file_path) ? paths.primary.file_path : existsSync11(paths.legacy.file_path) ? paths.legacy.file_path : null;
28328
+ const path = existsSync10(paths.primary.file_path) ? paths.primary.file_path : existsSync10(paths.legacy.file_path) ? paths.legacy.file_path : null;
28133
28329
  if (!path)
28134
28330
  return null;
28135
- const markdown = readFileSync7(path, "utf8");
28331
+ const markdown = readFileSync6(path, "utf8");
28136
28332
  return {
28137
28333
  path,
28138
28334
  markdown,
@@ -28144,7 +28340,7 @@ function inspectPlanArtifact(plan, db) {
28144
28340
  return null;
28145
28341
  const d = db || getDatabase();
28146
28342
  const paths = resolvePlanArtifactCandidatePaths(plan, d);
28147
- const path = existsSync11(paths.primary.file_path) ? paths.primary.file_path : existsSync11(paths.legacy.file_path) ? paths.legacy.file_path : null;
28343
+ const path = existsSync10(paths.primary.file_path) ? paths.primary.file_path : existsSync10(paths.legacy.file_path) ? paths.legacy.file_path : null;
28148
28344
  if (!path) {
28149
28345
  return {
28150
28346
  path: paths.primary.file_path,
@@ -28156,7 +28352,7 @@ function inspectPlanArtifact(plan, db) {
28156
28352
  };
28157
28353
  }
28158
28354
  try {
28159
- const artifact = parsePlanArtifactMarkdown(readFileSync7(path, "utf8"));
28355
+ const artifact = parsePlanArtifactMarkdown(readFileSync6(path, "utf8"));
28160
28356
  return {
28161
28357
  path,
28162
28358
  exists: true,
@@ -29233,8 +29429,8 @@ function renderRetrospectiveMarkdown(record) {
29233
29429
  init_database();
29234
29430
  init_projects();
29235
29431
  init_task_lists();
29236
- import { existsSync as existsSync12, readFileSync as readFileSync8, statSync as statSync5 } from "fs";
29237
- import { basename as basename3, dirname as dirname8, resolve as resolve12 } from "path";
29432
+ import { existsSync as existsSync11, readFileSync as readFileSync7, statSync as statSync5 } from "fs";
29433
+ import { basename as basename3, dirname as dirname7, resolve as resolve12 } from "path";
29238
29434
  function safeStat(path) {
29239
29435
  try {
29240
29436
  return statSync5(path);
@@ -29246,15 +29442,15 @@ function canonicalPath(input) {
29246
29442
  const resolved = resolve12(input);
29247
29443
  const stats2 = safeStat(resolved);
29248
29444
  if (stats2?.isFile())
29249
- return dirname8(resolved);
29445
+ return dirname7(resolved);
29250
29446
  return resolved;
29251
29447
  }
29252
29448
  function findUp(start, marker) {
29253
29449
  let current = canonicalPath(start);
29254
29450
  while (true) {
29255
- if (existsSync12(resolve12(current, marker)))
29451
+ if (existsSync11(resolve12(current, marker)))
29256
29452
  return current;
29257
- const parent = dirname8(current);
29453
+ const parent = dirname7(current);
29258
29454
  if (parent === current)
29259
29455
  return null;
29260
29456
  current = parent;
@@ -29264,10 +29460,10 @@ function readPackageJson2(path) {
29264
29460
  if (!path)
29265
29461
  return null;
29266
29462
  const file = resolve12(path, "package.json");
29267
- if (!existsSync12(file))
29463
+ if (!existsSync11(file))
29268
29464
  return null;
29269
29465
  try {
29270
- const parsed = JSON.parse(readFileSync8(file, "utf-8"));
29466
+ const parsed = JSON.parse(readFileSync7(file, "utf-8"));
29271
29467
  return parsed && typeof parsed === "object" ? parsed : null;
29272
29468
  } catch {
29273
29469
  return null;
@@ -29286,7 +29482,7 @@ function workspaceMarker(root, rootPackage) {
29286
29482
  if (rootPackage?.workspaces)
29287
29483
  markers.push("package.json#workspaces");
29288
29484
  for (const marker of ["pnpm-workspace.yaml", "turbo.json", "nx.json", "lerna.json", "rush.json", "bun.lock", "bun.lockb"]) {
29289
- if (existsSync12(resolve12(root, marker)))
29485
+ if (existsSync11(resolve12(root, marker)))
29290
29486
  markers.push(marker);
29291
29487
  }
29292
29488
  const kind = markers.find((marker) => marker !== "bun.lock" && marker !== "bun.lockb") ?? null;
@@ -29624,21 +29820,21 @@ var gatherTrainingData = async (options = {}) => {
29624
29820
  };
29625
29821
  // src/lib/model-config.ts
29626
29822
  init_sync_utils();
29627
- import { existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
29628
- import { join as join12 } from "path";
29823
+ import { existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
29824
+ import { join as join11 } from "path";
29629
29825
  var DEFAULT_MODEL = "gpt-4o-mini";
29630
29826
  function getConfigDir() {
29631
29827
  return getTodosGlobalDir();
29632
29828
  }
29633
29829
  function getConfigPath2() {
29634
- return join12(getConfigDir(), "config.json");
29830
+ return join11(getConfigDir(), "config.json");
29635
29831
  }
29636
29832
  function readConfig() {
29637
29833
  const configPath = getConfigPath2();
29638
- if (!existsSync13(configPath))
29834
+ if (!existsSync12(configPath))
29639
29835
  return {};
29640
29836
  try {
29641
- const raw = readFileSync9(configPath, "utf-8");
29837
+ const raw = readFileSync8(configPath, "utf-8");
29642
29838
  return JSON.parse(raw);
29643
29839
  } catch {
29644
29840
  return {};
@@ -29646,7 +29842,7 @@ function readConfig() {
29646
29842
  }
29647
29843
  function writeConfig(config) {
29648
29844
  const configDir = getConfigDir();
29649
- if (!existsSync13(configDir)) {
29845
+ if (!existsSync12(configDir)) {
29650
29846
  mkdirSync9(configDir, { recursive: true });
29651
29847
  }
29652
29848
  writeFileSync7(getConfigPath2(), JSON.stringify(config, null, 2) + `
@@ -30391,7 +30587,7 @@ init_database();
30391
30587
  init_tasks();
30392
30588
  init_config2();
30393
30589
  init_redaction();
30394
- import { existsSync as existsSync14, readFileSync as readFileSync10 } from "fs";
30590
+ import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
30395
30591
  var DEFAULT_RETRY = {
30396
30592
  attempts: 1,
30397
30593
  backoff_ms: 0
@@ -30554,7 +30750,7 @@ Timed out after ${provider.timeout_ms}ms`);
30554
30750
  };
30555
30751
  }
30556
30752
  function runCiLogProvider(input) {
30557
- const text = input.log_text ?? (input.log_path && existsSync14(input.log_path) ? readFileSync10(input.log_path, "utf-8") : "");
30753
+ const text = input.log_text ?? (input.log_path && existsSync13(input.log_path) ? readFileSync9(input.log_path, "utf-8") : "");
30558
30754
  return {
30559
30755
  status: classifyLog(text),
30560
30756
  attempts: 1,
@@ -30566,7 +30762,7 @@ function runBrowserProvider(input) {
30566
30762
  if (!input.artifact_path) {
30567
30763
  return { status: "unknown", attempts: 1, exit_code: null, output_summary: "browser provider needs a screenshot or artifact path" };
30568
30764
  }
30569
- if (!existsSync14(input.artifact_path)) {
30765
+ if (!existsSync13(input.artifact_path)) {
30570
30766
  return { status: "failed", attempts: 1, exit_code: null, output_summary: `artifact not found: ${input.artifact_path}` };
30571
30767
  }
30572
30768
  return {
@@ -30731,7 +30927,7 @@ function listVerificationRecords(filter = {}, db) {
30731
30927
  // src/lib/verification-evidence.ts
30732
30928
  init_database();
30733
30929
  import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync10 } from "fs";
30734
- import { dirname as dirname9 } from "path";
30930
+ import { dirname as dirname8 } from "path";
30735
30931
  var VERIFICATION_EVIDENCE_SCHEMA = "todos.verification_evidence.v1";
30736
30932
  function getMachineId3() {
30737
30933
  return process.env["TODOS_MACHINE_ID"] || __require("os").hostname();
@@ -30851,7 +31047,7 @@ function exportVerificationEvidence(filter = {}, db) {
30851
31047
  };
30852
31048
  }
30853
31049
  function writeVerificationExport(bundle, path) {
30854
- mkdirSync10(dirname9(path), { recursive: true });
31050
+ mkdirSync10(dirname8(path), { recursive: true });
30855
31051
  writeFileSync8(path, JSON.stringify(bundle, null, 2), "utf8");
30856
31052
  }
30857
31053
  // src/lib/policy-packs.ts
@@ -31211,21 +31407,21 @@ function resourceDiagnostics() {
31211
31407
  };
31212
31408
  }
31213
31409
  // src/lib/sandbox-profiles.ts
31214
- import { existsSync as existsSync15, readFileSync as readFileSync11, writeFileSync as writeFileSync9, mkdirSync as mkdirSync11 } from "fs";
31215
- import { join as join13, dirname as dirname10 } from "path";
31410
+ import { existsSync as existsSync14, readFileSync as readFileSync10, writeFileSync as writeFileSync9, mkdirSync as mkdirSync11 } from "fs";
31411
+ import { join as join12, dirname as dirname9 } from "path";
31216
31412
  var SANDBOX_PROFILE_VERSION = "todos.sandbox-profile.v1";
31217
31413
  function getProfilesPath() {
31218
31414
  if (process.env["TODOS_SANDBOX_PROFILES_PATH"]) {
31219
31415
  return process.env["TODOS_SANDBOX_PROFILES_PATH"];
31220
31416
  }
31221
- const localDir = join13(process.cwd(), ".todos");
31222
- const local = join13(localDir, "sandbox-profiles.json");
31223
- if (existsSync15(localDir))
31417
+ const localDir = join12(process.cwd(), ".todos");
31418
+ const local = join12(localDir, "sandbox-profiles.json");
31419
+ if (existsSync14(localDir))
31224
31420
  return local;
31225
- if (existsSync15(local))
31421
+ if (existsSync14(local))
31226
31422
  return local;
31227
31423
  const home = process.env["HOME"] || "~";
31228
- return join13(home, ".hasna", "todos", "sandbox-profiles.json");
31424
+ return join12(home, ".hasna", "todos", "sandbox-profiles.json");
31229
31425
  }
31230
31426
  var cached2 = null;
31231
31427
  function resetSandboxProfileCache() {
@@ -31257,11 +31453,11 @@ function loadSandboxProfiles() {
31257
31453
  if (cached2)
31258
31454
  return cached2;
31259
31455
  const path = getProfilesPath();
31260
- if (!existsSync15(path)) {
31456
+ if (!existsSync14(path)) {
31261
31457
  cached2 = getDefaultSandboxProfiles();
31262
31458
  return cached2;
31263
31459
  }
31264
- const parsed = JSON.parse(readFileSync11(path, "utf8"));
31460
+ const parsed = JSON.parse(readFileSync10(path, "utf8"));
31265
31461
  cached2 = parsed.profiles?.length ? parsed.profiles : getDefaultSandboxProfiles();
31266
31462
  return cached2;
31267
31463
  }
@@ -31270,7 +31466,7 @@ function getSandboxProfile(name) {
31270
31466
  }
31271
31467
  function saveSandboxProfiles(profiles) {
31272
31468
  const path = getProfilesPath();
31273
- mkdirSync11(dirname10(path), { recursive: true });
31469
+ mkdirSync11(dirname9(path), { recursive: true });
31274
31470
  writeFileSync9(path, JSON.stringify({ schema_version: SANDBOX_PROFILE_VERSION, profiles }, null, 2));
31275
31471
  cached2 = profiles;
31276
31472
  }
@@ -31637,7 +31833,7 @@ init_task_commits();
31637
31833
 
31638
31834
  // src/lib/git-traceability.ts
31639
31835
  init_task_commits();
31640
- import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
31836
+ import { existsSync as existsSync15, readFileSync as readFileSync11 } from "fs";
31641
31837
  import { spawnSync as spawnSync2 } from "child_process";
31642
31838
  import { resolve as resolve14 } from "path";
31643
31839
  var GIT_TRACEABILITY_SCHEMA_VERSION = "todos.git_traceability.v1";
@@ -31683,10 +31879,10 @@ function inspectGitCommit(sha, cwd) {
31683
31879
  }
31684
31880
  function loadCiSnapshot(path) {
31685
31881
  const target = path ? resolve14(path) : resolve14(process.cwd(), ".todos", "ci-snapshot.json");
31686
- if (!existsSync16(target))
31882
+ if (!existsSync15(target))
31687
31883
  return null;
31688
31884
  try {
31689
- const parsed = JSON.parse(readFileSync12(target, "utf8"));
31885
+ const parsed = JSON.parse(readFileSync11(target, "utf8"));
31690
31886
  return { ...parsed, captured_at: parsed.captured_at ?? new Date().toISOString() };
31691
31887
  } catch {
31692
31888
  return null;
@@ -31779,8 +31975,8 @@ function formatTraceabilityReport(report) {
31779
31975
  `);
31780
31976
  }
31781
31977
  // src/lib/mention-resolver.ts
31782
- import { existsSync as existsSync17, readdirSync as readdirSync3, readFileSync as readFileSync13, statSync as statSync6 } from "fs";
31783
- import { basename as basename4, isAbsolute, join as join14, relative as relative4, resolve as resolve15, sep as sep2 } from "path";
31978
+ import { existsSync as existsSync16, readdirSync as readdirSync3, readFileSync as readFileSync12, statSync as statSync6 } from "fs";
31979
+ import { basename as basename4, isAbsolute, join as join13, relative as relative4, resolve as resolve15, sep as sep2 } from "path";
31784
31980
  init_database();
31785
31981
  init_plans();
31786
31982
  init_task_runs();
@@ -31934,7 +32130,7 @@ function resolveFile(parsed, workspace) {
31934
32130
  return resolution;
31935
32131
  }
31936
32132
  resolution.path = relPath;
31937
- if (!existsSync17(absolutePath)) {
32133
+ if (!existsSync16(absolutePath)) {
31938
32134
  resolution.warnings.push("file does not exist in the local workspace");
31939
32135
  return resolution;
31940
32136
  }
@@ -31944,7 +32140,7 @@ function resolveFile(parsed, workspace) {
31944
32140
  return resolution;
31945
32141
  }
31946
32142
  if (parsed.line !== undefined) {
31947
- const lineCount = readFileSync13(absolutePath, "utf-8").split(/\r?\n/).length;
32143
+ const lineCount = readFileSync12(absolutePath, "utf-8").split(/\r?\n/).length;
31948
32144
  if (parsed.line < 1 || parsed.line > lineCount) {
31949
32145
  resolution.warnings.push(`line ${parsed.line} is outside the file range 1-${lineCount}`);
31950
32146
  return resolution;
@@ -31967,7 +32163,7 @@ function walkSourceFiles(root, current = root, files = []) {
31967
32163
  if (SKIP_DIRS.has(entry2.name))
31968
32164
  continue;
31969
32165
  }
31970
- const absolutePath = join14(current, entry2.name);
32166
+ const absolutePath = join13(current, entry2.name);
31971
32167
  if (entry2.isDirectory()) {
31972
32168
  if (!SKIP_DIRS.has(entry2.name))
31973
32169
  walkSourceFiles(root, absolutePath, files);
@@ -31997,7 +32193,7 @@ function resolveSymbol(parsed, workspace, maxMatches) {
31997
32193
  const pattern = symbolPattern(name);
31998
32194
  const matches = [];
31999
32195
  for (const file of walkSourceFiles(workspace)) {
32000
- const lines = readFileSync13(file, "utf-8").split(/\r?\n/);
32196
+ const lines = readFileSync12(file, "utf-8").split(/\r?\n/);
32001
32197
  for (let index = 0;index < lines.length; index += 1) {
32002
32198
  const line = lines[index];
32003
32199
  const found = pattern.exec(line);
@@ -33865,7 +34061,7 @@ function getAdapterDocsFingerprint() {
33865
34061
  // src/lib/inbox-intake.ts
33866
34062
  init_database();
33867
34063
  init_tasks();
33868
- import { existsSync as existsSync18, readFileSync as readFileSync14 } from "fs";
34064
+ import { existsSync as existsSync17, readFileSync as readFileSync13 } from "fs";
33869
34065
  import { basename as basename5 } from "path";
33870
34066
  import { createHash as createHash12 } from "crypto";
33871
34067
  init_secret_redaction();
@@ -33911,9 +34107,9 @@ function loadRawContent(input) {
33911
34107
  }
33912
34108
  }
33913
34109
  if (input.file_path) {
33914
- if (!existsSync18(input.file_path))
34110
+ if (!existsSync17(input.file_path))
33915
34111
  throw new Error(`File not found: ${input.file_path}`);
33916
- const raw = readFileSync14(input.file_path, "utf8");
34112
+ const raw = readFileSync13(input.file_path, "utf8");
33917
34113
  const name = basename5(input.file_path).toLowerCase();
33918
34114
  const source_type2 = input.source_type ?? (name.includes("ci") || name.endsWith(".log") ? "ci_log" : "file");
33919
34115
  return {
@@ -34532,7 +34728,7 @@ function formatNlIntakePreviewText(preview) {
34532
34728
  // src/lib/issue-importers.ts
34533
34729
  init_database();
34534
34730
  init_tasks();
34535
- import { existsSync as existsSync19, readFileSync as readFileSync15 } from "fs";
34731
+ import { existsSync as existsSync18, readFileSync as readFileSync14 } from "fs";
34536
34732
  var ISSUE_IMPORT_SCHEMA = "todos.issue_import.v1";
34537
34733
  var ISSUE_SOURCES = ["github", "linear", "jira", "auto"];
34538
34734
  var GITHUB_LABEL_PRIORITY = {
@@ -34751,9 +34947,9 @@ function parseIssueExport(data, source9 = "auto") {
34751
34947
  return normalized;
34752
34948
  }
34753
34949
  function loadIssueExportFromFile(path) {
34754
- if (!existsSync19(path))
34950
+ if (!existsSync18(path))
34755
34951
  throw new Error(`File not found: ${path}`);
34756
- return JSON.parse(readFileSync15(path, "utf8"));
34952
+ return JSON.parse(readFileSync14(path, "utf8"));
34757
34953
  }
34758
34954
  function loadIssueExportInput(input) {
34759
34955
  if (input.file_path) {
@@ -34911,8 +35107,8 @@ todos import issues ./linear.json --source linear --dry-run
34911
35107
  // src/lib/run-records.ts
34912
35108
  init_database();
34913
35109
  init_secret_redaction();
34914
- import { existsSync as existsSync20, mkdirSync as mkdirSync12, writeFileSync as writeFileSync10 } from "fs";
34915
- import { join as join15, dirname as dirname11 } from "path";
35110
+ import { existsSync as existsSync19, mkdirSync as mkdirSync12, writeFileSync as writeFileSync10 } from "fs";
35111
+ import { join as join14, dirname as dirname10 } from "path";
34916
35112
  var RUN_RECORD_SCHEMA = "todos.run_record.v1";
34917
35113
  var RUN_RECORD_STATUSES = ["active", "completed", "failed", "archived"];
34918
35114
  function parseJsonArray3(raw, fallback = []) {
@@ -35105,8 +35301,8 @@ function buildRunReplayBundle(id, db) {
35105
35301
  }
35106
35302
  function exportRunReplay(id, outputPath, db) {
35107
35303
  const bundle = buildRunReplayBundle(id, db);
35108
- const path = outputPath ?? join15(process.cwd(), ".todos", "replays", `${id.slice(0, 8)}.json`);
35109
- mkdirSync12(dirname11(path), { recursive: true });
35304
+ const path = outputPath ?? join14(process.cwd(), ".todos", "replays", `${id.slice(0, 8)}.json`);
35305
+ mkdirSync12(dirname10(path), { recursive: true });
35110
35306
  writeFileSync10(path, JSON.stringify(bundle, null, 2));
35111
35307
  const d = db || getDatabase();
35112
35308
  d.run(`UPDATE run_records SET replay_bundle = ?, updated_at = ? WHERE id = ?`, [path, now(), id]);
@@ -35145,16 +35341,16 @@ function formatRunRecordMarkdown(record) {
35145
35341
  `;
35146
35342
  }
35147
35343
  function getDefaultReplayDir() {
35148
- const local = join15(process.cwd(), ".todos", "replays");
35149
- if (existsSync20(join15(process.cwd(), ".todos")))
35344
+ const local = join14(process.cwd(), ".todos", "replays");
35345
+ if (existsSync19(join14(process.cwd(), ".todos")))
35150
35346
  return local;
35151
35347
  const home = process.env["HOME"] || "~";
35152
- return join15(home, ".hasna", "todos", "replays");
35348
+ return join14(home, ".hasna", "todos", "replays");
35153
35349
  }
35154
35350
  // src/lib/release-checks.ts
35155
35351
  init_secret_redaction();
35156
- import { existsSync as existsSync21, readFileSync as readFileSync16, readdirSync as readdirSync4, statSync as statSync7 } from "fs";
35157
- import { join as join16, relative as relative5 } from "path";
35352
+ import { existsSync as existsSync20, readFileSync as readFileSync15, readdirSync as readdirSync4, statSync as statSync7 } from "fs";
35353
+ import { join as join15, relative as relative5 } from "path";
35158
35354
  var RELEASE_CHECK_SCHEMA = "todos.release_check.v1";
35159
35355
  var FORBIDDEN_DIST_PATTERNS = [
35160
35356
  {
@@ -35167,16 +35363,16 @@ var FORBIDDEN_DIST_PATTERNS = [
35167
35363
  ];
35168
35364
  var REQUIRED_BINS = ["todos", "todos-mcp", "todos-serve"];
35169
35365
  function readPackageJson3(root) {
35170
- const path = join16(root, "package.json");
35171
- if (!existsSync21(path))
35366
+ const path = join15(root, "package.json");
35367
+ if (!existsSync20(path))
35172
35368
  throw new Error(`package.json not found in ${root}`);
35173
- return JSON.parse(readFileSync16(path, "utf8"));
35369
+ return JSON.parse(readFileSync15(path, "utf8"));
35174
35370
  }
35175
35371
  function walkFiles(dir, acc = []) {
35176
- if (!existsSync21(dir))
35372
+ if (!existsSync20(dir))
35177
35373
  return acc;
35178
35374
  for (const entry2 of readdirSync4(dir)) {
35179
- const full = join16(dir, entry2);
35375
+ const full = join15(dir, entry2);
35180
35376
  const st = statSync7(full);
35181
35377
  if (st.isDirectory())
35182
35378
  walkFiles(full, acc);
@@ -35194,8 +35390,8 @@ function auditPackageContents(root) {
35194
35390
  checks.push({ id: "files_dist", severity: "error", message: "package.json files must include dist" });
35195
35391
  }
35196
35392
  for (const pattern of files) {
35197
- const target = join16(root, pattern);
35198
- if (!existsSync21(target)) {
35393
+ const target = join15(root, pattern);
35394
+ if (!existsSync20(target)) {
35199
35395
  checks.push({ id: `files_missing_${pattern}`, severity: "error", message: `Published file path missing: ${pattern}` });
35200
35396
  }
35201
35397
  }
@@ -35209,8 +35405,8 @@ function auditPackageContents(root) {
35209
35405
  checks.push({ id: `bin_${name}`, severity: "error", message: `Missing bin entry: ${name}` });
35210
35406
  continue;
35211
35407
  }
35212
- const binPath = join16(root, rel);
35213
- if (!existsSync21(binPath)) {
35408
+ const binPath = join15(root, rel);
35409
+ if (!existsSync20(binPath)) {
35214
35410
  checks.push({ id: `bin_path_${name}`, severity: "error", message: `Bin file missing: ${rel}` });
35215
35411
  } else {
35216
35412
  checks.push({ id: `bin_ok_${name}`, severity: "info", message: `Bin present: ${name} \u2192 ${rel}` });
@@ -35227,8 +35423,8 @@ function auditPackageContents(root) {
35227
35423
  }
35228
35424
  function scanDistArtifacts(root) {
35229
35425
  const checks = [];
35230
- const distDir = join16(root, "dist");
35231
- if (!existsSync21(distDir)) {
35426
+ const distDir = join15(root, "dist");
35427
+ if (!existsSync20(distDir)) {
35232
35428
  checks.push({ id: "dist_missing", severity: "error", message: "dist/ directory not found \u2014 run bun run build" });
35233
35429
  return checks;
35234
35430
  }
@@ -35236,7 +35432,7 @@ function scanDistArtifacts(root) {
35236
35432
  const rel = relative5(root, file);
35237
35433
  let content;
35238
35434
  try {
35239
- content = readFileSync16(file, "utf8");
35435
+ content = readFileSync15(file, "utf8");
35240
35436
  } catch {
35241
35437
  continue;
35242
35438
  }
@@ -35538,8 +35734,8 @@ function renderReleaseNotesMarkdown(document) {
35538
35734
  // src/lib/db-backup.ts
35539
35735
  init_database();
35540
35736
  init_migrations();
35541
- import { existsSync as existsSync22, copyFileSync, mkdirSync as mkdirSync13, readFileSync as readFileSync17, renameSync, statSync as statSync8, writeFileSync as writeFileSync11, unlinkSync } from "fs";
35542
- import { dirname as dirname12, join as join17, resolve as resolve16 } from "path";
35737
+ import { existsSync as existsSync21, copyFileSync, mkdirSync as mkdirSync13, readFileSync as readFileSync16, renameSync, statSync as statSync8, writeFileSync as writeFileSync11, unlinkSync } from "fs";
35738
+ import { dirname as dirname11, join as join16, resolve as resolve16 } from "path";
35543
35739
  import { Database as Database4 } from "bun:sqlite";
35544
35740
  var DB_BACKUP_SCHEMA = "todos.db_backup.v1";
35545
35741
  function resolveDbPath(dbPath) {
@@ -35556,9 +35752,9 @@ function resolveDbPath(dbPath) {
35556
35752
  }
35557
35753
  function backupDatabase(outputPath, sourcePath) {
35558
35754
  const source9 = resolveDbPath(sourcePath);
35559
- if (!existsSync22(source9))
35755
+ if (!existsSync21(source9))
35560
35756
  throw new Error(`Database not found: ${source9}`);
35561
- mkdirSync13(dirname12(outputPath), { recursive: true });
35757
+ mkdirSync13(dirname11(outputPath), { recursive: true });
35562
35758
  closeDatabase();
35563
35759
  const src = new Database4(source9);
35564
35760
  try {
@@ -35579,14 +35775,14 @@ function backupDatabase(outputPath, sourcePath) {
35579
35775
  };
35580
35776
  }
35581
35777
  function restoreDatabase(backupPath, targetPath) {
35582
- if (!existsSync22(backupPath))
35778
+ if (!existsSync21(backupPath))
35583
35779
  throw new Error(`Backup not found: ${backupPath}`);
35584
35780
  const integrity = checkDatabaseIntegrity(backupPath);
35585
35781
  if (!integrity.ok) {
35586
35782
  throw new Error(`Backup failed integrity check: ${integrity.errors.join("; ")}`);
35587
35783
  }
35588
35784
  const target = targetPath ? resolve16(targetPath) : resolveDbPath();
35589
- mkdirSync13(dirname12(target), { recursive: true });
35785
+ mkdirSync13(dirname11(target), { recursive: true });
35590
35786
  closeDatabase();
35591
35787
  const staging = `${target}.restore.tmp`;
35592
35788
  try {
@@ -35595,7 +35791,7 @@ function restoreDatabase(backupPath, targetPath) {
35595
35791
  copyFileSync(backupPath, staging);
35596
35792
  for (const sidecar of [`${target}-wal`, `${target}-shm`]) {
35597
35793
  try {
35598
- if (existsSync22(sidecar))
35794
+ if (existsSync21(sidecar))
35599
35795
  unlinkSync(sidecar);
35600
35796
  } catch {}
35601
35797
  }
@@ -35612,7 +35808,7 @@ function restoreDatabase(backupPath, targetPath) {
35612
35808
  function checkDatabaseIntegrity(dbPath) {
35613
35809
  const path = dbPath ? resolve16(dbPath) : resolveDbPath();
35614
35810
  const errors = [];
35615
- if (!existsSync22(path)) {
35811
+ if (!existsSync21(path)) {
35616
35812
  return {
35617
35813
  schema_version: DB_BACKUP_SCHEMA,
35618
35814
  path,
@@ -35709,16 +35905,16 @@ function migrationDryRun(dbPath) {
35709
35905
  };
35710
35906
  }
35711
35907
  function defaultBackupPath(dbPath) {
35712
- const base = dbPath ? dirname12(resolve16(dbPath)) : dirname12(resolveDbPath());
35908
+ const base = dbPath ? dirname11(resolve16(dbPath)) : dirname11(resolveDbPath());
35713
35909
  const stamp = new Date().toISOString().replace(/[:.]/g, "-");
35714
- return join17(base, "backups", `todos-${stamp}.db`);
35910
+ return join16(base, "backups", `todos-${stamp}.db`);
35715
35911
  }
35716
35912
  function readBackupManifest(backupPath) {
35717
35913
  const manifestPath = `${backupPath}.json`;
35718
- if (!existsSync22(manifestPath))
35914
+ if (!existsSync21(manifestPath))
35719
35915
  return null;
35720
35916
  try {
35721
- return JSON.parse(readFileSync17(manifestPath, "utf8"));
35917
+ return JSON.parse(readFileSync16(manifestPath, "utf8"));
35722
35918
  } catch {
35723
35919
  return null;
35724
35920
  }
@@ -35728,7 +35924,7 @@ function writeBackupManifest(backupPath, result) {
35728
35924
  writeFileSyncSafe(manifestPath, JSON.stringify(result, null, 2));
35729
35925
  }
35730
35926
  function writeFileSyncSafe(path, content) {
35731
- mkdirSync13(dirname12(path), { recursive: true });
35927
+ mkdirSync13(dirname11(path), { recursive: true });
35732
35928
  writeFileSync11(path, content);
35733
35929
  }
35734
35930
  // src/lib/json-schemas.ts
@@ -36236,15 +36432,15 @@ ${SCHEMA_ENTITIES.map((e) => `- **${e}**: \`${JSON_SCHEMAS[e].schema_version}\``
36236
36432
  }
36237
36433
  function exportSchemasToDirectory(dir) {
36238
36434
  const { mkdirSync: mkdirSync14, writeFileSync: writeFileSync12 } = __require("fs");
36239
- const { join: join18 } = __require("path");
36435
+ const { join: join17 } = __require("path");
36240
36436
  mkdirSync14(dir, { recursive: true });
36241
36437
  const written = [];
36242
36438
  for (const entity of SCHEMA_ENTITIES) {
36243
- const path = join18(dir, `${entity}.${JSON_SCHEMAS[entity].schema_version.replace(/\./g, "-")}.json`);
36439
+ const path = join17(dir, `${entity}.${JSON_SCHEMAS[entity].schema_version.replace(/\./g, "-")}.json`);
36244
36440
  writeFileSync12(path, JSON.stringify(JSON_SCHEMAS[entity], null, 2));
36245
36441
  written.push(path);
36246
36442
  }
36247
- const catalogPath = join18(dir, "catalog.json");
36443
+ const catalogPath = join17(dir, "catalog.json");
36248
36444
  writeFileSync12(catalogPath, JSON.stringify({
36249
36445
  catalog_version: JSON_SCHEMA_CATALOG_VERSION,
36250
36446
  semver: SCHEMA_SEMVER,
@@ -37159,8 +37355,8 @@ init_tasks();
37159
37355
  init_plans();
37160
37356
  init_comments();
37161
37357
  init_templates();
37162
- import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, mkdirSync as mkdirSync14 } from "fs";
37163
- import { dirname as dirname13 } from "path";
37358
+ import { readFileSync as readFileSync17, writeFileSync as writeFileSync12, mkdirSync as mkdirSync14 } from "fs";
37359
+ import { dirname as dirname12 } from "path";
37164
37360
  init_secret_redaction();
37165
37361
  var BUNDLE_SCHEMA = "todos.bundle.v1";
37166
37362
  var BUNDLE_TYPES = ["full_export", "tasks", "partial"];
@@ -37568,11 +37764,11 @@ function importBundle(bundle, options = {}, db) {
37568
37764
  return result;
37569
37765
  }
37570
37766
  function writeBundleFile(bundle, path) {
37571
- mkdirSync14(dirname13(path), { recursive: true });
37767
+ mkdirSync14(dirname12(path), { recursive: true });
37572
37768
  writeFileSync12(path, JSON.stringify(bundle, null, 2), "utf8");
37573
37769
  }
37574
37770
  function readBundleFile(path) {
37575
- const raw = JSON.parse(readFileSync18(path, "utf8"));
37771
+ const raw = JSON.parse(readFileSync17(path, "utf8"));
37576
37772
  const validation = validateBundle(raw);
37577
37773
  if (!validation.valid)
37578
37774
  throw new Error(`Invalid bundle file: ${validation.errors.join("; ")}`);
@@ -38059,7 +38255,7 @@ init_plans();
38059
38255
  init_tasks();
38060
38256
  init_comments();
38061
38257
  import { writeFileSync as writeFileSync13, mkdirSync as mkdirSync15 } from "fs";
38062
- import { dirname as dirname14 } from "path";
38258
+ import { dirname as dirname13 } from "path";
38063
38259
  init_task_commits();
38064
38260
  var HANDOFF_PACKET_SCHEMA = "todos.handoff_packet.v1";
38065
38261
  function summarizeTask2(t) {
@@ -38234,7 +38430,7 @@ function formatHandoffPacket(packet, format = "json") {
38234
38430
  function exportHandoffPacket(input = {}, path, db) {
38235
38431
  const packet = createHandoffPacket(input, db);
38236
38432
  if (path) {
38237
- mkdirSync15(dirname14(path), { recursive: true });
38433
+ mkdirSync15(dirname13(path), { recursive: true });
38238
38434
  writeFileSync13(path, formatHandoffPacket(packet, "json"), "utf8");
38239
38435
  }
38240
38436
  return packet;
@@ -38848,7 +39044,7 @@ init_templates();
38848
39044
  init_database();
38849
39045
  init_templates();
38850
39046
  import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync14 } from "fs";
38851
- import { join as join18 } from "path";
39047
+ import { join as join17 } from "path";
38852
39048
  var BUILTIN_TEMPLATE_LIBRARY_VERSION = "2026-05-21";
38853
39049
  var BUILTIN_TEMPLATE_LIBRARY_SOURCE = "bundled-local-template-library";
38854
39050
  var TEMPLATE_LIBRARY_SCHEMA = "todos.template_library.v1";
@@ -39124,7 +39320,7 @@ function writeBuiltinTemplateFiles(directory) {
39124
39320
  mkdirSync16(directory, { recursive: true });
39125
39321
  const files = [];
39126
39322
  for (const entry2 of exportBuiltinTemplateFiles()) {
39127
- const path = join18(directory, entry2.filename);
39323
+ const path = join17(directory, entry2.filename);
39128
39324
  writeFileSync14(path, `${JSON.stringify(entry2.template, null, 2)}
39129
39325
  `, "utf-8");
39130
39326
  files.push(path);
@@ -39168,8 +39364,8 @@ function initBuiltinTemplates(db) {
39168
39364
  }
39169
39365
  // src/lib/template-library.ts
39170
39366
  init_database();
39171
- import { writeFileSync as writeFileSync15, readFileSync as readFileSync19, mkdirSync as mkdirSync17 } from "fs";
39172
- import { dirname as dirname15 } from "path";
39367
+ import { writeFileSync as writeFileSync15, readFileSync as readFileSync18, mkdirSync as mkdirSync17 } from "fs";
39368
+ import { dirname as dirname14 } from "path";
39173
39369
  init_templates();
39174
39370
  function listTemplateLibrary(db) {
39175
39371
  const d = db || getDatabase();
@@ -39212,7 +39408,7 @@ function exportTemplateLibraryCatalog(path, db) {
39212
39408
  templates: listTemplateLibrary(db)
39213
39409
  };
39214
39410
  if (path) {
39215
- mkdirSync17(dirname15(path), { recursive: true });
39411
+ mkdirSync17(dirname14(path), { recursive: true });
39216
39412
  writeFileSync15(path, JSON.stringify(catalog, null, 2), "utf8");
39217
39413
  }
39218
39414
  return catalog;
@@ -39230,7 +39426,7 @@ function exportInstalledTemplate(name, db) {
39230
39426
  }
39231
39427
  function importTemplateFromFile(path, db) {
39232
39428
  const d = db || getDatabase();
39233
- const raw = JSON.parse(readFileSync19(path, "utf8"));
39429
+ const raw = JSON.parse(readFileSync18(path, "utf8"));
39234
39430
  const payload = raw.template ?? raw;
39235
39431
  const created = importTemplate(payload, d);
39236
39432
  return { id: created.id, name: created.name };
@@ -39416,9 +39612,9 @@ init_tasks();
39416
39612
  init_redaction();
39417
39613
  init_sync_utils();
39418
39614
  import { createHash as createHash13 } from "crypto";
39419
- import { existsSync as existsSync23, readFileSync as readFileSync20, statSync as statSync9 } from "fs";
39615
+ import { existsSync as existsSync22, readFileSync as readFileSync19, statSync as statSync9 } from "fs";
39420
39616
  import { hostname as hostname3, platform, arch } from "os";
39421
- import { dirname as dirname16, join as join19, resolve as resolve17 } from "path";
39617
+ import { dirname as dirname15, join as join18, resolve as resolve17 } from "path";
39422
39618
  import { tmpdir as tmpdir3 } from "os";
39423
39619
  var MANIFEST_FILES = ["package.json", "dashboard/package.json", "sdk/package.json"];
39424
39620
  var LOCKFILES = ["bun.lock", "bun.lockb", "package-lock.json", "npm-shrinkwrap.json"];
@@ -39440,20 +39636,20 @@ function sha2565(value) {
39440
39636
  return createHash13("sha256").update(value).digest("hex");
39441
39637
  }
39442
39638
  function fileRecord(root, relativePath) {
39443
- const path = join19(root, relativePath);
39444
- if (!existsSync23(path))
39639
+ const path = join18(root, relativePath);
39640
+ if (!existsSync22(path))
39445
39641
  return null;
39446
39642
  const stat = statSync9(path);
39447
39643
  if (!stat.isFile())
39448
39644
  return null;
39449
- const content = readFileSync20(path);
39645
+ const content = readFileSync19(path);
39450
39646
  return { path: relativePath, sha256: sha2565(content), size_bytes: content.length };
39451
39647
  }
39452
39648
  function manifestRecord(root, relativePath) {
39453
39649
  const base = fileRecord(root, relativePath);
39454
39650
  if (!base)
39455
39651
  return null;
39456
- const parsed = readJsonFile(join19(root, relativePath));
39652
+ const parsed = readJsonFile(join18(root, relativePath));
39457
39653
  if (!parsed)
39458
39654
  return { ...base, redacted: {} };
39459
39655
  const redacted = redactValue({
@@ -39548,8 +39744,8 @@ function commandEnv(env, includeValues) {
39548
39744
  function defaultSnapshotDir() {
39549
39745
  const dbPath = getDatabasePath();
39550
39746
  if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
39551
- return join19(tmpdir3(), "hasna-todos", "environment-snapshots");
39552
- return join19(dirname16(resolve17(dbPath)), "environment-snapshots");
39747
+ return join18(tmpdir3(), "hasna-todos", "environment-snapshots");
39748
+ return join18(dirname15(resolve17(dbPath)), "environment-snapshots");
39553
39749
  }
39554
39750
  function snapshotWithId(snapshot) {
39555
39751
  const digest = sha2565(JSON.stringify(snapshot)).slice(0, 24);
@@ -39596,8 +39792,8 @@ function captureEnvironmentSnapshot(input = {}) {
39596
39792
  });
39597
39793
  }
39598
39794
  function writeEnvironmentSnapshot(snapshot, outputPath) {
39599
- const path = outputPath ? resolve17(outputPath) : join19(defaultSnapshotDir(), `${snapshot.id}.json`);
39600
- ensureDir2(dirname16(path));
39795
+ const path = outputPath ? resolve17(outputPath) : join18(defaultSnapshotDir(), `${snapshot.id}.json`);
39796
+ ensureDir2(dirname15(path));
39601
39797
  writeJsonFile(path, snapshot);
39602
39798
  return path;
39603
39799
  }
@@ -39691,7 +39887,7 @@ init_projects();
39691
39887
  init_plans();
39692
39888
  import { createHash as createHash14 } from "crypto";
39693
39889
  import { mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
39694
- import { dirname as dirname17, join as join20 } from "path";
39890
+ import { dirname as dirname16, join as join19 } from "path";
39695
39891
  var DECISION_RECORD_SCHEMA = "todos.decision_record.v1";
39696
39892
  var KNOWLEDGE_SNAPSHOT_SCHEMA = "todos.knowledge_snapshot.v1";
39697
39893
  var DECISION_STATUSES = ["proposed", "accepted", "deprecated", "superseded", "rejected"];
@@ -39921,8 +40117,8 @@ function exportDecisionRecord(id, outputPath, format = "markdown", db) {
39921
40117
  if (!record)
39922
40118
  throw new Error(`Decision record not found: ${id}`);
39923
40119
  const content = format === "markdown" ? formatDecisionRecordMarkdown(record) : JSON.stringify(record, null, 2);
39924
- const path = outputPath ?? join20(process.cwd(), ".todos", "decisions", `${record.short_ref}.${format === "markdown" ? "md" : "json"}`);
39925
- mkdirSync18(dirname17(path), { recursive: true });
40120
+ const path = outputPath ?? join19(process.cwd(), ".todos", "decisions", `${record.short_ref}.${format === "markdown" ? "md" : "json"}`);
40121
+ mkdirSync18(dirname16(path), { recursive: true });
39926
40122
  writeFileSync16(path, content, "utf8");
39927
40123
  return { path, content };
39928
40124
  }
@@ -40069,8 +40265,8 @@ function exportKnowledgeSnapshot(id, outputPath, format = "markdown", db) {
40069
40265
  throw new Error(`Knowledge snapshot not found: ${id}`);
40070
40266
  const content = format === "markdown" ? formatKnowledgeSnapshotMarkdown(record) : JSON.stringify(record, null, 2);
40071
40267
  const slug = record.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
40072
- const path = outputPath ?? join20(process.cwd(), ".todos", "knowledge", `${slug || record.id.slice(0, 8)}.${format === "markdown" ? "md" : "json"}`);
40073
- mkdirSync18(dirname17(path), { recursive: true });
40268
+ const path = outputPath ?? join19(process.cwd(), ".todos", "knowledge", `${slug || record.id.slice(0, 8)}.${format === "markdown" ? "md" : "json"}`);
40269
+ mkdirSync18(dirname16(path), { recursive: true });
40074
40270
  writeFileSync16(path, content, "utf8");
40075
40271
  return { path, content };
40076
40272
  }
@@ -40103,7 +40299,7 @@ init_tasks();
40103
40299
  init_task_status();
40104
40300
  init_secret_redaction();
40105
40301
  import { writeFileSync as writeFileSync17, mkdirSync as mkdirSync19 } from "fs";
40106
- import { dirname as dirname18 } from "path";
40302
+ import { dirname as dirname17 } from "path";
40107
40303
  var REPORT_EXPORT_SCHEMA = "todos.report_export.v1";
40108
40304
  var REPORT_KINDS = ["project", "plan", "run", "evidence", "roadmap", "retrospective"];
40109
40305
  var REPORT_FORMATS = ["markdown", "html"];
@@ -40334,7 +40530,7 @@ function formatReportExport(data, format) {
40334
40530
  return format === "html" ? formatReportHtml(data) : formatReportMarkdown(data);
40335
40531
  }
40336
40532
  function writeReportExport(data, format, path) {
40337
- mkdirSync19(dirname18(path), { recursive: true });
40533
+ mkdirSync19(dirname17(path), { recursive: true });
40338
40534
  writeFileSync17(path, formatReportExport(data, format), "utf8");
40339
40535
  }
40340
40536
  function exportReport(input, db) {
@@ -40368,8 +40564,8 @@ todos report export --kind retrospective --days 14 --format markdown --out retro
40368
40564
  `;
40369
40565
  }
40370
40566
  // src/lib/command-aliases.ts
40371
- import { existsSync as existsSync24, readFileSync as readFileSync21, writeFileSync as writeFileSync18, mkdirSync as mkdirSync20 } from "fs";
40372
- import { join as join21 } from "path";
40567
+ import { existsSync as existsSync23, readFileSync as readFileSync20, writeFileSync as writeFileSync18, mkdirSync as mkdirSync20 } from "fs";
40568
+ import { join as join20 } from "path";
40373
40569
  var COMMAND_ALIASES_SCHEMA = "todos.command_aliases.v1";
40374
40570
  var RESERVED = new Set([...listTopLevelCommands(), "help", "version", "alias", "shortcuts"]);
40375
40571
  var BUILTIN_SHORTCUTS = [
@@ -40388,7 +40584,7 @@ var BUILTIN_SHORTCUTS = [
40388
40584
  { pattern: /^reports?$/, argv: ["report", "docs"], explain: "Report export documentation" }
40389
40585
  ];
40390
40586
  function aliasesPath(cwd = process.cwd()) {
40391
- return join21(cwd, ".todos", "aliases.json");
40587
+ return join20(cwd, ".todos", "aliases.json");
40392
40588
  }
40393
40589
  function emptyStore() {
40394
40590
  return { schema_version: COMMAND_ALIASES_SCHEMA, aliases: {}, updated_at: new Date(0).toISOString() };
@@ -40405,9 +40601,9 @@ function validateAliasName(name) {
40405
40601
  }
40406
40602
  function loadAliasStore(cwd) {
40407
40603
  const path = aliasesPath(cwd);
40408
- if (!existsSync24(path))
40604
+ if (!existsSync23(path))
40409
40605
  return emptyStore();
40410
- const parsed = JSON.parse(readFileSync21(path, "utf8"));
40606
+ const parsed = JSON.parse(readFileSync20(path, "utf8"));
40411
40607
  if (parsed.schema_version !== COMMAND_ALIASES_SCHEMA) {
40412
40608
  throw new Error(`Unsupported alias store schema: ${parsed.schema_version}`);
40413
40609
  }
@@ -40415,7 +40611,7 @@ function loadAliasStore(cwd) {
40415
40611
  }
40416
40612
  function saveAliasStore(store, cwd) {
40417
40613
  const path = aliasesPath(cwd);
40418
- mkdirSync20(join21(path, ".."), { recursive: true });
40614
+ mkdirSync20(join20(path, ".."), { recursive: true });
40419
40615
  store.updated_at = new Date().toISOString();
40420
40616
  writeFileSync18(path, JSON.stringify(store, null, 2), "utf8");
40421
40617
  }
@@ -41070,18 +41266,18 @@ function createBranchWorkPlan(input, db) {
41070
41266
  init_database();
41071
41267
  init_templates();
41072
41268
  init_plans();
41073
- import { existsSync as existsSync25, readFileSync as readFileSync22, writeFileSync as writeFileSync19, mkdirSync as mkdirSync21 } from "fs";
41074
- import { join as join22 } from "path";
41269
+ import { existsSync as existsSync24, readFileSync as readFileSync21, writeFileSync as writeFileSync19, mkdirSync as mkdirSync21 } from "fs";
41270
+ import { join as join21 } from "path";
41075
41271
  var USER_SCAFFOLD_SCHEMA = "todos.user_scaffold.v1";
41076
41272
  var SCAFFOLD_KINDS = ["task", "project", "plan", "checklist", "contract", "verification_policy"];
41077
41273
  function storeDir(cwd = process.cwd()) {
41078
- return join22(cwd, ".todos", "scaffolds");
41274
+ return join21(cwd, ".todos", "scaffolds");
41079
41275
  }
41080
41276
  function storePath(cwd) {
41081
- return join22(storeDir(cwd), "store.json");
41277
+ return join21(storeDir(cwd), "store.json");
41082
41278
  }
41083
41279
  function versionsDir(cwd) {
41084
- return join22(storeDir(cwd), "versions");
41280
+ return join21(storeDir(cwd), "versions");
41085
41281
  }
41086
41282
  function slugify4(name) {
41087
41283
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
@@ -41091,9 +41287,9 @@ function emptyStore2() {
41091
41287
  }
41092
41288
  function loadUserScaffoldStore(cwd) {
41093
41289
  const path = storePath(cwd);
41094
- if (!existsSync25(path))
41290
+ if (!existsSync24(path))
41095
41291
  return emptyStore2();
41096
- const parsed = JSON.parse(readFileSync22(path, "utf8"));
41292
+ const parsed = JSON.parse(readFileSync21(path, "utf8"));
41097
41293
  if (parsed.schema_version !== USER_SCAFFOLD_SCHEMA) {
41098
41294
  throw new Error(`Unsupported scaffold store schema: ${parsed.schema_version}`);
41099
41295
  }
@@ -41106,7 +41302,7 @@ function saveUserScaffoldStore(store, cwd) {
41106
41302
  }
41107
41303
  function snapshotVersion(scaffold, cwd) {
41108
41304
  mkdirSync21(versionsDir(cwd), { recursive: true });
41109
- const path = join22(versionsDir(cwd), `${scaffold.id}-v${scaffold.version}.json`);
41305
+ const path = join21(versionsDir(cwd), `${scaffold.id}-v${scaffold.version}.json`);
41110
41306
  writeFileSync19(path, JSON.stringify(scaffold, null, 2), "utf8");
41111
41307
  }
41112
41308
  function listUserScaffolds(kind, cwd) {
@@ -41353,7 +41549,7 @@ function listLinkedTemplates(db, cwd) {
41353
41549
  // src/lib/agent-workflow-demo.ts
41354
41550
  init_database();
41355
41551
  import { mkdtempSync } from "fs";
41356
- import { join as join23 } from "path";
41552
+ import { join as join22 } from "path";
41357
41553
  import { tmpdir as tmpdir4 } from "os";
41358
41554
  init_projects();
41359
41555
  init_task_lists();
@@ -41374,7 +41570,7 @@ function setupEphemeralDemoDb(options = {}) {
41374
41570
  if (options.db_path) {
41375
41571
  db_path = options.db_path;
41376
41572
  } else if (options.persist) {
41377
- db_path = join23(mkdtempSync(join23(tmpdir4(), "todos-demo-")), "todos.db");
41573
+ db_path = join22(mkdtempSync(join22(tmpdir4(), "todos-demo-")), "todos.db");
41378
41574
  } else {
41379
41575
  db_path = ":memory:";
41380
41576
  }
@@ -43708,16 +43904,16 @@ function runSearchView(idOrName, db) {
43708
43904
  init_tasks();
43709
43905
  init_config2();
43710
43906
  init_sync_utils();
43711
- import { existsSync as existsSync26, readFileSync as readFileSync23, readdirSync as readdirSync5, writeFileSync as writeFileSync20 } from "fs";
43712
- import { join as join24 } from "path";
43907
+ import { existsSync as existsSync25, readFileSync as readFileSync22, readdirSync as readdirSync5, writeFileSync as writeFileSync20 } from "fs";
43908
+ import { join as join23 } from "path";
43713
43909
  function getTaskListDir(taskListId) {
43714
- return join24(HOME, ".claude", "tasks", taskListId);
43910
+ return join23(HOME, ".claude", "tasks", taskListId);
43715
43911
  }
43716
43912
  function readClaudeTask(dir, filename) {
43717
- return readJsonFile(join24(dir, filename));
43913
+ return readJsonFile(join23(dir, filename));
43718
43914
  }
43719
43915
  function writeClaudeTask(dir, task2) {
43720
- writeJsonFile(join24(dir, `${task2.id}.json`), task2);
43916
+ writeJsonFile(join23(dir, `${task2.id}.json`), task2);
43721
43917
  }
43722
43918
  function toClaudeStatus(status) {
43723
43919
  if (status === "pending" || status === "in_progress" || status === "completed") {
@@ -43729,14 +43925,14 @@ function toSqliteStatus(status) {
43729
43925
  return status;
43730
43926
  }
43731
43927
  function readPrefixCounter(dir) {
43732
- const path = join24(dir, ".prefix-counter");
43733
- if (!existsSync26(path))
43928
+ const path = join23(dir, ".prefix-counter");
43929
+ if (!existsSync25(path))
43734
43930
  return 0;
43735
- const val = parseInt(readFileSync23(path, "utf-8").trim(), 10);
43931
+ const val = parseInt(readFileSync22(path, "utf-8").trim(), 10);
43736
43932
  return isNaN(val) ? 0 : val;
43737
43933
  }
43738
43934
  function writePrefixCounter(dir, value) {
43739
- writeFileSync20(join24(dir, ".prefix-counter"), String(value));
43935
+ writeFileSync20(join23(dir, ".prefix-counter"), String(value));
43740
43936
  }
43741
43937
  function formatPrefixedSubject(title, prefix, counter) {
43742
43938
  const padded = String(counter).padStart(5, "0");
@@ -43763,7 +43959,7 @@ function taskToClaudeTask(task2, claudeTaskId, existingMeta) {
43763
43959
  }
43764
43960
  function pushToClaudeTaskList(taskListId, projectId, options = {}) {
43765
43961
  const dir = getTaskListDir(taskListId);
43766
- if (!existsSync26(dir))
43962
+ if (!existsSync25(dir))
43767
43963
  ensureDir2(dir);
43768
43964
  const filter = {};
43769
43965
  if (projectId)
@@ -43772,7 +43968,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
43772
43968
  const existingByTodosId = new Map;
43773
43969
  const files = listJsonFiles(dir);
43774
43970
  for (const f of files) {
43775
- const path = join24(dir, f);
43971
+ const path = join23(dir, f);
43776
43972
  const ct = readClaudeTask(dir, f);
43777
43973
  if (ct?.metadata?.["todos_id"]) {
43778
43974
  existingByTodosId.set(ct.metadata["todos_id"], { task: ct, mtimeMs: getFileMtimeMs(path) });
@@ -43859,7 +44055,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
43859
44055
  }
43860
44056
  function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
43861
44057
  const dir = getTaskListDir(taskListId);
43862
- if (!existsSync26(dir)) {
44058
+ if (!existsSync25(dir)) {
43863
44059
  return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
43864
44060
  }
43865
44061
  const files = readdirSync5(dir).filter((f) => f.endsWith(".json"));
@@ -43879,7 +44075,7 @@ function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
43879
44075
  }
43880
44076
  for (const f of files) {
43881
44077
  try {
43882
- const filePath = join24(dir, f);
44078
+ const filePath = join23(dir, f);
43883
44079
  const ct = readClaudeTask(dir, f);
43884
44080
  if (!ct)
43885
44081
  continue;
@@ -43950,20 +44146,20 @@ function syncClaudeTaskList(taskListId, projectId, options = {}) {
43950
44146
  init_tasks();
43951
44147
  init_sync_utils();
43952
44148
  init_config2();
43953
- import { existsSync as existsSync27 } from "fs";
43954
- import { join as join25 } from "path";
44149
+ import { existsSync as existsSync26 } from "fs";
44150
+ import { join as join24 } from "path";
43955
44151
  function agentBaseDir(agent) {
43956
44152
  const key = `TODOS_${agent.toUpperCase()}_TASKS_DIR`;
43957
- return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join25(getTodosGlobalDir(), "agents");
44153
+ return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join24(getTodosGlobalDir(), "agents");
43958
44154
  }
43959
44155
  function getTaskListDir2(agent, taskListId) {
43960
- return join25(agentBaseDir(agent), agent, taskListId);
44156
+ return join24(agentBaseDir(agent), agent, taskListId);
43961
44157
  }
43962
44158
  function readAgentTask(dir, filename) {
43963
- return readJsonFile(join25(dir, filename));
44159
+ return readJsonFile(join24(dir, filename));
43964
44160
  }
43965
44161
  function writeAgentTask(dir, task2) {
43966
- writeJsonFile(join25(dir, `${task2.id}.json`), task2);
44162
+ writeJsonFile(join24(dir, `${task2.id}.json`), task2);
43967
44163
  }
43968
44164
  function taskToAgentTask(task2, externalId, existingMeta) {
43969
44165
  return {
@@ -43988,7 +44184,7 @@ function metadataKey(agent) {
43988
44184
  }
43989
44185
  function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
43990
44186
  const dir = getTaskListDir2(agent, taskListId);
43991
- if (!existsSync27(dir))
44187
+ if (!existsSync26(dir))
43992
44188
  ensureDir2(dir);
43993
44189
  const filter = {};
43994
44190
  if (projectId)
@@ -43997,7 +44193,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
43997
44193
  const existingByTodosId = new Map;
43998
44194
  const files = listJsonFiles(dir);
43999
44195
  for (const f of files) {
44000
- const path = join25(dir, f);
44196
+ const path = join24(dir, f);
44001
44197
  const at = readAgentTask(dir, f);
44002
44198
  if (at?.metadata?.["todos_id"]) {
44003
44199
  existingByTodosId.set(at.metadata["todos_id"], { task: at, mtimeMs: getFileMtimeMs(path) });
@@ -44071,7 +44267,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
44071
44267
  }
44072
44268
  function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
44073
44269
  const dir = getTaskListDir2(agent, taskListId);
44074
- if (!existsSync27(dir)) {
44270
+ if (!existsSync26(dir)) {
44075
44271
  return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
44076
44272
  }
44077
44273
  const files = listJsonFiles(dir);
@@ -44090,7 +44286,7 @@ function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
44090
44286
  }
44091
44287
  for (const f of files) {
44092
44288
  try {
44093
- const filePath = join25(dir, f);
44289
+ const filePath = join24(dir, f);
44094
44290
  const at = readAgentTask(dir, f);
44095
44291
  if (!at)
44096
44292
  continue;
@@ -44230,9 +44426,9 @@ function syncWithAgents(agents, taskListIdByAgent, projectId, direction = "both"
44230
44426
  // src/lib/extract.ts
44231
44427
  init_tasks();
44232
44428
  init_task_files();
44233
- import { existsSync as existsSync28, readFileSync as readFileSync24, statSync as statSync10 } from "fs";
44429
+ import { existsSync as existsSync27, readFileSync as readFileSync23, statSync as statSync10 } from "fs";
44234
44430
  import { createHash as createHash15 } from "crypto";
44235
- import { relative as relative6, resolve as resolve18, join as join26 } from "path";
44431
+ import { relative as relative6, resolve as resolve18, join as join25 } from "path";
44236
44432
  var EXTRACT_TAGS = ["TODO", "FIXME", "HACK", "XXX", "BUG", "NOTE"];
44237
44433
  var DEFAULT_EXTENSIONS = new Set([
44238
44434
  ".ts",
@@ -44303,11 +44499,11 @@ function normalizePathForMatch(value) {
44303
44499
  }
44304
44500
  function readGitignorePatterns(basePath) {
44305
44501
  const root = statSync10(basePath).isFile() ? resolve18(basePath, "..") : basePath;
44306
- const gitignorePath = join26(root, ".gitignore");
44307
- if (!existsSync28(gitignorePath))
44502
+ const gitignorePath = join25(root, ".gitignore");
44503
+ if (!existsSync27(gitignorePath))
44308
44504
  return [];
44309
44505
  try {
44310
- return readFileSync24(gitignorePath, "utf-8").split(`
44506
+ return readFileSync23(gitignorePath, "utf-8").split(`
44311
44507
  `).map((line) => line.trim()).filter((line) => line && !line.startsWith("#") && !line.startsWith("!"));
44312
44508
  } catch {
44313
44509
  return [];
@@ -44446,9 +44642,9 @@ function buildCodebaseIndex(options) {
44446
44642
  const files = collectFiles(basePath, extensions, excludes, respectGitignore);
44447
44643
  const indexed = [];
44448
44644
  for (const file of files) {
44449
- const fullPath = statSync10(basePath).isFile() ? basePath : join26(basePath, file);
44645
+ const fullPath = statSync10(basePath).isFile() ? basePath : join25(basePath, file);
44450
44646
  try {
44451
- const source9 = readFileSync24(fullPath, "utf-8");
44647
+ const source9 = readFileSync23(fullPath, "utf-8");
44452
44648
  const relPath = statSync10(basePath).isFile() ? relative6(resolve18(basePath, ".."), fullPath) : file;
44453
44649
  indexed.push({
44454
44650
  file: relPath,
@@ -44477,9 +44673,9 @@ function extractTodos(options, db) {
44477
44673
  const files = collectFiles(basePath, extensions, excludes, respectGitignore);
44478
44674
  const allComments = [];
44479
44675
  for (const file of files) {
44480
- const fullPath = statSync10(basePath).isFile() ? basePath : join26(basePath, file);
44676
+ const fullPath = statSync10(basePath).isFile() ? basePath : join25(basePath, file);
44481
44677
  try {
44482
- const source9 = readFileSync24(fullPath, "utf-8");
44678
+ const source9 = readFileSync23(fullPath, "utf-8");
44483
44679
  const relPath = statSync10(basePath).isFile() ? relative6(resolve18(basePath, ".."), fullPath) : file;
44484
44680
  const comments = extractFromSource(source9, relPath, tags);
44485
44681
  allComments.push(...comments);
@@ -45193,7 +45389,7 @@ function renderWorkflowStatesMarkdown(states = listWorkflowStates()) {
45193
45389
  // src/lib/agent-replay-simulator.ts
45194
45390
  init_redaction();
45195
45391
  import { createHash as createHash16 } from "crypto";
45196
- import { readFileSync as readFileSync25 } from "fs";
45392
+ import { readFileSync as readFileSync24 } from "fs";
45197
45393
  function isObject(value) {
45198
45394
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
45199
45395
  }
@@ -45426,7 +45622,7 @@ function simulateAgentReplay(input, options = {}) {
45426
45622
  };
45427
45623
  }
45428
45624
  function simulateAgentReplayFile(path, options = {}) {
45429
- const parsed = JSON.parse(readFileSync25(path, "utf8"));
45625
+ const parsed = JSON.parse(readFileSync24(path, "utf8"));
45430
45626
  return simulateAgentReplay(parsed, options);
45431
45627
  }
45432
45628
  function renderAgentReplaySimulationMarkdown(simulation) {
@@ -45454,8 +45650,8 @@ function renderAgentReplaySimulationMarkdown(simulation) {
45454
45650
  // src/lib/local-extensions.ts
45455
45651
  init_config2();
45456
45652
  import { createHash as createHash17, createVerify } from "crypto";
45457
- import { existsSync as existsSync29, readdirSync as readdirSync6, readFileSync as readFileSync26, statSync as statSync11 } from "fs";
45458
- import { basename as basename6, join as join27, resolve as resolve19 } from "path";
45653
+ import { existsSync as existsSync28, readdirSync as readdirSync6, readFileSync as readFileSync25, statSync as statSync11 } from "fs";
45654
+ import { basename as basename6, join as join26, resolve as resolve19 } from "path";
45459
45655
  init_redaction();
45460
45656
  init_runner_sandbox();
45461
45657
  function isObject2(value) {
@@ -45538,7 +45734,7 @@ function normalizeManifest(input) {
45538
45734
  };
45539
45735
  }
45540
45736
  function parseJson(path) {
45541
- return JSON.parse(readFileSync26(path, "utf8"));
45737
+ return JSON.parse(readFileSync25(path, "utf8"));
45542
45738
  }
45543
45739
  function sha2566(bytes) {
45544
45740
  return `sha256:${createHash17("sha256").update(bytes).digest("hex")}`;
@@ -45737,13 +45933,13 @@ function verifyExtensionSignature(input) {
45737
45933
  }
45738
45934
  function inspectExtensionSource(source9) {
45739
45935
  const resolved = resolve19(source9);
45740
- if (!existsSync29(resolved))
45936
+ if (!existsSync28(resolved))
45741
45937
  throw new Error(`extension source not found: ${source9}`);
45742
45938
  const stat = statSync11(resolved);
45743
- const manifestPath = stat.isDirectory() ? [join27(resolved, "todos.extension.json"), join27(resolved, "extension.json")].find(existsSync29) : resolved;
45939
+ const manifestPath = stat.isDirectory() ? [join26(resolved, "todos.extension.json"), join26(resolved, "extension.json")].find(existsSync28) : resolved;
45744
45940
  if (!manifestPath)
45745
45941
  throw new Error(`extension directory ${source9} is missing todos.extension.json`);
45746
- const raw = readFileSync26(manifestPath);
45942
+ const raw = readFileSync25(manifestPath);
45747
45943
  const parsed = parseJson(manifestPath);
45748
45944
  const bundle = isObject2(parsed) && isObject2(parsed["manifest"]);
45749
45945
  const manifest = normalizeManifest(bundle ? parsed["manifest"] : parsed);
@@ -45836,20 +46032,20 @@ function projectExtensionSources(projectPath) {
45836
46032
  return [];
45837
46033
  const root = resolve19(projectPath);
45838
46034
  const candidates = [
45839
- join27(root, "todos.extension.json"),
45840
- join27(root, ".todos", "todos.extension.json")
46035
+ join26(root, "todos.extension.json"),
46036
+ join26(root, ".todos", "todos.extension.json")
45841
46037
  ];
45842
- const extensionDir = join27(root, ".todos", "extensions");
45843
- if (existsSync29(extensionDir)) {
46038
+ const extensionDir = join26(root, ".todos", "extensions");
46039
+ if (existsSync28(extensionDir)) {
45844
46040
  for (const entry2 of readdirSync6(extensionDir)) {
45845
46041
  if (entry2.startsWith("."))
45846
46042
  continue;
45847
- const full = join27(extensionDir, entry2);
46043
+ const full = join26(extensionDir, entry2);
45848
46044
  if (statSync11(full).isDirectory() || entry2.endsWith(".json"))
45849
46045
  candidates.push(full);
45850
46046
  }
45851
46047
  }
45852
- return candidates.filter(existsSync29);
46048
+ return candidates.filter(existsSync28);
45853
46049
  }
45854
46050
  function discoverLocalExtensions(options = {}) {
45855
46051
  const config = loadConfig();
@@ -46151,6 +46347,11 @@ var IDLE_TMUX_COMMANDS = new Set([
46151
46347
  "tmux",
46152
46348
  "zsh"
46153
46349
  ]);
46350
+ function ensureTmuxAvailable() {
46351
+ if (!Bun.which("tmux", { PATH: process.env.PATH ?? "" })) {
46352
+ throw new Error("tmux is not installed or not in PATH");
46353
+ }
46354
+ }
46154
46355
  function parseTmuxTarget(spec) {
46155
46356
  if (!spec || spec.trim() === "") {
46156
46357
  throw new Error("tmux target spec cannot be empty");
@@ -46192,6 +46393,7 @@ function formatTmuxTarget(target) {
46192
46393
  async function validateTmuxTarget(spec) {
46193
46394
  const target = parseTmuxTarget(spec);
46194
46395
  const targetStr = formatTmuxTarget(target);
46396
+ ensureTmuxAvailable();
46195
46397
  let proc;
46196
46398
  try {
46197
46399
  proc = Bun.spawn(["tmux", "list-panes", "-t", targetStr], {
@@ -46208,6 +46410,7 @@ async function validateTmuxTarget(spec) {
46208
46410
  }
46209
46411
  }
46210
46412
  async function inspectTmuxPane(target) {
46413
+ ensureTmuxAvailable();
46211
46414
  const proc = Bun.spawn([
46212
46415
  "tmux",
46213
46416
  "display-message",
@@ -46267,6 +46470,7 @@ async function sendToTmux(target, message, delayMs, options = false) {
46267
46470
  console.log(`[dry-run] message: ${message.slice(0, 200)}`);
46268
46471
  return;
46269
46472
  }
46473
+ ensureTmuxAvailable();
46270
46474
  if (!opts.confirmBusy) {
46271
46475
  const pane = await inspectTmuxPane(target);
46272
46476
  const status = tmuxPaneBusyStatus(pane);
@@ -46721,7 +46925,7 @@ init_redaction();
46721
46925
  // src/lib/retention-cleanup.ts
46722
46926
  init_artifact_store();
46723
46927
  init_database();
46724
- import { existsSync as existsSync30, unlinkSync as unlinkSync2 } from "fs";
46928
+ import { existsSync as existsSync29, unlinkSync as unlinkSync2 } from "fs";
46725
46929
  var RETENTION_CLEANUP_CONFIRMATION = "delete-local-retention-data";
46726
46930
  var ALL_SCOPES = ["comments", "runs", "verifications", "expired_artifacts"];
46727
46931
  var EMPTY_COUNTS = {
@@ -46932,7 +47136,7 @@ function applyRetentionCleanup(input, db) {
46932
47136
  for (const artifact of report.candidates.artifact_files) {
46933
47137
  try {
46934
47138
  const path = artifactStorePath(artifact.relative_path);
46935
- if (!existsSync30(path)) {
47139
+ if (!existsSync29(path)) {
46936
47140
  report.warnings.push(`stored artifact already missing: ${artifact.relative_path}`);
46937
47141
  continue;
46938
47142
  }
@@ -47176,8 +47380,8 @@ init_database();
47176
47380
  init_migrations();
47177
47381
  init_schema();
47178
47382
  init_recurrence();
47179
- import { chmodSync, copyFileSync as copyFileSync2, existsSync as existsSync31, mkdirSync as mkdirSync22, statSync as statSync12 } from "fs";
47180
- import { basename as basename7, dirname as dirname19, join as join28 } from "path";
47383
+ import { chmodSync, copyFileSync as copyFileSync2, existsSync as existsSync30, mkdirSync as mkdirSync22, statSync as statSync12 } from "fs";
47384
+ import { basename as basename7, dirname as dirname18, join as join27 } from "path";
47181
47385
  var REQUIRED_TABLES2 = [
47182
47386
  "_migrations",
47183
47387
  "projects",
@@ -47284,7 +47488,7 @@ function findMissingProjectRoots(db) {
47284
47488
  continue;
47285
47489
  if (!row.path.startsWith("/"))
47286
47490
  continue;
47287
- if (!existsSync31(row.path))
47491
+ if (!existsSync30(row.path))
47288
47492
  missing++;
47289
47493
  }
47290
47494
  return missing;
@@ -47344,16 +47548,16 @@ function databasePermissionsAreUnsafe(dbPath) {
47344
47548
  function createBackup(dbPath) {
47345
47549
  if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
47346
47550
  return;
47347
- if (!existsSync31(dbPath))
47551
+ if (!existsSync30(dbPath))
47348
47552
  return;
47349
47553
  const stamp = now().replace(/[:.]/g, "-");
47350
- const backupDir = join28(dirname19(dbPath), `${basename7(dbPath)}.backup-${stamp}`);
47554
+ const backupDir = join27(dirname18(dbPath), `${basename7(dbPath)}.backup-${stamp}`);
47351
47555
  const files = [];
47352
47556
  mkdirSync22(backupDir, { recursive: true });
47353
47557
  for (const source9 of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
47354
- if (!existsSync31(source9))
47558
+ if (!existsSync30(source9))
47355
47559
  continue;
47356
- const target = join28(backupDir, basename7(source9));
47560
+ const target = join27(backupDir, basename7(source9));
47357
47561
  copyFileSync2(source9, target);
47358
47562
  files.push(target);
47359
47563
  }