@hasna/todos 0.15.49 → 0.15.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4075,23 +4075,118 @@ var init_identity_mapping = __esm(() => {
4075
4075
  });
4076
4076
  });
4077
4077
 
4078
- // src/lib/sync-utils.ts
4079
- import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
4080
- import { createHash } from "crypto";
4078
+ // node_modules/.bun/@hasna+paths@0.1.0/node_modules/@hasna/paths/dist/index.js
4081
4079
  import { homedir } from "os";
4082
4080
  import { join } from "path";
4081
+ function assertApp(app) {
4082
+ if (typeof app !== "string" || app.length === 0) {
4083
+ throw new TypeError("paths: app must be a non-empty string");
4084
+ }
4085
+ if (!APP_SLUG_RE.test(app)) {
4086
+ throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
4087
+ }
4088
+ }
4089
+ function envOf(options) {
4090
+ return options.env ?? process.env;
4091
+ }
4092
+ function envValue(options, kind) {
4093
+ const value = envOf(options)[KIND_ENV[kind]];
4094
+ return typeof value === "string" && value.length > 0 ? value : undefined;
4095
+ }
4096
+ function isMacOS(platform) {
4097
+ return platform === "darwin";
4098
+ }
4099
+ function baseDir(kind, options) {
4100
+ const override = envValue(options, kind);
4101
+ if (override)
4102
+ return override;
4103
+ const home = options.home ?? homedir();
4104
+ const platform = options.platform ?? process.platform;
4105
+ if (isMacOS(platform)) {
4106
+ switch (kind) {
4107
+ case "config":
4108
+ case "data":
4109
+ return join(home, "Library", "Application Support", "Hasna");
4110
+ case "cache":
4111
+ return join(home, "Library", "Caches", "Hasna");
4112
+ case "state":
4113
+ return join(home, "Library", "Logs", "Hasna");
4114
+ }
4115
+ }
4116
+ switch (kind) {
4117
+ case "config":
4118
+ return join(home, ".config", "hasna");
4119
+ case "data":
4120
+ return join(home, ".local", "share", "hasna");
4121
+ case "state":
4122
+ return join(home, ".local", "state", "hasna");
4123
+ case "cache":
4124
+ return join(home, ".cache", "hasna");
4125
+ }
4126
+ }
4127
+ function resolvePath(kind, options) {
4128
+ assertApp(options.app);
4129
+ const appSegment = options.internal === true ? join("internal", options.app) : options.app;
4130
+ return join(baseDir(kind, options), appSegment);
4131
+ }
4132
+ function dataDir(options) {
4133
+ return resolvePath("data", options);
4134
+ }
4135
+ var KIND_ENV, APP_SLUG_RE;
4136
+ var init_dist = __esm(() => {
4137
+ KIND_ENV = {
4138
+ config: "HASNA_CONFIG_HOME",
4139
+ data: "HASNA_DATA_HOME",
4140
+ state: "HASNA_STATE_HOME",
4141
+ cache: "HASNA_CACHE_HOME"
4142
+ };
4143
+ APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
4144
+ });
4145
+
4146
+ // src/lib/paths.ts
4147
+ import { existsSync as existsSync2 } from "fs";
4148
+ import { homedir as homedir2 } from "os";
4149
+ import { join as join2, resolve as resolve2 } from "path";
4150
+ function effectiveHome(env = process.env) {
4151
+ return env.HOME || env.USERPROFILE || homedir2();
4152
+ }
4153
+ function legacyHomeDir(env = process.env) {
4154
+ return join2(effectiveHome(env), ".hasna", "todos");
4155
+ }
4156
+ function resolverHome(env = process.env) {
4157
+ return dataDir({ app: "todos", home: effectiveHome(env), env });
4158
+ }
4159
+ function adoptResolverHome(resolved, env = process.env) {
4160
+ const dataOverride = env.HASNA_DATA_HOME;
4161
+ if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
4162
+ return true;
4163
+ return existsSync2(join2(resolved, "todos.db")) || existsSync2(join2(resolved, "config.json"));
4164
+ }
4165
+ function getTodosDir(env = process.env) {
4166
+ const resolved = resolverHome(env);
4167
+ return resolve2(adoptResolverHome(resolved, env) ? resolved : legacyHomeDir(env));
4168
+ }
4169
+ var init_paths = __esm(() => {
4170
+ init_dist();
4171
+ });
4172
+
4173
+ // src/lib/sync-utils.ts
4174
+ import { existsSync as existsSync3, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
4175
+ import { createHash } from "crypto";
4176
+ import { homedir as homedir3 } from "os";
4177
+ import { join as join3 } from "path";
4083
4178
  function getHomeDir() {
4084
- return process.env["HOME"] || process.env["USERPROFILE"] || homedir();
4179
+ return process.env["HOME"] || process.env["USERPROFILE"] || homedir3();
4085
4180
  }
4086
4181
  function getTodosGlobalDir() {
4087
- return join(getHomeDir(), ".hasna", "todos");
4182
+ return getTodosDir();
4088
4183
  }
4089
4184
  function ensureDir(dir) {
4090
- if (!existsSync2(dir))
4185
+ if (!existsSync3(dir))
4091
4186
  mkdirSync(dir, { recursive: true });
4092
4187
  }
4093
4188
  function listJsonFiles(dir) {
4094
- if (!existsSync2(dir))
4189
+ if (!existsSync3(dir))
4095
4190
  return [];
4096
4191
  return readdirSync(dir).filter((f) => f.endsWith(".json"));
4097
4192
  }
@@ -4107,14 +4202,14 @@ function writeJsonFile(path, data) {
4107
4202
  `);
4108
4203
  }
4109
4204
  function readHighWaterMark(dir) {
4110
- const path = join(dir, ".highwatermark");
4111
- if (!existsSync2(path))
4205
+ const path = join3(dir, ".highwatermark");
4206
+ if (!existsSync3(path))
4112
4207
  return 1;
4113
4208
  const val = parseInt(readFileSync(path, "utf-8").trim(), 10);
4114
4209
  return isNaN(val) ? 1 : val;
4115
4210
  }
4116
4211
  function writeHighWaterMark(dir, value) {
4117
- writeFileSync(join(dir, ".highwatermark"), String(value));
4212
+ writeFileSync(join3(dir, ".highwatermark"), String(value));
4118
4213
  }
4119
4214
  function getFileMtimeMs(path) {
4120
4215
  try {
@@ -4169,6 +4264,7 @@ function hasSyncFingerprintChanged(record) {
4169
4264
  }
4170
4265
  var TODO_SYNC_FINGERPRINT_KEY = "todos_sync_fingerprint", HOME;
4171
4266
  var init_sync_utils = __esm(() => {
4267
+ init_paths();
4172
4268
  HOME = getHomeDir();
4173
4269
  });
4174
4270
 
@@ -4479,18 +4575,18 @@ __export(exports_database, {
4479
4575
  LOCK_EXPIRY_MINUTES: () => LOCK_EXPIRY_MINUTES
4480
4576
  });
4481
4577
  import { Database } from "bun:sqlite";
4482
- import { existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
4483
- import { dirname, join as join2, resolve as resolve2 } from "path";
4578
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
4579
+ import { dirname, join as join4, resolve as resolve3 } from "path";
4484
4580
  function isInMemoryDb(path) {
4485
4581
  return path === ":memory:" || path.startsWith("file::memory:");
4486
4582
  }
4487
4583
  function findNearestProjectDb(startDir) {
4488
4584
  const gitRoot = findGitRoot(startDir);
4489
- const stopAt = gitRoot ? resolve2(gitRoot) : resolve2(startDir);
4490
- let dir = resolve2(startDir);
4585
+ const stopAt = gitRoot ? resolve3(gitRoot) : resolve3(startDir);
4586
+ let dir = resolve3(startDir);
4491
4587
  while (true) {
4492
- const candidate = join2(dir, ".hasna", "todos", "todos.db");
4493
- if (existsSync3(candidate))
4588
+ const candidate = join4(dir, ".hasna", "todos", "todos.db");
4589
+ if (existsSync4(candidate))
4494
4590
  return candidate;
4495
4591
  if (dir === stopAt)
4496
4592
  break;
@@ -4502,9 +4598,9 @@ function findNearestProjectDb(startDir) {
4502
4598
  return null;
4503
4599
  }
4504
4600
  function findGitRoot(startDir) {
4505
- let dir = resolve2(startDir);
4601
+ let dir = resolve3(startDir);
4506
4602
  while (true) {
4507
- if (existsSync3(join2(dir, ".git")))
4603
+ if (existsSync4(join4(dir, ".git")))
4508
4604
  return dir;
4509
4605
  const parent = dirname(dir);
4510
4606
  if (parent === dir)
@@ -4514,7 +4610,7 @@ function findGitRoot(startDir) {
4514
4610
  return null;
4515
4611
  }
4516
4612
  function getGlobalDbPath() {
4517
- return join2(getHomeDir(), ".hasna", "todos", "todos.db");
4613
+ return join4(getTodosGlobalDir(), "todos.db");
4518
4614
  }
4519
4615
  function hasExplicitProjectArg(args = process.argv.slice(2)) {
4520
4616
  return args.some((arg) => arg === "--project" || arg.startsWith("--project="));
@@ -4552,7 +4648,7 @@ function getDbPath() {
4552
4648
  if (process.env["TODOS_DB_SCOPE"] === "project") {
4553
4649
  const gitRoot = findGitRoot(cwd);
4554
4650
  if (gitRoot && canCreateScopedProjectDb()) {
4555
- return join2(gitRoot, ".hasna", "todos", "todos.db");
4651
+ return join4(gitRoot, ".hasna", "todos", "todos.db");
4556
4652
  }
4557
4653
  }
4558
4654
  return getGlobalDbPath();
@@ -4563,8 +4659,8 @@ function getDatabasePath() {
4563
4659
  function ensureDir2(filePath) {
4564
4660
  if (isInMemoryDb(filePath))
4565
4661
  return;
4566
- const dir = dirname(resolve2(filePath));
4567
- if (!existsSync3(dir)) {
4662
+ const dir = dirname(resolve3(filePath));
4663
+ if (!existsSync4(dir)) {
4568
4664
  mkdirSync2(dir, { recursive: true });
4569
4665
  }
4570
4666
  }
@@ -4741,10 +4837,10 @@ var init_database = __esm(() => {
4741
4837
  });
4742
4838
 
4743
4839
  // src/lib/config.ts
4744
- import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
4745
- import { dirname as dirname2, join as join3 } from "path";
4840
+ import { existsSync as existsSync5, readFileSync as readFileSync2 } from "fs";
4841
+ import { dirname as dirname2, join as join5 } from "path";
4746
4842
  function getConfigPath() {
4747
- return join3(getTodosGlobalDir(), "config.json");
4843
+ return join5(getTodosGlobalDir(), "config.json");
4748
4844
  }
4749
4845
  function normalizeAgent(agent) {
4750
4846
  return agent.trim().toLowerCase();
@@ -4752,7 +4848,7 @@ function normalizeAgent(agent) {
4752
4848
  function loadConfig() {
4753
4849
  if (cached)
4754
4850
  return cached;
4755
- if (!existsSync4(getConfigPath())) {
4851
+ if (!existsSync5(getConfigPath())) {
4756
4852
  cached = {};
4757
4853
  return cached;
4758
4854
  }
@@ -4775,7 +4871,7 @@ function updateConfig(patch) {
4775
4871
  }
4776
4872
  function getTodosAiConfig() {
4777
4873
  const configPath = getConfigPath();
4778
- if (!existsSync4(configPath))
4874
+ if (!existsSync5(configPath))
4779
4875
  return {};
4780
4876
  const parsed = JSON.parse(readFileSync2(configPath, "utf8"));
4781
4877
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
@@ -5393,14 +5489,14 @@ var init_completion_guard = __esm(() => {
5393
5489
 
5394
5490
  // src/lib/event-emission-safety.ts
5395
5491
  import { tmpdir } from "os";
5396
- import { resolve as resolve3, sep } from "path";
5492
+ import { resolve as resolve4, sep } from "path";
5397
5493
  function envFlag(name) {
5398
5494
  const value = process.env[name]?.trim().toLowerCase();
5399
5495
  return value === "1" || value === "true" || value === "yes" || value === "on";
5400
5496
  }
5401
5497
  function isUnder(parent, child) {
5402
- const normalizedParent = resolve3(parent);
5403
- const normalizedChild = resolve3(child);
5498
+ const normalizedParent = resolve4(parent);
5499
+ const normalizedChild = resolve4(child);
5404
5500
  return normalizedChild === normalizedParent || normalizedChild.startsWith(`${normalizedParent}${sep}`);
5405
5501
  }
5406
5502
  function databasePathFromDatabase(db) {
@@ -5561,9 +5657,9 @@ var init_redaction = __esm(() => {
5561
5657
  });
5562
5658
 
5563
5659
  // src/lib/workspace-trust.ts
5564
- import { relative, resolve as resolve4 } from "path";
5660
+ import { relative, resolve as resolve5 } from "path";
5565
5661
  function normalizePath(path) {
5566
- return resolve4(path);
5662
+ return resolve5(path);
5567
5663
  }
5568
5664
  function unique2(values) {
5569
5665
  return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
@@ -5745,9 +5841,9 @@ var init_workspace_trust = __esm(() => {
5745
5841
  });
5746
5842
 
5747
5843
  // src/lib/runner-sandbox.ts
5748
- import { relative as relative2, resolve as resolve5 } from "path";
5844
+ import { relative as relative2, resolve as resolve6 } from "path";
5749
5845
  function normalizePath2(path) {
5750
- return resolve5(path);
5846
+ return resolve6(path);
5751
5847
  }
5752
5848
  function unique3(values) {
5753
5849
  return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
@@ -5940,7 +6036,7 @@ var init_runner_sandbox = __esm(() => {
5940
6036
  // src/lib/event-hooks.ts
5941
6037
  import { createHash as createHash2, randomUUID } from "crypto";
5942
6038
  import { appendFileSync, mkdirSync as mkdirSync3 } from "fs";
5943
- import { dirname as dirname3, resolve as resolve6 } from "path";
6039
+ import { dirname as dirname3, resolve as resolve7 } from "path";
5944
6040
  import { createConnection } from "net";
5945
6041
  function safeName(name) {
5946
6042
  const trimmed = name.trim();
@@ -6078,7 +6174,7 @@ async function deliverHook(hook, envelope) {
6078
6174
  if (hook.target === "stdout") {
6079
6175
  output = line.trim();
6080
6176
  } else if (hook.target === "file") {
6081
- const filePath = resolve6(hook.file_path);
6177
+ const filePath = resolve7(hook.file_path);
6082
6178
  mkdirSync3(dirname3(filePath), { recursive: true });
6083
6179
  appendFileSync(filePath, line);
6084
6180
  } else if (hook.target === "socket") {
@@ -6199,9 +6295,9 @@ var init_event_hooks = __esm(() => {
6199
6295
  // node_modules/.bun/@hasna+events@0.1.16/node_modules/@hasna/events/dist/index.js
6200
6296
  import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
6201
6297
  import { Buffer as Buffer2 } from "buffer";
6202
- import { existsSync as existsSync5 } from "fs";
6203
- import { homedir as homedir2 } from "os";
6204
- import { join as join4 } from "path";
6298
+ import { existsSync as existsSync6 } from "fs";
6299
+ import { homedir as homedir4 } from "os";
6300
+ import { join as join6 } from "path";
6205
6301
  import { createHmac, timingSafeEqual } from "crypto";
6206
6302
  import { randomUUID as randomUUID2 } from "crypto";
6207
6303
  import { spawn } from "child_process";
@@ -6302,7 +6398,7 @@ function channelMatchesEvent(channel, event) {
6302
6398
  return channel.filters.some((filter) => eventMatchesFilter(event, filter));
6303
6399
  }
6304
6400
  function getEventsDataDir(override) {
6305
- return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join4(homedir2(), ".hasna", "events");
6401
+ return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join6(homedir4(), ".hasna", "events");
6306
6402
  }
6307
6403
 
6308
6404
  class JsonEventsStore {
@@ -6311,12 +6407,12 @@ class JsonEventsStore {
6311
6407
  channelsPath;
6312
6408
  eventsPath;
6313
6409
  deliveriesPath;
6314
- constructor(dataDir = getEventsDataDir()) {
6315
- this.dataDir = dataDir;
6316
- this.runtime = localJsonRuntime(dataDir);
6317
- this.channelsPath = join4(dataDir, "channels.json");
6318
- this.eventsPath = join4(dataDir, "events.json");
6319
- this.deliveriesPath = join4(dataDir, "deliveries.json");
6410
+ constructor(dataDir2 = getEventsDataDir()) {
6411
+ this.dataDir = dataDir2;
6412
+ this.runtime = localJsonRuntime(dataDir2);
6413
+ this.channelsPath = join6(dataDir2, "channels.json");
6414
+ this.eventsPath = join6(dataDir2, "events.json");
6415
+ this.deliveriesPath = join6(dataDir2, "deliveries.json");
6320
6416
  }
6321
6417
  async init() {
6322
6418
  await mkdir(this.dataDir, { recursive: true, mode: 448 });
@@ -6433,7 +6529,7 @@ class JsonEventsStore {
6433
6529
  };
6434
6530
  }
6435
6531
  async ensureArrayFile(path) {
6436
- if (!existsSync5(path)) {
6532
+ if (!existsSync6(path)) {
6437
6533
  await writeFile(path, `[]
6438
6534
  `, { encoding: "utf-8", mode: 384 });
6439
6535
  }
@@ -6463,7 +6559,7 @@ class JsonEventsStore {
6463
6559
  });
6464
6560
  }
6465
6561
  }
6466
- function localJsonRuntime(dataDir = getEventsDataDir()) {
6562
+ function localJsonRuntime(dataDir2 = getEventsDataDir()) {
6467
6563
  return {
6468
6564
  mode: "local-files",
6469
6565
  name: "json-events-store",
@@ -6476,7 +6572,7 @@ function localJsonRuntime(dataDir = getEventsDataDir()) {
6476
6572
  durable: true,
6477
6573
  idempotency: "best-effort-local",
6478
6574
  replayCursors: true,
6479
- description: `Local JSON files in ${dataDir}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
6575
+ description: `Local JSON files in ${dataDir2}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
6480
6576
  };
6481
6577
  }
6482
6578
  function encodeLocalJsonEventCursor(offset, options = {}) {
@@ -6655,7 +6751,7 @@ async function dispatchCommand(event, channel) {
6655
6751
  HASNA_EVENT_SCHEMA_VERSION: event.schemaVersion,
6656
6752
  HASNA_EVENT_JSON: eventJson
6657
6753
  };
6658
- return new Promise((resolve7) => {
6754
+ return new Promise((resolve8) => {
6659
6755
  const child = spawn(channel.command.command, channel.command.args ?? [], {
6660
6756
  cwd: channel.command.cwd,
6661
6757
  env,
@@ -6673,7 +6769,7 @@ async function dispatchCommand(event, channel) {
6673
6769
  });
6674
6770
  child.on("error", (error) => {
6675
6771
  clearTimeout(timeout);
6676
- resolve7({
6772
+ resolve8({
6677
6773
  attempt: 1,
6678
6774
  status: "failed",
6679
6775
  startedAt,
@@ -6686,7 +6782,7 @@ async function dispatchCommand(event, channel) {
6686
6782
  child.on("close", (code, signal) => {
6687
6783
  clearTimeout(timeout);
6688
6784
  const success = code === 0;
6689
- resolve7({
6785
+ resolve8({
6690
6786
  attempt: 1,
6691
6787
  status: success ? "success" : "failed",
6692
6788
  startedAt,
@@ -7028,7 +7124,7 @@ function normalizeRetryPolicy(policy) {
7028
7124
  };
7029
7125
  }
7030
7126
  var HASNA_EVENTS_DIR_ENV = "HASNA_EVENTS_DIR", HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME", LOCAL_JSON_EVENT_CURSOR_PREFIX = "local-json-v1:", DEFAULT_EVENT_PAGE_LIMIT = 100, MAX_EVENT_PAGE_LIMIT = 1000, DEFAULT_SIGNATURE_TOLERANCE_MS, EventValidationError, defaultEventTypeCatalog, APP_EVENT_V1_MAX_DATA_BYTES;
7031
- var init_dist = __esm(() => {
7127
+ var init_dist2 = __esm(() => {
7032
7128
  DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1000;
7033
7129
  EventValidationError = class EventValidationError extends Error {
7034
7130
  eventType;
@@ -7451,7 +7547,7 @@ function emitSharedTaskEventQuiet(input) {
7451
7547
  }
7452
7548
  var SOURCE = "todos";
7453
7549
  var init_shared_events = __esm(() => {
7454
- init_dist();
7550
+ init_dist2();
7455
7551
  init_database();
7456
7552
  init_projects();
7457
7553
  init_task_lists();
@@ -7459,7 +7555,7 @@ var init_shared_events = __esm(() => {
7459
7555
  });
7460
7556
 
7461
7557
  // src/lib/secret-redaction.ts
7462
- import { readFileSync as readFileSync3, existsSync as existsSync6 } from "fs";
7558
+ import { readFileSync as readFileSync3, existsSync as existsSync7 } from "fs";
7463
7559
  function registerCustomRedactor(fn) {
7464
7560
  customRedactors.push(fn);
7465
7561
  }
@@ -7524,7 +7620,7 @@ function scanAndRedactText(text, options = {}) {
7524
7620
  };
7525
7621
  }
7526
7622
  function scanFileForSecrets(path, options = {}) {
7527
- if (!existsSync6(path))
7623
+ if (!existsSync7(path))
7528
7624
  throw new Error(`File not found: ${path}`);
7529
7625
  const content = readFileSync3(path, "utf8");
7530
7626
  return scanAndRedactText(content, options);
@@ -9782,17 +9878,17 @@ function sanitizeCreateTaskInput(input) {
9782
9878
  return {
9783
9879
  ...input,
9784
9880
  title: sanitizePreWriteText(input.title, "task.title"),
9785
- description: input.description !== undefined ? sanitizePreWriteText(input.description, "task.description") : undefined,
9881
+ description: input.description == null ? input.description : sanitizePreWriteText(input.description, "task.description"),
9786
9882
  tags: input.tags !== undefined ? sanitizePreWriteValue(input.tags, "task.tags") : undefined,
9787
9883
  metadata: input.metadata !== undefined ? sanitizePreWriteValue(input.metadata, "task.metadata") : undefined,
9788
- reason: input.reason !== undefined ? sanitizePreWriteText(input.reason, "task.reason") : undefined
9884
+ reason: input.reason == null ? input.reason : sanitizePreWriteText(input.reason, "task.reason")
9789
9885
  };
9790
9886
  }
9791
9887
  function sanitizeUpdateTaskInput(input) {
9792
9888
  return {
9793
9889
  ...input,
9794
9890
  title: input.title !== undefined ? sanitizePreWriteText(input.title, "task.title") : undefined,
9795
- description: input.description !== undefined ? sanitizePreWriteText(input.description, "task.description") : undefined,
9891
+ description: input.description == null ? input.description : sanitizePreWriteText(input.description, "task.description"),
9796
9892
  tags: input.tags !== undefined ? sanitizePreWriteValue(input.tags, "task.tags") : undefined,
9797
9893
  metadata: input.metadata !== undefined ? sanitizePreWriteValue(input.metadata, "task.metadata") : undefined
9798
9894
  };
@@ -11646,28 +11742,28 @@ var init_boards = __esm(() => {
11646
11742
 
11647
11743
  // src/lib/artifact-store.ts
11648
11744
  import { createHash as createHash3 } from "crypto";
11649
- import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync4, rmSync, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
11650
- import { basename, dirname as dirname4, join as join5, resolve as resolve7 } from "path";
11745
+ import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync4, rmSync, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
11746
+ import { basename, dirname as dirname4, join as join7, resolve as resolve8 } from "path";
11651
11747
  import { tmpdir as tmpdir2 } from "os";
11652
11748
  function isInMemoryDb2(path) {
11653
11749
  return path === ":memory:" || path.startsWith("file::memory:");
11654
11750
  }
11655
11751
  function artifactStoreRoot() {
11656
11752
  if (process.env["HASNA_TODOS_ARTIFACTS_DIR"])
11657
- return resolve7(process.env["HASNA_TODOS_ARTIFACTS_DIR"]);
11753
+ return resolve8(process.env["HASNA_TODOS_ARTIFACTS_DIR"]);
11658
11754
  if (process.env["TODOS_ARTIFACTS_DIR"])
11659
- return resolve7(process.env["TODOS_ARTIFACTS_DIR"]);
11755
+ return resolve8(process.env["TODOS_ARTIFACTS_DIR"]);
11660
11756
  const dbPath = getDatabasePath();
11661
11757
  if (isInMemoryDb2(dbPath))
11662
- return join5(tmpdir2(), "hasna-todos-artifacts");
11663
- return join5(dirname4(resolve7(dbPath)), "artifacts");
11758
+ return join7(tmpdir2(), "hasna-todos-artifacts");
11759
+ return join7(dirname4(resolve8(dbPath)), "artifacts");
11664
11760
  }
11665
11761
  function artifactStorePath(relativePath) {
11666
11762
  const normalized = relativePath.replace(/\\/g, "/");
11667
11763
  if (normalized.includes("..") || normalized.startsWith("/") || normalized.length === 0) {
11668
11764
  throw new Error("Invalid artifact store path");
11669
11765
  }
11670
- return join5(artifactStoreRoot(), normalized);
11766
+ return join7(artifactStoreRoot(), normalized);
11671
11767
  }
11672
11768
  function sha256(buffer) {
11673
11769
  return createHash3("sha256").update(buffer).digest("hex");
@@ -11707,8 +11803,8 @@ function mediaTypeFor(path, textLike) {
11707
11803
  return "application/octet-stream";
11708
11804
  }
11709
11805
  function storeArtifactContent(input) {
11710
- const sourcePath = resolve7(input.path);
11711
- if (!existsSync7(sourcePath))
11806
+ const sourcePath = resolve8(input.path);
11807
+ if (!existsSync8(sourcePath))
11712
11808
  return null;
11713
11809
  const sourceStat = statSync2(sourcePath);
11714
11810
  if (!sourceStat.isFile())
@@ -11725,9 +11821,9 @@ function storeArtifactContent(input) {
11725
11821
  redactionStatus = "redacted";
11726
11822
  }
11727
11823
  const storedSha = sha256(storedBuffer);
11728
- const relativePath = join5("sha256", storedSha.slice(0, 2), storedSha).replace(/\\/g, "/");
11824
+ const relativePath = join7("sha256", storedSha.slice(0, 2), storedSha).replace(/\\/g, "/");
11729
11825
  const destination = artifactStorePath(relativePath);
11730
- if (!existsSync7(destination)) {
11826
+ if (!existsSync8(destination)) {
11731
11827
  mkdirSync4(dirname4(destination), { recursive: true });
11732
11828
  writeFileSync2(destination, storedBuffer);
11733
11829
  }
@@ -11787,7 +11883,7 @@ function verifyStoredArtifact(input) {
11787
11883
  };
11788
11884
  }
11789
11885
  const storedPath = artifactStorePath(store.relative_path);
11790
- if (!existsSync7(storedPath)) {
11886
+ if (!existsSync8(storedPath)) {
11791
11887
  return {
11792
11888
  id: input.id,
11793
11889
  path: input.path,
@@ -11862,20 +11958,20 @@ function importStoredArtifactContent(content) {
11862
11958
  }
11863
11959
  function getArtifactStoreRoot(dbPath) {
11864
11960
  if (process.env["HASNA_TODOS_ARTIFACTS_DIR"])
11865
- return resolve7(process.env["HASNA_TODOS_ARTIFACTS_DIR"]);
11961
+ return resolve8(process.env["HASNA_TODOS_ARTIFACTS_DIR"]);
11866
11962
  if (process.env["TODOS_ARTIFACTS_DIR"])
11867
- return resolve7(process.env["TODOS_ARTIFACTS_DIR"]);
11963
+ return resolve8(process.env["TODOS_ARTIFACTS_DIR"]);
11868
11964
  const path = dbPath ?? getDatabasePath();
11869
11965
  if (isInMemoryDb2(path))
11870
- return join5(tmpdir2(), "hasna-todos-artifacts");
11871
- return join5(dirname4(resolve7(path)), "artifacts");
11966
+ return join7(tmpdir2(), "hasna-todos-artifacts");
11967
+ return join7(dirname4(resolve8(path)), "artifacts");
11872
11968
  }
11873
11969
  function computeContentHash(path) {
11874
- return sha256(readFileSync4(resolve7(path)));
11970
+ return sha256(readFileSync4(resolve8(path)));
11875
11971
  }
11876
11972
  function storeArtifactFile(input) {
11877
- const sourcePath = resolve7(input.sourcePath);
11878
- if (!existsSync7(sourcePath)) {
11973
+ const sourcePath = resolve8(input.sourcePath);
11974
+ if (!existsSync8(sourcePath)) {
11879
11975
  throw new Error(`Source file not found: ${input.sourcePath}`);
11880
11976
  }
11881
11977
  if (!statSync2(sourcePath).isFile()) {
@@ -11888,7 +11984,7 @@ function storeArtifactFile(input) {
11888
11984
  let localPath = sourcePath;
11889
11985
  if (storageMode === "copy") {
11890
11986
  const fileName = input.name && input.name.trim().length > 0 ? basename(input.name) : basename(sourcePath);
11891
- const destination = join5(getArtifactStoreRoot(input.dbPath), input.artifactId, fileName);
11987
+ const destination = join7(getArtifactStoreRoot(input.dbPath), input.artifactId, fileName);
11892
11988
  mkdirSync4(dirname4(destination), { recursive: true });
11893
11989
  writeFileSync2(destination, buffer);
11894
11990
  localPath = destination;
@@ -11898,7 +11994,7 @@ function storeArtifactFile(input) {
11898
11994
  function deleteStoredArtifactFile(localPath, storageMode, _dbPath2) {
11899
11995
  if (storageMode === "reference")
11900
11996
  return false;
11901
- if (!localPath || !existsSync7(localPath))
11997
+ if (!localPath || !existsSync8(localPath))
11902
11998
  return false;
11903
11999
  rmSync(localPath, { force: true });
11904
12000
  try {
@@ -11923,7 +12019,7 @@ function buildArtifactExportManifest(artifacts, dbPath) {
11923
12019
  };
11924
12020
  }
11925
12021
  function writeArtifactExportManifest(manifest, outputPath) {
11926
- const destination = resolve7(outputPath);
12022
+ const destination = resolve8(outputPath);
11927
12023
  mkdirSync4(dirname4(destination), { recursive: true });
11928
12024
  writeFileSync2(destination, `${JSON.stringify(manifest, null, 2)}
11929
12025
  `);
@@ -13193,7 +13289,7 @@ var init_dispatches = __esm(() => {
13193
13289
  // package.json
13194
13290
  var package_default = {
13195
13291
  name: "@hasna/todos",
13196
- version: "0.15.49",
13292
+ version: "0.15.51",
13197
13293
  description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
13198
13294
  type: "module",
13199
13295
  main: "dist/index.js",
@@ -13252,6 +13348,7 @@ var package_default = {
13252
13348
  files: [
13253
13349
  "dist",
13254
13350
  "dashboard/dist",
13351
+ "postinstall.js",
13255
13352
  "LICENSE",
13256
13353
  "README.md"
13257
13354
  ],
@@ -13278,7 +13375,7 @@ var package_default = {
13278
13375
  "test:attested-container-compatibility-vector": "bun test scripts/attested-container-compatibility-vector.test.ts",
13279
13376
  "issue:release-review": "bun run scripts/issue-npm-release-agent-review.ts",
13280
13377
  prepublishOnly: "bun run scripts/verify-public-release.ts --mode=publish",
13281
- postinstall: "mkdir -p $HOME/.hasna/todos $HOME/.hasna/todos/training 2>/dev/null || true"
13378
+ postinstall: "node postinstall.js"
13282
13379
  },
13283
13380
  keywords: [
13284
13381
  "todos",
@@ -13312,13 +13409,15 @@ var package_default = {
13312
13409
  author: "Andrei Hasna <andrei@hasna.com>",
13313
13410
  license: "Apache-2.0",
13314
13411
  dependencies: {
13315
- "@hasna/contracts": "0.14.0",
13412
+ "@hasna/contracts": "0.14.2",
13316
13413
  "@hasna/events": "^0.1.11",
13414
+ "@hasna/paths": "0.1.0",
13317
13415
  "@modelcontextprotocol/sdk": "^1.12.1",
13318
13416
  chalk: "^5.4.1",
13319
13417
  commander: "^13.1.0",
13320
13418
  ink: "^5.2.0",
13321
13419
  react: "^18.3.1",
13420
+ "signal-exit": "3.0.7",
13322
13421
  zod: "3.25.76"
13323
13422
  },
13324
13423
  overrides: {
@@ -16553,7 +16652,7 @@ function todosAiExitCodeForResult(result) {
16553
16652
  }
16554
16653
  // src/lib/onboarding-fixtures.ts
16555
16654
  import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync3 } from "fs";
16556
- import { join as join6 } from "path";
16655
+ import { join as join8 } from "path";
16557
16656
 
16558
16657
  // src/lib/local-bridge.ts
16559
16658
  init_database();
@@ -17490,7 +17589,7 @@ function writeOnboardingFixtureFiles(directory) {
17490
17589
  mkdirSync5(directory, { recursive: true });
17491
17590
  const files = [];
17492
17591
  for (const fixture of allFixtures()) {
17493
- const path = join6(directory, `${fixture.summary.name}.bridge.json`);
17592
+ const path = join8(directory, `${fixture.summary.name}.bridge.json`);
17494
17593
  writeFileSync3(path, `${JSON.stringify(fixture.bundle, null, 2)}
17495
17594
  `, "utf-8");
17496
17595
  files.push(path);
@@ -17508,7 +17607,7 @@ function importOnboardingFixture(options = {}) {
17508
17607
  init_database();
17509
17608
  import { createHash as createHash4 } from "crypto";
17510
17609
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
17511
- import { dirname as dirname5, resolve as resolve8 } from "path";
17610
+ import { dirname as dirname5, resolve as resolve9 } from "path";
17512
17611
  import { mkdirSync as mkdirSync6 } from "fs";
17513
17612
  var TODOS_LOCAL_BACKUP_KIND = "hasna.todos.local-backup";
17514
17613
  var TODOS_LOCAL_BACKUP_SCHEMA_VERSION = 1;
@@ -17615,14 +17714,14 @@ function createLocalBackup(options = {}, db) {
17615
17714
  return backup;
17616
17715
  }
17617
17716
  function writeLocalBackupFile(backup, outputPath) {
17618
- const path = resolve8(outputPath);
17717
+ const path = resolve9(outputPath);
17619
17718
  mkdirSync6(dirname5(path), { recursive: true });
17620
17719
  writeFileSync4(path, `${JSON.stringify(backup, null, 2)}
17621
17720
  `);
17622
17721
  return path;
17623
17722
  }
17624
17723
  function readLocalBackupFile(path) {
17625
- return JSON.parse(readFileSync5(resolve8(path), "utf-8"));
17724
+ return JSON.parse(readFileSync5(resolve9(path), "utf-8"));
17626
17725
  }
17627
17726
  function verifyLocalBackup(value, options = {}, db) {
17628
17727
  const verifiedAt = options.verified_at ?? now();
@@ -18316,7 +18415,7 @@ function renderLocalSnapshotMarkdown(snapshot) {
18316
18415
  }
18317
18416
  // src/lib/sdk-integration-fixtures.ts
18318
18417
  import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync5 } from "fs";
18319
- import { join as join7 } from "path";
18418
+ import { join as join9 } from "path";
18320
18419
 
18321
18420
  // src/cli-mcp-parity.ts
18322
18421
  function source4(version) {
@@ -20287,7 +20386,7 @@ function writeSdkIntegrationFixtures(directory, options = {}) {
20287
20386
  ];
20288
20387
  const written = [];
20289
20388
  for (const [name, payload] of files) {
20290
- const file = join7(directory, name);
20389
+ const file = join9(directory, name);
20291
20390
  writeFileSync5(file, `${JSON.stringify(payload, null, 2)}
20292
20391
  `, "utf-8");
20293
20392
  written.push(file);
@@ -21570,7 +21669,7 @@ function renderLocalAuditLedgerMarkdown(ledger) {
21570
21669
  init_migrations();
21571
21670
  init_schema();
21572
21671
  import { readFileSync as readFileSync6 } from "fs";
21573
- import { join as join8, resolve as resolve9 } from "path";
21672
+ import { join as join10, resolve as resolve10 } from "path";
21574
21673
  import { Database as Database2 } from "bun:sqlite";
21575
21674
  var LOCAL_RELEASE_COMPATIBILITY_SCHEMA_VERSION = 1;
21576
21675
  var EXPECTED_PACKAGE_NAME = "@hasna/todos";
@@ -21616,7 +21715,7 @@ function warn(id, message, details) {
21616
21715
  return { id, status: "warning", message, details };
21617
21716
  }
21618
21717
  function readPackageJson(root) {
21619
- return JSON.parse(readFileSync6(join8(root, "package.json"), "utf8"));
21718
+ return JSON.parse(readFileSync6(join10(root, "package.json"), "utf8"));
21620
21719
  }
21621
21720
  function sortedKeys(value) {
21622
21721
  return Object.keys(value ?? {}).sort((left, right) => left.localeCompare(right));
@@ -21712,7 +21811,7 @@ function checkChangelog() {
21712
21811
  ];
21713
21812
  }
21714
21813
  function createReleaseCompatibilityReport(options = {}) {
21715
- const root = resolve9(options.root ?? process.cwd());
21814
+ const root = resolve10(options.root ?? process.cwd());
21716
21815
  const packageJson = readPackageJson(root);
21717
21816
  const simulatedLevels = options.simulated_levels ?? defaultSimulationLevels();
21718
21817
  const checks = [
@@ -30707,7 +30806,7 @@ async function retryOnTransientPostgresError(fn, attempts = 2, delayMs = 150) {
30707
30806
  lastError = error;
30708
30807
  if (!isTransientPostgresError(error) || attempt === attempts)
30709
30808
  throw error;
30710
- await new Promise((resolve10) => setTimeout(resolve10, delayMs * attempt));
30809
+ await new Promise((resolve11) => setTimeout(resolve11, delayMs * attempt));
30711
30810
  }
30712
30811
  }
30713
30812
  throw lastError;
@@ -30808,8 +30907,8 @@ class TodosShadowMirror {
30808
30907
  async flush() {
30809
30908
  if (this.idle())
30810
30909
  return;
30811
- await new Promise((resolve10) => {
30812
- this.idleResolvers.push(resolve10);
30910
+ await new Promise((resolve11) => {
30911
+ this.idleResolvers.push(resolve11);
30813
30912
  this.pump();
30814
30913
  });
30815
30914
  }
@@ -30821,8 +30920,8 @@ class TodosShadowMirror {
30821
30920
  return;
30822
30921
  const resolvers = this.idleResolvers;
30823
30922
  this.idleResolvers = [];
30824
- for (const resolve10 of resolvers)
30825
- resolve10();
30923
+ for (const resolve11 of resolvers)
30924
+ resolve11();
30826
30925
  }
30827
30926
  pump() {
30828
30927
  if (this.pumping)
@@ -31301,7 +31400,7 @@ class TodosShadowOutbox {
31301
31400
  const remaining = deadline - Date.now();
31302
31401
  if (remaining <= 0)
31303
31402
  break;
31304
- await new Promise((resolve10) => setTimeout(resolve10, Math.min(200, remaining)));
31403
+ await new Promise((resolve11) => setTimeout(resolve11, Math.min(200, remaining)));
31305
31404
  }
31306
31405
  }
31307
31406
  return this.getStats();
@@ -32605,7 +32704,7 @@ class TodosClient {
32605
32704
  return this._fetchWithRetry(path, { method: "DELETE" });
32606
32705
  }
32607
32706
  _sleep(ms) {
32608
- return new Promise((resolve10) => setTimeout(resolve10, ms));
32707
+ return new Promise((resolve11) => setTimeout(resolve11, ms));
32609
32708
  }
32610
32709
  async getHealth() {
32611
32710
  return this._get("/api/health");
@@ -34262,8 +34361,8 @@ class SqlitePrGroupLedgerPersistence {
34262
34361
  async transaction(fn) {
34263
34362
  const previous = sqliteTransactionTails.get(this.db) ?? Promise.resolve();
34264
34363
  let release;
34265
- const current = new Promise((resolve10) => {
34266
- release = resolve10;
34364
+ const current = new Promise((resolve11) => {
34365
+ release = resolve11;
34267
34366
  });
34268
34367
  sqliteTransactionTails.set(this.db, current);
34269
34368
  await previous;
@@ -36281,8 +36380,8 @@ class SqliteTodosProjectRegistrationBackend {
36281
36380
  async transaction(fn) {
36282
36381
  const previous = sqliteTransactionTails2.get(this.db) ?? Promise.resolve();
36283
36382
  let release;
36284
- const current = new Promise((resolve10) => {
36285
- release = resolve10;
36383
+ const current = new Promise((resolve11) => {
36384
+ release = resolve11;
36286
36385
  });
36287
36386
  sqliteTransactionTails2.set(this.db, current);
36288
36387
  await previous;
@@ -42561,8 +42660,8 @@ class SqliteTodosTaskManifestBackend {
42561
42660
  async serialized(run) {
42562
42661
  const previous = sqliteTails.get(this.db) ?? Promise.resolve();
42563
42662
  let release;
42564
- const current = new Promise((resolve10) => {
42565
- release = resolve10;
42663
+ const current = new Promise((resolve11) => {
42664
+ release = resolve11;
42566
42665
  });
42567
42666
  const tail = previous.then(() => current);
42568
42667
  sqliteTails.set(this.db, tail);
@@ -44903,8 +45002,8 @@ class SqliteTodosTaskSubtreeTransferBackend {
44903
45002
  async serialized(run) {
44904
45003
  const previous = sqliteTails2.get(this.db) ?? Promise.resolve();
44905
45004
  let release;
44906
- const current = new Promise((resolve10) => {
44907
- release = resolve10;
45005
+ const current = new Promise((resolve11) => {
45006
+ release = resolve11;
44908
45007
  });
44909
45008
  const tail = previous.then(() => current);
44910
45009
  sqliteTails2.set(this.db, tail);
@@ -46217,8 +46316,8 @@ var DANGEROUS_TOOLS = new Set([
46217
46316
  "merge_tasks",
46218
46317
  "cancel_agent_run"
46219
46318
  ]);
46220
- function resolveAccessProfile(envValue) {
46221
- const raw = (envValue ?? process.env["TODOS_PROFILE"] ?? "full").toLowerCase();
46319
+ function resolveAccessProfile(envValue2) {
46320
+ const raw = (envValue2 ?? process.env["TODOS_PROFILE"] ?? "full").toLowerCase();
46222
46321
  if (ACCESS_PROFILES.includes(raw))
46223
46322
  return raw;
46224
46323
  if (raw === "readonly")
@@ -47761,8 +47860,8 @@ init_task_crud();
47761
47860
  init_redaction();
47762
47861
  import { Database as Database3 } from "bun:sqlite";
47763
47862
  import { createHash as createHash17 } from "crypto";
47764
- import { existsSync as existsSync9, readdirSync as readdirSync2, statSync as statSync4 } from "fs";
47765
- import { basename as basename2, dirname as dirname6, join as join9, resolve as resolve10 } from "path";
47863
+ import { existsSync as existsSync10, readdirSync as readdirSync2, statSync as statSync4 } from "fs";
47864
+ import { basename as basename2, dirname as dirname6, join as join11, resolve as resolve11 } from "path";
47766
47865
 
47767
47866
  // src/lib/task-routing.ts
47768
47867
  init_database();
@@ -47770,7 +47869,7 @@ init_projects();
47770
47869
  init_task_crud();
47771
47870
  init_task_lifecycle();
47772
47871
  init_task_lists();
47773
- import { existsSync as existsSync8, statSync as statSync3 } from "fs";
47872
+ import { existsSync as existsSync9, statSync as statSync3 } from "fs";
47774
47873
  var DEFAULT_STALE_IN_PROGRESS_MS = 3 * 24 * 60 * 60 * 1000;
47775
47874
  var TERMINAL_WORKFLOW_STATES = new Set([
47776
47875
  "failed",
@@ -47825,7 +47924,7 @@ function routeConcurrencyKey(task3, project, taskList, projectPath) {
47825
47924
  }
47826
47925
  function directoryExists(path) {
47827
47926
  try {
47828
- return existsSync8(path) && statSync3(path).isDirectory();
47927
+ return existsSync9(path) && statSync3(path).isDirectory();
47829
47928
  } catch {
47830
47929
  return false;
47831
47930
  }
@@ -48026,7 +48125,7 @@ function pointerPatch(previous, input, key2) {
48026
48125
 
48027
48126
  // src/lib/task-route-sources.ts
48028
48127
  var TASK_ROUTE_SOURCE_DISCOVERY_SCHEMA_VERSION = "todos.task_route_sources.v1";
48029
- var TODO_STORE_RELATIVE_PATH = join9(".hasna", "todos", "todos.db");
48128
+ var TODO_STORE_RELATIVE_PATH = join11(".hasna", "todos", "todos.db");
48030
48129
  var ROOT_SCAN_MAX_DEPTH = 5;
48031
48130
  var SKIPPED_SCAN_DIRS = new Set([
48032
48131
  ".git",
@@ -48040,7 +48139,7 @@ var SKIPPED_SCAN_DIRS = new Set([
48040
48139
  ".cache"
48041
48140
  ]);
48042
48141
  function normalizePath3(input) {
48043
- return resolve10(input);
48142
+ return resolve11(input);
48044
48143
  }
48045
48144
  function sourceStoreId(sourceDbPath) {
48046
48145
  const digest3 = createHash17("sha256").update(sourceDbPath).digest("hex").slice(0, 16);
@@ -48102,8 +48201,8 @@ function discoverStoresUnderRoot(sourceRoot) {
48102
48201
  const rootPath = normalizePath3(sourceRoot);
48103
48202
  const errors2 = [];
48104
48203
  const stores = [];
48105
- if (!existsSync9(rootPath)) {
48106
- const ref = createStoreRef(join9(rootPath, TODO_STORE_RELATIVE_PATH));
48204
+ if (!existsSync10(rootPath)) {
48205
+ const ref = createStoreRef(join11(rootPath, TODO_STORE_RELATIVE_PATH));
48107
48206
  errors2.push({
48108
48207
  ...ref,
48109
48208
  code: "SOURCE_ROOT_MISSING",
@@ -48115,7 +48214,7 @@ function discoverStoresUnderRoot(sourceRoot) {
48115
48214
  try {
48116
48215
  rootStat = statSync4(rootPath);
48117
48216
  } catch (error) {
48118
- const ref = createStoreRef(join9(rootPath, TODO_STORE_RELATIVE_PATH));
48217
+ const ref = createStoreRef(join11(rootPath, TODO_STORE_RELATIVE_PATH));
48119
48218
  errors2.push({
48120
48219
  ...ref,
48121
48220
  code: "SOURCE_ROOT_UNREADABLE",
@@ -48128,8 +48227,8 @@ function discoverStoresUnderRoot(sourceRoot) {
48128
48227
  return { stores, errors: errors2 };
48129
48228
  }
48130
48229
  function scanDirectory(dir, depth) {
48131
- const candidate = join9(dir, TODO_STORE_RELATIVE_PATH);
48132
- if (existsSync9(candidate)) {
48230
+ const candidate = join11(dir, TODO_STORE_RELATIVE_PATH);
48231
+ if (existsSync10(candidate)) {
48133
48232
  stores.push(createStoreRef(candidate));
48134
48233
  }
48135
48234
  if (depth >= ROOT_SCAN_MAX_DEPTH)
@@ -48149,7 +48248,7 @@ function discoverStoresUnderRoot(sourceRoot) {
48149
48248
  for (const entry2 of entries) {
48150
48249
  if (!entry2.isDirectory() || SKIPPED_SCAN_DIRS.has(entry2.name))
48151
48250
  continue;
48152
- scanDirectory(join9(dir, entry2.name), depth + 1);
48251
+ scanDirectory(join11(dir, entry2.name), depth + 1);
48153
48252
  }
48154
48253
  }
48155
48254
  scanDirectory(rootPath, 0);
@@ -48175,7 +48274,7 @@ function collectStoreRefs(input) {
48175
48274
  };
48176
48275
  }
48177
48276
  function openReadonlyStore(ref) {
48178
- if (!existsSync9(ref.source_db_path)) {
48277
+ if (!existsSync10(ref.source_db_path)) {
48179
48278
  throw Object.assign(new Error(`Store does not exist: ${ref.source_db_path}`), { code: "STORE_MISSING" });
48180
48279
  }
48181
48280
  return new Database3(ref.source_db_path, { readonly: true, create: false });
@@ -48487,8 +48586,8 @@ init_plans();
48487
48586
  init_database();
48488
48587
  init_projects();
48489
48588
  init_tasks();
48490
- import { existsSync as existsSync10, mkdirSync as mkdirSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
48491
- import { join as join10, resolve as resolve11 } from "path";
48589
+ import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
48590
+ import { join as join12, resolve as resolve12 } from "path";
48492
48591
  var PLAN_MARKDOWN_SCHEMA = "hasna.todos.plan/v1";
48493
48592
  function assertSafePathSegment(value, label) {
48494
48593
  const trimmed = value.trim();
@@ -48532,7 +48631,7 @@ function resolvePlanArtifactProject(input) {
48532
48631
  const ref = input.project_id || input.project_ref;
48533
48632
  if (!ref)
48534
48633
  throw new Error("Plan artifacts require a project id or project reference");
48535
- const byPath = getProjectByPath(resolve11(ref), db);
48634
+ const byPath = getProjectByPath(resolve12(ref), db);
48536
48635
  if (byPath)
48537
48636
  return byPath;
48538
48637
  const resolvedId = resolvePartialId(db, "projects", ref);
@@ -48549,8 +48648,8 @@ function resolvePlanArtifactProject(input) {
48549
48648
  function resolvePlanArtifactPaths(input) {
48550
48649
  const project = resolvePlanArtifactProject(input);
48551
48650
  const projectId = assertSafePathSegment(project.id, "project id");
48552
- const projectRoot = resolve11(project.path);
48553
- const directory = join10(projectRoot, ".hasna", "todos", "plans", projectId);
48651
+ const projectRoot = resolve12(project.path);
48652
+ const directory = join12(projectRoot, ".hasna", "todos", "plans", projectId);
48554
48653
  const planId = input.plan_id ? assertSafePathSegment(input.plan_id, "plan id") : null;
48555
48654
  const planSlug = input.plan_slug ? assertSafePathSegment(slugify(input.plan_slug), "plan slug") : null;
48556
48655
  const fileName = planId ? planSlug ? `${planSlug}--${planId.slice(0, 8)}.md` : `${planId}.md` : null;
@@ -48558,7 +48657,7 @@ function resolvePlanArtifactPaths(input) {
48558
48657
  project_id: project.id,
48559
48658
  project_root: projectRoot,
48560
48659
  directory,
48561
- file_path: fileName ? join10(directory, fileName) : directory
48660
+ file_path: fileName ? join12(directory, fileName) : directory
48562
48661
  };
48563
48662
  }
48564
48663
  function resolvePlanArtifactCandidatePaths(plan, db) {
@@ -48724,7 +48823,7 @@ function readPlanArtifact(plan, db) {
48724
48823
  return null;
48725
48824
  const d = db || getDatabase();
48726
48825
  const paths = resolvePlanArtifactCandidatePaths(plan, d);
48727
- const path = existsSync10(paths.primary.file_path) ? paths.primary.file_path : existsSync10(paths.legacy.file_path) ? paths.legacy.file_path : null;
48826
+ const path = existsSync11(paths.primary.file_path) ? paths.primary.file_path : existsSync11(paths.legacy.file_path) ? paths.legacy.file_path : null;
48728
48827
  if (!path)
48729
48828
  return null;
48730
48829
  const markdown = readFileSync7(path, "utf8");
@@ -48739,7 +48838,7 @@ function inspectPlanArtifact(plan, db) {
48739
48838
  return null;
48740
48839
  const d = db || getDatabase();
48741
48840
  const paths = resolvePlanArtifactCandidatePaths(plan, d);
48742
- const path = existsSync10(paths.primary.file_path) ? paths.primary.file_path : existsSync10(paths.legacy.file_path) ? paths.legacy.file_path : null;
48841
+ const path = existsSync11(paths.primary.file_path) ? paths.primary.file_path : existsSync11(paths.legacy.file_path) ? paths.legacy.file_path : null;
48743
48842
  if (!path) {
48744
48843
  return {
48745
48844
  path: paths.primary.file_path,
@@ -49828,8 +49927,8 @@ function renderRetrospectiveMarkdown(record) {
49828
49927
  init_database();
49829
49928
  init_projects();
49830
49929
  init_task_lists();
49831
- import { existsSync as existsSync11, readFileSync as readFileSync8, statSync as statSync5 } from "fs";
49832
- import { basename as basename3, dirname as dirname7, resolve as resolve12 } from "path";
49930
+ import { existsSync as existsSync12, readFileSync as readFileSync8, statSync as statSync5 } from "fs";
49931
+ import { basename as basename3, dirname as dirname7, resolve as resolve13 } from "path";
49833
49932
  function safeStat(path) {
49834
49933
  try {
49835
49934
  return statSync5(path);
@@ -49838,7 +49937,7 @@ function safeStat(path) {
49838
49937
  }
49839
49938
  }
49840
49939
  function canonicalPath(input) {
49841
- const resolved = resolve12(input);
49940
+ const resolved = resolve13(input);
49842
49941
  const stats2 = safeStat(resolved);
49843
49942
  if (stats2?.isFile())
49844
49943
  return dirname7(resolved);
@@ -49847,7 +49946,7 @@ function canonicalPath(input) {
49847
49946
  function findUp(start, marker) {
49848
49947
  let current = canonicalPath(start);
49849
49948
  while (true) {
49850
- if (existsSync11(resolve12(current, marker)))
49949
+ if (existsSync12(resolve13(current, marker)))
49851
49950
  return current;
49852
49951
  const parent = dirname7(current);
49853
49952
  if (parent === current)
@@ -49858,8 +49957,8 @@ function findUp(start, marker) {
49858
49957
  function readPackageJson2(path) {
49859
49958
  if (!path)
49860
49959
  return null;
49861
- const file = resolve12(path, "package.json");
49862
- if (!existsSync11(file))
49960
+ const file = resolve13(path, "package.json");
49961
+ if (!existsSync12(file))
49863
49962
  return null;
49864
49963
  try {
49865
49964
  const parsed = JSON.parse(readFileSync8(file, "utf-8"));
@@ -49881,7 +49980,7 @@ function workspaceMarker(root, rootPackage) {
49881
49980
  if (rootPackage?.workspaces)
49882
49981
  markers.push("package.json#workspaces");
49883
49982
  for (const marker of ["pnpm-workspace.yaml", "turbo.json", "nx.json", "lerna.json", "rush.json", "bun.lock", "bun.lockb"]) {
49884
- if (existsSync11(resolve12(root, marker)))
49983
+ if (existsSync12(resolve13(root, marker)))
49885
49984
  markers.push(marker);
49886
49985
  }
49887
49986
  const kind = markers.find((marker) => marker !== "bun.lock" && marker !== "bun.lockb") ?? null;
@@ -50219,18 +50318,18 @@ var gatherTrainingData = async (options = {}) => {
50219
50318
  };
50220
50319
  // src/lib/model-config.ts
50221
50320
  init_sync_utils();
50222
- import { existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
50223
- import { join as join11 } from "path";
50321
+ import { existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
50322
+ import { join as join13 } from "path";
50224
50323
  var DEFAULT_MODEL = "gpt-4o-mini";
50225
50324
  function getConfigDir() {
50226
50325
  return getTodosGlobalDir();
50227
50326
  }
50228
50327
  function getConfigPath2() {
50229
- return join11(getConfigDir(), "config.json");
50328
+ return join13(getConfigDir(), "config.json");
50230
50329
  }
50231
50330
  function readConfig() {
50232
50331
  const configPath = getConfigPath2();
50233
- if (!existsSync12(configPath))
50332
+ if (!existsSync13(configPath))
50234
50333
  return {};
50235
50334
  try {
50236
50335
  const raw = readFileSync9(configPath, "utf-8");
@@ -50241,7 +50340,7 @@ function readConfig() {
50241
50340
  }
50242
50341
  function writeConfig(config) {
50243
50342
  const configDir = getConfigDir();
50244
- if (!existsSync12(configDir)) {
50343
+ if (!existsSync13(configDir)) {
50245
50344
  mkdirSync9(configDir, { recursive: true });
50246
50345
  }
50247
50346
  writeFileSync7(getConfigPath2(), JSON.stringify(config, null, 2) + `
@@ -50989,7 +51088,7 @@ init_database();
50989
51088
  init_tasks();
50990
51089
  init_config2();
50991
51090
  init_redaction();
50992
- import { existsSync as existsSync13, readFileSync as readFileSync10 } from "fs";
51091
+ import { existsSync as existsSync14, readFileSync as readFileSync10 } from "fs";
50993
51092
  var DEFAULT_RETRY = {
50994
51093
  attempts: 1,
50995
51094
  backoff_ms: 0
@@ -51097,7 +51196,7 @@ function classifyLog(text) {
51097
51196
  async function sleep2(ms) {
51098
51197
  if (ms <= 0)
51099
51198
  return;
51100
- await new Promise((resolve13) => setTimeout(resolve13, ms));
51199
+ await new Promise((resolve14) => setTimeout(resolve14, ms));
51101
51200
  }
51102
51201
  async function runCommandProvider(provider, input) {
51103
51202
  const commandTemplate = input.command || provider.command;
@@ -51152,7 +51251,7 @@ Timed out after ${provider.timeout_ms}ms`);
51152
51251
  };
51153
51252
  }
51154
51253
  function runCiLogProvider(input) {
51155
- const text = input.log_text ?? (input.log_path && existsSync13(input.log_path) ? readFileSync10(input.log_path, "utf-8") : "");
51254
+ const text = input.log_text ?? (input.log_path && existsSync14(input.log_path) ? readFileSync10(input.log_path, "utf-8") : "");
51156
51255
  return {
51157
51256
  status: classifyLog(text),
51158
51257
  attempts: 1,
@@ -51164,7 +51263,7 @@ function runBrowserProvider(input) {
51164
51263
  if (!input.artifact_path) {
51165
51264
  return { status: "unknown", attempts: 1, exit_code: null, output_summary: "browser provider needs a screenshot or artifact path" };
51166
51265
  }
51167
- if (!existsSync13(input.artifact_path)) {
51266
+ if (!existsSync14(input.artifact_path)) {
51168
51267
  return { status: "failed", attempts: 1, exit_code: null, output_summary: `artifact not found: ${input.artifact_path}` };
51169
51268
  }
51170
51269
  return {
@@ -51458,9 +51557,9 @@ init_database();
51458
51557
  init_tasks();
51459
51558
  init_task_runs();
51460
51559
  init_config2();
51461
- import { relative as relative3, resolve as resolve13 } from "path";
51560
+ import { relative as relative3, resolve as resolve14 } from "path";
51462
51561
  function normalizePath4(path) {
51463
- return resolve13(path);
51562
+ return resolve14(path);
51464
51563
  }
51465
51564
  function unique4(values) {
51466
51565
  return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
@@ -51515,7 +51614,7 @@ function commandMatches(commands, pattern) {
51515
51614
  }
51516
51615
  function pathMatches(paths, pattern, root) {
51517
51616
  return paths.filter((path) => {
51518
- const candidate = path.startsWith("/") ? path : resolve13(root, path);
51617
+ const candidate = path.startsWith("/") ? path : resolve14(root, path);
51519
51618
  if (!isPathInside3(root, candidate))
51520
51619
  return matchesPattern4(path, pattern);
51521
51620
  return matchesPattern4(path, pattern) || matchesPattern4(relative3(root, candidate), pattern);
@@ -51810,20 +51909,20 @@ function resourceDiagnostics() {
51810
51909
  }
51811
51910
  // src/lib/sandbox-profiles.ts
51812
51911
  init_sync_utils();
51813
- import { existsSync as existsSync14, readFileSync as readFileSync11, writeFileSync as writeFileSync9, mkdirSync as mkdirSync11 } from "fs";
51814
- import { join as join12, dirname as dirname9 } from "path";
51912
+ import { existsSync as existsSync15, readFileSync as readFileSync11, writeFileSync as writeFileSync9, mkdirSync as mkdirSync11 } from "fs";
51913
+ import { join as join14, dirname as dirname9 } from "path";
51815
51914
  var SANDBOX_PROFILE_VERSION = "todos.sandbox-profile.v1";
51816
51915
  function getProfilesPath() {
51817
51916
  if (process.env["TODOS_SANDBOX_PROFILES_PATH"]) {
51818
51917
  return process.env["TODOS_SANDBOX_PROFILES_PATH"];
51819
51918
  }
51820
- const localDir = join12(process.cwd(), ".todos");
51821
- const local = join12(localDir, "sandbox-profiles.json");
51822
- if (existsSync14(localDir))
51919
+ const localDir = join14(process.cwd(), ".todos");
51920
+ const local = join14(localDir, "sandbox-profiles.json");
51921
+ if (existsSync15(localDir))
51823
51922
  return local;
51824
- if (existsSync14(local))
51923
+ if (existsSync15(local))
51825
51924
  return local;
51826
- return join12(getHomeDir(), ".hasna", "todos", "sandbox-profiles.json");
51925
+ return join14(getTodosGlobalDir(), "sandbox-profiles.json");
51827
51926
  }
51828
51927
  var cached2 = null;
51829
51928
  function resetSandboxProfileCache() {
@@ -51855,7 +51954,7 @@ function loadSandboxProfiles() {
51855
51954
  if (cached2)
51856
51955
  return cached2;
51857
51956
  const path = getProfilesPath();
51858
- if (!existsSync14(path)) {
51957
+ if (!existsSync15(path)) {
51859
51958
  cached2 = getDefaultSandboxProfiles();
51860
51959
  return cached2;
51861
51960
  }
@@ -52235,9 +52334,9 @@ init_task_commits();
52235
52334
 
52236
52335
  // src/lib/git-traceability.ts
52237
52336
  init_task_commits();
52238
- import { existsSync as existsSync15, readFileSync as readFileSync12 } from "fs";
52337
+ import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
52239
52338
  import { spawnSync as spawnSync2 } from "child_process";
52240
- import { resolve as resolve14 } from "path";
52339
+ import { resolve as resolve15 } from "path";
52241
52340
  var GIT_TRACEABILITY_SCHEMA_VERSION = "todos.git_traceability.v1";
52242
52341
  function runGit(args, cwd) {
52243
52342
  const result = spawnSync2("git", args, { cwd, encoding: "utf8" });
@@ -52280,8 +52379,8 @@ function inspectGitCommit(sha, cwd) {
52280
52379
  };
52281
52380
  }
52282
52381
  function loadCiSnapshot(path) {
52283
- const target = path ? resolve14(path) : resolve14(process.cwd(), ".todos", "ci-snapshot.json");
52284
- if (!existsSync15(target))
52382
+ const target = path ? resolve15(path) : resolve15(process.cwd(), ".todos", "ci-snapshot.json");
52383
+ if (!existsSync16(target))
52285
52384
  return null;
52286
52385
  try {
52287
52386
  const parsed = JSON.parse(readFileSync12(target, "utf8"));
@@ -52377,8 +52476,8 @@ function formatTraceabilityReport(report) {
52377
52476
  `);
52378
52477
  }
52379
52478
  // src/lib/mention-resolver.ts
52380
- import { existsSync as existsSync16, readdirSync as readdirSync3, readFileSync as readFileSync13, statSync as statSync6 } from "fs";
52381
- import { basename as basename4, isAbsolute, join as join13, relative as relative4, resolve as resolve15, sep as sep2 } from "path";
52479
+ import { existsSync as existsSync17, readdirSync as readdirSync3, readFileSync as readFileSync13, statSync as statSync6 } from "fs";
52480
+ import { basename as basename4, isAbsolute, join as join15, relative as relative4, resolve as resolve16, sep as sep2 } from "path";
52382
52481
  init_database();
52383
52482
  init_plans();
52384
52483
  init_task_runs();
@@ -52457,7 +52556,7 @@ function backlink(kind, key2, label, target = key2) {
52457
52556
  return { kind, key: key2, label, target };
52458
52557
  }
52459
52558
  function normalizeWorkspace(workspace) {
52460
- return resolve15(workspace || process.cwd());
52559
+ return resolve16(workspace || process.cwd());
52461
52560
  }
52462
52561
  function isInside(root, absolutePath) {
52463
52562
  const rel = relative4(root, absolutePath);
@@ -52525,14 +52624,14 @@ function resolveFile(parsed, workspace) {
52525
52624
  resolution.warnings.push("path is empty or escapes the workspace");
52526
52625
  return resolution;
52527
52626
  }
52528
- const absolutePath = resolve15(workspace, relPath);
52627
+ const absolutePath = resolve16(workspace, relPath);
52529
52628
  if (!isInside(workspace, absolutePath)) {
52530
52629
  resolution.path = relPath;
52531
52630
  resolution.warnings.push("path escapes the workspace");
52532
52631
  return resolution;
52533
52632
  }
52534
52633
  resolution.path = relPath;
52535
- if (!existsSync16(absolutePath)) {
52634
+ if (!existsSync17(absolutePath)) {
52536
52635
  resolution.warnings.push("file does not exist in the local workspace");
52537
52636
  return resolution;
52538
52637
  }
@@ -52565,7 +52664,7 @@ function walkSourceFiles(root, current = root, files = []) {
52565
52664
  if (SKIP_DIRS.has(entry2.name))
52566
52665
  continue;
52567
52666
  }
52568
- const absolutePath = join13(current, entry2.name);
52667
+ const absolutePath = join15(current, entry2.name);
52569
52668
  if (entry2.isDirectory()) {
52570
52669
  if (!SKIP_DIRS.has(entry2.name))
52571
52670
  walkSourceFiles(root, absolutePath, files);
@@ -53918,7 +54017,7 @@ function getAdapterDocsFingerprint() {
53918
54017
  // src/lib/inbox-intake.ts
53919
54018
  init_database();
53920
54019
  init_tasks();
53921
- import { existsSync as existsSync17, readFileSync as readFileSync14 } from "fs";
54020
+ import { existsSync as existsSync18, readFileSync as readFileSync14 } from "fs";
53922
54021
  import { basename as basename5 } from "path";
53923
54022
  import { createHash as createHash19 } from "crypto";
53924
54023
  init_secret_redaction();
@@ -53964,7 +54063,7 @@ function loadRawContent(input) {
53964
54063
  }
53965
54064
  }
53966
54065
  if (input.file_path) {
53967
- if (!existsSync17(input.file_path))
54066
+ if (!existsSync18(input.file_path))
53968
54067
  throw new Error(`File not found: ${input.file_path}`);
53969
54068
  const raw = readFileSync14(input.file_path, "utf8");
53970
54069
  const name = basename5(input.file_path).toLowerCase();
@@ -54585,7 +54684,7 @@ function formatNlIntakePreviewText(preview) {
54585
54684
  // src/lib/issue-importers.ts
54586
54685
  init_database();
54587
54686
  init_tasks();
54588
- import { existsSync as existsSync18, readFileSync as readFileSync15 } from "fs";
54687
+ import { existsSync as existsSync19, readFileSync as readFileSync15 } from "fs";
54589
54688
  var ISSUE_IMPORT_SCHEMA = "todos.issue_import.v1";
54590
54689
  var ISSUE_SOURCES = ["github", "linear", "jira", "auto"];
54591
54690
  var GITHUB_LABEL_PRIORITY = {
@@ -54804,7 +54903,7 @@ function parseIssueExport(data, source9 = "auto") {
54804
54903
  return normalized;
54805
54904
  }
54806
54905
  function loadIssueExportFromFile(path) {
54807
- if (!existsSync18(path))
54906
+ if (!existsSync19(path))
54808
54907
  throw new Error(`File not found: ${path}`);
54809
54908
  return JSON.parse(readFileSync15(path, "utf8"));
54810
54909
  }
@@ -54965,8 +55064,8 @@ todos import issues ./linear.json --source linear --dry-run
54965
55064
  init_sync_utils();
54966
55065
  init_database();
54967
55066
  init_secret_redaction();
54968
- import { existsSync as existsSync19, mkdirSync as mkdirSync12, writeFileSync as writeFileSync10 } from "fs";
54969
- import { join as join14, dirname as dirname10 } from "path";
55067
+ import { existsSync as existsSync20, mkdirSync as mkdirSync12, writeFileSync as writeFileSync10 } from "fs";
55068
+ import { join as join16, dirname as dirname10 } from "path";
54970
55069
  var RUN_RECORD_SCHEMA = "todos.run_record.v1";
54971
55070
  var RUN_RECORD_STATUSES = ["active", "completed", "failed", "archived"];
54972
55071
  function parseJsonArray3(raw, fallback = []) {
@@ -55159,7 +55258,7 @@ function buildRunReplayBundle(id, db) {
55159
55258
  }
55160
55259
  function exportRunReplay(id, outputPath, db) {
55161
55260
  const bundle = buildRunReplayBundle(id, db);
55162
- const path = outputPath ?? join14(process.cwd(), ".todos", "replays", `${id.slice(0, 8)}.json`);
55261
+ const path = outputPath ?? join16(process.cwd(), ".todos", "replays", `${id.slice(0, 8)}.json`);
55163
55262
  mkdirSync12(dirname10(path), { recursive: true });
55164
55263
  writeFileSync10(path, JSON.stringify(bundle, null, 2));
55165
55264
  const d = db || getDatabase();
@@ -55199,15 +55298,15 @@ function formatRunRecordMarkdown(record) {
55199
55298
  `;
55200
55299
  }
55201
55300
  function getDefaultReplayDir() {
55202
- const local = join14(process.cwd(), ".todos", "replays");
55203
- if (existsSync19(join14(process.cwd(), ".todos")))
55301
+ const local = join16(process.cwd(), ".todos", "replays");
55302
+ if (existsSync20(join16(process.cwd(), ".todos")))
55204
55303
  return local;
55205
- return join14(getHomeDir(), ".hasna", "todos", "replays");
55304
+ return join16(getTodosGlobalDir(), "replays");
55206
55305
  }
55207
55306
  // src/lib/release-checks.ts
55208
55307
  init_secret_redaction();
55209
- import { existsSync as existsSync20, readFileSync as readFileSync16, readdirSync as readdirSync4, statSync as statSync7 } from "fs";
55210
- import { join as join15, relative as relative5 } from "path";
55308
+ import { existsSync as existsSync21, readFileSync as readFileSync16, readdirSync as readdirSync4, statSync as statSync7 } from "fs";
55309
+ import { join as join17, relative as relative5 } from "path";
55211
55310
  var RELEASE_CHECK_SCHEMA = "todos.release_check.v1";
55212
55311
  var FORBIDDEN_DIST_PATTERNS = [
55213
55312
  {
@@ -55220,16 +55319,16 @@ var FORBIDDEN_DIST_PATTERNS = [
55220
55319
  ];
55221
55320
  var REQUIRED_BINS = ["todos", "todos-mcp", "todos-serve"];
55222
55321
  function readPackageJson3(root) {
55223
- const path = join15(root, "package.json");
55224
- if (!existsSync20(path))
55322
+ const path = join17(root, "package.json");
55323
+ if (!existsSync21(path))
55225
55324
  throw new Error(`package.json not found in ${root}`);
55226
55325
  return JSON.parse(readFileSync16(path, "utf8"));
55227
55326
  }
55228
55327
  function walkFiles(dir, acc = []) {
55229
- if (!existsSync20(dir))
55328
+ if (!existsSync21(dir))
55230
55329
  return acc;
55231
55330
  for (const entry2 of readdirSync4(dir)) {
55232
- const full = join15(dir, entry2);
55331
+ const full = join17(dir, entry2);
55233
55332
  const st = statSync7(full);
55234
55333
  if (st.isDirectory())
55235
55334
  walkFiles(full, acc);
@@ -55247,8 +55346,8 @@ function auditPackageContents(root) {
55247
55346
  checks.push({ id: "files_dist", severity: "error", message: "package.json files must include dist" });
55248
55347
  }
55249
55348
  for (const pattern of files) {
55250
- const target = join15(root, pattern);
55251
- if (!existsSync20(target)) {
55349
+ const target = join17(root, pattern);
55350
+ if (!existsSync21(target)) {
55252
55351
  checks.push({ id: `files_missing_${pattern}`, severity: "error", message: `Published file path missing: ${pattern}` });
55253
55352
  }
55254
55353
  }
@@ -55262,8 +55361,8 @@ function auditPackageContents(root) {
55262
55361
  checks.push({ id: `bin_${name}`, severity: "error", message: `Missing bin entry: ${name}` });
55263
55362
  continue;
55264
55363
  }
55265
- const binPath = join15(root, rel);
55266
- if (!existsSync20(binPath)) {
55364
+ const binPath = join17(root, rel);
55365
+ if (!existsSync21(binPath)) {
55267
55366
  checks.push({ id: `bin_path_${name}`, severity: "error", message: `Bin file missing: ${rel}` });
55268
55367
  } else {
55269
55368
  checks.push({ id: `bin_ok_${name}`, severity: "info", message: `Bin present: ${name} \u2192 ${rel}` });
@@ -55280,8 +55379,8 @@ function auditPackageContents(root) {
55280
55379
  }
55281
55380
  function scanDistArtifacts(root) {
55282
55381
  const checks = [];
55283
- const distDir = join15(root, "dist");
55284
- if (!existsSync20(distDir)) {
55382
+ const distDir = join17(root, "dist");
55383
+ if (!existsSync21(distDir)) {
55285
55384
  checks.push({ id: "dist_missing", severity: "error", message: "dist/ directory not found \u2014 run bun run build" });
55286
55385
  return checks;
55287
55386
  }
@@ -55591,15 +55690,15 @@ function renderReleaseNotesMarkdown(document) {
55591
55690
  // src/lib/db-backup.ts
55592
55691
  init_database();
55593
55692
  init_migrations();
55594
- import { existsSync as existsSync21, copyFileSync, mkdirSync as mkdirSync13, readFileSync as readFileSync17, renameSync, statSync as statSync8, writeFileSync as writeFileSync11, unlinkSync } from "fs";
55595
- import { dirname as dirname11, join as join16, resolve as resolve16 } from "path";
55693
+ import { existsSync as existsSync22, copyFileSync, mkdirSync as mkdirSync13, readFileSync as readFileSync17, renameSync, statSync as statSync8, writeFileSync as writeFileSync11, unlinkSync } from "fs";
55694
+ import { dirname as dirname11, join as join18, resolve as resolve17 } from "path";
55596
55695
  import { Database as Database4 } from "bun:sqlite";
55597
55696
  var DB_BACKUP_SCHEMA = "todos.db_backup.v1";
55598
55697
  function resolveDbPath(dbPath) {
55599
55698
  if (dbPath)
55600
- return resolve16(dbPath);
55699
+ return resolve17(dbPath);
55601
55700
  if (process.env["TODOS_DB_PATH"] && process.env["TODOS_DB_PATH"] !== ":memory:") {
55602
- return resolve16(process.env["TODOS_DB_PATH"]);
55701
+ return resolve17(process.env["TODOS_DB_PATH"]);
55603
55702
  }
55604
55703
  const db = getDatabase();
55605
55704
  const filename = db.filename;
@@ -55609,7 +55708,7 @@ function resolveDbPath(dbPath) {
55609
55708
  }
55610
55709
  function backupDatabase(outputPath, sourcePath) {
55611
55710
  const source9 = resolveDbPath(sourcePath);
55612
- if (!existsSync21(source9))
55711
+ if (!existsSync22(source9))
55613
55712
  throw new Error(`Database not found: ${source9}`);
55614
55713
  mkdirSync13(dirname11(outputPath), { recursive: true });
55615
55714
  closeDatabase();
@@ -55632,13 +55731,13 @@ function backupDatabase(outputPath, sourcePath) {
55632
55731
  };
55633
55732
  }
55634
55733
  function restoreDatabase(backupPath, targetPath) {
55635
- if (!existsSync21(backupPath))
55734
+ if (!existsSync22(backupPath))
55636
55735
  throw new Error(`Backup not found: ${backupPath}`);
55637
55736
  const integrity = checkDatabaseIntegrity(backupPath);
55638
55737
  if (!integrity.ok) {
55639
55738
  throw new Error(`Backup failed integrity check: ${integrity.errors.join("; ")}`);
55640
55739
  }
55641
- const target = targetPath ? resolve16(targetPath) : resolveDbPath();
55740
+ const target = targetPath ? resolve17(targetPath) : resolveDbPath();
55642
55741
  mkdirSync13(dirname11(target), { recursive: true });
55643
55742
  closeDatabase();
55644
55743
  const staging = `${target}.restore.tmp`;
@@ -55648,7 +55747,7 @@ function restoreDatabase(backupPath, targetPath) {
55648
55747
  copyFileSync(backupPath, staging);
55649
55748
  for (const sidecar of [`${target}-wal`, `${target}-shm`]) {
55650
55749
  try {
55651
- if (existsSync21(sidecar))
55750
+ if (existsSync22(sidecar))
55652
55751
  unlinkSync(sidecar);
55653
55752
  } catch {}
55654
55753
  }
@@ -55663,9 +55762,9 @@ function restoreDatabase(backupPath, targetPath) {
55663
55762
  };
55664
55763
  }
55665
55764
  function checkDatabaseIntegrity(dbPath) {
55666
- const path = dbPath ? resolve16(dbPath) : resolveDbPath();
55765
+ const path = dbPath ? resolve17(dbPath) : resolveDbPath();
55667
55766
  const errors2 = [];
55668
- if (!existsSync21(path)) {
55767
+ if (!existsSync22(path)) {
55669
55768
  return {
55670
55769
  schema_version: DB_BACKUP_SCHEMA,
55671
55770
  path,
@@ -55728,7 +55827,7 @@ function checkDatabaseIntegrity(dbPath) {
55728
55827
  };
55729
55828
  }
55730
55829
  function compactDatabase(dbPath) {
55731
- const path = dbPath ? resolve16(dbPath) : resolveDbPath();
55830
+ const path = dbPath ? resolve17(dbPath) : resolveDbPath();
55732
55831
  const before = statSync8(path).size;
55733
55832
  const db = new Database4(path);
55734
55833
  db.exec("VACUUM");
@@ -55738,7 +55837,7 @@ function compactDatabase(dbPath) {
55738
55837
  return { path, bytes_before: before, bytes_after: after };
55739
55838
  }
55740
55839
  function migrationDryRun(dbPath) {
55741
- const path = dbPath ? resolve16(dbPath) : resolveDbPath();
55840
+ const path = dbPath ? resolve17(dbPath) : resolveDbPath();
55742
55841
  const db = new Database4(path, { readonly: true });
55743
55842
  let current = 0;
55744
55843
  try {
@@ -55762,13 +55861,13 @@ function migrationDryRun(dbPath) {
55762
55861
  };
55763
55862
  }
55764
55863
  function defaultBackupPath(dbPath) {
55765
- const base = dbPath ? dirname11(resolve16(dbPath)) : dirname11(resolveDbPath());
55864
+ const base = dbPath ? dirname11(resolve17(dbPath)) : dirname11(resolveDbPath());
55766
55865
  const stamp = new Date().toISOString().replace(/[:.]/g, "-");
55767
- return join16(base, "backups", `todos-${stamp}.db`);
55866
+ return join18(base, "backups", `todos-${stamp}.db`);
55768
55867
  }
55769
55868
  function readBackupManifest(backupPath) {
55770
55869
  const manifestPath = `${backupPath}.json`;
55771
- if (!existsSync21(manifestPath))
55870
+ if (!existsSync22(manifestPath))
55772
55871
  return null;
55773
55872
  try {
55774
55873
  return JSON.parse(readFileSync17(manifestPath, "utf8"));
@@ -56289,15 +56388,15 @@ ${SCHEMA_ENTITIES.map((e) => `- **${e}**: \`${JSON_SCHEMAS[e].schema_version}\``
56289
56388
  }
56290
56389
  function exportSchemasToDirectory(dir) {
56291
56390
  const { mkdirSync: mkdirSync14, writeFileSync: writeFileSync12 } = __require("fs");
56292
- const { join: join17 } = __require("path");
56391
+ const { join: join19 } = __require("path");
56293
56392
  mkdirSync14(dir, { recursive: true });
56294
56393
  const written = [];
56295
56394
  for (const entity of SCHEMA_ENTITIES) {
56296
- const path = join17(dir, `${entity}.${JSON_SCHEMAS[entity].schema_version.replace(/\./g, "-")}.json`);
56395
+ const path = join19(dir, `${entity}.${JSON_SCHEMAS[entity].schema_version.replace(/\./g, "-")}.json`);
56297
56396
  writeFileSync12(path, JSON.stringify(JSON_SCHEMAS[entity], null, 2));
56298
56397
  written.push(path);
56299
56398
  }
56300
- const catalogPath = join17(dir, "catalog.json");
56399
+ const catalogPath = join19(dir, "catalog.json");
56301
56400
  writeFileSync12(catalogPath, JSON.stringify({
56302
56401
  catalog_version: JSON_SCHEMA_CATALOG_VERSION,
56303
56402
  semver: SCHEMA_SEMVER,
@@ -58832,7 +58931,7 @@ init_templates();
58832
58931
  init_database();
58833
58932
  init_templates();
58834
58933
  import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync14 } from "fs";
58835
- import { join as join17 } from "path";
58934
+ import { join as join19 } from "path";
58836
58935
  var BUILTIN_TEMPLATE_LIBRARY_VERSION = "2026-05-21";
58837
58936
  var BUILTIN_TEMPLATE_LIBRARY_SOURCE = "bundled-local-template-library";
58838
58937
  var TEMPLATE_LIBRARY_SCHEMA = "todos.template_library.v1";
@@ -59108,7 +59207,7 @@ function writeBuiltinTemplateFiles(directory) {
59108
59207
  mkdirSync16(directory, { recursive: true });
59109
59208
  const files = [];
59110
59209
  for (const entry2 of exportBuiltinTemplateFiles()) {
59111
- const path = join17(directory, entry2.filename);
59210
+ const path = join19(directory, entry2.filename);
59112
59211
  writeFileSync14(path, `${JSON.stringify(entry2.template, null, 2)}
59113
59212
  `, "utf-8");
59114
59213
  files.push(path);
@@ -59400,9 +59499,9 @@ init_tasks();
59400
59499
  init_redaction();
59401
59500
  init_sync_utils();
59402
59501
  import { createHash as createHash20 } from "crypto";
59403
- import { existsSync as existsSync22, readFileSync as readFileSync20, statSync as statSync9 } from "fs";
59502
+ import { existsSync as existsSync23, readFileSync as readFileSync20, statSync as statSync9 } from "fs";
59404
59503
  import { hostname as hostname3, platform, arch } from "os";
59405
- import { dirname as dirname15, join as join18, resolve as resolve17 } from "path";
59504
+ import { dirname as dirname15, join as join20, resolve as resolve18 } from "path";
59406
59505
  import { tmpdir as tmpdir3 } from "os";
59407
59506
  var MANIFEST_FILES = ["package.json", "dashboard/package.json", "sdk/package.json"];
59408
59507
  var LOCKFILES = ["bun.lock", "bun.lockb", "package-lock.json", "npm-shrinkwrap.json"];
@@ -59424,8 +59523,8 @@ function sha2566(value) {
59424
59523
  return createHash20("sha256").update(value).digest("hex");
59425
59524
  }
59426
59525
  function fileRecord(root, relativePath) {
59427
- const path = join18(root, relativePath);
59428
- if (!existsSync22(path))
59526
+ const path = join20(root, relativePath);
59527
+ if (!existsSync23(path))
59429
59528
  return null;
59430
59529
  const stat = statSync9(path);
59431
59530
  if (!stat.isFile())
@@ -59437,7 +59536,7 @@ function manifestRecord(root, relativePath) {
59437
59536
  const base = fileRecord(root, relativePath);
59438
59537
  if (!base)
59439
59538
  return null;
59440
- const parsed = readJsonFile(join18(root, relativePath));
59539
+ const parsed = readJsonFile(join20(root, relativePath));
59441
59540
  if (!parsed)
59442
59541
  return { ...base, redacted: {} };
59443
59542
  const redacted = redactValue({
@@ -59532,15 +59631,15 @@ function commandEnv(env, includeValues) {
59532
59631
  function defaultSnapshotDir() {
59533
59632
  const dbPath = getDatabasePath();
59534
59633
  if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
59535
- return join18(tmpdir3(), "hasna-todos", "environment-snapshots");
59536
- return join18(dirname15(resolve17(dbPath)), "environment-snapshots");
59634
+ return join20(tmpdir3(), "hasna-todos", "environment-snapshots");
59635
+ return join20(dirname15(resolve18(dbPath)), "environment-snapshots");
59537
59636
  }
59538
59637
  function snapshotWithId(snapshot) {
59539
59638
  const digest3 = sha2566(JSON.stringify(snapshot)).slice(0, 24);
59540
59639
  return { id: `env_${digest3}`, ...snapshot };
59541
59640
  }
59542
59641
  function captureEnvironmentSnapshot(input = {}) {
59543
- const root = resolve17(input.root || process.cwd());
59642
+ const root = resolve18(input.root || process.cwd());
59544
59643
  const env = input.env || process.env;
59545
59644
  const warnings = [];
59546
59645
  const manifests = MANIFEST_FILES.map((file) => manifestRecord(root, file)).filter((file) => Boolean(file));
@@ -59580,13 +59679,13 @@ function captureEnvironmentSnapshot(input = {}) {
59580
59679
  });
59581
59680
  }
59582
59681
  function writeEnvironmentSnapshot(snapshot, outputPath) {
59583
- const path = outputPath ? resolve17(outputPath) : join18(defaultSnapshotDir(), `${snapshot.id}.json`);
59682
+ const path = outputPath ? resolve18(outputPath) : join20(defaultSnapshotDir(), `${snapshot.id}.json`);
59584
59683
  ensureDir(dirname15(path));
59585
59684
  writeJsonFile(path, snapshot);
59586
59685
  return path;
59587
59686
  }
59588
59687
  function readEnvironmentSnapshot(path) {
59589
- const snapshot = readJsonFile(resolve17(path));
59688
+ const snapshot = readJsonFile(resolve18(path));
59590
59689
  if (!snapshot || snapshot.schema_version !== 1 || typeof snapshot.id !== "string") {
59591
59690
  throw new Error(`Invalid environment snapshot: ${path}`);
59592
59691
  }
@@ -59675,7 +59774,7 @@ init_projects();
59675
59774
  init_plans();
59676
59775
  import { createHash as createHash21 } from "crypto";
59677
59776
  import { mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
59678
- import { dirname as dirname16, join as join19 } from "path";
59777
+ import { dirname as dirname16, join as join21 } from "path";
59679
59778
  var DECISION_RECORD_SCHEMA = "todos.decision_record.v1";
59680
59779
  var KNOWLEDGE_SNAPSHOT_SCHEMA = "todos.knowledge_snapshot.v1";
59681
59780
  var DECISION_STATUSES = ["proposed", "accepted", "deprecated", "superseded", "rejected"];
@@ -59905,7 +60004,7 @@ function exportDecisionRecord(id, outputPath, format = "markdown", db) {
59905
60004
  if (!record)
59906
60005
  throw new Error(`Decision record not found: ${id}`);
59907
60006
  const content = format === "markdown" ? formatDecisionRecordMarkdown(record) : JSON.stringify(record, null, 2);
59908
- const path = outputPath ?? join19(process.cwd(), ".todos", "decisions", `${record.short_ref}.${format === "markdown" ? "md" : "json"}`);
60007
+ const path = outputPath ?? join21(process.cwd(), ".todos", "decisions", `${record.short_ref}.${format === "markdown" ? "md" : "json"}`);
59909
60008
  mkdirSync18(dirname16(path), { recursive: true });
59910
60009
  writeFileSync16(path, content, "utf8");
59911
60010
  return { path, content };
@@ -60053,7 +60152,7 @@ function exportKnowledgeSnapshot(id, outputPath, format = "markdown", db) {
60053
60152
  throw new Error(`Knowledge snapshot not found: ${id}`);
60054
60153
  const content = format === "markdown" ? formatKnowledgeSnapshotMarkdown(record) : JSON.stringify(record, null, 2);
60055
60154
  const slug = record.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
60056
- const path = outputPath ?? join19(process.cwd(), ".todos", "knowledge", `${slug || record.id.slice(0, 8)}.${format === "markdown" ? "md" : "json"}`);
60155
+ const path = outputPath ?? join21(process.cwd(), ".todos", "knowledge", `${slug || record.id.slice(0, 8)}.${format === "markdown" ? "md" : "json"}`);
60057
60156
  mkdirSync18(dirname16(path), { recursive: true });
60058
60157
  writeFileSync16(path, content, "utf8");
60059
60158
  return { path, content };
@@ -60352,8 +60451,8 @@ todos report export --kind retrospective --days 14 --format markdown --out retro
60352
60451
  `;
60353
60452
  }
60354
60453
  // src/lib/command-aliases.ts
60355
- import { existsSync as existsSync23, readFileSync as readFileSync21, writeFileSync as writeFileSync18, mkdirSync as mkdirSync20 } from "fs";
60356
- import { join as join20 } from "path";
60454
+ import { existsSync as existsSync24, readFileSync as readFileSync21, writeFileSync as writeFileSync18, mkdirSync as mkdirSync20 } from "fs";
60455
+ import { join as join22 } from "path";
60357
60456
  var COMMAND_ALIASES_SCHEMA = "todos.command_aliases.v1";
60358
60457
  var RESERVED = new Set([...listTopLevelCommands(), "help", "version", "alias", "shortcuts"]);
60359
60458
  var BUILTIN_SHORTCUTS = [
@@ -60372,7 +60471,7 @@ var BUILTIN_SHORTCUTS = [
60372
60471
  { pattern: /^reports?$/, argv: ["report", "docs"], explain: "Report export documentation" }
60373
60472
  ];
60374
60473
  function aliasesPath(cwd = process.cwd()) {
60375
- return join20(cwd, ".todos", "aliases.json");
60474
+ return join22(cwd, ".todos", "aliases.json");
60376
60475
  }
60377
60476
  function emptyStore() {
60378
60477
  return { schema_version: COMMAND_ALIASES_SCHEMA, aliases: {}, updated_at: new Date(0).toISOString() };
@@ -60389,7 +60488,7 @@ function validateAliasName(name) {
60389
60488
  }
60390
60489
  function loadAliasStore(cwd) {
60391
60490
  const path = aliasesPath(cwd);
60392
- if (!existsSync23(path))
60491
+ if (!existsSync24(path))
60393
60492
  return emptyStore();
60394
60493
  const parsed = JSON.parse(readFileSync21(path, "utf8"));
60395
60494
  if (parsed.schema_version !== COMMAND_ALIASES_SCHEMA) {
@@ -60399,7 +60498,7 @@ function loadAliasStore(cwd) {
60399
60498
  }
60400
60499
  function saveAliasStore(store, cwd) {
60401
60500
  const path = aliasesPath(cwd);
60402
- mkdirSync20(join20(path, ".."), { recursive: true });
60501
+ mkdirSync20(join22(path, ".."), { recursive: true });
60403
60502
  store.updated_at = new Date().toISOString();
60404
60503
  writeFileSync18(path, JSON.stringify(store, null, 2), "utf8");
60405
60504
  }
@@ -61054,18 +61153,18 @@ function createBranchWorkPlan(input, db) {
61054
61153
  init_database();
61055
61154
  init_templates();
61056
61155
  init_plans();
61057
- import { existsSync as existsSync24, readFileSync as readFileSync22, writeFileSync as writeFileSync19, mkdirSync as mkdirSync21 } from "fs";
61058
- import { join as join21 } from "path";
61156
+ import { existsSync as existsSync25, readFileSync as readFileSync22, writeFileSync as writeFileSync19, mkdirSync as mkdirSync21 } from "fs";
61157
+ import { join as join23 } from "path";
61059
61158
  var USER_SCAFFOLD_SCHEMA = "todos.user_scaffold.v1";
61060
61159
  var SCAFFOLD_KINDS = ["task", "project", "plan", "checklist", "contract", "verification_policy"];
61061
61160
  function storeDir(cwd = process.cwd()) {
61062
- return join21(cwd, ".todos", "scaffolds");
61161
+ return join23(cwd, ".todos", "scaffolds");
61063
61162
  }
61064
61163
  function storePath(cwd) {
61065
- return join21(storeDir(cwd), "store.json");
61164
+ return join23(storeDir(cwd), "store.json");
61066
61165
  }
61067
61166
  function versionsDir(cwd) {
61068
- return join21(storeDir(cwd), "versions");
61167
+ return join23(storeDir(cwd), "versions");
61069
61168
  }
61070
61169
  function slugify4(name) {
61071
61170
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
@@ -61075,7 +61174,7 @@ function emptyStore2() {
61075
61174
  }
61076
61175
  function loadUserScaffoldStore(cwd) {
61077
61176
  const path = storePath(cwd);
61078
- if (!existsSync24(path))
61177
+ if (!existsSync25(path))
61079
61178
  return emptyStore2();
61080
61179
  const parsed = JSON.parse(readFileSync22(path, "utf8"));
61081
61180
  if (parsed.schema_version !== USER_SCAFFOLD_SCHEMA) {
@@ -61090,7 +61189,7 @@ function saveUserScaffoldStore(store, cwd) {
61090
61189
  }
61091
61190
  function snapshotVersion(scaffold, cwd) {
61092
61191
  mkdirSync21(versionsDir(cwd), { recursive: true });
61093
- const path = join21(versionsDir(cwd), `${scaffold.id}-v${scaffold.version}.json`);
61192
+ const path = join23(versionsDir(cwd), `${scaffold.id}-v${scaffold.version}.json`);
61094
61193
  writeFileSync19(path, JSON.stringify(scaffold, null, 2), "utf8");
61095
61194
  }
61096
61195
  function listUserScaffolds(kind, cwd) {
@@ -61337,7 +61436,7 @@ function listLinkedTemplates(db, cwd) {
61337
61436
  // src/lib/agent-workflow-demo.ts
61338
61437
  init_database();
61339
61438
  import { mkdtempSync } from "fs";
61340
- import { join as join22 } from "path";
61439
+ import { join as join24 } from "path";
61341
61440
  import { tmpdir as tmpdir4 } from "os";
61342
61441
  init_projects();
61343
61442
  init_task_lists();
@@ -61358,7 +61457,7 @@ function setupEphemeralDemoDb(options = {}) {
61358
61457
  if (options.db_path) {
61359
61458
  db_path = options.db_path;
61360
61459
  } else if (options.persist) {
61361
- db_path = join22(mkdtempSync(join22(tmpdir4(), "todos-demo-")), "todos.db");
61460
+ db_path = join24(mkdtempSync(join24(tmpdir4(), "todos-demo-")), "todos.db");
61362
61461
  } else {
61363
61462
  db_path = ":memory:";
61364
61463
  }
@@ -63695,16 +63794,16 @@ function runSearchView(idOrName, db) {
63695
63794
  init_tasks();
63696
63795
  init_config2();
63697
63796
  init_sync_utils();
63698
- import { existsSync as existsSync25, readFileSync as readFileSync23, readdirSync as readdirSync5, writeFileSync as writeFileSync20 } from "fs";
63699
- import { join as join23 } from "path";
63797
+ import { existsSync as existsSync26, readFileSync as readFileSync23, readdirSync as readdirSync5, writeFileSync as writeFileSync20 } from "fs";
63798
+ import { join as join25 } from "path";
63700
63799
  function getTaskListDir(taskListId) {
63701
- return join23(HOME, ".claude", "tasks", taskListId);
63800
+ return join25(HOME, ".claude", "tasks", taskListId);
63702
63801
  }
63703
63802
  function readClaudeTask(dir, filename) {
63704
- return readJsonFile(join23(dir, filename));
63803
+ return readJsonFile(join25(dir, filename));
63705
63804
  }
63706
63805
  function writeClaudeTask(dir, task3) {
63707
- writeJsonFile(join23(dir, `${task3.id}.json`), task3);
63806
+ writeJsonFile(join25(dir, `${task3.id}.json`), task3);
63708
63807
  }
63709
63808
  function toClaudeStatus(status3) {
63710
63809
  if (status3 === "pending" || status3 === "in_progress" || status3 === "completed") {
@@ -63716,14 +63815,14 @@ function toSqliteStatus(status3) {
63716
63815
  return status3;
63717
63816
  }
63718
63817
  function readPrefixCounter(dir) {
63719
- const path = join23(dir, ".prefix-counter");
63720
- if (!existsSync25(path))
63818
+ const path = join25(dir, ".prefix-counter");
63819
+ if (!existsSync26(path))
63721
63820
  return 0;
63722
63821
  const val = parseInt(readFileSync23(path, "utf-8").trim(), 10);
63723
63822
  return isNaN(val) ? 0 : val;
63724
63823
  }
63725
63824
  function writePrefixCounter(dir, value) {
63726
- writeFileSync20(join23(dir, ".prefix-counter"), String(value));
63825
+ writeFileSync20(join25(dir, ".prefix-counter"), String(value));
63727
63826
  }
63728
63827
  function formatPrefixedSubject(title, prefix, counter) {
63729
63828
  const padded = String(counter).padStart(5, "0");
@@ -63750,7 +63849,7 @@ function taskToClaudeTask(task3, claudeTaskId, existingMeta) {
63750
63849
  }
63751
63850
  function pushToClaudeTaskList(taskListId, projectId, options = {}) {
63752
63851
  const dir = getTaskListDir(taskListId);
63753
- if (!existsSync25(dir))
63852
+ if (!existsSync26(dir))
63754
63853
  ensureDir(dir);
63755
63854
  const filter = {};
63756
63855
  if (projectId)
@@ -63759,7 +63858,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
63759
63858
  const existingByTodosId = new Map;
63760
63859
  const files = listJsonFiles(dir);
63761
63860
  for (const f of files) {
63762
- const path = join23(dir, f);
63861
+ const path = join25(dir, f);
63763
63862
  const ct = readClaudeTask(dir, f);
63764
63863
  if (ct?.metadata?.["todos_id"]) {
63765
63864
  existingByTodosId.set(ct.metadata["todos_id"], { task: ct, mtimeMs: getFileMtimeMs(path) });
@@ -63848,7 +63947,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
63848
63947
  }
63849
63948
  function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
63850
63949
  const dir = getTaskListDir(taskListId);
63851
- if (!existsSync25(dir)) {
63950
+ if (!existsSync26(dir)) {
63852
63951
  return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
63853
63952
  }
63854
63953
  const files = readdirSync5(dir).filter((f) => f.endsWith(".json"));
@@ -63868,7 +63967,7 @@ function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
63868
63967
  }
63869
63968
  for (const f of files) {
63870
63969
  try {
63871
- const filePath = join23(dir, f);
63970
+ const filePath = join25(dir, f);
63872
63971
  const ct = readClaudeTask(dir, f);
63873
63972
  if (!ct)
63874
63973
  continue;
@@ -63939,20 +64038,20 @@ function syncClaudeTaskList(taskListId, projectId, options = {}) {
63939
64038
  init_tasks();
63940
64039
  init_sync_utils();
63941
64040
  init_config2();
63942
- import { existsSync as existsSync26 } from "fs";
63943
- import { join as join24 } from "path";
64041
+ import { existsSync as existsSync27 } from "fs";
64042
+ import { join as join26 } from "path";
63944
64043
  function agentBaseDir(agent) {
63945
64044
  const key2 = `TODOS_${agent.toUpperCase()}_TASKS_DIR`;
63946
- return process.env[key2] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join24(getTodosGlobalDir(), "agents");
64045
+ return process.env[key2] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join26(getTodosGlobalDir(), "agents");
63947
64046
  }
63948
64047
  function getTaskListDir2(agent, taskListId) {
63949
- return join24(agentBaseDir(agent), agent, taskListId);
64048
+ return join26(agentBaseDir(agent), agent, taskListId);
63950
64049
  }
63951
64050
  function readAgentTask(dir, filename) {
63952
- return readJsonFile(join24(dir, filename));
64051
+ return readJsonFile(join26(dir, filename));
63953
64052
  }
63954
64053
  function writeAgentTask(dir, task3) {
63955
- writeJsonFile(join24(dir, `${task3.id}.json`), task3);
64054
+ writeJsonFile(join26(dir, `${task3.id}.json`), task3);
63956
64055
  }
63957
64056
  function taskToAgentTask(task3, externalId, existingMeta) {
63958
64057
  return withSyncFingerprint({
@@ -63977,7 +64076,7 @@ function metadataKey(agent) {
63977
64076
  }
63978
64077
  function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
63979
64078
  const dir = getTaskListDir2(agent, taskListId);
63980
- if (!existsSync26(dir))
64079
+ if (!existsSync27(dir))
63981
64080
  ensureDir(dir);
63982
64081
  const filter = {};
63983
64082
  if (projectId)
@@ -63986,7 +64085,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
63986
64085
  const existingByTodosId = new Map;
63987
64086
  const files = listJsonFiles(dir);
63988
64087
  for (const f of files) {
63989
- const path = join24(dir, f);
64088
+ const path = join26(dir, f);
63990
64089
  const at = readAgentTask(dir, f);
63991
64090
  if (at?.metadata?.["todos_id"]) {
63992
64091
  existingByTodosId.set(at.metadata["todos_id"], { task: at, mtimeMs: getFileMtimeMs(path) });
@@ -64062,7 +64161,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
64062
64161
  }
64063
64162
  function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
64064
64163
  const dir = getTaskListDir2(agent, taskListId);
64065
- if (!existsSync26(dir)) {
64164
+ if (!existsSync27(dir)) {
64066
64165
  return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
64067
64166
  }
64068
64167
  const files = listJsonFiles(dir);
@@ -64081,7 +64180,7 @@ function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
64081
64180
  }
64082
64181
  for (const f of files) {
64083
64182
  try {
64084
- const filePath = join24(dir, f);
64183
+ const filePath = join26(dir, f);
64085
64184
  const at = readAgentTask(dir, f);
64086
64185
  if (!at)
64087
64186
  continue;
@@ -64221,9 +64320,9 @@ function syncWithAgents(agents, taskListIdByAgent, projectId, direction = "both"
64221
64320
  // src/lib/extract.ts
64222
64321
  init_tasks();
64223
64322
  init_task_files();
64224
- import { existsSync as existsSync27, readFileSync as readFileSync24, statSync as statSync10 } from "fs";
64323
+ import { existsSync as existsSync28, readFileSync as readFileSync24, statSync as statSync10 } from "fs";
64225
64324
  import { createHash as createHash22 } from "crypto";
64226
- import { relative as relative6, resolve as resolve18, join as join25 } from "path";
64325
+ import { relative as relative6, resolve as resolve19, join as join27 } from "path";
64227
64326
  var EXTRACT_TAGS = ["TODO", "FIXME", "HACK", "XXX", "BUG", "NOTE"];
64228
64327
  var DEFAULT_EXTENSIONS = new Set([
64229
64328
  ".ts",
@@ -64293,9 +64392,9 @@ function normalizePathForMatch(value) {
64293
64392
  return value.replace(/\\/g, "/").replace(/^\.\//, "");
64294
64393
  }
64295
64394
  function readGitignorePatterns(basePath) {
64296
- const root = statSync10(basePath).isFile() ? resolve18(basePath, "..") : basePath;
64297
- const gitignorePath = join25(root, ".gitignore");
64298
- if (!existsSync27(gitignorePath))
64395
+ const root = statSync10(basePath).isFile() ? resolve19(basePath, "..") : basePath;
64396
+ const gitignorePath = join27(root, ".gitignore");
64397
+ if (!existsSync28(gitignorePath))
64299
64398
  return [];
64300
64399
  try {
64301
64400
  return readFileSync24(gitignorePath, "utf-8").split(`
@@ -64429,7 +64528,7 @@ function collectFiles(basePath, extensions, excludes, respectGitignore) {
64429
64528
  return files.sort();
64430
64529
  }
64431
64530
  function buildCodebaseIndex(options) {
64432
- const basePath = resolve18(options.path);
64531
+ const basePath = resolve19(options.path);
64433
64532
  const tags = options.patterns || [...EXTRACT_TAGS];
64434
64533
  const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
64435
64534
  const excludes = options.exclude || [];
@@ -64437,10 +64536,10 @@ function buildCodebaseIndex(options) {
64437
64536
  const files = collectFiles(basePath, extensions, excludes, respectGitignore);
64438
64537
  const indexed = [];
64439
64538
  for (const file of files) {
64440
- const fullPath = statSync10(basePath).isFile() ? basePath : join25(basePath, file);
64539
+ const fullPath = statSync10(basePath).isFile() ? basePath : join27(basePath, file);
64441
64540
  try {
64442
64541
  const source9 = readFileSync24(fullPath, "utf-8");
64443
- const relPath = statSync10(basePath).isFile() ? relative6(resolve18(basePath, ".."), fullPath) : file;
64542
+ const relPath = statSync10(basePath).isFile() ? relative6(resolve19(basePath, ".."), fullPath) : file;
64444
64543
  indexed.push({
64445
64544
  file: relPath,
64446
64545
  checksum: stableHash(source9).slice(0, 24),
@@ -64460,7 +64559,7 @@ function buildCodebaseIndex(options) {
64460
64559
  };
64461
64560
  }
64462
64561
  function extractTodos(options, db) {
64463
- const basePath = resolve18(options.path);
64562
+ const basePath = resolve19(options.path);
64464
64563
  const tags = options.patterns || [...EXTRACT_TAGS];
64465
64564
  const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
64466
64565
  const excludes = options.exclude || [];
@@ -64468,10 +64567,10 @@ function extractTodos(options, db) {
64468
64567
  const files = collectFiles(basePath, extensions, excludes, respectGitignore);
64469
64568
  const allComments = [];
64470
64569
  for (const file of files) {
64471
- const fullPath = statSync10(basePath).isFile() ? basePath : join25(basePath, file);
64570
+ const fullPath = statSync10(basePath).isFile() ? basePath : join27(basePath, file);
64472
64571
  try {
64473
64572
  const source9 = readFileSync24(fullPath, "utf-8");
64474
- const relPath = statSync10(basePath).isFile() ? relative6(resolve18(basePath, ".."), fullPath) : file;
64573
+ const relPath = statSync10(basePath).isFile() ? relative6(resolve19(basePath, ".."), fullPath) : file;
64475
64574
  const comments = extractFromSource(source9, relPath, tags);
64476
64575
  allComments.push(...comments);
64477
64576
  } catch {}
@@ -64565,7 +64664,7 @@ async function watchSourceTodos(options, onRun) {
64565
64664
  const interval = Math.max(100, options.interval_ms || 2000);
64566
64665
  const once = options.once !== false && (!options.max_runs || options.max_runs <= 1);
64567
64666
  const maxRuns = options.max_runs ?? (once ? 1 : Number.POSITIVE_INFINITY);
64568
- const root = resolve18(options.path);
64667
+ const root = resolve19(options.path);
64569
64668
  const runs = [];
64570
64669
  let previous = new Map;
64571
64670
  for (let runNumber = 1;runNumber <= maxRuns; runNumber++) {
@@ -65447,8 +65546,8 @@ function renderAgentReplaySimulationMarkdown(simulation) {
65447
65546
  // src/lib/local-extensions.ts
65448
65547
  init_config2();
65449
65548
  import { createHash as createHash24, createVerify } from "crypto";
65450
- import { existsSync as existsSync28, readdirSync as readdirSync6, readFileSync as readFileSync26, statSync as statSync11 } from "fs";
65451
- import { basename as basename6, join as join26, resolve as resolve19 } from "path";
65549
+ import { existsSync as existsSync29, readdirSync as readdirSync6, readFileSync as readFileSync26, statSync as statSync11 } from "fs";
65550
+ import { basename as basename6, join as join28, resolve as resolve20 } from "path";
65452
65551
  init_redaction();
65453
65552
  init_runner_sandbox();
65454
65553
  function isObject2(value) {
@@ -65729,11 +65828,11 @@ function verifyExtensionSignature(input) {
65729
65828
  return verifier.verify(input.public_key, decodeSignature(input.signature));
65730
65829
  }
65731
65830
  function inspectExtensionSource(source9) {
65732
- const resolved = resolve19(source9);
65733
- if (!existsSync28(resolved))
65831
+ const resolved = resolve20(source9);
65832
+ if (!existsSync29(resolved))
65734
65833
  throw new Error(`extension source not found: ${source9}`);
65735
65834
  const stat = statSync11(resolved);
65736
- const manifestPath = stat.isDirectory() ? [join26(resolved, "todos.extension.json"), join26(resolved, "extension.json")].find(existsSync28) : resolved;
65835
+ const manifestPath = stat.isDirectory() ? [join28(resolved, "todos.extension.json"), join28(resolved, "extension.json")].find(existsSync29) : resolved;
65737
65836
  if (!manifestPath)
65738
65837
  throw new Error(`extension directory ${source9} is missing todos.extension.json`);
65739
65838
  const raw = readFileSync26(manifestPath);
@@ -65827,26 +65926,26 @@ function testExtensionCompatibility(sourceOrManifest) {
65827
65926
  function projectExtensionSources(projectPath) {
65828
65927
  if (!projectPath)
65829
65928
  return [];
65830
- const root = resolve19(projectPath);
65929
+ const root = resolve20(projectPath);
65831
65930
  const candidates = [
65832
- join26(root, "todos.extension.json"),
65833
- join26(root, ".todos", "todos.extension.json")
65931
+ join28(root, "todos.extension.json"),
65932
+ join28(root, ".todos", "todos.extension.json")
65834
65933
  ];
65835
- const extensionDir = join26(root, ".todos", "extensions");
65836
- if (existsSync28(extensionDir)) {
65934
+ const extensionDir = join28(root, ".todos", "extensions");
65935
+ if (existsSync29(extensionDir)) {
65837
65936
  for (const entry2 of readdirSync6(extensionDir)) {
65838
65937
  if (entry2.startsWith("."))
65839
65938
  continue;
65840
- const full = join26(extensionDir, entry2);
65939
+ const full = join28(extensionDir, entry2);
65841
65940
  if (statSync11(full).isDirectory() || entry2.endsWith(".json"))
65842
65941
  candidates.push(full);
65843
65942
  }
65844
65943
  }
65845
- return candidates.filter(existsSync28);
65944
+ return candidates.filter(existsSync29);
65846
65945
  }
65847
65946
  function discoverLocalExtensions(options = {}) {
65848
65947
  const config = loadConfig();
65849
- const projectPath = options.project_path ? resolve19(options.project_path) : null;
65948
+ const projectPath = options.project_path ? resolve20(options.project_path) : null;
65850
65949
  const configuredSources = [
65851
65950
  ...config.extension_sources || [],
65852
65951
  ...projectPath ? config.project_overrides?.[projectPath]?.extension_sources || [] : []
@@ -65854,7 +65953,7 @@ function discoverLocalExtensions(options = {}) {
65854
65953
  const sources = Array.from(new Set([
65855
65954
  ...configuredSources,
65856
65955
  ...projectExtensionSources(projectPath || undefined)
65857
- ])).map((source9) => projectPath && !source9.startsWith("/") ? resolve19(projectPath, source9) : resolve19(source9));
65956
+ ])).map((source9) => projectPath && !source9.startsWith("/") ? resolve20(projectPath, source9) : resolve20(source9));
65858
65957
  const warnings = [];
65859
65958
  const discovered = [];
65860
65959
  for (const source9 of sources) {
@@ -66722,7 +66821,7 @@ init_redaction();
66722
66821
  // src/lib/retention-cleanup.ts
66723
66822
  init_artifact_store();
66724
66823
  init_database();
66725
- import { existsSync as existsSync29, unlinkSync as unlinkSync2 } from "fs";
66824
+ import { existsSync as existsSync30, unlinkSync as unlinkSync2 } from "fs";
66726
66825
  var RETENTION_CLEANUP_CONFIRMATION = "delete-local-retention-data";
66727
66826
  var ALL_SCOPES = ["comments", "runs", "verifications", "expired_artifacts"];
66728
66827
  var EMPTY_COUNTS = {
@@ -66933,7 +67032,7 @@ function applyRetentionCleanup(input, db) {
66933
67032
  for (const artifact of report.candidates.artifact_files) {
66934
67033
  try {
66935
67034
  const path = artifactStorePath(artifact.relative_path);
66936
- if (!existsSync29(path)) {
67035
+ if (!existsSync30(path)) {
66937
67036
  report.warnings.push(`stored artifact already missing: ${artifact.relative_path}`);
66938
67037
  continue;
66939
67038
  }
@@ -67174,8 +67273,8 @@ init_artifact_store();
67174
67273
 
67175
67274
  // src/lib/doctor.ts
67176
67275
  init_database();
67177
- import { chmodSync, copyFileSync as copyFileSync2, existsSync as existsSync30, mkdirSync as mkdirSync22, statSync as statSync12 } from "fs";
67178
- import { basename as basename7, dirname as dirname18, join as join27 } from "path";
67276
+ import { chmodSync, copyFileSync as copyFileSync2, existsSync as existsSync31, mkdirSync as mkdirSync22, statSync as statSync12 } from "fs";
67277
+ import { basename as basename7, dirname as dirname18, join as join29 } from "path";
67179
67278
  init_migrations();
67180
67279
  init_schema();
67181
67280
  init_recurrence();
@@ -67285,7 +67384,7 @@ function findMissingProjectRoots(db) {
67285
67384
  continue;
67286
67385
  if (!row.path.startsWith("/"))
67287
67386
  continue;
67288
- if (!existsSync30(row.path))
67387
+ if (!existsSync31(row.path))
67289
67388
  missing++;
67290
67389
  }
67291
67390
  return missing;
@@ -67345,16 +67444,16 @@ function databasePermissionsAreUnsafe(dbPath) {
67345
67444
  function createBackup(dbPath) {
67346
67445
  if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
67347
67446
  return;
67348
- if (!existsSync30(dbPath))
67447
+ if (!existsSync31(dbPath))
67349
67448
  return;
67350
67449
  const stamp = now().replace(/[:.]/g, "-");
67351
- const backupDir = join27(dirname18(dbPath), `${basename7(dbPath)}.backup-${stamp}`);
67450
+ const backupDir = join29(dirname18(dbPath), `${basename7(dbPath)}.backup-${stamp}`);
67352
67451
  const files = [];
67353
67452
  mkdirSync22(backupDir, { recursive: true });
67354
67453
  for (const source9 of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
67355
- if (!existsSync30(source9))
67454
+ if (!existsSync31(source9))
67356
67455
  continue;
67357
- const target = join27(backupDir, basename7(source9));
67456
+ const target = join29(backupDir, basename7(source9));
67358
67457
  copyFileSync2(source9, target);
67359
67458
  files.push(target);
67360
67459
  }