@hasna/todos 0.11.90 → 0.11.93

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 (45) hide show
  1. package/README.md +7 -2
  2. package/dist/cli/cloud-router.d.ts +67 -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 +19499 -30656
  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 +571 -314
  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 +922 -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/cloud.d.ts +10 -0
  31. package/dist/server/cloud.d.ts.map +1 -1
  32. package/dist/server/index.js +2305 -8137
  33. package/dist/server/openapi.d.ts +366 -2
  34. package/dist/server/openapi.d.ts.map +1 -1
  35. package/dist/server/v1.d.ts.map +1 -1
  36. package/dist/storage/interfaces.d.ts +10 -0
  37. package/dist/storage/interfaces.d.ts.map +1 -1
  38. package/dist/storage/local-sqlite.d.ts.map +1 -1
  39. package/dist/storage/postgres-adapter.d.ts.map +1 -1
  40. package/dist/storage/postgres-sync.d.ts +22 -0
  41. package/dist/storage/postgres-sync.d.ts.map +1 -1
  42. package/dist/storage.js +166 -15
  43. package/dist/types/index.d.ts +2 -2
  44. package/dist/types/index.d.ts.map +1 -1
  45. 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.93",
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));
@@ -23389,6 +23488,27 @@ function clockColumnsForTable(table) {
23389
23488
  }
23390
23489
 
23391
23490
  // src/storage/local-sqlite.ts
23491
+ var TASK_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
23492
+ function resolveTaskRefLocal(db, ref) {
23493
+ const raw = ref.trim().toLowerCase();
23494
+ if (!raw)
23495
+ return null;
23496
+ if (TASK_UUID_RE.test(raw))
23497
+ return getTask(raw, db);
23498
+ const prefixRows = db.query("SELECT id FROM tasks WHERE LOWER(id) LIKE ? ESCAPE '\\' LIMIT 2").all(`${raw.replace(/[\\%_]/g, (c) => `\\${c}`)}%`);
23499
+ if (prefixRows.length > 1) {
23500
+ throw new Error(`Task reference is ambiguous: "${ref}"`);
23501
+ }
23502
+ if (prefixRows.length === 1)
23503
+ return getTask(prefixRows[0].id, db);
23504
+ const shortIdRows = db.query("SELECT id FROM tasks WHERE LOWER(short_id) = ? LIMIT 2").all(raw);
23505
+ if (shortIdRows.length > 1) {
23506
+ throw new Error(`Task reference is ambiguous: "${ref}"`);
23507
+ }
23508
+ if (shortIdRows.length === 1)
23509
+ return getTask(shortIdRows[0].id, db);
23510
+ return null;
23511
+ }
23392
23512
  function createLocalSqliteTodosStorageAdapter(options = {}) {
23393
23513
  const database = () => options.db ?? getDatabase();
23394
23514
  let adapter;
@@ -23404,6 +23524,7 @@ function createLocalSqliteTodosStorageAdapter(options = {}) {
23404
23524
  tasks: {
23405
23525
  create: (input) => createTask(input, database()),
23406
23526
  get: (id) => getTask(id, database()),
23527
+ resolveRef: (ref) => resolveTaskRefLocal(database(), ref),
23407
23528
  list: (filter = {}) => listTasks(filter, database()),
23408
23529
  count: (filter = {}) => countTasks(filter, database()),
23409
23530
  update: (id, input) => updateTask(id, input, database()),
@@ -23634,7 +23755,6 @@ function postgresTodosCommentCursorIndexSql(tableName = DEFAULT_TODOS_POSTGRES_S
23634
23755
  ON ${tableName} (service, (payload->>'task_id'), (payload->>'created_at'), object_id)
23635
23756
  WHERE object_type = 'comments' AND deleted_at IS NULL`;
23636
23757
  }
23637
-
23638
23758
  class PostgresTodosSyncStore {
23639
23759
  client;
23640
23760
  service;
@@ -23921,6 +24041,7 @@ function createPostgresTodosStorageAdapter(options) {
23921
24041
  tasks: {
23922
24042
  create: (input, context) => createTask2(input, store, context),
23923
24043
  get: (id) => store.get("tasks", id),
24044
+ resolveRef: (ref) => store.resolveTaskRef(ref),
23924
24045
  list: (filter = {}) => store.listTasks(filter),
23925
24046
  count: (filter = {}) => store.countTasks(filter),
23926
24047
  update: (id, input) => updateTask2(id, input, store),
@@ -23970,7 +24091,7 @@ function createPostgresTodosStorageAdapter(options) {
23970
24091
  get: (id) => store.get("plans", id),
23971
24092
  list: async (projectId) => (await store.list("plans")).filter((plan) => projectId === undefined || plan.project_id === projectId).sort((a, b) => a.name.localeCompare(b.name)),
23972
24093
  update: (id, input) => updatePlan2(id, input, store),
23973
- delete: (id, context) => store.delete("plans", id, context)
24094
+ delete: (id, context) => store.deletePlan(id, context)
23974
24095
  },
23975
24096
  agents: {
23976
24097
  register: (input, context) => registerAgent2(input, store, context),
@@ -24173,6 +24294,37 @@ class PostgresJsonRecordStore {
24173
24294
  const row = result.rows[0];
24174
24295
  return row ? payloadRecord2(row.payload) : null;
24175
24296
  }
24297
+ async resolveTaskRef(ref) {
24298
+ await this.ensureSchema();
24299
+ const raw = ref.trim().toLowerCase();
24300
+ if (!raw)
24301
+ return null;
24302
+ const lastCode = raw.charCodeAt(raw.length - 1);
24303
+ if (lastCode < 65535) {
24304
+ const upper = raw.slice(0, -1) + String.fromCharCode(lastCode + 1);
24305
+ const prefixResult = await this.options.client.query(`/* todos:resolve-task-ref-prefix */ SELECT payload FROM ${this.tableName}
24306
+ WHERE service = $1 AND object_type = 'tasks' AND deleted_at IS NULL
24307
+ AND object_id COLLATE "C" >= $2 AND object_id COLLATE "C" < $3
24308
+ LIMIT 2`, [this.service, raw, upper]);
24309
+ if (prefixResult.rows.length > 1) {
24310
+ throw new Error(`Task reference is ambiguous: "${ref}"`);
24311
+ }
24312
+ if (prefixResult.rows.length === 1) {
24313
+ return payloadRecord2(prefixResult.rows[0].payload);
24314
+ }
24315
+ }
24316
+ const shortIdResult = await this.options.client.query(`/* todos:resolve-task-ref-short-id */ SELECT payload FROM ${this.tableName}
24317
+ WHERE service = $1 AND object_type = 'tasks' AND deleted_at IS NULL
24318
+ AND LOWER(payload->>'short_id') = $2
24319
+ LIMIT 2`, [this.service, raw]);
24320
+ if (shortIdResult.rows.length > 1) {
24321
+ throw new Error(`Task reference is ambiguous: "${ref}"`);
24322
+ }
24323
+ if (shortIdResult.rows.length === 1) {
24324
+ return payloadRecord2(shortIdResult.rows[0].payload);
24325
+ }
24326
+ return null;
24327
+ }
24176
24328
  async countTasks(filter) {
24177
24329
  await this.ensureSchema();
24178
24330
  const { where, params } = this.buildTaskFilterSql(filter);
@@ -24254,6 +24406,62 @@ class PostgresJsonRecordStore {
24254
24406
  }
24255
24407
  return value;
24256
24408
  }
24409
+ async completeTask(id, agentId, options) {
24410
+ await this.ensureSchema();
24411
+ const operationTimestamp = new Date().toISOString();
24412
+ const completedAt2 = options?.completed_at ?? operationTimestamp;
24413
+ const evidence = options ? {
24414
+ ...options.files_changed !== undefined ? { files_changed: options.files_changed } : {},
24415
+ ...options.test_results !== undefined ? { test_results: options.test_results } : {},
24416
+ ...options.commit_hash !== undefined ? { commit_hash: options.commit_hash } : {},
24417
+ ...options.notes !== undefined ? { notes: options.notes } : {},
24418
+ ...options.attachment_ids !== undefined ? { attachment_ids: options.attachment_ids } : {}
24419
+ } : {};
24420
+ const hasEvidence = Object.keys(evidence).length > 0;
24421
+ const hasConfidence = options?.confidence !== undefined;
24422
+ const result = await this.options.client.query(`/* todos:complete-task-atomic */ UPDATE ${this.tableName}
24423
+ SET payload = payload || jsonb_build_object(
24424
+ 'status', 'completed',
24425
+ 'assigned_to', CASE
24426
+ WHEN jsonb_typeof(payload->'assigned_to') = 'string' THEN payload->'assigned_to'
24427
+ ELSE COALESCE(to_jsonb($3::text), 'null'::jsonb)
24428
+ END,
24429
+ 'completed_at', $4::text,
24430
+ 'updated_at', $9::text,
24431
+ 'version', COALESCE((payload->>'version')::integer, 0) + 1,
24432
+ 'metadata',
24433
+ (CASE WHEN jsonb_typeof(payload->'metadata') = 'object'
24434
+ THEN payload->'metadata' ELSE '{}'::jsonb END)
24435
+ || CASE WHEN $5::boolean THEN jsonb_build_object(
24436
+ '_evidence',
24437
+ (CASE WHEN jsonb_typeof(payload->'metadata'->'_evidence') = 'object'
24438
+ THEN payload->'metadata'->'_evidence' ELSE '{}'::jsonb END) || $6::jsonb
24439
+ ) ELSE '{}'::jsonb END
24440
+ || CASE WHEN $7::boolean THEN jsonb_build_object(
24441
+ '_completion',
24442
+ (CASE WHEN jsonb_typeof(payload->'metadata'->'_completion') = 'object'
24443
+ THEN payload->'metadata'->'_completion' ELSE '{}'::jsonb END)
24444
+ || jsonb_build_object('confidence', $8::double precision)
24445
+ ) ELSE '{}'::jsonb END
24446
+ ) || CASE WHEN $7::boolean
24447
+ THEN jsonb_build_object('confidence', $8::double precision)
24448
+ ELSE '{}'::jsonb END,
24449
+ updated_at = $9::timestamptz,
24450
+ version = COALESCE(version, 0) + 1
24451
+ WHERE service = $1 AND object_type = 'tasks' AND object_id = $2 AND deleted_at IS NULL
24452
+ RETURNING payload`, [
24453
+ this.service,
24454
+ id,
24455
+ agentId ?? null,
24456
+ completedAt2,
24457
+ hasEvidence,
24458
+ jsonbParam(evidence),
24459
+ hasConfidence,
24460
+ options?.confidence ?? null,
24461
+ operationTimestamp
24462
+ ]);
24463
+ return result.rows[0] ? payloadRecord2(result.rows[0].payload) : null;
24464
+ }
24257
24465
  async renameProject(id, newSlug, name, context = {}) {
24258
24466
  await this.ensureSchema();
24259
24467
  const normalizedSlug = slugifyRaw(newSlug);
@@ -24370,6 +24578,41 @@ class PostgresJsonRecordStore {
24370
24578
  version: numberValue3(existing["version"])
24371
24579
  }, context);
24372
24580
  }
24581
+ async deletePlan(id, context = {}) {
24582
+ await this.ensureSchema();
24583
+ const timestamp2 = new Date().toISOString();
24584
+ const result = await this.options.client.query(`/* todos:delete-plan-atomic */ WITH target AS (
24585
+ SELECT payload FROM ${this.tableName}
24586
+ WHERE service = $1 AND object_type = 'plans' AND object_id = $2 AND deleted_at IS NULL
24587
+ FOR UPDATE
24588
+ ), updated_tasks AS (
24589
+ UPDATE ${this.tableName} r SET
24590
+ payload = jsonb_set(
24591
+ jsonb_set(r.payload, '{plan_id}', 'null'::jsonb, true),
24592
+ '{version}',
24593
+ to_jsonb(COALESCE((r.payload->>'version')::int, 0) + 1),
24594
+ true
24595
+ ) || jsonb_build_object('updated_at', $3::text),
24596
+ updated_at = $3::timestamptz,
24597
+ source_machine_id = COALESCE($4, r.source_machine_id),
24598
+ version = COALESCE(r.version, 0) + 1
24599
+ WHERE r.service = $1 AND r.object_type = 'tasks' AND r.deleted_at IS NULL
24600
+ AND r.payload->>'plan_id' = $2 AND EXISTS (SELECT 1 FROM target)
24601
+ RETURNING 1
24602
+ ), deleted_plan AS (
24603
+ UPDATE ${this.tableName} r SET
24604
+ deleted_at = $3::timestamptz,
24605
+ updated_at = $3::timestamptz,
24606
+ source_machine_id = COALESCE($4, r.source_machine_id),
24607
+ version = COALESCE(r.version, 0) + 1
24608
+ FROM target
24609
+ WHERE r.service = $1 AND r.object_type = 'plans' AND r.object_id = $2 AND r.deleted_at IS NULL
24610
+ RETURNING 1
24611
+ ) SELECT
24612
+ EXISTS (SELECT 1 FROM target) AS found,
24613
+ (SELECT count(*) FROM updated_tasks) AS tasks_updated`, [this.service, id, timestamp2, this.machineId(context)]);
24614
+ return Boolean(result.rows[0]?.found);
24615
+ }
24373
24616
  async tombstone(tombstone, context = {}) {
24374
24617
  await this.ensureSchema();
24375
24618
  const deletedAt = stringValue2(tombstone.deleted_at) ?? new Date().toISOString();
@@ -24523,14 +24766,10 @@ async function startTask2(id, agentId, store) {
24523
24766
  }, store);
24524
24767
  }
24525
24768
  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);
24769
+ const task2 = await store.completeTask(id, agentId, options);
24770
+ if (!task2)
24771
+ throw new Error(`tasks record not found: ${id}`);
24772
+ return task2;
24534
24773
  }
24535
24774
  async function failTask2(id, agentId, reason, options, store) {
24536
24775
  const task2 = await requireRecord("tasks", id, store);
@@ -25104,8 +25343,9 @@ async function resolvePostgresPlanSlug(options) {
25104
25343
  const used = new Set(plans.filter((plan) => plan.project_id === options.projectId && plan.id !== options.excludeId && plan.slug).map((plan) => plan.slug));
25105
25344
  if (options.slug !== undefined) {
25106
25345
  const slug = normalizePlanSlug2(options.slug);
25107
- if (used.has(slug))
25108
- throw new Error(`Plan slug already exists in this scope: ${slug}`);
25346
+ if (used.has(slug)) {
25347
+ throw new ResourceConflictError("PLAN_SLUG_CONFLICT", `Plan slug already exists in this scope: ${slug}`);
25348
+ }
25109
25349
  return slug;
25110
25350
  }
25111
25351
  const base = planSlugBase4(options.name);
@@ -25143,13 +25383,22 @@ function numberValue3(value) {
25143
25383
  return typeof value === "number" && Number.isSafeInteger(value) ? value : null;
25144
25384
  }
25145
25385
  function isPostgresUniqueViolation(error) {
25146
- return typeof error === "object" && error !== null && error.code === "23505";
25386
+ if (typeof error !== "object" || error === null)
25387
+ return false;
25388
+ const candidate = error;
25389
+ const states = [candidate.code, candidate.errno, candidate.sqlState, candidate.sqlstate];
25390
+ if (typeof candidate.cause === "object" && candidate.cause !== null) {
25391
+ const cause = candidate.cause;
25392
+ states.push(cause.code, cause.errno, cause.sqlState, cause.sqlstate);
25393
+ }
25394
+ return states.some((state) => String(state) === "23505");
25147
25395
  }
25148
25396
  function postgresConstraintName(error) {
25149
25397
  if (typeof error !== "object" || error === null)
25150
25398
  return "";
25151
25399
  const candidate = error;
25152
- const constraint = candidate.constraint ?? candidate.constraint_name;
25400
+ const cause = typeof candidate.cause === "object" && candidate.cause !== null ? candidate.cause : undefined;
25401
+ const constraint = candidate.constraint ?? candidate.constraint_name ?? cause?.constraint ?? cause?.constraint_name;
25153
25402
  return typeof constraint === "string" ? constraint : "";
25154
25403
  }
25155
25404
 
@@ -27167,8 +27416,8 @@ init_task_crud();
27167
27416
  init_redaction();
27168
27417
  import { Database as Database3 } from "bun:sqlite";
27169
27418
  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";
27419
+ import { existsSync as existsSync9, readdirSync as readdirSync2, statSync as statSync4 } from "fs";
27420
+ import { basename as basename2, dirname as dirname6, join as join9, resolve as resolve10 } from "path";
27172
27421
 
27173
27422
  // src/lib/task-routing.ts
27174
27423
  init_database();
@@ -27176,7 +27425,7 @@ init_projects();
27176
27425
  init_task_crud();
27177
27426
  init_task_lifecycle();
27178
27427
  init_task_lists();
27179
- import { existsSync as existsSync9, statSync as statSync3 } from "fs";
27428
+ import { existsSync as existsSync8, statSync as statSync3 } from "fs";
27180
27429
  var DEFAULT_STALE_IN_PROGRESS_MS = 3 * 24 * 60 * 60 * 1000;
27181
27430
  var TERMINAL_WORKFLOW_STATES = new Set([
27182
27431
  "failed",
@@ -27231,7 +27480,7 @@ function routeConcurrencyKey(task2, project, taskList, projectPath) {
27231
27480
  }
27232
27481
  function directoryExists(path) {
27233
27482
  try {
27234
- return existsSync9(path) && statSync3(path).isDirectory();
27483
+ return existsSync8(path) && statSync3(path).isDirectory();
27235
27484
  } catch {
27236
27485
  return false;
27237
27486
  }
@@ -27432,7 +27681,7 @@ function pointerPatch(previous, input, key) {
27432
27681
 
27433
27682
  // src/lib/task-route-sources.ts
27434
27683
  var TASK_ROUTE_SOURCE_DISCOVERY_SCHEMA_VERSION = "todos.task_route_sources.v1";
27435
- var TODO_STORE_RELATIVE_PATH = join10(".hasna", "todos", "todos.db");
27684
+ var TODO_STORE_RELATIVE_PATH = join9(".hasna", "todos", "todos.db");
27436
27685
  var ROOT_SCAN_MAX_DEPTH = 5;
27437
27686
  var SKIPPED_SCAN_DIRS = new Set([
27438
27687
  ".git",
@@ -27455,9 +27704,9 @@ function sourceStoreId(sourceDbPath) {
27455
27704
  function inferSourceRepoPath(sourceDbPath) {
27456
27705
  const normalized = normalizePath3(sourceDbPath);
27457
27706
  if (normalized.endsWith(TODO_STORE_RELATIVE_PATH)) {
27458
- return dirname7(dirname7(dirname7(normalized)));
27707
+ return dirname6(dirname6(dirname6(normalized)));
27459
27708
  }
27460
- return dirname7(normalized);
27709
+ return dirname6(normalized);
27461
27710
  }
27462
27711
  function createStoreRef(sourceDbPath) {
27463
27712
  const normalized = normalizePath3(sourceDbPath);
@@ -27508,8 +27757,8 @@ function discoverStoresUnderRoot(sourceRoot) {
27508
27757
  const rootPath = normalizePath3(sourceRoot);
27509
27758
  const errors = [];
27510
27759
  const stores = [];
27511
- if (!existsSync10(rootPath)) {
27512
- const ref = createStoreRef(join10(rootPath, TODO_STORE_RELATIVE_PATH));
27760
+ if (!existsSync9(rootPath)) {
27761
+ const ref = createStoreRef(join9(rootPath, TODO_STORE_RELATIVE_PATH));
27513
27762
  errors.push({
27514
27763
  ...ref,
27515
27764
  code: "SOURCE_ROOT_MISSING",
@@ -27521,7 +27770,7 @@ function discoverStoresUnderRoot(sourceRoot) {
27521
27770
  try {
27522
27771
  rootStat = statSync4(rootPath);
27523
27772
  } catch (error) {
27524
- const ref = createStoreRef(join10(rootPath, TODO_STORE_RELATIVE_PATH));
27773
+ const ref = createStoreRef(join9(rootPath, TODO_STORE_RELATIVE_PATH));
27525
27774
  errors.push({
27526
27775
  ...ref,
27527
27776
  code: "SOURCE_ROOT_UNREADABLE",
@@ -27534,8 +27783,8 @@ function discoverStoresUnderRoot(sourceRoot) {
27534
27783
  return { stores, errors };
27535
27784
  }
27536
27785
  function scanDirectory(dir, depth) {
27537
- const candidate = join10(dir, TODO_STORE_RELATIVE_PATH);
27538
- if (existsSync10(candidate)) {
27786
+ const candidate = join9(dir, TODO_STORE_RELATIVE_PATH);
27787
+ if (existsSync9(candidate)) {
27539
27788
  stores.push(createStoreRef(candidate));
27540
27789
  }
27541
27790
  if (depth >= ROOT_SCAN_MAX_DEPTH)
@@ -27555,7 +27804,7 @@ function discoverStoresUnderRoot(sourceRoot) {
27555
27804
  for (const entry2 of entries) {
27556
27805
  if (!entry2.isDirectory() || SKIPPED_SCAN_DIRS.has(entry2.name))
27557
27806
  continue;
27558
- scanDirectory(join10(dir, entry2.name), depth + 1);
27807
+ scanDirectory(join9(dir, entry2.name), depth + 1);
27559
27808
  }
27560
27809
  }
27561
27810
  scanDirectory(rootPath, 0);
@@ -27581,7 +27830,7 @@ function collectStoreRefs(input) {
27581
27830
  };
27582
27831
  }
27583
27832
  function openReadonlyStore(ref) {
27584
- if (!existsSync10(ref.source_db_path)) {
27833
+ if (!existsSync9(ref.source_db_path)) {
27585
27834
  throw Object.assign(new Error(`Store does not exist: ${ref.source_db_path}`), { code: "STORE_MISSING" });
27586
27835
  }
27587
27836
  return new Database3(ref.source_db_path, { readonly: true, create: false });
@@ -27892,8 +28141,8 @@ init_plans();
27892
28141
  init_database();
27893
28142
  init_projects();
27894
28143
  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";
28144
+ import { existsSync as existsSync10, mkdirSync as mkdirSync8, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "fs";
28145
+ import { join as join10, resolve as resolve11 } from "path";
27897
28146
  var PLAN_MARKDOWN_SCHEMA = "hasna.todos.plan/v1";
27898
28147
  function assertSafePathSegment(value, label) {
27899
28148
  const trimmed = value.trim();
@@ -27955,7 +28204,7 @@ function resolvePlanArtifactPaths(input) {
27955
28204
  const project = resolvePlanArtifactProject(input);
27956
28205
  const projectId = assertSafePathSegment(project.id, "project id");
27957
28206
  const projectRoot = resolve11(project.path);
27958
- const directory = join11(projectRoot, ".hasna", "todos", "plans", projectId);
28207
+ const directory = join10(projectRoot, ".hasna", "todos", "plans", projectId);
27959
28208
  const planId = input.plan_id ? assertSafePathSegment(input.plan_id, "plan id") : null;
27960
28209
  const planSlug = input.plan_slug ? assertSafePathSegment(slugify(input.plan_slug), "plan slug") : null;
27961
28210
  const fileName = planId ? planSlug ? `${planSlug}--${planId.slice(0, 8)}.md` : `${planId}.md` : null;
@@ -27963,7 +28212,7 @@ function resolvePlanArtifactPaths(input) {
27963
28212
  project_id: project.id,
27964
28213
  project_root: projectRoot,
27965
28214
  directory,
27966
- file_path: fileName ? join11(directory, fileName) : directory
28215
+ file_path: fileName ? join10(directory, fileName) : directory
27967
28216
  };
27968
28217
  }
27969
28218
  function resolvePlanArtifactCandidatePaths(plan, db) {
@@ -28129,10 +28378,10 @@ function readPlanArtifact(plan, db) {
28129
28378
  return null;
28130
28379
  const d = db || getDatabase();
28131
28380
  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;
28381
+ const path = existsSync10(paths.primary.file_path) ? paths.primary.file_path : existsSync10(paths.legacy.file_path) ? paths.legacy.file_path : null;
28133
28382
  if (!path)
28134
28383
  return null;
28135
- const markdown = readFileSync7(path, "utf8");
28384
+ const markdown = readFileSync6(path, "utf8");
28136
28385
  return {
28137
28386
  path,
28138
28387
  markdown,
@@ -28144,7 +28393,7 @@ function inspectPlanArtifact(plan, db) {
28144
28393
  return null;
28145
28394
  const d = db || getDatabase();
28146
28395
  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;
28396
+ const path = existsSync10(paths.primary.file_path) ? paths.primary.file_path : existsSync10(paths.legacy.file_path) ? paths.legacy.file_path : null;
28148
28397
  if (!path) {
28149
28398
  return {
28150
28399
  path: paths.primary.file_path,
@@ -28156,7 +28405,7 @@ function inspectPlanArtifact(plan, db) {
28156
28405
  };
28157
28406
  }
28158
28407
  try {
28159
- const artifact = parsePlanArtifactMarkdown(readFileSync7(path, "utf8"));
28408
+ const artifact = parsePlanArtifactMarkdown(readFileSync6(path, "utf8"));
28160
28409
  return {
28161
28410
  path,
28162
28411
  exists: true,
@@ -29233,8 +29482,8 @@ function renderRetrospectiveMarkdown(record) {
29233
29482
  init_database();
29234
29483
  init_projects();
29235
29484
  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";
29485
+ import { existsSync as existsSync11, readFileSync as readFileSync7, statSync as statSync5 } from "fs";
29486
+ import { basename as basename3, dirname as dirname7, resolve as resolve12 } from "path";
29238
29487
  function safeStat(path) {
29239
29488
  try {
29240
29489
  return statSync5(path);
@@ -29246,15 +29495,15 @@ function canonicalPath(input) {
29246
29495
  const resolved = resolve12(input);
29247
29496
  const stats2 = safeStat(resolved);
29248
29497
  if (stats2?.isFile())
29249
- return dirname8(resolved);
29498
+ return dirname7(resolved);
29250
29499
  return resolved;
29251
29500
  }
29252
29501
  function findUp(start, marker) {
29253
29502
  let current = canonicalPath(start);
29254
29503
  while (true) {
29255
- if (existsSync12(resolve12(current, marker)))
29504
+ if (existsSync11(resolve12(current, marker)))
29256
29505
  return current;
29257
- const parent = dirname8(current);
29506
+ const parent = dirname7(current);
29258
29507
  if (parent === current)
29259
29508
  return null;
29260
29509
  current = parent;
@@ -29264,10 +29513,10 @@ function readPackageJson2(path) {
29264
29513
  if (!path)
29265
29514
  return null;
29266
29515
  const file = resolve12(path, "package.json");
29267
- if (!existsSync12(file))
29516
+ if (!existsSync11(file))
29268
29517
  return null;
29269
29518
  try {
29270
- const parsed = JSON.parse(readFileSync8(file, "utf-8"));
29519
+ const parsed = JSON.parse(readFileSync7(file, "utf-8"));
29271
29520
  return parsed && typeof parsed === "object" ? parsed : null;
29272
29521
  } catch {
29273
29522
  return null;
@@ -29286,7 +29535,7 @@ function workspaceMarker(root, rootPackage) {
29286
29535
  if (rootPackage?.workspaces)
29287
29536
  markers.push("package.json#workspaces");
29288
29537
  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)))
29538
+ if (existsSync11(resolve12(root, marker)))
29290
29539
  markers.push(marker);
29291
29540
  }
29292
29541
  const kind = markers.find((marker) => marker !== "bun.lock" && marker !== "bun.lockb") ?? null;
@@ -29624,21 +29873,21 @@ var gatherTrainingData = async (options = {}) => {
29624
29873
  };
29625
29874
  // src/lib/model-config.ts
29626
29875
  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";
29876
+ import { existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
29877
+ import { join as join11 } from "path";
29629
29878
  var DEFAULT_MODEL = "gpt-4o-mini";
29630
29879
  function getConfigDir() {
29631
29880
  return getTodosGlobalDir();
29632
29881
  }
29633
29882
  function getConfigPath2() {
29634
- return join12(getConfigDir(), "config.json");
29883
+ return join11(getConfigDir(), "config.json");
29635
29884
  }
29636
29885
  function readConfig() {
29637
29886
  const configPath = getConfigPath2();
29638
- if (!existsSync13(configPath))
29887
+ if (!existsSync12(configPath))
29639
29888
  return {};
29640
29889
  try {
29641
- const raw = readFileSync9(configPath, "utf-8");
29890
+ const raw = readFileSync8(configPath, "utf-8");
29642
29891
  return JSON.parse(raw);
29643
29892
  } catch {
29644
29893
  return {};
@@ -29646,7 +29895,7 @@ function readConfig() {
29646
29895
  }
29647
29896
  function writeConfig(config) {
29648
29897
  const configDir = getConfigDir();
29649
- if (!existsSync13(configDir)) {
29898
+ if (!existsSync12(configDir)) {
29650
29899
  mkdirSync9(configDir, { recursive: true });
29651
29900
  }
29652
29901
  writeFileSync7(getConfigPath2(), JSON.stringify(config, null, 2) + `
@@ -30391,7 +30640,7 @@ init_database();
30391
30640
  init_tasks();
30392
30641
  init_config2();
30393
30642
  init_redaction();
30394
- import { existsSync as existsSync14, readFileSync as readFileSync10 } from "fs";
30643
+ import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
30395
30644
  var DEFAULT_RETRY = {
30396
30645
  attempts: 1,
30397
30646
  backoff_ms: 0
@@ -30554,7 +30803,7 @@ Timed out after ${provider.timeout_ms}ms`);
30554
30803
  };
30555
30804
  }
30556
30805
  function runCiLogProvider(input) {
30557
- const text = input.log_text ?? (input.log_path && existsSync14(input.log_path) ? readFileSync10(input.log_path, "utf-8") : "");
30806
+ const text = input.log_text ?? (input.log_path && existsSync13(input.log_path) ? readFileSync9(input.log_path, "utf-8") : "");
30558
30807
  return {
30559
30808
  status: classifyLog(text),
30560
30809
  attempts: 1,
@@ -30566,7 +30815,7 @@ function runBrowserProvider(input) {
30566
30815
  if (!input.artifact_path) {
30567
30816
  return { status: "unknown", attempts: 1, exit_code: null, output_summary: "browser provider needs a screenshot or artifact path" };
30568
30817
  }
30569
- if (!existsSync14(input.artifact_path)) {
30818
+ if (!existsSync13(input.artifact_path)) {
30570
30819
  return { status: "failed", attempts: 1, exit_code: null, output_summary: `artifact not found: ${input.artifact_path}` };
30571
30820
  }
30572
30821
  return {
@@ -30731,7 +30980,7 @@ function listVerificationRecords(filter = {}, db) {
30731
30980
  // src/lib/verification-evidence.ts
30732
30981
  init_database();
30733
30982
  import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync10 } from "fs";
30734
- import { dirname as dirname9 } from "path";
30983
+ import { dirname as dirname8 } from "path";
30735
30984
  var VERIFICATION_EVIDENCE_SCHEMA = "todos.verification_evidence.v1";
30736
30985
  function getMachineId3() {
30737
30986
  return process.env["TODOS_MACHINE_ID"] || __require("os").hostname();
@@ -30851,7 +31100,7 @@ function exportVerificationEvidence(filter = {}, db) {
30851
31100
  };
30852
31101
  }
30853
31102
  function writeVerificationExport(bundle, path) {
30854
- mkdirSync10(dirname9(path), { recursive: true });
31103
+ mkdirSync10(dirname8(path), { recursive: true });
30855
31104
  writeFileSync8(path, JSON.stringify(bundle, null, 2), "utf8");
30856
31105
  }
30857
31106
  // src/lib/policy-packs.ts
@@ -31211,21 +31460,21 @@ function resourceDiagnostics() {
31211
31460
  };
31212
31461
  }
31213
31462
  // 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";
31463
+ import { existsSync as existsSync14, readFileSync as readFileSync10, writeFileSync as writeFileSync9, mkdirSync as mkdirSync11 } from "fs";
31464
+ import { join as join12, dirname as dirname9 } from "path";
31216
31465
  var SANDBOX_PROFILE_VERSION = "todos.sandbox-profile.v1";
31217
31466
  function getProfilesPath() {
31218
31467
  if (process.env["TODOS_SANDBOX_PROFILES_PATH"]) {
31219
31468
  return process.env["TODOS_SANDBOX_PROFILES_PATH"];
31220
31469
  }
31221
- const localDir = join13(process.cwd(), ".todos");
31222
- const local = join13(localDir, "sandbox-profiles.json");
31223
- if (existsSync15(localDir))
31470
+ const localDir = join12(process.cwd(), ".todos");
31471
+ const local = join12(localDir, "sandbox-profiles.json");
31472
+ if (existsSync14(localDir))
31224
31473
  return local;
31225
- if (existsSync15(local))
31474
+ if (existsSync14(local))
31226
31475
  return local;
31227
31476
  const home = process.env["HOME"] || "~";
31228
- return join13(home, ".hasna", "todos", "sandbox-profiles.json");
31477
+ return join12(home, ".hasna", "todos", "sandbox-profiles.json");
31229
31478
  }
31230
31479
  var cached2 = null;
31231
31480
  function resetSandboxProfileCache() {
@@ -31257,11 +31506,11 @@ function loadSandboxProfiles() {
31257
31506
  if (cached2)
31258
31507
  return cached2;
31259
31508
  const path = getProfilesPath();
31260
- if (!existsSync15(path)) {
31509
+ if (!existsSync14(path)) {
31261
31510
  cached2 = getDefaultSandboxProfiles();
31262
31511
  return cached2;
31263
31512
  }
31264
- const parsed = JSON.parse(readFileSync11(path, "utf8"));
31513
+ const parsed = JSON.parse(readFileSync10(path, "utf8"));
31265
31514
  cached2 = parsed.profiles?.length ? parsed.profiles : getDefaultSandboxProfiles();
31266
31515
  return cached2;
31267
31516
  }
@@ -31270,7 +31519,7 @@ function getSandboxProfile(name) {
31270
31519
  }
31271
31520
  function saveSandboxProfiles(profiles) {
31272
31521
  const path = getProfilesPath();
31273
- mkdirSync11(dirname10(path), { recursive: true });
31522
+ mkdirSync11(dirname9(path), { recursive: true });
31274
31523
  writeFileSync9(path, JSON.stringify({ schema_version: SANDBOX_PROFILE_VERSION, profiles }, null, 2));
31275
31524
  cached2 = profiles;
31276
31525
  }
@@ -31637,7 +31886,7 @@ init_task_commits();
31637
31886
 
31638
31887
  // src/lib/git-traceability.ts
31639
31888
  init_task_commits();
31640
- import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
31889
+ import { existsSync as existsSync15, readFileSync as readFileSync11 } from "fs";
31641
31890
  import { spawnSync as spawnSync2 } from "child_process";
31642
31891
  import { resolve as resolve14 } from "path";
31643
31892
  var GIT_TRACEABILITY_SCHEMA_VERSION = "todos.git_traceability.v1";
@@ -31683,10 +31932,10 @@ function inspectGitCommit(sha, cwd) {
31683
31932
  }
31684
31933
  function loadCiSnapshot(path) {
31685
31934
  const target = path ? resolve14(path) : resolve14(process.cwd(), ".todos", "ci-snapshot.json");
31686
- if (!existsSync16(target))
31935
+ if (!existsSync15(target))
31687
31936
  return null;
31688
31937
  try {
31689
- const parsed = JSON.parse(readFileSync12(target, "utf8"));
31938
+ const parsed = JSON.parse(readFileSync11(target, "utf8"));
31690
31939
  return { ...parsed, captured_at: parsed.captured_at ?? new Date().toISOString() };
31691
31940
  } catch {
31692
31941
  return null;
@@ -31779,8 +32028,8 @@ function formatTraceabilityReport(report) {
31779
32028
  `);
31780
32029
  }
31781
32030
  // 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";
32031
+ import { existsSync as existsSync16, readdirSync as readdirSync3, readFileSync as readFileSync12, statSync as statSync6 } from "fs";
32032
+ import { basename as basename4, isAbsolute, join as join13, relative as relative4, resolve as resolve15, sep as sep2 } from "path";
31784
32033
  init_database();
31785
32034
  init_plans();
31786
32035
  init_task_runs();
@@ -31934,7 +32183,7 @@ function resolveFile(parsed, workspace) {
31934
32183
  return resolution;
31935
32184
  }
31936
32185
  resolution.path = relPath;
31937
- if (!existsSync17(absolutePath)) {
32186
+ if (!existsSync16(absolutePath)) {
31938
32187
  resolution.warnings.push("file does not exist in the local workspace");
31939
32188
  return resolution;
31940
32189
  }
@@ -31944,7 +32193,7 @@ function resolveFile(parsed, workspace) {
31944
32193
  return resolution;
31945
32194
  }
31946
32195
  if (parsed.line !== undefined) {
31947
- const lineCount = readFileSync13(absolutePath, "utf-8").split(/\r?\n/).length;
32196
+ const lineCount = readFileSync12(absolutePath, "utf-8").split(/\r?\n/).length;
31948
32197
  if (parsed.line < 1 || parsed.line > lineCount) {
31949
32198
  resolution.warnings.push(`line ${parsed.line} is outside the file range 1-${lineCount}`);
31950
32199
  return resolution;
@@ -31967,7 +32216,7 @@ function walkSourceFiles(root, current = root, files = []) {
31967
32216
  if (SKIP_DIRS.has(entry2.name))
31968
32217
  continue;
31969
32218
  }
31970
- const absolutePath = join14(current, entry2.name);
32219
+ const absolutePath = join13(current, entry2.name);
31971
32220
  if (entry2.isDirectory()) {
31972
32221
  if (!SKIP_DIRS.has(entry2.name))
31973
32222
  walkSourceFiles(root, absolutePath, files);
@@ -31997,7 +32246,7 @@ function resolveSymbol(parsed, workspace, maxMatches) {
31997
32246
  const pattern = symbolPattern(name);
31998
32247
  const matches = [];
31999
32248
  for (const file of walkSourceFiles(workspace)) {
32000
- const lines = readFileSync13(file, "utf-8").split(/\r?\n/);
32249
+ const lines = readFileSync12(file, "utf-8").split(/\r?\n/);
32001
32250
  for (let index = 0;index < lines.length; index += 1) {
32002
32251
  const line = lines[index];
32003
32252
  const found = pattern.exec(line);
@@ -33865,7 +34114,7 @@ function getAdapterDocsFingerprint() {
33865
34114
  // src/lib/inbox-intake.ts
33866
34115
  init_database();
33867
34116
  init_tasks();
33868
- import { existsSync as existsSync18, readFileSync as readFileSync14 } from "fs";
34117
+ import { existsSync as existsSync17, readFileSync as readFileSync13 } from "fs";
33869
34118
  import { basename as basename5 } from "path";
33870
34119
  import { createHash as createHash12 } from "crypto";
33871
34120
  init_secret_redaction();
@@ -33911,9 +34160,9 @@ function loadRawContent(input) {
33911
34160
  }
33912
34161
  }
33913
34162
  if (input.file_path) {
33914
- if (!existsSync18(input.file_path))
34163
+ if (!existsSync17(input.file_path))
33915
34164
  throw new Error(`File not found: ${input.file_path}`);
33916
- const raw = readFileSync14(input.file_path, "utf8");
34165
+ const raw = readFileSync13(input.file_path, "utf8");
33917
34166
  const name = basename5(input.file_path).toLowerCase();
33918
34167
  const source_type2 = input.source_type ?? (name.includes("ci") || name.endsWith(".log") ? "ci_log" : "file");
33919
34168
  return {
@@ -34532,7 +34781,7 @@ function formatNlIntakePreviewText(preview) {
34532
34781
  // src/lib/issue-importers.ts
34533
34782
  init_database();
34534
34783
  init_tasks();
34535
- import { existsSync as existsSync19, readFileSync as readFileSync15 } from "fs";
34784
+ import { existsSync as existsSync18, readFileSync as readFileSync14 } from "fs";
34536
34785
  var ISSUE_IMPORT_SCHEMA = "todos.issue_import.v1";
34537
34786
  var ISSUE_SOURCES = ["github", "linear", "jira", "auto"];
34538
34787
  var GITHUB_LABEL_PRIORITY = {
@@ -34751,9 +35000,9 @@ function parseIssueExport(data, source9 = "auto") {
34751
35000
  return normalized;
34752
35001
  }
34753
35002
  function loadIssueExportFromFile(path) {
34754
- if (!existsSync19(path))
35003
+ if (!existsSync18(path))
34755
35004
  throw new Error(`File not found: ${path}`);
34756
- return JSON.parse(readFileSync15(path, "utf8"));
35005
+ return JSON.parse(readFileSync14(path, "utf8"));
34757
35006
  }
34758
35007
  function loadIssueExportInput(input) {
34759
35008
  if (input.file_path) {
@@ -34911,8 +35160,8 @@ todos import issues ./linear.json --source linear --dry-run
34911
35160
  // src/lib/run-records.ts
34912
35161
  init_database();
34913
35162
  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";
35163
+ import { existsSync as existsSync19, mkdirSync as mkdirSync12, writeFileSync as writeFileSync10 } from "fs";
35164
+ import { join as join14, dirname as dirname10 } from "path";
34916
35165
  var RUN_RECORD_SCHEMA = "todos.run_record.v1";
34917
35166
  var RUN_RECORD_STATUSES = ["active", "completed", "failed", "archived"];
34918
35167
  function parseJsonArray3(raw, fallback = []) {
@@ -35105,8 +35354,8 @@ function buildRunReplayBundle(id, db) {
35105
35354
  }
35106
35355
  function exportRunReplay(id, outputPath, db) {
35107
35356
  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 });
35357
+ const path = outputPath ?? join14(process.cwd(), ".todos", "replays", `${id.slice(0, 8)}.json`);
35358
+ mkdirSync12(dirname10(path), { recursive: true });
35110
35359
  writeFileSync10(path, JSON.stringify(bundle, null, 2));
35111
35360
  const d = db || getDatabase();
35112
35361
  d.run(`UPDATE run_records SET replay_bundle = ?, updated_at = ? WHERE id = ?`, [path, now(), id]);
@@ -35145,16 +35394,16 @@ function formatRunRecordMarkdown(record) {
35145
35394
  `;
35146
35395
  }
35147
35396
  function getDefaultReplayDir() {
35148
- const local = join15(process.cwd(), ".todos", "replays");
35149
- if (existsSync20(join15(process.cwd(), ".todos")))
35397
+ const local = join14(process.cwd(), ".todos", "replays");
35398
+ if (existsSync19(join14(process.cwd(), ".todos")))
35150
35399
  return local;
35151
35400
  const home = process.env["HOME"] || "~";
35152
- return join15(home, ".hasna", "todos", "replays");
35401
+ return join14(home, ".hasna", "todos", "replays");
35153
35402
  }
35154
35403
  // src/lib/release-checks.ts
35155
35404
  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";
35405
+ import { existsSync as existsSync20, readFileSync as readFileSync15, readdirSync as readdirSync4, statSync as statSync7 } from "fs";
35406
+ import { join as join15, relative as relative5 } from "path";
35158
35407
  var RELEASE_CHECK_SCHEMA = "todos.release_check.v1";
35159
35408
  var FORBIDDEN_DIST_PATTERNS = [
35160
35409
  {
@@ -35167,16 +35416,16 @@ var FORBIDDEN_DIST_PATTERNS = [
35167
35416
  ];
35168
35417
  var REQUIRED_BINS = ["todos", "todos-mcp", "todos-serve"];
35169
35418
  function readPackageJson3(root) {
35170
- const path = join16(root, "package.json");
35171
- if (!existsSync21(path))
35419
+ const path = join15(root, "package.json");
35420
+ if (!existsSync20(path))
35172
35421
  throw new Error(`package.json not found in ${root}`);
35173
- return JSON.parse(readFileSync16(path, "utf8"));
35422
+ return JSON.parse(readFileSync15(path, "utf8"));
35174
35423
  }
35175
35424
  function walkFiles(dir, acc = []) {
35176
- if (!existsSync21(dir))
35425
+ if (!existsSync20(dir))
35177
35426
  return acc;
35178
35427
  for (const entry2 of readdirSync4(dir)) {
35179
- const full = join16(dir, entry2);
35428
+ const full = join15(dir, entry2);
35180
35429
  const st = statSync7(full);
35181
35430
  if (st.isDirectory())
35182
35431
  walkFiles(full, acc);
@@ -35194,8 +35443,8 @@ function auditPackageContents(root) {
35194
35443
  checks.push({ id: "files_dist", severity: "error", message: "package.json files must include dist" });
35195
35444
  }
35196
35445
  for (const pattern of files) {
35197
- const target = join16(root, pattern);
35198
- if (!existsSync21(target)) {
35446
+ const target = join15(root, pattern);
35447
+ if (!existsSync20(target)) {
35199
35448
  checks.push({ id: `files_missing_${pattern}`, severity: "error", message: `Published file path missing: ${pattern}` });
35200
35449
  }
35201
35450
  }
@@ -35209,8 +35458,8 @@ function auditPackageContents(root) {
35209
35458
  checks.push({ id: `bin_${name}`, severity: "error", message: `Missing bin entry: ${name}` });
35210
35459
  continue;
35211
35460
  }
35212
- const binPath = join16(root, rel);
35213
- if (!existsSync21(binPath)) {
35461
+ const binPath = join15(root, rel);
35462
+ if (!existsSync20(binPath)) {
35214
35463
  checks.push({ id: `bin_path_${name}`, severity: "error", message: `Bin file missing: ${rel}` });
35215
35464
  } else {
35216
35465
  checks.push({ id: `bin_ok_${name}`, severity: "info", message: `Bin present: ${name} \u2192 ${rel}` });
@@ -35227,8 +35476,8 @@ function auditPackageContents(root) {
35227
35476
  }
35228
35477
  function scanDistArtifacts(root) {
35229
35478
  const checks = [];
35230
- const distDir = join16(root, "dist");
35231
- if (!existsSync21(distDir)) {
35479
+ const distDir = join15(root, "dist");
35480
+ if (!existsSync20(distDir)) {
35232
35481
  checks.push({ id: "dist_missing", severity: "error", message: "dist/ directory not found \u2014 run bun run build" });
35233
35482
  return checks;
35234
35483
  }
@@ -35236,7 +35485,7 @@ function scanDistArtifacts(root) {
35236
35485
  const rel = relative5(root, file);
35237
35486
  let content;
35238
35487
  try {
35239
- content = readFileSync16(file, "utf8");
35488
+ content = readFileSync15(file, "utf8");
35240
35489
  } catch {
35241
35490
  continue;
35242
35491
  }
@@ -35538,8 +35787,8 @@ function renderReleaseNotesMarkdown(document) {
35538
35787
  // src/lib/db-backup.ts
35539
35788
  init_database();
35540
35789
  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";
35790
+ import { existsSync as existsSync21, copyFileSync, mkdirSync as mkdirSync13, readFileSync as readFileSync16, renameSync, statSync as statSync8, writeFileSync as writeFileSync11, unlinkSync } from "fs";
35791
+ import { dirname as dirname11, join as join16, resolve as resolve16 } from "path";
35543
35792
  import { Database as Database4 } from "bun:sqlite";
35544
35793
  var DB_BACKUP_SCHEMA = "todos.db_backup.v1";
35545
35794
  function resolveDbPath(dbPath) {
@@ -35556,9 +35805,9 @@ function resolveDbPath(dbPath) {
35556
35805
  }
35557
35806
  function backupDatabase(outputPath, sourcePath) {
35558
35807
  const source9 = resolveDbPath(sourcePath);
35559
- if (!existsSync22(source9))
35808
+ if (!existsSync21(source9))
35560
35809
  throw new Error(`Database not found: ${source9}`);
35561
- mkdirSync13(dirname12(outputPath), { recursive: true });
35810
+ mkdirSync13(dirname11(outputPath), { recursive: true });
35562
35811
  closeDatabase();
35563
35812
  const src = new Database4(source9);
35564
35813
  try {
@@ -35579,14 +35828,14 @@ function backupDatabase(outputPath, sourcePath) {
35579
35828
  };
35580
35829
  }
35581
35830
  function restoreDatabase(backupPath, targetPath) {
35582
- if (!existsSync22(backupPath))
35831
+ if (!existsSync21(backupPath))
35583
35832
  throw new Error(`Backup not found: ${backupPath}`);
35584
35833
  const integrity = checkDatabaseIntegrity(backupPath);
35585
35834
  if (!integrity.ok) {
35586
35835
  throw new Error(`Backup failed integrity check: ${integrity.errors.join("; ")}`);
35587
35836
  }
35588
35837
  const target = targetPath ? resolve16(targetPath) : resolveDbPath();
35589
- mkdirSync13(dirname12(target), { recursive: true });
35838
+ mkdirSync13(dirname11(target), { recursive: true });
35590
35839
  closeDatabase();
35591
35840
  const staging = `${target}.restore.tmp`;
35592
35841
  try {
@@ -35595,7 +35844,7 @@ function restoreDatabase(backupPath, targetPath) {
35595
35844
  copyFileSync(backupPath, staging);
35596
35845
  for (const sidecar of [`${target}-wal`, `${target}-shm`]) {
35597
35846
  try {
35598
- if (existsSync22(sidecar))
35847
+ if (existsSync21(sidecar))
35599
35848
  unlinkSync(sidecar);
35600
35849
  } catch {}
35601
35850
  }
@@ -35612,7 +35861,7 @@ function restoreDatabase(backupPath, targetPath) {
35612
35861
  function checkDatabaseIntegrity(dbPath) {
35613
35862
  const path = dbPath ? resolve16(dbPath) : resolveDbPath();
35614
35863
  const errors = [];
35615
- if (!existsSync22(path)) {
35864
+ if (!existsSync21(path)) {
35616
35865
  return {
35617
35866
  schema_version: DB_BACKUP_SCHEMA,
35618
35867
  path,
@@ -35709,16 +35958,16 @@ function migrationDryRun(dbPath) {
35709
35958
  };
35710
35959
  }
35711
35960
  function defaultBackupPath(dbPath) {
35712
- const base = dbPath ? dirname12(resolve16(dbPath)) : dirname12(resolveDbPath());
35961
+ const base = dbPath ? dirname11(resolve16(dbPath)) : dirname11(resolveDbPath());
35713
35962
  const stamp = new Date().toISOString().replace(/[:.]/g, "-");
35714
- return join17(base, "backups", `todos-${stamp}.db`);
35963
+ return join16(base, "backups", `todos-${stamp}.db`);
35715
35964
  }
35716
35965
  function readBackupManifest(backupPath) {
35717
35966
  const manifestPath = `${backupPath}.json`;
35718
- if (!existsSync22(manifestPath))
35967
+ if (!existsSync21(manifestPath))
35719
35968
  return null;
35720
35969
  try {
35721
- return JSON.parse(readFileSync17(manifestPath, "utf8"));
35970
+ return JSON.parse(readFileSync16(manifestPath, "utf8"));
35722
35971
  } catch {
35723
35972
  return null;
35724
35973
  }
@@ -35728,7 +35977,7 @@ function writeBackupManifest(backupPath, result) {
35728
35977
  writeFileSyncSafe(manifestPath, JSON.stringify(result, null, 2));
35729
35978
  }
35730
35979
  function writeFileSyncSafe(path, content) {
35731
- mkdirSync13(dirname12(path), { recursive: true });
35980
+ mkdirSync13(dirname11(path), { recursive: true });
35732
35981
  writeFileSync11(path, content);
35733
35982
  }
35734
35983
  // src/lib/json-schemas.ts
@@ -36236,15 +36485,15 @@ ${SCHEMA_ENTITIES.map((e) => `- **${e}**: \`${JSON_SCHEMAS[e].schema_version}\``
36236
36485
  }
36237
36486
  function exportSchemasToDirectory(dir) {
36238
36487
  const { mkdirSync: mkdirSync14, writeFileSync: writeFileSync12 } = __require("fs");
36239
- const { join: join18 } = __require("path");
36488
+ const { join: join17 } = __require("path");
36240
36489
  mkdirSync14(dir, { recursive: true });
36241
36490
  const written = [];
36242
36491
  for (const entity of SCHEMA_ENTITIES) {
36243
- const path = join18(dir, `${entity}.${JSON_SCHEMAS[entity].schema_version.replace(/\./g, "-")}.json`);
36492
+ const path = join17(dir, `${entity}.${JSON_SCHEMAS[entity].schema_version.replace(/\./g, "-")}.json`);
36244
36493
  writeFileSync12(path, JSON.stringify(JSON_SCHEMAS[entity], null, 2));
36245
36494
  written.push(path);
36246
36495
  }
36247
- const catalogPath = join18(dir, "catalog.json");
36496
+ const catalogPath = join17(dir, "catalog.json");
36248
36497
  writeFileSync12(catalogPath, JSON.stringify({
36249
36498
  catalog_version: JSON_SCHEMA_CATALOG_VERSION,
36250
36499
  semver: SCHEMA_SEMVER,
@@ -37159,8 +37408,8 @@ init_tasks();
37159
37408
  init_plans();
37160
37409
  init_comments();
37161
37410
  init_templates();
37162
- import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, mkdirSync as mkdirSync14 } from "fs";
37163
- import { dirname as dirname13 } from "path";
37411
+ import { readFileSync as readFileSync17, writeFileSync as writeFileSync12, mkdirSync as mkdirSync14 } from "fs";
37412
+ import { dirname as dirname12 } from "path";
37164
37413
  init_secret_redaction();
37165
37414
  var BUNDLE_SCHEMA = "todos.bundle.v1";
37166
37415
  var BUNDLE_TYPES = ["full_export", "tasks", "partial"];
@@ -37568,11 +37817,11 @@ function importBundle(bundle, options = {}, db) {
37568
37817
  return result;
37569
37818
  }
37570
37819
  function writeBundleFile(bundle, path) {
37571
- mkdirSync14(dirname13(path), { recursive: true });
37820
+ mkdirSync14(dirname12(path), { recursive: true });
37572
37821
  writeFileSync12(path, JSON.stringify(bundle, null, 2), "utf8");
37573
37822
  }
37574
37823
  function readBundleFile(path) {
37575
- const raw = JSON.parse(readFileSync18(path, "utf8"));
37824
+ const raw = JSON.parse(readFileSync17(path, "utf8"));
37576
37825
  const validation = validateBundle(raw);
37577
37826
  if (!validation.valid)
37578
37827
  throw new Error(`Invalid bundle file: ${validation.errors.join("; ")}`);
@@ -38059,7 +38308,7 @@ init_plans();
38059
38308
  init_tasks();
38060
38309
  init_comments();
38061
38310
  import { writeFileSync as writeFileSync13, mkdirSync as mkdirSync15 } from "fs";
38062
- import { dirname as dirname14 } from "path";
38311
+ import { dirname as dirname13 } from "path";
38063
38312
  init_task_commits();
38064
38313
  var HANDOFF_PACKET_SCHEMA = "todos.handoff_packet.v1";
38065
38314
  function summarizeTask2(t) {
@@ -38234,7 +38483,7 @@ function formatHandoffPacket(packet, format = "json") {
38234
38483
  function exportHandoffPacket(input = {}, path, db) {
38235
38484
  const packet = createHandoffPacket(input, db);
38236
38485
  if (path) {
38237
- mkdirSync15(dirname14(path), { recursive: true });
38486
+ mkdirSync15(dirname13(path), { recursive: true });
38238
38487
  writeFileSync13(path, formatHandoffPacket(packet, "json"), "utf8");
38239
38488
  }
38240
38489
  return packet;
@@ -38848,7 +39097,7 @@ init_templates();
38848
39097
  init_database();
38849
39098
  init_templates();
38850
39099
  import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync14 } from "fs";
38851
- import { join as join18 } from "path";
39100
+ import { join as join17 } from "path";
38852
39101
  var BUILTIN_TEMPLATE_LIBRARY_VERSION = "2026-05-21";
38853
39102
  var BUILTIN_TEMPLATE_LIBRARY_SOURCE = "bundled-local-template-library";
38854
39103
  var TEMPLATE_LIBRARY_SCHEMA = "todos.template_library.v1";
@@ -39124,7 +39373,7 @@ function writeBuiltinTemplateFiles(directory) {
39124
39373
  mkdirSync16(directory, { recursive: true });
39125
39374
  const files = [];
39126
39375
  for (const entry2 of exportBuiltinTemplateFiles()) {
39127
- const path = join18(directory, entry2.filename);
39376
+ const path = join17(directory, entry2.filename);
39128
39377
  writeFileSync14(path, `${JSON.stringify(entry2.template, null, 2)}
39129
39378
  `, "utf-8");
39130
39379
  files.push(path);
@@ -39168,8 +39417,8 @@ function initBuiltinTemplates(db) {
39168
39417
  }
39169
39418
  // src/lib/template-library.ts
39170
39419
  init_database();
39171
- import { writeFileSync as writeFileSync15, readFileSync as readFileSync19, mkdirSync as mkdirSync17 } from "fs";
39172
- import { dirname as dirname15 } from "path";
39420
+ import { writeFileSync as writeFileSync15, readFileSync as readFileSync18, mkdirSync as mkdirSync17 } from "fs";
39421
+ import { dirname as dirname14 } from "path";
39173
39422
  init_templates();
39174
39423
  function listTemplateLibrary(db) {
39175
39424
  const d = db || getDatabase();
@@ -39212,7 +39461,7 @@ function exportTemplateLibraryCatalog(path, db) {
39212
39461
  templates: listTemplateLibrary(db)
39213
39462
  };
39214
39463
  if (path) {
39215
- mkdirSync17(dirname15(path), { recursive: true });
39464
+ mkdirSync17(dirname14(path), { recursive: true });
39216
39465
  writeFileSync15(path, JSON.stringify(catalog, null, 2), "utf8");
39217
39466
  }
39218
39467
  return catalog;
@@ -39230,7 +39479,7 @@ function exportInstalledTemplate(name, db) {
39230
39479
  }
39231
39480
  function importTemplateFromFile(path, db) {
39232
39481
  const d = db || getDatabase();
39233
- const raw = JSON.parse(readFileSync19(path, "utf8"));
39482
+ const raw = JSON.parse(readFileSync18(path, "utf8"));
39234
39483
  const payload = raw.template ?? raw;
39235
39484
  const created = importTemplate(payload, d);
39236
39485
  return { id: created.id, name: created.name };
@@ -39416,9 +39665,9 @@ init_tasks();
39416
39665
  init_redaction();
39417
39666
  init_sync_utils();
39418
39667
  import { createHash as createHash13 } from "crypto";
39419
- import { existsSync as existsSync23, readFileSync as readFileSync20, statSync as statSync9 } from "fs";
39668
+ import { existsSync as existsSync22, readFileSync as readFileSync19, statSync as statSync9 } from "fs";
39420
39669
  import { hostname as hostname3, platform, arch } from "os";
39421
- import { dirname as dirname16, join as join19, resolve as resolve17 } from "path";
39670
+ import { dirname as dirname15, join as join18, resolve as resolve17 } from "path";
39422
39671
  import { tmpdir as tmpdir3 } from "os";
39423
39672
  var MANIFEST_FILES = ["package.json", "dashboard/package.json", "sdk/package.json"];
39424
39673
  var LOCKFILES = ["bun.lock", "bun.lockb", "package-lock.json", "npm-shrinkwrap.json"];
@@ -39440,20 +39689,20 @@ function sha2565(value) {
39440
39689
  return createHash13("sha256").update(value).digest("hex");
39441
39690
  }
39442
39691
  function fileRecord(root, relativePath) {
39443
- const path = join19(root, relativePath);
39444
- if (!existsSync23(path))
39692
+ const path = join18(root, relativePath);
39693
+ if (!existsSync22(path))
39445
39694
  return null;
39446
39695
  const stat = statSync9(path);
39447
39696
  if (!stat.isFile())
39448
39697
  return null;
39449
- const content = readFileSync20(path);
39698
+ const content = readFileSync19(path);
39450
39699
  return { path: relativePath, sha256: sha2565(content), size_bytes: content.length };
39451
39700
  }
39452
39701
  function manifestRecord(root, relativePath) {
39453
39702
  const base = fileRecord(root, relativePath);
39454
39703
  if (!base)
39455
39704
  return null;
39456
- const parsed = readJsonFile(join19(root, relativePath));
39705
+ const parsed = readJsonFile(join18(root, relativePath));
39457
39706
  if (!parsed)
39458
39707
  return { ...base, redacted: {} };
39459
39708
  const redacted = redactValue({
@@ -39548,8 +39797,8 @@ function commandEnv(env, includeValues) {
39548
39797
  function defaultSnapshotDir() {
39549
39798
  const dbPath = getDatabasePath();
39550
39799
  if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
39551
- return join19(tmpdir3(), "hasna-todos", "environment-snapshots");
39552
- return join19(dirname16(resolve17(dbPath)), "environment-snapshots");
39800
+ return join18(tmpdir3(), "hasna-todos", "environment-snapshots");
39801
+ return join18(dirname15(resolve17(dbPath)), "environment-snapshots");
39553
39802
  }
39554
39803
  function snapshotWithId(snapshot) {
39555
39804
  const digest = sha2565(JSON.stringify(snapshot)).slice(0, 24);
@@ -39596,8 +39845,8 @@ function captureEnvironmentSnapshot(input = {}) {
39596
39845
  });
39597
39846
  }
39598
39847
  function writeEnvironmentSnapshot(snapshot, outputPath) {
39599
- const path = outputPath ? resolve17(outputPath) : join19(defaultSnapshotDir(), `${snapshot.id}.json`);
39600
- ensureDir2(dirname16(path));
39848
+ const path = outputPath ? resolve17(outputPath) : join18(defaultSnapshotDir(), `${snapshot.id}.json`);
39849
+ ensureDir2(dirname15(path));
39601
39850
  writeJsonFile(path, snapshot);
39602
39851
  return path;
39603
39852
  }
@@ -39691,7 +39940,7 @@ init_projects();
39691
39940
  init_plans();
39692
39941
  import { createHash as createHash14 } from "crypto";
39693
39942
  import { mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
39694
- import { dirname as dirname17, join as join20 } from "path";
39943
+ import { dirname as dirname16, join as join19 } from "path";
39695
39944
  var DECISION_RECORD_SCHEMA = "todos.decision_record.v1";
39696
39945
  var KNOWLEDGE_SNAPSHOT_SCHEMA = "todos.knowledge_snapshot.v1";
39697
39946
  var DECISION_STATUSES = ["proposed", "accepted", "deprecated", "superseded", "rejected"];
@@ -39921,8 +40170,8 @@ function exportDecisionRecord(id, outputPath, format = "markdown", db) {
39921
40170
  if (!record)
39922
40171
  throw new Error(`Decision record not found: ${id}`);
39923
40172
  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 });
40173
+ const path = outputPath ?? join19(process.cwd(), ".todos", "decisions", `${record.short_ref}.${format === "markdown" ? "md" : "json"}`);
40174
+ mkdirSync18(dirname16(path), { recursive: true });
39926
40175
  writeFileSync16(path, content, "utf8");
39927
40176
  return { path, content };
39928
40177
  }
@@ -40069,8 +40318,8 @@ function exportKnowledgeSnapshot(id, outputPath, format = "markdown", db) {
40069
40318
  throw new Error(`Knowledge snapshot not found: ${id}`);
40070
40319
  const content = format === "markdown" ? formatKnowledgeSnapshotMarkdown(record) : JSON.stringify(record, null, 2);
40071
40320
  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 });
40321
+ const path = outputPath ?? join19(process.cwd(), ".todos", "knowledge", `${slug || record.id.slice(0, 8)}.${format === "markdown" ? "md" : "json"}`);
40322
+ mkdirSync18(dirname16(path), { recursive: true });
40074
40323
  writeFileSync16(path, content, "utf8");
40075
40324
  return { path, content };
40076
40325
  }
@@ -40103,7 +40352,7 @@ init_tasks();
40103
40352
  init_task_status();
40104
40353
  init_secret_redaction();
40105
40354
  import { writeFileSync as writeFileSync17, mkdirSync as mkdirSync19 } from "fs";
40106
- import { dirname as dirname18 } from "path";
40355
+ import { dirname as dirname17 } from "path";
40107
40356
  var REPORT_EXPORT_SCHEMA = "todos.report_export.v1";
40108
40357
  var REPORT_KINDS = ["project", "plan", "run", "evidence", "roadmap", "retrospective"];
40109
40358
  var REPORT_FORMATS = ["markdown", "html"];
@@ -40334,7 +40583,7 @@ function formatReportExport(data, format) {
40334
40583
  return format === "html" ? formatReportHtml(data) : formatReportMarkdown(data);
40335
40584
  }
40336
40585
  function writeReportExport(data, format, path) {
40337
- mkdirSync19(dirname18(path), { recursive: true });
40586
+ mkdirSync19(dirname17(path), { recursive: true });
40338
40587
  writeFileSync17(path, formatReportExport(data, format), "utf8");
40339
40588
  }
40340
40589
  function exportReport(input, db) {
@@ -40368,8 +40617,8 @@ todos report export --kind retrospective --days 14 --format markdown --out retro
40368
40617
  `;
40369
40618
  }
40370
40619
  // 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";
40620
+ import { existsSync as existsSync23, readFileSync as readFileSync20, writeFileSync as writeFileSync18, mkdirSync as mkdirSync20 } from "fs";
40621
+ import { join as join20 } from "path";
40373
40622
  var COMMAND_ALIASES_SCHEMA = "todos.command_aliases.v1";
40374
40623
  var RESERVED = new Set([...listTopLevelCommands(), "help", "version", "alias", "shortcuts"]);
40375
40624
  var BUILTIN_SHORTCUTS = [
@@ -40388,7 +40637,7 @@ var BUILTIN_SHORTCUTS = [
40388
40637
  { pattern: /^reports?$/, argv: ["report", "docs"], explain: "Report export documentation" }
40389
40638
  ];
40390
40639
  function aliasesPath(cwd = process.cwd()) {
40391
- return join21(cwd, ".todos", "aliases.json");
40640
+ return join20(cwd, ".todos", "aliases.json");
40392
40641
  }
40393
40642
  function emptyStore() {
40394
40643
  return { schema_version: COMMAND_ALIASES_SCHEMA, aliases: {}, updated_at: new Date(0).toISOString() };
@@ -40405,9 +40654,9 @@ function validateAliasName(name) {
40405
40654
  }
40406
40655
  function loadAliasStore(cwd) {
40407
40656
  const path = aliasesPath(cwd);
40408
- if (!existsSync24(path))
40657
+ if (!existsSync23(path))
40409
40658
  return emptyStore();
40410
- const parsed = JSON.parse(readFileSync21(path, "utf8"));
40659
+ const parsed = JSON.parse(readFileSync20(path, "utf8"));
40411
40660
  if (parsed.schema_version !== COMMAND_ALIASES_SCHEMA) {
40412
40661
  throw new Error(`Unsupported alias store schema: ${parsed.schema_version}`);
40413
40662
  }
@@ -40415,7 +40664,7 @@ function loadAliasStore(cwd) {
40415
40664
  }
40416
40665
  function saveAliasStore(store, cwd) {
40417
40666
  const path = aliasesPath(cwd);
40418
- mkdirSync20(join21(path, ".."), { recursive: true });
40667
+ mkdirSync20(join20(path, ".."), { recursive: true });
40419
40668
  store.updated_at = new Date().toISOString();
40420
40669
  writeFileSync18(path, JSON.stringify(store, null, 2), "utf8");
40421
40670
  }
@@ -41070,18 +41319,18 @@ function createBranchWorkPlan(input, db) {
41070
41319
  init_database();
41071
41320
  init_templates();
41072
41321
  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";
41322
+ import { existsSync as existsSync24, readFileSync as readFileSync21, writeFileSync as writeFileSync19, mkdirSync as mkdirSync21 } from "fs";
41323
+ import { join as join21 } from "path";
41075
41324
  var USER_SCAFFOLD_SCHEMA = "todos.user_scaffold.v1";
41076
41325
  var SCAFFOLD_KINDS = ["task", "project", "plan", "checklist", "contract", "verification_policy"];
41077
41326
  function storeDir(cwd = process.cwd()) {
41078
- return join22(cwd, ".todos", "scaffolds");
41327
+ return join21(cwd, ".todos", "scaffolds");
41079
41328
  }
41080
41329
  function storePath(cwd) {
41081
- return join22(storeDir(cwd), "store.json");
41330
+ return join21(storeDir(cwd), "store.json");
41082
41331
  }
41083
41332
  function versionsDir(cwd) {
41084
- return join22(storeDir(cwd), "versions");
41333
+ return join21(storeDir(cwd), "versions");
41085
41334
  }
41086
41335
  function slugify4(name) {
41087
41336
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
@@ -41091,9 +41340,9 @@ function emptyStore2() {
41091
41340
  }
41092
41341
  function loadUserScaffoldStore(cwd) {
41093
41342
  const path = storePath(cwd);
41094
- if (!existsSync25(path))
41343
+ if (!existsSync24(path))
41095
41344
  return emptyStore2();
41096
- const parsed = JSON.parse(readFileSync22(path, "utf8"));
41345
+ const parsed = JSON.parse(readFileSync21(path, "utf8"));
41097
41346
  if (parsed.schema_version !== USER_SCAFFOLD_SCHEMA) {
41098
41347
  throw new Error(`Unsupported scaffold store schema: ${parsed.schema_version}`);
41099
41348
  }
@@ -41106,7 +41355,7 @@ function saveUserScaffoldStore(store, cwd) {
41106
41355
  }
41107
41356
  function snapshotVersion(scaffold, cwd) {
41108
41357
  mkdirSync21(versionsDir(cwd), { recursive: true });
41109
- const path = join22(versionsDir(cwd), `${scaffold.id}-v${scaffold.version}.json`);
41358
+ const path = join21(versionsDir(cwd), `${scaffold.id}-v${scaffold.version}.json`);
41110
41359
  writeFileSync19(path, JSON.stringify(scaffold, null, 2), "utf8");
41111
41360
  }
41112
41361
  function listUserScaffolds(kind, cwd) {
@@ -41353,7 +41602,7 @@ function listLinkedTemplates(db, cwd) {
41353
41602
  // src/lib/agent-workflow-demo.ts
41354
41603
  init_database();
41355
41604
  import { mkdtempSync } from "fs";
41356
- import { join as join23 } from "path";
41605
+ import { join as join22 } from "path";
41357
41606
  import { tmpdir as tmpdir4 } from "os";
41358
41607
  init_projects();
41359
41608
  init_task_lists();
@@ -41374,7 +41623,7 @@ function setupEphemeralDemoDb(options = {}) {
41374
41623
  if (options.db_path) {
41375
41624
  db_path = options.db_path;
41376
41625
  } else if (options.persist) {
41377
- db_path = join23(mkdtempSync(join23(tmpdir4(), "todos-demo-")), "todos.db");
41626
+ db_path = join22(mkdtempSync(join22(tmpdir4(), "todos-demo-")), "todos.db");
41378
41627
  } else {
41379
41628
  db_path = ":memory:";
41380
41629
  }
@@ -43708,16 +43957,16 @@ function runSearchView(idOrName, db) {
43708
43957
  init_tasks();
43709
43958
  init_config2();
43710
43959
  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";
43960
+ import { existsSync as existsSync25, readFileSync as readFileSync22, readdirSync as readdirSync5, writeFileSync as writeFileSync20 } from "fs";
43961
+ import { join as join23 } from "path";
43713
43962
  function getTaskListDir(taskListId) {
43714
- return join24(HOME, ".claude", "tasks", taskListId);
43963
+ return join23(HOME, ".claude", "tasks", taskListId);
43715
43964
  }
43716
43965
  function readClaudeTask(dir, filename) {
43717
- return readJsonFile(join24(dir, filename));
43966
+ return readJsonFile(join23(dir, filename));
43718
43967
  }
43719
43968
  function writeClaudeTask(dir, task2) {
43720
- writeJsonFile(join24(dir, `${task2.id}.json`), task2);
43969
+ writeJsonFile(join23(dir, `${task2.id}.json`), task2);
43721
43970
  }
43722
43971
  function toClaudeStatus(status) {
43723
43972
  if (status === "pending" || status === "in_progress" || status === "completed") {
@@ -43729,14 +43978,14 @@ function toSqliteStatus(status) {
43729
43978
  return status;
43730
43979
  }
43731
43980
  function readPrefixCounter(dir) {
43732
- const path = join24(dir, ".prefix-counter");
43733
- if (!existsSync26(path))
43981
+ const path = join23(dir, ".prefix-counter");
43982
+ if (!existsSync25(path))
43734
43983
  return 0;
43735
- const val = parseInt(readFileSync23(path, "utf-8").trim(), 10);
43984
+ const val = parseInt(readFileSync22(path, "utf-8").trim(), 10);
43736
43985
  return isNaN(val) ? 0 : val;
43737
43986
  }
43738
43987
  function writePrefixCounter(dir, value) {
43739
- writeFileSync20(join24(dir, ".prefix-counter"), String(value));
43988
+ writeFileSync20(join23(dir, ".prefix-counter"), String(value));
43740
43989
  }
43741
43990
  function formatPrefixedSubject(title, prefix, counter) {
43742
43991
  const padded = String(counter).padStart(5, "0");
@@ -43763,7 +44012,7 @@ function taskToClaudeTask(task2, claudeTaskId, existingMeta) {
43763
44012
  }
43764
44013
  function pushToClaudeTaskList(taskListId, projectId, options = {}) {
43765
44014
  const dir = getTaskListDir(taskListId);
43766
- if (!existsSync26(dir))
44015
+ if (!existsSync25(dir))
43767
44016
  ensureDir2(dir);
43768
44017
  const filter = {};
43769
44018
  if (projectId)
@@ -43772,7 +44021,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
43772
44021
  const existingByTodosId = new Map;
43773
44022
  const files = listJsonFiles(dir);
43774
44023
  for (const f of files) {
43775
- const path = join24(dir, f);
44024
+ const path = join23(dir, f);
43776
44025
  const ct = readClaudeTask(dir, f);
43777
44026
  if (ct?.metadata?.["todos_id"]) {
43778
44027
  existingByTodosId.set(ct.metadata["todos_id"], { task: ct, mtimeMs: getFileMtimeMs(path) });
@@ -43859,7 +44108,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
43859
44108
  }
43860
44109
  function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
43861
44110
  const dir = getTaskListDir(taskListId);
43862
- if (!existsSync26(dir)) {
44111
+ if (!existsSync25(dir)) {
43863
44112
  return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
43864
44113
  }
43865
44114
  const files = readdirSync5(dir).filter((f) => f.endsWith(".json"));
@@ -43879,7 +44128,7 @@ function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
43879
44128
  }
43880
44129
  for (const f of files) {
43881
44130
  try {
43882
- const filePath = join24(dir, f);
44131
+ const filePath = join23(dir, f);
43883
44132
  const ct = readClaudeTask(dir, f);
43884
44133
  if (!ct)
43885
44134
  continue;
@@ -43950,20 +44199,20 @@ function syncClaudeTaskList(taskListId, projectId, options = {}) {
43950
44199
  init_tasks();
43951
44200
  init_sync_utils();
43952
44201
  init_config2();
43953
- import { existsSync as existsSync27 } from "fs";
43954
- import { join as join25 } from "path";
44202
+ import { existsSync as existsSync26 } from "fs";
44203
+ import { join as join24 } from "path";
43955
44204
  function agentBaseDir(agent) {
43956
44205
  const key = `TODOS_${agent.toUpperCase()}_TASKS_DIR`;
43957
- return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join25(getTodosGlobalDir(), "agents");
44206
+ return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join24(getTodosGlobalDir(), "agents");
43958
44207
  }
43959
44208
  function getTaskListDir2(agent, taskListId) {
43960
- return join25(agentBaseDir(agent), agent, taskListId);
44209
+ return join24(agentBaseDir(agent), agent, taskListId);
43961
44210
  }
43962
44211
  function readAgentTask(dir, filename) {
43963
- return readJsonFile(join25(dir, filename));
44212
+ return readJsonFile(join24(dir, filename));
43964
44213
  }
43965
44214
  function writeAgentTask(dir, task2) {
43966
- writeJsonFile(join25(dir, `${task2.id}.json`), task2);
44215
+ writeJsonFile(join24(dir, `${task2.id}.json`), task2);
43967
44216
  }
43968
44217
  function taskToAgentTask(task2, externalId, existingMeta) {
43969
44218
  return {
@@ -43988,7 +44237,7 @@ function metadataKey(agent) {
43988
44237
  }
43989
44238
  function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
43990
44239
  const dir = getTaskListDir2(agent, taskListId);
43991
- if (!existsSync27(dir))
44240
+ if (!existsSync26(dir))
43992
44241
  ensureDir2(dir);
43993
44242
  const filter = {};
43994
44243
  if (projectId)
@@ -43997,7 +44246,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
43997
44246
  const existingByTodosId = new Map;
43998
44247
  const files = listJsonFiles(dir);
43999
44248
  for (const f of files) {
44000
- const path = join25(dir, f);
44249
+ const path = join24(dir, f);
44001
44250
  const at = readAgentTask(dir, f);
44002
44251
  if (at?.metadata?.["todos_id"]) {
44003
44252
  existingByTodosId.set(at.metadata["todos_id"], { task: at, mtimeMs: getFileMtimeMs(path) });
@@ -44071,7 +44320,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
44071
44320
  }
44072
44321
  function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
44073
44322
  const dir = getTaskListDir2(agent, taskListId);
44074
- if (!existsSync27(dir)) {
44323
+ if (!existsSync26(dir)) {
44075
44324
  return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
44076
44325
  }
44077
44326
  const files = listJsonFiles(dir);
@@ -44090,7 +44339,7 @@ function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
44090
44339
  }
44091
44340
  for (const f of files) {
44092
44341
  try {
44093
- const filePath = join25(dir, f);
44342
+ const filePath = join24(dir, f);
44094
44343
  const at = readAgentTask(dir, f);
44095
44344
  if (!at)
44096
44345
  continue;
@@ -44230,9 +44479,9 @@ function syncWithAgents(agents, taskListIdByAgent, projectId, direction = "both"
44230
44479
  // src/lib/extract.ts
44231
44480
  init_tasks();
44232
44481
  init_task_files();
44233
- import { existsSync as existsSync28, readFileSync as readFileSync24, statSync as statSync10 } from "fs";
44482
+ import { existsSync as existsSync27, readFileSync as readFileSync23, statSync as statSync10 } from "fs";
44234
44483
  import { createHash as createHash15 } from "crypto";
44235
- import { relative as relative6, resolve as resolve18, join as join26 } from "path";
44484
+ import { relative as relative6, resolve as resolve18, join as join25 } from "path";
44236
44485
  var EXTRACT_TAGS = ["TODO", "FIXME", "HACK", "XXX", "BUG", "NOTE"];
44237
44486
  var DEFAULT_EXTENSIONS = new Set([
44238
44487
  ".ts",
@@ -44303,11 +44552,11 @@ function normalizePathForMatch(value) {
44303
44552
  }
44304
44553
  function readGitignorePatterns(basePath) {
44305
44554
  const root = statSync10(basePath).isFile() ? resolve18(basePath, "..") : basePath;
44306
- const gitignorePath = join26(root, ".gitignore");
44307
- if (!existsSync28(gitignorePath))
44555
+ const gitignorePath = join25(root, ".gitignore");
44556
+ if (!existsSync27(gitignorePath))
44308
44557
  return [];
44309
44558
  try {
44310
- return readFileSync24(gitignorePath, "utf-8").split(`
44559
+ return readFileSync23(gitignorePath, "utf-8").split(`
44311
44560
  `).map((line) => line.trim()).filter((line) => line && !line.startsWith("#") && !line.startsWith("!"));
44312
44561
  } catch {
44313
44562
  return [];
@@ -44446,9 +44695,9 @@ function buildCodebaseIndex(options) {
44446
44695
  const files = collectFiles(basePath, extensions, excludes, respectGitignore);
44447
44696
  const indexed = [];
44448
44697
  for (const file of files) {
44449
- const fullPath = statSync10(basePath).isFile() ? basePath : join26(basePath, file);
44698
+ const fullPath = statSync10(basePath).isFile() ? basePath : join25(basePath, file);
44450
44699
  try {
44451
- const source9 = readFileSync24(fullPath, "utf-8");
44700
+ const source9 = readFileSync23(fullPath, "utf-8");
44452
44701
  const relPath = statSync10(basePath).isFile() ? relative6(resolve18(basePath, ".."), fullPath) : file;
44453
44702
  indexed.push({
44454
44703
  file: relPath,
@@ -44477,9 +44726,9 @@ function extractTodos(options, db) {
44477
44726
  const files = collectFiles(basePath, extensions, excludes, respectGitignore);
44478
44727
  const allComments = [];
44479
44728
  for (const file of files) {
44480
- const fullPath = statSync10(basePath).isFile() ? basePath : join26(basePath, file);
44729
+ const fullPath = statSync10(basePath).isFile() ? basePath : join25(basePath, file);
44481
44730
  try {
44482
- const source9 = readFileSync24(fullPath, "utf-8");
44731
+ const source9 = readFileSync23(fullPath, "utf-8");
44483
44732
  const relPath = statSync10(basePath).isFile() ? relative6(resolve18(basePath, ".."), fullPath) : file;
44484
44733
  const comments = extractFromSource(source9, relPath, tags);
44485
44734
  allComments.push(...comments);
@@ -45193,7 +45442,7 @@ function renderWorkflowStatesMarkdown(states = listWorkflowStates()) {
45193
45442
  // src/lib/agent-replay-simulator.ts
45194
45443
  init_redaction();
45195
45444
  import { createHash as createHash16 } from "crypto";
45196
- import { readFileSync as readFileSync25 } from "fs";
45445
+ import { readFileSync as readFileSync24 } from "fs";
45197
45446
  function isObject(value) {
45198
45447
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
45199
45448
  }
@@ -45426,7 +45675,7 @@ function simulateAgentReplay(input, options = {}) {
45426
45675
  };
45427
45676
  }
45428
45677
  function simulateAgentReplayFile(path, options = {}) {
45429
- const parsed = JSON.parse(readFileSync25(path, "utf8"));
45678
+ const parsed = JSON.parse(readFileSync24(path, "utf8"));
45430
45679
  return simulateAgentReplay(parsed, options);
45431
45680
  }
45432
45681
  function renderAgentReplaySimulationMarkdown(simulation) {
@@ -45454,8 +45703,8 @@ function renderAgentReplaySimulationMarkdown(simulation) {
45454
45703
  // src/lib/local-extensions.ts
45455
45704
  init_config2();
45456
45705
  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";
45706
+ import { existsSync as existsSync28, readdirSync as readdirSync6, readFileSync as readFileSync25, statSync as statSync11 } from "fs";
45707
+ import { basename as basename6, join as join26, resolve as resolve19 } from "path";
45459
45708
  init_redaction();
45460
45709
  init_runner_sandbox();
45461
45710
  function isObject2(value) {
@@ -45538,7 +45787,7 @@ function normalizeManifest(input) {
45538
45787
  };
45539
45788
  }
45540
45789
  function parseJson(path) {
45541
- return JSON.parse(readFileSync26(path, "utf8"));
45790
+ return JSON.parse(readFileSync25(path, "utf8"));
45542
45791
  }
45543
45792
  function sha2566(bytes) {
45544
45793
  return `sha256:${createHash17("sha256").update(bytes).digest("hex")}`;
@@ -45737,13 +45986,13 @@ function verifyExtensionSignature(input) {
45737
45986
  }
45738
45987
  function inspectExtensionSource(source9) {
45739
45988
  const resolved = resolve19(source9);
45740
- if (!existsSync29(resolved))
45989
+ if (!existsSync28(resolved))
45741
45990
  throw new Error(`extension source not found: ${source9}`);
45742
45991
  const stat = statSync11(resolved);
45743
- const manifestPath = stat.isDirectory() ? [join27(resolved, "todos.extension.json"), join27(resolved, "extension.json")].find(existsSync29) : resolved;
45992
+ const manifestPath = stat.isDirectory() ? [join26(resolved, "todos.extension.json"), join26(resolved, "extension.json")].find(existsSync28) : resolved;
45744
45993
  if (!manifestPath)
45745
45994
  throw new Error(`extension directory ${source9} is missing todos.extension.json`);
45746
- const raw = readFileSync26(manifestPath);
45995
+ const raw = readFileSync25(manifestPath);
45747
45996
  const parsed = parseJson(manifestPath);
45748
45997
  const bundle = isObject2(parsed) && isObject2(parsed["manifest"]);
45749
45998
  const manifest = normalizeManifest(bundle ? parsed["manifest"] : parsed);
@@ -45836,20 +46085,20 @@ function projectExtensionSources(projectPath) {
45836
46085
  return [];
45837
46086
  const root = resolve19(projectPath);
45838
46087
  const candidates = [
45839
- join27(root, "todos.extension.json"),
45840
- join27(root, ".todos", "todos.extension.json")
46088
+ join26(root, "todos.extension.json"),
46089
+ join26(root, ".todos", "todos.extension.json")
45841
46090
  ];
45842
- const extensionDir = join27(root, ".todos", "extensions");
45843
- if (existsSync29(extensionDir)) {
46091
+ const extensionDir = join26(root, ".todos", "extensions");
46092
+ if (existsSync28(extensionDir)) {
45844
46093
  for (const entry2 of readdirSync6(extensionDir)) {
45845
46094
  if (entry2.startsWith("."))
45846
46095
  continue;
45847
- const full = join27(extensionDir, entry2);
46096
+ const full = join26(extensionDir, entry2);
45848
46097
  if (statSync11(full).isDirectory() || entry2.endsWith(".json"))
45849
46098
  candidates.push(full);
45850
46099
  }
45851
46100
  }
45852
- return candidates.filter(existsSync29);
46101
+ return candidates.filter(existsSync28);
45853
46102
  }
45854
46103
  function discoverLocalExtensions(options = {}) {
45855
46104
  const config = loadConfig();
@@ -46151,6 +46400,11 @@ var IDLE_TMUX_COMMANDS = new Set([
46151
46400
  "tmux",
46152
46401
  "zsh"
46153
46402
  ]);
46403
+ function ensureTmuxAvailable() {
46404
+ if (!Bun.which("tmux", { PATH: process.env.PATH ?? "" })) {
46405
+ throw new Error("tmux is not installed or not in PATH");
46406
+ }
46407
+ }
46154
46408
  function parseTmuxTarget(spec) {
46155
46409
  if (!spec || spec.trim() === "") {
46156
46410
  throw new Error("tmux target spec cannot be empty");
@@ -46192,6 +46446,7 @@ function formatTmuxTarget(target) {
46192
46446
  async function validateTmuxTarget(spec) {
46193
46447
  const target = parseTmuxTarget(spec);
46194
46448
  const targetStr = formatTmuxTarget(target);
46449
+ ensureTmuxAvailable();
46195
46450
  let proc;
46196
46451
  try {
46197
46452
  proc = Bun.spawn(["tmux", "list-panes", "-t", targetStr], {
@@ -46208,6 +46463,7 @@ async function validateTmuxTarget(spec) {
46208
46463
  }
46209
46464
  }
46210
46465
  async function inspectTmuxPane(target) {
46466
+ ensureTmuxAvailable();
46211
46467
  const proc = Bun.spawn([
46212
46468
  "tmux",
46213
46469
  "display-message",
@@ -46267,6 +46523,7 @@ async function sendToTmux(target, message, delayMs, options = false) {
46267
46523
  console.log(`[dry-run] message: ${message.slice(0, 200)}`);
46268
46524
  return;
46269
46525
  }
46526
+ ensureTmuxAvailable();
46270
46527
  if (!opts.confirmBusy) {
46271
46528
  const pane = await inspectTmuxPane(target);
46272
46529
  const status = tmuxPaneBusyStatus(pane);
@@ -46721,7 +46978,7 @@ init_redaction();
46721
46978
  // src/lib/retention-cleanup.ts
46722
46979
  init_artifact_store();
46723
46980
  init_database();
46724
- import { existsSync as existsSync30, unlinkSync as unlinkSync2 } from "fs";
46981
+ import { existsSync as existsSync29, unlinkSync as unlinkSync2 } from "fs";
46725
46982
  var RETENTION_CLEANUP_CONFIRMATION = "delete-local-retention-data";
46726
46983
  var ALL_SCOPES = ["comments", "runs", "verifications", "expired_artifacts"];
46727
46984
  var EMPTY_COUNTS = {
@@ -46932,7 +47189,7 @@ function applyRetentionCleanup(input, db) {
46932
47189
  for (const artifact of report.candidates.artifact_files) {
46933
47190
  try {
46934
47191
  const path = artifactStorePath(artifact.relative_path);
46935
- if (!existsSync30(path)) {
47192
+ if (!existsSync29(path)) {
46936
47193
  report.warnings.push(`stored artifact already missing: ${artifact.relative_path}`);
46937
47194
  continue;
46938
47195
  }
@@ -47176,8 +47433,8 @@ init_database();
47176
47433
  init_migrations();
47177
47434
  init_schema();
47178
47435
  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";
47436
+ import { chmodSync, copyFileSync as copyFileSync2, existsSync as existsSync30, mkdirSync as mkdirSync22, statSync as statSync12 } from "fs";
47437
+ import { basename as basename7, dirname as dirname18, join as join27 } from "path";
47181
47438
  var REQUIRED_TABLES2 = [
47182
47439
  "_migrations",
47183
47440
  "projects",
@@ -47284,7 +47541,7 @@ function findMissingProjectRoots(db) {
47284
47541
  continue;
47285
47542
  if (!row.path.startsWith("/"))
47286
47543
  continue;
47287
- if (!existsSync31(row.path))
47544
+ if (!existsSync30(row.path))
47288
47545
  missing++;
47289
47546
  }
47290
47547
  return missing;
@@ -47344,16 +47601,16 @@ function databasePermissionsAreUnsafe(dbPath) {
47344
47601
  function createBackup(dbPath) {
47345
47602
  if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
47346
47603
  return;
47347
- if (!existsSync31(dbPath))
47604
+ if (!existsSync30(dbPath))
47348
47605
  return;
47349
47606
  const stamp = now().replace(/[:.]/g, "-");
47350
- const backupDir = join28(dirname19(dbPath), `${basename7(dbPath)}.backup-${stamp}`);
47607
+ const backupDir = join27(dirname18(dbPath), `${basename7(dbPath)}.backup-${stamp}`);
47351
47608
  const files = [];
47352
47609
  mkdirSync22(backupDir, { recursive: true });
47353
47610
  for (const source9 of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
47354
- if (!existsSync31(source9))
47611
+ if (!existsSync30(source9))
47355
47612
  continue;
47356
- const target = join28(backupDir, basename7(source9));
47613
+ const target = join27(backupDir, basename7(source9));
47357
47614
  copyFileSync2(source9, target);
47358
47615
  files.push(target);
47359
47616
  }