@hasna/todos 0.11.53 → 0.11.54

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/cli/index.js CHANGED
@@ -1011,7 +1011,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1011
1011
  this._exitCallback = (err) => {
1012
1012
  if (err.code !== "commander.executeSubCommandAsync") {
1013
1013
  throw err;
1014
- } else {}
1014
+ }
1015
1015
  };
1016
1016
  }
1017
1017
  return this;
@@ -2119,15 +2119,15 @@ var init_esm = __esm(() => {
2119
2119
  });
2120
2120
 
2121
2121
  // src/lib/package-version.ts
2122
- import { existsSync, readFileSync } from "fs";
2123
- import { dirname, join } from "path";
2122
+ import { existsSync as existsSync2, readFileSync } from "fs";
2123
+ import { dirname, join as join2 } from "path";
2124
2124
  import { fileURLToPath } from "url";
2125
2125
  function getPackageVersion(fromUrl = import.meta.url) {
2126
2126
  try {
2127
2127
  let dir = dirname(fileURLToPath(fromUrl));
2128
2128
  for (let i = 0;i < 5; i++) {
2129
- const pkgPath = join(dir, "package.json");
2130
- if (existsSync(pkgPath)) {
2129
+ const pkgPath = join2(dir, "package.json");
2130
+ if (existsSync2(pkgPath)) {
2131
2131
  return JSON.parse(readFileSync(pkgPath, "utf-8")).version || "0.0.0";
2132
2132
  }
2133
2133
  const parent = dirname(dir);
@@ -4285,7 +4285,7 @@ var init_schema = __esm(() => {
4285
4285
  });
4286
4286
 
4287
4287
  // src/db/machines.ts
4288
- import { existsSync as existsSync2 } from "fs";
4288
+ import { existsSync as existsSync3 } from "fs";
4289
4289
  import { hostname as osHostname, platform as osPlatform, arch as osArch } from "os";
4290
4290
  import { resolve } from "path";
4291
4291
  import { spawnSync } from "child_process";
@@ -4351,11 +4351,11 @@ function getOrCreateLocalMachine(db) {
4351
4351
  const plat = osPlatform();
4352
4352
  const existing = d.query("SELECT * FROM machines WHERE name = ?").get(name);
4353
4353
  if (existing) {
4354
- d.run("UPDATE machines SET hostname = ?, platform = ?, last_seen_at = ? WHERE id = ?", [host, plat, now(), existing.id]);
4355
- return rowToMachine({ ...existing, hostname: host, platform: plat, last_seen_at: now() });
4354
+ d.run("UPDATE machines SET hostname = ?, platform = ?, last_seen_at = ? WHERE id = ?", [host, plat, now2(), existing.id]);
4355
+ return rowToMachine({ ...existing, hostname: host, platform: plat, last_seen_at: now2() });
4356
4356
  }
4357
4357
  const id = uuid();
4358
- const ts = now();
4358
+ const ts = now2();
4359
4359
  d.run("INSERT INTO machines (id, name, hostname, platform, last_seen_at, metadata, created_at) VALUES (?, ?, ?, ?, ?, '{}', ?)", [id, name, host, plat, ts, ts]);
4360
4360
  return { id, name, hostname: host, platform: plat, ssh_address: null, is_primary: false, last_seen_at: ts, archived_at: null, metadata: {}, created_at: ts };
4361
4361
  }
@@ -4391,7 +4391,7 @@ function registerMachine(name, opts, db) {
4391
4391
  opts.hostname ?? existing.hostname,
4392
4392
  opts.platform ?? existing.platform,
4393
4393
  opts.ssh_address ?? existing.ssh_address,
4394
- now(),
4394
+ now2(),
4395
4395
  JSON.stringify(metadata),
4396
4396
  existing.id
4397
4397
  ]);
@@ -4401,7 +4401,7 @@ function registerMachine(name, opts, db) {
4401
4401
  return getMachine(existing.id, d);
4402
4402
  }
4403
4403
  const id = uuid();
4404
- const ts = now();
4404
+ const ts = now2();
4405
4405
  const host = opts.hostname || osHostname();
4406
4406
  const plat = opts.platform || osPlatform();
4407
4407
  d.run("INSERT INTO machines (id, name, hostname, platform, ssh_address, last_seen_at, is_primary, metadata, created_at) VALUES (?, ?, ?, ?, ?, ?, 0, ?, ?)", [id, name, host, plat, opts.ssh_address ?? null, ts, JSON.stringify(metadata), ts]);
@@ -4423,7 +4423,7 @@ function updateMachineHeartbeat(idOrName, opts = {}, db) {
4423
4423
  }, d);
4424
4424
  }
4425
4425
  const metadata = topologyMetadata({ arch: osArch(), ...opts }, parseMetadata(row.metadata));
4426
- const ts = now();
4426
+ const ts = now2();
4427
4427
  d.run("UPDATE machines SET hostname = ?, platform = ?, ssh_address = ?, last_seen_at = ?, metadata = ? WHERE id = ?", [
4428
4428
  opts.hostname ?? row.hostname ?? osHostname(),
4429
4429
  opts.platform ?? row.platform ?? osPlatform(),
@@ -4492,7 +4492,7 @@ function getMachineTopologyDiagnostics(opts = {}, db, at = new Date) {
4492
4492
  message: `${project.name} has ${distinctPaths.length} different machine-local paths`
4493
4493
  });
4494
4494
  }
4495
- if (localRow && !existsSync2(localRow.path)) {
4495
+ if (localRow && !existsSync3(localRow.path)) {
4496
4496
  pathIssues.push({
4497
4497
  type: "path_missing",
4498
4498
  project_id: project.id,
@@ -4503,7 +4503,7 @@ function getMachineTopologyDiagnostics(opts = {}, db, at = new Date) {
4503
4503
  message: `Local path does not exist on this machine: ${localRow.path}`
4504
4504
  });
4505
4505
  }
4506
- if (!localRow && project.path && machineById.has(localMachine.id) && !existsSync2(project.path)) {
4506
+ if (!localRow && project.path && machineById.has(localMachine.id) && !existsSync3(project.path)) {
4507
4507
  pathIssues.push({
4508
4508
  type: "path_missing",
4509
4509
  project_id: project.id,
@@ -4551,7 +4551,7 @@ function archiveMachine(id, db) {
4551
4551
  if (activeCount.cnt > 0) {
4552
4552
  throw new Error(`Cannot archive machine with ${activeCount.cnt} active/pending tasks`);
4553
4553
  }
4554
- d.run("UPDATE machines SET archived_at = ? WHERE id = ?", [now(), id]);
4554
+ d.run("UPDATE machines SET archived_at = ? WHERE id = ?", [now2(), id]);
4555
4555
  }
4556
4556
  function unarchiveMachine(id, db) {
4557
4557
  const d = db || getDatabase();
@@ -4616,7 +4616,7 @@ __export(exports_database, {
4616
4616
  uuid: () => uuid,
4617
4617
  resolvePartialId: () => resolvePartialId,
4618
4618
  resetDatabase: () => resetDatabase,
4619
- now: () => now,
4619
+ now: () => now2,
4620
4620
  lockExpiryCutoff: () => lockExpiryCutoff,
4621
4621
  isLockExpired: () => isLockExpired,
4622
4622
  getDatabasePath: () => getDatabasePath,
@@ -4626,8 +4626,8 @@ __export(exports_database, {
4626
4626
  LOCK_EXPIRY_MINUTES: () => LOCK_EXPIRY_MINUTES
4627
4627
  });
4628
4628
  import { Database } from "bun:sqlite";
4629
- import { existsSync as existsSync3, mkdirSync } from "fs";
4630
- import { dirname as dirname2, join as join2, resolve as resolve2 } from "path";
4629
+ import { existsSync as existsSync4, mkdirSync } from "fs";
4630
+ import { dirname as dirname2, join as join3, resolve as resolve2 } from "path";
4631
4631
  function isInMemoryDb(path) {
4632
4632
  return path === ":memory:" || path.startsWith("file::memory:");
4633
4633
  }
@@ -4636,8 +4636,8 @@ function findNearestProjectDb(startDir) {
4636
4636
  const stopAt = gitRoot ? resolve2(gitRoot) : resolve2(startDir);
4637
4637
  let dir = resolve2(startDir);
4638
4638
  while (true) {
4639
- const candidate = join2(dir, ".hasna", "todos", "todos.db");
4640
- if (existsSync3(candidate))
4639
+ const candidate = join3(dir, ".hasna", "todos", "todos.db");
4640
+ if (existsSync4(candidate))
4641
4641
  return candidate;
4642
4642
  if (dir === stopAt)
4643
4643
  break;
@@ -4651,7 +4651,7 @@ function findNearestProjectDb(startDir) {
4651
4651
  function findGitRoot(startDir) {
4652
4652
  let dir = resolve2(startDir);
4653
4653
  while (true) {
4654
- if (existsSync3(join2(dir, ".git")))
4654
+ if (existsSync4(join3(dir, ".git")))
4655
4655
  return dir;
4656
4656
  const parent = dirname2(dir);
4657
4657
  if (parent === dir)
@@ -4674,11 +4674,11 @@ function getDbPath() {
4674
4674
  if (process.env["TODOS_DB_SCOPE"] === "project") {
4675
4675
  const gitRoot = findGitRoot(cwd);
4676
4676
  if (gitRoot) {
4677
- return join2(gitRoot, ".hasna", "todos", "todos.db");
4677
+ return join3(gitRoot, ".hasna", "todos", "todos.db");
4678
4678
  }
4679
4679
  }
4680
4680
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
4681
- return join2(home, ".hasna", "todos", "todos.db");
4681
+ return join3(home, ".hasna", "todos", "todos.db");
4682
4682
  }
4683
4683
  function getDatabasePath() {
4684
4684
  return getDbPath();
@@ -4687,7 +4687,7 @@ function ensureDir(filePath) {
4687
4687
  if (isInMemoryDb(filePath))
4688
4688
  return;
4689
4689
  const dir = dirname2(resolve2(filePath));
4690
- if (!existsSync3(dir)) {
4690
+ if (!existsSync4(dir)) {
4691
4691
  mkdirSync(dir, { recursive: true });
4692
4692
  }
4693
4693
  }
@@ -4722,7 +4722,7 @@ function resetDatabase() {
4722
4722
  _db = null;
4723
4723
  _dbPath = null;
4724
4724
  }
4725
- function now() {
4725
+ function now2() {
4726
4726
  return new Date().toISOString();
4727
4727
  }
4728
4728
  function uuid() {
@@ -4958,7 +4958,7 @@ function generatePrefix(name, db) {
4958
4958
  function createProject(input, db) {
4959
4959
  const d = db || getDatabase();
4960
4960
  const id = uuid();
4961
- const timestamp = now();
4961
+ const timestamp = now2();
4962
4962
  const taskListId = input.task_list_id ?? `todos-${slugify(input.name)}`;
4963
4963
  const taskPrefix = input.task_prefix || generatePrefix(input.name, d);
4964
4964
  d.run(`INSERT INTO projects (id, name, path, description, task_list_id, task_prefix, task_counter, created_at, updated_at)
@@ -4992,7 +4992,7 @@ function updateProject(id, input, db) {
4992
4992
  if (!project)
4993
4993
  throw new ProjectNotFoundError(id);
4994
4994
  const sets = ["updated_at = ?"];
4995
- const params = [now()];
4995
+ const params = [now2()];
4996
4996
  if (input.name !== undefined) {
4997
4997
  sets.push("name = ?");
4998
4998
  params.push(input.name);
@@ -5019,7 +5019,7 @@ function renameProject(id, input, db) {
5019
5019
  if (!project)
5020
5020
  throw new ProjectNotFoundError(id);
5021
5021
  let taskListsUpdated = 0;
5022
- const ts = now();
5022
+ const ts = now2();
5023
5023
  if (input.new_slug !== undefined) {
5024
5024
  const normalised = input.new_slug.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-|-$/g, "");
5025
5025
  if (!normalised)
@@ -5053,7 +5053,7 @@ function rowToSource(row) {
5053
5053
  function addProjectSource(input, db) {
5054
5054
  const d = db || getDatabase();
5055
5055
  const id = uuid();
5056
- const timestamp = now();
5056
+ const timestamp = now2();
5057
5057
  d.run(`INSERT INTO project_sources (id, project_id, type, name, uri, description, metadata, created_at, updated_at)
5058
5058
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
5059
5059
  id,
@@ -5091,7 +5091,7 @@ function nextTaskShortId(projectId, db) {
5091
5091
  const project = getProject(projectId, d);
5092
5092
  if (!project || !project.task_prefix)
5093
5093
  return null;
5094
- d.run("UPDATE projects SET task_counter = task_counter + 1, updated_at = ? WHERE id = ?", [now(), projectId]);
5094
+ d.run("UPDATE projects SET task_counter = task_counter + 1, updated_at = ? WHERE id = ?", [now2(), projectId]);
5095
5095
  const updated = getProject(projectId, d);
5096
5096
  const padded = String(updated.task_counter).padStart(5, "0");
5097
5097
  return `${updated.task_prefix}-${padded}`;
@@ -5102,7 +5102,7 @@ function ensureProject(name, path, db) {
5102
5102
  if (existing) {
5103
5103
  if (!existing.task_prefix) {
5104
5104
  const prefix = generatePrefix(existing.name, d);
5105
- d.run("UPDATE projects SET task_prefix = ?, updated_at = ? WHERE id = ?", [prefix, now(), existing.id]);
5105
+ d.run("UPDATE projects SET task_prefix = ?, updated_at = ? WHERE id = ?", [prefix, now2(), existing.id]);
5106
5106
  return getProject(existing.id, d);
5107
5107
  }
5108
5108
  setMachineLocalPath(existing.id, path, d);
@@ -5115,7 +5115,7 @@ function ensureProject(name, path, db) {
5115
5115
  function setMachineLocalPath(projectId, path, db) {
5116
5116
  const d = db || getDatabase();
5117
5117
  const machineId = getMachineId(d);
5118
- const ts = now();
5118
+ const ts = now2();
5119
5119
  const existing = d.query("SELECT * FROM project_machine_paths WHERE project_id = ? AND machine_id = ?").get(projectId, machineId);
5120
5120
  if (existing) {
5121
5121
  if (existing.path !== path) {
@@ -5155,20 +5155,20 @@ var init_projects = __esm(() => {
5155
5155
  });
5156
5156
 
5157
5157
  // src/lib/sync-utils.ts
5158
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, readdirSync, statSync, writeFileSync } from "fs";
5159
- import { join as join3 } from "path";
5158
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync2, readdirSync, statSync, writeFileSync } from "fs";
5159
+ import { join as join4 } from "path";
5160
5160
  function getHomeDir() {
5161
5161
  return process.env["HOME"] || process.env["USERPROFILE"] || "~";
5162
5162
  }
5163
5163
  function getTodosGlobalDir() {
5164
- return join3(getHomeDir(), ".hasna", "todos");
5164
+ return join4(getHomeDir(), ".hasna", "todos");
5165
5165
  }
5166
5166
  function ensureDir2(dir) {
5167
- if (!existsSync4(dir))
5167
+ if (!existsSync5(dir))
5168
5168
  mkdirSync2(dir, { recursive: true });
5169
5169
  }
5170
5170
  function listJsonFiles(dir) {
5171
- if (!existsSync4(dir))
5171
+ if (!existsSync5(dir))
5172
5172
  return [];
5173
5173
  return readdirSync(dir).filter((f) => f.endsWith(".json"));
5174
5174
  }
@@ -5184,14 +5184,14 @@ function writeJsonFile(path, data) {
5184
5184
  `);
5185
5185
  }
5186
5186
  function readHighWaterMark(dir) {
5187
- const path = join3(dir, ".highwatermark");
5188
- if (!existsSync4(path))
5187
+ const path = join4(dir, ".highwatermark");
5188
+ if (!existsSync5(path))
5189
5189
  return 1;
5190
5190
  const val = parseInt(readFileSync2(path, "utf-8").trim(), 10);
5191
5191
  return isNaN(val) ? 1 : val;
5192
5192
  }
5193
5193
  function writeHighWaterMark(dir, value) {
5194
- writeFileSync(join3(dir, ".highwatermark"), String(value));
5194
+ writeFileSync(join4(dir, ".highwatermark"), String(value));
5195
5195
  }
5196
5196
  function getFileMtimeMs(path) {
5197
5197
  try {
@@ -5233,10 +5233,10 @@ __export(exports_config, {
5233
5233
  getAgentTaskListId: () => getAgentTaskListId,
5234
5234
  getAgentPoolForProject: () => getAgentPoolForProject
5235
5235
  });
5236
- import { existsSync as existsSync5 } from "fs";
5237
- import { dirname as dirname3, join as join4 } from "path";
5236
+ import { existsSync as existsSync6 } from "fs";
5237
+ import { dirname as dirname3, join as join5 } from "path";
5238
5238
  function getConfigPath() {
5239
- return join4(getTodosGlobalDir(), "config.json");
5239
+ return join5(getTodosGlobalDir(), "config.json");
5240
5240
  }
5241
5241
  function resetConfig() {
5242
5242
  cached = null;
@@ -5247,7 +5247,7 @@ function normalizeAgent(agent) {
5247
5247
  function loadConfig() {
5248
5248
  if (cached)
5249
5249
  return cached;
5250
- if (!existsSync5(getConfigPath())) {
5250
+ if (!existsSync6(getConfigPath())) {
5251
5251
  cached = {};
5252
5252
  return cached;
5253
5253
  }
@@ -5400,7 +5400,7 @@ var init_completion_guard = __esm(() => {
5400
5400
  var exports_redaction = {};
5401
5401
  __export(exports_redaction, {
5402
5402
  upsertSecretSafetyConfig: () => upsertSecretSafetyConfig,
5403
- redactValue: () => redactValue,
5403
+ redactValue: () => redactValue2,
5404
5404
  redactEvidenceText: () => redactEvidenceText,
5405
5405
  listSecretFindings: () => listSecretFindings,
5406
5406
  hasSecretFindings: () => hasSecretFindings,
@@ -5440,18 +5440,18 @@ function redactEvidenceText(value) {
5440
5440
  }
5441
5441
  return redacted;
5442
5442
  }
5443
- function redactValue(value) {
5443
+ function redactValue2(value) {
5444
5444
  if (typeof value === "string")
5445
5445
  return redactEvidenceText(value);
5446
5446
  if (Array.isArray(value))
5447
- return value.map(redactValue);
5447
+ return value.map(redactValue2);
5448
5448
  if (value && typeof value === "object") {
5449
5449
  const redacted = {};
5450
5450
  for (const [key, child] of Object.entries(value)) {
5451
5451
  if (isSecretKey(key)) {
5452
5452
  redacted[key] = "[REDACTED]";
5453
5453
  } else {
5454
- redacted[key] = redactValue(child);
5454
+ redacted[key] = redactValue2(child);
5455
5455
  }
5456
5456
  }
5457
5457
  return redacted;
@@ -5913,7 +5913,7 @@ __export(exports_event_hooks, {
5913
5913
  emitLocalEventHooks: () => emitLocalEventHooks,
5914
5914
  LOCAL_EVENT_TYPES: () => LOCAL_EVENT_TYPES
5915
5915
  });
5916
- import { createHash, randomUUID } from "crypto";
5916
+ import { createHash, randomUUID as randomUUID3 } from "crypto";
5917
5917
  import { appendFileSync, mkdirSync as mkdirSync3 } from "fs";
5918
5918
  import { dirname as dirname4, resolve as resolve5 } from "path";
5919
5919
  import { createConnection } from "net";
@@ -5974,10 +5974,10 @@ function canonicalEvent(input) {
5974
5974
  }
5975
5975
  function buildEnvelope(type, payload, timestamp = new Date().toISOString()) {
5976
5976
  const base = {
5977
- id: randomUUID(),
5977
+ id: randomUUID3(),
5978
5978
  type,
5979
5979
  timestamp,
5980
- payload: redactValue(payload ?? {}),
5980
+ payload: redactValue2(payload ?? {}),
5981
5981
  source: { package: "@hasna/todos", local_only: true }
5982
5982
  };
5983
5983
  const digest = createHash("sha256").update(canonicalEvent(base)).digest("hex");
@@ -6191,7 +6191,7 @@ function redactText(text, options = {}) {
6191
6191
  return out;
6192
6192
  }
6193
6193
  function redactExportRecord(record) {
6194
- const base = redactValue(record);
6194
+ const base = redactValue2(record);
6195
6195
  for (const [key, value] of Object.entries(base)) {
6196
6196
  if (typeof value === "string") {
6197
6197
  base[key] = redactText(value);
@@ -6269,7 +6269,7 @@ function redactActivityRecord(record) {
6269
6269
  function logActivity(input, db) {
6270
6270
  const d = db || getDatabase();
6271
6271
  const id = uuid();
6272
- const ts = input.created_at ?? now();
6272
+ const ts = input.created_at ?? now2();
6273
6273
  const machineId = input.machine_id ?? getMachineId2();
6274
6274
  d.run(`INSERT INTO activity_log (
6275
6275
  id, entity_type, entity_id, action, field, old_value, new_value,
@@ -6337,7 +6337,7 @@ function exportActivityLog(filter = {}, db) {
6337
6337
  const records = listActivity({ ...filter, limit: filter.limit ?? 1000, order: "asc" }, db).map(redactActivityRecord);
6338
6338
  return {
6339
6339
  schema_version: ACTIVITY_LOG_SCHEMA,
6340
- exported_at: now(),
6340
+ exported_at: now2(),
6341
6341
  records
6342
6342
  };
6343
6343
  }
@@ -6418,7 +6418,7 @@ __export(exports_audit, {
6418
6418
  function logTaskChange(taskId, action, field, oldValue, newValue, agentId, db) {
6419
6419
  const d = db || getDatabase();
6420
6420
  const id = uuid();
6421
- const timestamp = now();
6421
+ const timestamp = now2();
6422
6422
  d.run(`INSERT INTO task_history (id, task_id, action, field, old_value, new_value, agent_id, created_at)
6423
6423
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [id, taskId, action, field || null, oldValue ?? null, newValue ?? null, agentId || null, timestamp]);
6424
6424
  try {
@@ -6577,7 +6577,7 @@ function createWebhook(input, db) {
6577
6577
  input.task_list_id || null,
6578
6578
  input.agent_id || null,
6579
6579
  input.task_id || null,
6580
- now()
6580
+ now2()
6581
6581
  ]);
6582
6582
  return getWebhook(id, d);
6583
6583
  }
@@ -6596,7 +6596,7 @@ function deleteWebhook(id, db) {
6596
6596
  }
6597
6597
  function logDelivery(d, webhookId, event, payload, statusCode, response, attempt) {
6598
6598
  const id = uuid();
6599
- d.run(`INSERT INTO webhook_deliveries (id, webhook_id, event, payload, status_code, response, attempt, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [id, webhookId, event, payload, statusCode, response, attempt, now()]);
6599
+ d.run(`INSERT INTO webhook_deliveries (id, webhook_id, event, payload, status_code, response, attempt, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [id, webhookId, event, payload, statusCode, response, attempt, now2()]);
6600
6600
  }
6601
6601
  function matchesScope(wh, payload) {
6602
6602
  if (wh.project_id && payload.project_id !== wh.project_id)
@@ -6666,14 +6666,14 @@ async function deliverWebhook(wh, event, body, attempt, db) {
6666
6666
  activeDeliveries--;
6667
6667
  }
6668
6668
  }
6669
- async function dispatchWebhook(event, payload, db) {
6669
+ async function dispatchWebhook2(event, payload, db) {
6670
6670
  const d = db || getDatabase();
6671
6671
  const webhooks = listWebhooks(d).filter((w) => w.active && (w.events.length === 0 || w.events.includes(event)));
6672
6672
  const payloadObj = typeof payload === "object" && payload !== null ? payload : {};
6673
6673
  for (const wh of webhooks) {
6674
6674
  if (!matchesScope(wh, payloadObj))
6675
6675
  continue;
6676
- const body = JSON.stringify({ event, payload, timestamp: now() });
6676
+ const body = JSON.stringify({ event, payload, timestamp: now2() });
6677
6677
  deliverWebhook(wh, event, body, 1, d).catch((err) => {
6678
6678
  console.error(`[webhook] Dispatch failed for webhook ${wh.id}:`, err);
6679
6679
  });
@@ -6723,7 +6723,7 @@ function replaceTaskTags(taskId, tags, db) {
6723
6723
  }
6724
6724
  function createTask(input, db) {
6725
6725
  const d = db || getDatabase();
6726
- const timestamp = now();
6726
+ const timestamp = now2();
6727
6727
  const tags = input.tags || [];
6728
6728
  const assignedBy = input.assigned_by || input.agent_id;
6729
6729
  const assignedFromProject = input.assigned_from_project || null;
@@ -6783,7 +6783,7 @@ function createTask(input, db) {
6783
6783
  insertTaskTags(id, tags, d);
6784
6784
  }
6785
6785
  const task = getTask(id, d);
6786
- dispatchWebhook("task.created", { id: task.id, short_id: task.short_id, title: task.title, status: task.status, priority: task.priority, project_id: task.project_id, assigned_to: task.assigned_to }, d).catch(() => {});
6786
+ dispatchWebhook2("task.created", { id: task.id, short_id: task.short_id, title: task.title, status: task.status, priority: task.priority, project_id: task.project_id, assigned_to: task.assigned_to }, d).catch(() => {});
6787
6787
  return task;
6788
6788
  }
6789
6789
  function getTask(id, db) {
@@ -7002,7 +7002,7 @@ function updateTask(id, input, db) {
7002
7002
  if (task.version !== input.version) {
7003
7003
  throw new VersionConflictError(id, input.version, task.version);
7004
7004
  }
7005
- const timestamp = now();
7005
+ const timestamp = now2();
7006
7006
  const completionTimestamp = input.completed_at ?? timestamp;
7007
7007
  const sets = ["version = version + 1", "updated_at = ?"];
7008
7008
  const params = [timestamp];
@@ -7097,7 +7097,7 @@ function updateTask(id, input, db) {
7097
7097
  sets.push("approved_by = ?");
7098
7098
  params.push(input.approved_by);
7099
7099
  sets.push("approved_at = ?");
7100
- params.push(now());
7100
+ params.push(now2());
7101
7101
  }
7102
7102
  if (input.recurrence_rule !== undefined) {
7103
7103
  sets.push("recurrence_rule = ?");
@@ -7128,11 +7128,11 @@ function updateTask(id, input, db) {
7128
7128
  if (input.approved_by !== undefined)
7129
7129
  logTaskChange(id, "approve", "approved_by", null, input.approved_by, agentId, d);
7130
7130
  if (input.assigned_to !== undefined && input.assigned_to !== task.assigned_to) {
7131
- dispatchWebhook("task.assigned", { id, assigned_to: input.assigned_to, title: task.title }, d).catch(() => {});
7131
+ dispatchWebhook2("task.assigned", { id, assigned_to: input.assigned_to, title: task.title }, d).catch(() => {});
7132
7132
  emitLocalEventHooksQuiet({ type: "task.assigned", payload: { id, assigned_to: input.assigned_to, title: task.title } });
7133
7133
  }
7134
7134
  if (input.status !== undefined && input.status !== task.status) {
7135
- dispatchWebhook("task.status_changed", { id, old_status: task.status, new_status: input.status, title: task.title }, d).catch(() => {});
7135
+ dispatchWebhook2("task.status_changed", { id, old_status: task.status, new_status: input.status, title: task.title }, d).catch(() => {});
7136
7136
  emitLocalEventHooksQuiet({ type: "task.status_changed", payload: { id, old_status: task.status, new_status: input.status, title: task.title } });
7137
7137
  }
7138
7138
  if (input.approved_by !== undefined) {
@@ -7330,7 +7330,7 @@ function createTemplate(input, db) {
7330
7330
  input.project_id || null,
7331
7331
  input.plan_id || null,
7332
7332
  JSON.stringify(input.metadata || {}),
7333
- now()
7333
+ now2()
7334
7334
  ]);
7335
7335
  if (input.tasks && input.tasks.length > 0) {
7336
7336
  addTemplateTasks(id, input.tasks, d);
@@ -7375,7 +7375,7 @@ function updateTemplate(id, updates, db) {
7375
7375
  metadata: current.metadata,
7376
7376
  tasks: current.tasks
7377
7377
  });
7378
- d.run(`INSERT INTO template_versions (id, template_id, version, snapshot, created_at) VALUES (?, ?, ?, ?, ?)`, [uuid(), resolved, current.version, snapshot, now()]);
7378
+ d.run(`INSERT INTO template_versions (id, template_id, version, snapshot, created_at) VALUES (?, ?, ?, ?, ?)`, [uuid(), resolved, current.version, snapshot, now2()]);
7379
7379
  }
7380
7380
  const sets = ["version = version + 1"];
7381
7381
  const values = [];
@@ -7459,7 +7459,7 @@ function addTemplateTasks(templateId, tasks, db) {
7459
7459
  task.include_template_id || null,
7460
7460
  JSON.stringify(task.depends_on || []),
7461
7461
  JSON.stringify(task.metadata || {}),
7462
- now()
7462
+ now2()
7463
7463
  ]);
7464
7464
  const row = d.query("SELECT * FROM template_tasks WHERE id = ?").get(id);
7465
7465
  if (row)
@@ -7821,7 +7821,7 @@ function moveTask(taskId, target, db) {
7821
7821
  if (!task)
7822
7822
  throw new TaskNotFoundError(taskId);
7823
7823
  const sets = ["updated_at = ?", "version = version + 1"];
7824
- const params = [now()];
7824
+ const params = [now2()];
7825
7825
  if (target.task_list_id !== undefined) {
7826
7826
  sets.push("task_list_id = ?");
7827
7827
  params.push(target.task_list_id);
@@ -7908,7 +7908,7 @@ function startTask(id, agentId, db) {
7908
7908
  throw new Error(`Task is blocked by ${blocking.length} unfinished dependency(ies): ${blockerIds}`);
7909
7909
  }
7910
7910
  const cutoff = lockExpiryCutoff();
7911
- const timestamp = now();
7911
+ const timestamp = now2();
7912
7912
  const result = d.run(`UPDATE tasks SET status = 'in_progress', assigned_to = ?, locked_by = ?, locked_at = ?, started_at = COALESCE(started_at, ?), version = version + 1, updated_at = ?
7913
7913
  WHERE id = ? AND status IN ('pending', 'in_progress') AND (locked_by IS NULL OR locked_by = ? OR locked_at < ?)`, [agentId, agentId, timestamp, timestamp, timestamp, id, agentId, cutoff]);
7914
7914
  if (result.changes === 0) {
@@ -7922,7 +7922,7 @@ function startTask(id, agentId, db) {
7922
7922
  throw new Error(`Task ${id} could not be started because it changed during claim`);
7923
7923
  }
7924
7924
  logTaskChange(id, "start", "status", "pending", "in_progress", agentId, d);
7925
- dispatchWebhook("task.started", { id, agent_id: agentId, title: task.title }, d).catch(() => {});
7925
+ dispatchWebhook2("task.started", { id, agent_id: agentId, title: task.title }, d).catch(() => {});
7926
7926
  emitLocalEventHooksQuiet({ type: "task.started", payload: { id, agent_id: agentId, title: task.title } });
7927
7927
  return { ...task, status: "in_progress", assigned_to: agentId, locked_by: agentId, locked_at: timestamp, started_at: task.started_at || timestamp, version: task.version + 1, updated_at: timestamp };
7928
7928
  }
@@ -7944,7 +7944,7 @@ function completeTask(id, agentId, db, options) {
7944
7944
  completionMeta._completion = { confidence: options.confidence };
7945
7945
  }
7946
7946
  const hasMeta = Object.keys(completionMeta).length > 0;
7947
- const timestamp = options?.completed_at || now();
7947
+ const timestamp = options?.completed_at || now2();
7948
7948
  const confidence = options?.confidence !== undefined ? options.confidence : null;
7949
7949
  const tx = d.transaction(() => {
7950
7950
  if (hasMeta) {
@@ -7960,7 +7960,7 @@ function completeTask(id, agentId, db, options) {
7960
7960
  });
7961
7961
  tx();
7962
7962
  logTaskChange(id, "complete", "status", task.status, "completed", agentId || null, d);
7963
- dispatchWebhook("task.completed", { id, agent_id: agentId, title: task.title, completed_at: timestamp }, d).catch(() => {});
7963
+ dispatchWebhook2("task.completed", { id, agent_id: agentId, title: task.title, completed_at: timestamp }, d).catch(() => {});
7964
7964
  emitLocalEventHooksQuiet({ type: "task.completed", payload: { id, agent_id: agentId, title: task.title, completed_at: timestamp } });
7965
7965
  let spawnedTask = null;
7966
7966
  if (task.recurrence_rule && !options?.skip_recurrence) {
@@ -8002,7 +8002,7 @@ function completeTask(id, agentId, db, options) {
8002
8002
  if (unblockedDeps.length > 0) {
8003
8003
  meta._unblocked = unblockedDeps.map((d2) => ({ id: d2.id, short_id: d2.short_id, title: d2.title }));
8004
8004
  for (const dep of unblockedDeps) {
8005
- dispatchWebhook("task.unblocked", { id: dep.id, unblocked_by: id, title: dep.title }, d).catch(() => {});
8005
+ dispatchWebhook2("task.unblocked", { id: dep.id, unblocked_by: id, title: dep.title }, d).catch(() => {});
8006
8006
  emitLocalEventHooksQuiet({ type: "task.unblocked", payload: { id: dep.id, unblocked_by: id, title: dep.title } });
8007
8007
  }
8008
8008
  }
@@ -8020,13 +8020,13 @@ function lockTask(id, agentId, db) {
8020
8020
  };
8021
8021
  }
8022
8022
  if (task.locked_by === agentId && !isLockExpired(task.locked_at)) {
8023
- const timestamp2 = now();
8023
+ const timestamp2 = now2();
8024
8024
  d.run(`UPDATE tasks SET locked_at = ?, updated_at = ?, version = version + 1 WHERE id = ? AND locked_by = ?`, [timestamp2, timestamp2, id, agentId]);
8025
8025
  logTaskChange(id, "lock_renew", "locked_by", agentId, agentId, agentId, d);
8026
8026
  return { success: true, locked_by: agentId, locked_at: timestamp2, expires_at: lockExpiresAt(timestamp2) };
8027
8027
  }
8028
8028
  const cutoff = lockExpiryCutoff();
8029
- const timestamp = now();
8029
+ const timestamp = now2();
8030
8030
  const result = d.run(`UPDATE tasks SET locked_by = ?, locked_at = ?, version = version + 1, updated_at = ?
8031
8031
  WHERE id = ? AND status NOT IN ('completed', 'cancelled') AND (locked_by IS NULL OR locked_by = ? OR locked_at < ?)`, [agentId, timestamp, timestamp, id, agentId, cutoff]);
8032
8032
  if (result.changes === 0) {
@@ -8063,7 +8063,7 @@ function unlockTask(id, agentId, db) {
8063
8063
  if (agentId && task.locked_by && task.locked_by !== agentId) {
8064
8064
  throw new LockError(id, task.locked_by);
8065
8065
  }
8066
- const timestamp = now();
8066
+ const timestamp = now2();
8067
8067
  d.run(`UPDATE tasks SET locked_by = NULL, locked_at = NULL, version = version + 1, updated_at = ?
8068
8068
  WHERE id = ?`, [timestamp, id]);
8069
8069
  return true;
@@ -8182,15 +8182,15 @@ function failTask(id, agentId, reason, options, db) {
8182
8182
  reason: reason || "Unknown failure",
8183
8183
  error_code: options?.error_code || null,
8184
8184
  failed_by: agentId || null,
8185
- failed_at: now(),
8185
+ failed_at: now2(),
8186
8186
  retry_requested: options?.retry || false
8187
8187
  }
8188
8188
  };
8189
- const timestamp = now();
8189
+ const timestamp = now2();
8190
8190
  d.run(`UPDATE tasks SET status = 'failed', locked_by = NULL, locked_at = NULL, metadata = ?, version = version + 1, updated_at = ?
8191
8191
  WHERE id = ?`, [JSON.stringify(meta), timestamp, id]);
8192
8192
  logTaskChange(id, "fail", "status", task.status, "failed", agentId || null, d);
8193
- dispatchWebhook("task.failed", { id, reason, error_code: options?.error_code, agent_id: agentId, title: task.title }, d).catch(() => {});
8193
+ dispatchWebhook2("task.failed", { id, reason, error_code: options?.error_code, agent_id: agentId, title: task.title }, d).catch(() => {});
8194
8194
  emitLocalEventHooksQuiet({ type: "task.failed", payload: { id, reason, error_code: options?.error_code, agent_id: agentId, title: task.title } });
8195
8195
  const failedTask = {
8196
8196
  ...task,
@@ -8267,7 +8267,7 @@ function stealTask(agentId, opts, db) {
8267
8267
  const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
8268
8268
  staleTasks.sort((a, b) => (priorityOrder[a.priority] ?? 9) - (priorityOrder[b.priority] ?? 9));
8269
8269
  const target = staleTasks[0];
8270
- const timestamp = now();
8270
+ const timestamp = now2();
8271
8271
  const cutoff = new Date(Date.now() - staleMinutes * 60 * 1000).toISOString();
8272
8272
  const result = d.run(`UPDATE tasks SET assigned_to = ?, locked_by = ?, locked_at = ?, updated_at = ?, version = version + 1
8273
8273
  WHERE id = ? AND status = 'in_progress' AND (updated_at < ? OR (locked_at IS NOT NULL AND locked_at < ?))`, [agentId, agentId, timestamp, timestamp, target.id, cutoff, cutoff]);
@@ -8275,7 +8275,7 @@ function stealTask(agentId, opts, db) {
8275
8275
  return null;
8276
8276
  logTaskChange(target.id, "steal", "assigned_to", target.assigned_to, agentId, agentId, d);
8277
8277
  logTaskChange(target.id, "steal", "locked_by", target.locked_by, agentId, agentId, d);
8278
- dispatchWebhook("task.assigned", { id: target.id, agent_id: agentId, title: target.title, stolen_from: target.assigned_to }, d).catch(() => {});
8278
+ dispatchWebhook2("task.assigned", { id: target.id, agent_id: agentId, title: target.title, stolen_from: target.assigned_to }, d).catch(() => {});
8279
8279
  emitLocalEventHooksQuiet({ type: "task.assigned", payload: { id: target.id, agent_id: agentId, title: target.title, stolen_from: target.assigned_to } });
8280
8280
  return { ...target, assigned_to: agentId, locked_by: agentId, locked_at: timestamp, updated_at: timestamp, version: target.version + 1 };
8281
8281
  }
@@ -8344,7 +8344,7 @@ function getStatus(filters, agentId, options, db) {
8344
8344
  const next_task = getNextTask(agentId, filters, d);
8345
8345
  const stale = getStaleTasks(30, filters, d);
8346
8346
  const conditions = ["recurrence_rule IS NOT NULL", "status = 'pending'", "due_at < ?"];
8347
- const params = [now()];
8347
+ const params = [now2()];
8348
8348
  if (filters?.project_id) {
8349
8349
  conditions.push("project_id = ?");
8350
8350
  params.push(filters.project_id);
@@ -8453,7 +8453,7 @@ function redistributeStaleTasks(agentId, options, db) {
8453
8453
  const maxAge = options?.max_age_minutes ?? 60;
8454
8454
  const stale = getStaleTasks(maxAge, options?.project_id ? { project_id: options.project_id } : undefined, d);
8455
8455
  const limited = options?.limit ? stale.slice(0, options.limit) : stale;
8456
- const timestamp = now();
8456
+ const timestamp = now2();
8457
8457
  const released = [];
8458
8458
  for (const t of limited) {
8459
8459
  d.run(`UPDATE tasks SET locked_by = NULL, locked_at = NULL, status = 'pending', version = version + 1, updated_at = ? WHERE id = ?`, [timestamp, t.id]);
@@ -8600,7 +8600,7 @@ function archiveTasks(options, db) {
8600
8600
  conditions.push("updated_at < ?");
8601
8601
  params.push(cutoff);
8602
8602
  }
8603
- const ts = now();
8603
+ const ts = now2();
8604
8604
  const result = d.run(`UPDATE tasks SET archived_at = ? WHERE ${conditions.join(" AND ")}`, [ts, ...params]);
8605
8605
  return { archived: result.changes };
8606
8606
  }
@@ -8787,7 +8787,7 @@ function assertPositiveMinutes(minutes) {
8787
8787
  function recalculateTaskActualMinutes(taskId, db) {
8788
8788
  const row = db.query("SELECT COALESCE(SUM(minutes), 0) as total FROM task_time_logs WHERE task_id = ?").get(taskId);
8789
8789
  const total = Number(row.total || 0);
8790
- db.run("UPDATE tasks SET actual_minutes = ?, updated_at = ? WHERE id = ?", [total, now(), taskId]);
8790
+ db.run("UPDATE tasks SET actual_minutes = ?, updated_at = ? WHERE id = ?", [total, now2(), taskId]);
8791
8791
  return total;
8792
8792
  }
8793
8793
  function logTime(input, db) {
@@ -8795,7 +8795,7 @@ function logTime(input, db) {
8795
8795
  if (!getTask(input.task_id, d))
8796
8796
  throw new Error(`Task not found: ${input.task_id}`);
8797
8797
  const id = uuid();
8798
- const ts = now();
8798
+ const ts = now2();
8799
8799
  const minutes = assertPositiveMinutes(input.minutes);
8800
8800
  d.run(`INSERT INTO task_time_logs (id, task_id, run_id, focus_session_id, agent_id, minutes, started_at, ended_at, notes, created_at)
8801
8801
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [id, input.task_id, input.run_id || null, input.focus_session_id || null, input.agent_id || null, minutes, input.started_at || null, input.ended_at || null, input.notes || null, ts]);
@@ -8822,7 +8822,7 @@ function startFocusSession(input, db) {
8822
8822
  if (input.task_id && !getTask(input.task_id, d))
8823
8823
  throw new Error(`Task not found: ${input.task_id}`);
8824
8824
  const id = uuid();
8825
- const ts = now();
8825
+ const ts = now2();
8826
8826
  const startedAt = input.started_at || ts;
8827
8827
  d.run(`INSERT INTO focus_sessions (
8828
8828
  id, task_id, plan_id, run_id, agent_id, title, status, started_at, last_resumed_at,
@@ -8892,7 +8892,7 @@ function pauseFocusSession(id, pausedAt, db) {
8892
8892
  throw new Error(`Focus session not found: ${id}`);
8893
8893
  if (session.status !== "active")
8894
8894
  throw new Error(`Focus session is ${session.status}, not active`);
8895
- const ts = now();
8895
+ const ts = now2();
8896
8896
  const pauseAt = pausedAt || ts;
8897
8897
  const minutes = session.actual_minutes + minutesBetween(session.last_resumed_at, pauseAt);
8898
8898
  d.run("UPDATE focus_sessions SET status = 'paused', actual_minutes = ?, paused_at = ?, last_resumed_at = NULL, updated_at = ? WHERE id = ?", [minutes, pauseAt, ts, id]);
@@ -8905,7 +8905,7 @@ function resumeFocusSession(id, resumedAt, db) {
8905
8905
  throw new Error(`Focus session not found: ${id}`);
8906
8906
  if (session.status !== "paused")
8907
8907
  throw new Error(`Focus session is ${session.status}, not paused`);
8908
- const ts = now();
8908
+ const ts = now2();
8909
8909
  const resumed = resumedAt || ts;
8910
8910
  d.run("UPDATE focus_sessions SET status = 'active', paused_at = NULL, last_resumed_at = ?, updated_at = ? WHERE id = ?", [resumed, ts, id]);
8911
8911
  return getFocusSession(id, d);
@@ -8917,7 +8917,7 @@ function stopFocusSession(input, db) {
8917
8917
  throw new Error(`Focus session not found: ${input.id}`);
8918
8918
  if (session.status === "completed" || session.status === "cancelled")
8919
8919
  return session;
8920
- const ts = now();
8920
+ const ts = now2();
8921
8921
  const endedAt = input.ended_at || ts;
8922
8922
  const finalMinutes = session.status === "active" ? session.actual_minutes + minutesBetween(session.last_resumed_at, endedAt) : session.actual_minutes;
8923
8923
  const finalStatus = input.status || "completed";
@@ -8996,7 +8996,7 @@ function getTimeReport(opts, db) {
8996
8996
  function watchTask(taskId, agentId, db) {
8997
8997
  const d = db || getDatabase();
8998
8998
  const id = uuid();
8999
- const ts = now();
8999
+ const ts = now2();
9000
9000
  d.run(`INSERT OR IGNORE INTO task_watchers (id, task_id, agent_id, created_at) VALUES (?, ?, ?, ?)`, [id, taskId, agentId, ts]);
9001
9001
  const existing = d.query(`SELECT * FROM task_watchers WHERE task_id = ? AND agent_id = ?`).get(taskId, agentId);
9002
9002
  return existing;
@@ -9012,11 +9012,11 @@ function getTaskWatchers(taskId, db) {
9012
9012
  }
9013
9013
  function notifyWatchers(taskId, event, data, db) {
9014
9014
  const watchers = getTaskWatchers(taskId, db);
9015
- dispatchWebhook(`task.watcher.${event}`, { task_id: taskId, watchers: watchers.map((w) => w.agent_id), ...data }, db).catch(() => {});
9015
+ dispatchWebhook2(`task.watcher.${event}`, { task_id: taskId, watchers: watchers.map((w) => w.agent_id), ...data }, db).catch(() => {});
9016
9016
  }
9017
9017
  function logCost(taskId, tokens, usd, db) {
9018
9018
  const d = db || getDatabase();
9019
- d.run("UPDATE tasks SET cost_tokens = cost_tokens + ?, cost_usd = cost_usd + ?, updated_at = ? WHERE id = ?", [tokens, usd, now(), taskId]);
9019
+ d.run("UPDATE tasks SET cost_tokens = cost_tokens + ?, cost_usd = cost_usd + ?, updated_at = ? WHERE id = ?", [tokens, usd, now2(), taskId]);
9020
9020
  }
9021
9021
  var init_task_relations = __esm(() => {
9022
9022
  init_database();
@@ -9029,7 +9029,7 @@ var init_task_relations = __esm(() => {
9029
9029
  function createPlan(input, db) {
9030
9030
  const d = db || getDatabase();
9031
9031
  const id = uuid();
9032
- const timestamp = now();
9032
+ const timestamp = now2();
9033
9033
  d.run(`INSERT INTO plans (id, project_id, task_list_id, agent_id, name, description, status, created_at, updated_at)
9034
9034
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
9035
9035
  id,
@@ -9062,7 +9062,7 @@ function updatePlan(id, input, db) {
9062
9062
  if (!plan)
9063
9063
  throw new PlanNotFoundError(id);
9064
9064
  const sets = ["updated_at = ?"];
9065
- const params = [now()];
9065
+ const params = [now2()];
9066
9066
  if (input.name !== undefined) {
9067
9067
  sets.push("name = ?");
9068
9068
  params.push(input.name);
@@ -9104,7 +9104,7 @@ var init_plans = __esm(() => {
9104
9104
  });
9105
9105
 
9106
9106
  // src/db/boards.ts
9107
- function parseJsonObject(value) {
9107
+ function parseJsonObject2(value) {
9108
9108
  if (!value)
9109
9109
  return {};
9110
9110
  if (typeof value === "object" && !Array.isArray(value))
@@ -9147,7 +9147,7 @@ function rowToTaskBoard(row) {
9147
9147
  return {
9148
9148
  ...row,
9149
9149
  lanes: normalizeLanes(row.scope, parseJsonArray(row.lanes)),
9150
- filters: parseJsonObject(row.filters)
9150
+ filters: parseJsonObject2(row.filters)
9151
9151
  };
9152
9152
  }
9153
9153
  function maybeFilter(value) {
@@ -9156,7 +9156,7 @@ function maybeFilter(value) {
9156
9156
  function createTaskBoard(input, db) {
9157
9157
  const d = db || getDatabase();
9158
9158
  const id = uuid();
9159
- const timestamp = now();
9159
+ const timestamp = now2();
9160
9160
  const scope = input.scope || "tasks";
9161
9161
  const lanes = normalizeLanes(scope, input.lanes);
9162
9162
  d.run(`INSERT INTO task_boards (id, name, scope, project_id, task_list_id, plan_id, agent_id, lanes, filters, created_at, updated_at)
@@ -9220,7 +9220,7 @@ function updateTaskBoard(idOrName, input, db) {
9220
9220
  if (!board)
9221
9221
  throw new Error(`Board not found: ${idOrName}`);
9222
9222
  const sets = ["updated_at = ?"];
9223
- const params = [now()];
9223
+ const params = [now2()];
9224
9224
  if (input.name !== undefined) {
9225
9225
  sets.push("name = ?");
9226
9226
  params.push(input.name);
@@ -9375,7 +9375,7 @@ function buildTaskBoardSnapshot(idOrBoard, db) {
9375
9375
  const lanes = buildLaneSnapshots(board, cards);
9376
9376
  return {
9377
9377
  board,
9378
- generated_at: now(),
9378
+ generated_at: now2(),
9379
9379
  lanes,
9380
9380
  totals: {
9381
9381
  cards: cards.length,
@@ -9442,7 +9442,7 @@ function exportTaskBoardBundle(idOrName, db) {
9442
9442
  return {
9443
9443
  kind: "hasna.todos.task-board",
9444
9444
  schemaVersion: 1,
9445
- exportedAt: now(),
9445
+ exportedAt: now2(),
9446
9446
  boards
9447
9447
  };
9448
9448
  }
@@ -9506,8 +9506,8 @@ var init_boards = __esm(() => {
9506
9506
 
9507
9507
  // src/lib/artifact-store.ts
9508
9508
  import { createHash as createHash2 } from "crypto";
9509
- import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync3, rmSync, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
9510
- import { basename, dirname as dirname5, join as join5, resolve as resolve6 } from "path";
9509
+ import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync3, rmSync, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
9510
+ import { basename, dirname as dirname5, join as join6, resolve as resolve6 } from "path";
9511
9511
  import { tmpdir } from "os";
9512
9512
  function isInMemoryDb2(path) {
9513
9513
  return path === ":memory:" || path.startsWith("file::memory:");
@@ -9519,15 +9519,15 @@ function artifactStoreRoot() {
9519
9519
  return resolve6(process.env["TODOS_ARTIFACTS_DIR"]);
9520
9520
  const dbPath = getDatabasePath();
9521
9521
  if (isInMemoryDb2(dbPath))
9522
- return join5(tmpdir(), "hasna-todos-artifacts");
9523
- return join5(dirname5(resolve6(dbPath)), "artifacts");
9522
+ return join6(tmpdir(), "hasna-todos-artifacts");
9523
+ return join6(dirname5(resolve6(dbPath)), "artifacts");
9524
9524
  }
9525
9525
  function artifactStorePath(relativePath) {
9526
9526
  const normalized = relativePath.replace(/\\/g, "/");
9527
9527
  if (normalized.includes("..") || normalized.startsWith("/") || normalized.length === 0) {
9528
9528
  throw new Error("Invalid artifact store path");
9529
9529
  }
9530
- return join5(artifactStoreRoot(), normalized);
9530
+ return join6(artifactStoreRoot(), normalized);
9531
9531
  }
9532
9532
  function sha256(buffer) {
9533
9533
  return createHash2("sha256").update(buffer).digest("hex");
@@ -9568,7 +9568,7 @@ function mediaTypeFor(path, textLike) {
9568
9568
  }
9569
9569
  function storeArtifactContent(input) {
9570
9570
  const sourcePath = resolve6(input.path);
9571
- if (!existsSync6(sourcePath))
9571
+ if (!existsSync7(sourcePath))
9572
9572
  return null;
9573
9573
  const sourceStat = statSync2(sourcePath);
9574
9574
  if (!sourceStat.isFile())
@@ -9585,9 +9585,9 @@ function storeArtifactContent(input) {
9585
9585
  redactionStatus = "redacted";
9586
9586
  }
9587
9587
  const storedSha = sha256(storedBuffer);
9588
- const relativePath = join5("sha256", storedSha.slice(0, 2), storedSha).replace(/\\/g, "/");
9588
+ const relativePath = join6("sha256", storedSha.slice(0, 2), storedSha).replace(/\\/g, "/");
9589
9589
  const destination = artifactStorePath(relativePath);
9590
- if (!existsSync6(destination)) {
9590
+ if (!existsSync7(destination)) {
9591
9591
  mkdirSync4(dirname5(destination), { recursive: true });
9592
9592
  writeFileSync2(destination, storedBuffer);
9593
9593
  }
@@ -9647,7 +9647,7 @@ function verifyStoredArtifact(input) {
9647
9647
  };
9648
9648
  }
9649
9649
  const storedPath = artifactStorePath(store.relative_path);
9650
- if (!existsSync6(storedPath)) {
9650
+ if (!existsSync7(storedPath)) {
9651
9651
  return {
9652
9652
  id: input.id,
9653
9653
  path: input.path,
@@ -9741,7 +9741,7 @@ function addComment(input, db) {
9741
9741
  throw new TaskNotFoundError(input.task_id);
9742
9742
  }
9743
9743
  const id = uuid();
9744
- const timestamp = now();
9744
+ const timestamp = now2();
9745
9745
  d.run(`INSERT INTO task_comments (id, task_id, agent_id, session_id, content, type, progress_pct, created_at)
9746
9746
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
9747
9747
  id,
@@ -9805,7 +9805,7 @@ __export(exports_task_files, {
9805
9805
  function addTaskFile(input, db) {
9806
9806
  const d = db || getDatabase();
9807
9807
  const id = uuid();
9808
- const timestamp = now();
9808
+ const timestamp = now2();
9809
9809
  const existing = d.query("SELECT id FROM task_files WHERE task_id = ? AND path = ?").get(input.task_id, input.path);
9810
9810
  if (existing) {
9811
9811
  d.run("UPDATE task_files SET status = ?, agent_id = ?, note = ?, updated_at = ? WHERE id = ?", [input.status || "active", input.agent_id || null, input.note || null, timestamp, existing.id]);
@@ -9829,7 +9829,7 @@ function findTasksByFile(path, db) {
9829
9829
  }
9830
9830
  function updateTaskFileStatus(taskId, path, status, agentId, db) {
9831
9831
  const d = db || getDatabase();
9832
- const timestamp = now();
9832
+ const timestamp = now2();
9833
9833
  d.run("UPDATE task_files SET status = ?, agent_id = COALESCE(?, agent_id), updated_at = ? WHERE task_id = ? AND path = ?", [status, agentId || null, timestamp, taskId, path]);
9834
9834
  const row = d.query("SELECT * FROM task_files WHERE task_id = ? AND path = ?").get(taskId, path);
9835
9835
  return row;
@@ -10040,7 +10040,7 @@ function linkTaskToCommit(input, db) {
10040
10040
  input.release_tag ?? null,
10041
10041
  input.repo_path ?? null,
10042
10042
  traceJson ?? "{}",
10043
- now()
10043
+ now2()
10044
10044
  ]);
10045
10045
  return rowToCommit(d.query("SELECT * FROM task_commits WHERE id = ?").get(id));
10046
10046
  }
@@ -10061,7 +10061,7 @@ function unlinkTaskCommit(taskId, sha, db) {
10061
10061
  }
10062
10062
  function linkTaskGitRef(input, db) {
10063
10063
  const d = db || getDatabase();
10064
- const timestamp = now();
10064
+ const timestamp = now2();
10065
10065
  const metadata = JSON.stringify(input.metadata || {});
10066
10066
  const existing = d.query("SELECT * FROM task_git_refs WHERE task_id = ? AND ref_type = ? AND name = ?").get(input.task_id, input.ref_type, input.name);
10067
10067
  if (existing) {
@@ -10083,7 +10083,7 @@ function findTasksByGitRef(ref, db) {
10083
10083
  function addTaskVerification(input, db) {
10084
10084
  const d = db || getDatabase();
10085
10085
  const id = uuid();
10086
- const runAt = input.run_at || now();
10086
+ const runAt = input.run_at || now2();
10087
10087
  d.run("INSERT INTO task_verifications (id, task_id, command, status, output_summary, artifact_path, agent_id, run_at, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", [
10088
10088
  id,
10089
10089
  input.task_id,
@@ -10093,7 +10093,7 @@ function addTaskVerification(input, db) {
10093
10093
  input.artifact_path ?? null,
10094
10094
  input.agent_id ?? null,
10095
10095
  runAt,
10096
- now()
10096
+ now2()
10097
10097
  ]);
10098
10098
  return rowToVerification(d.query("SELECT * FROM task_verifications WHERE id = ?").get(id));
10099
10099
  }
@@ -10179,7 +10179,7 @@ function startTaskRun(input, db) {
10179
10179
  if (!getTask(input.task_id, d))
10180
10180
  throw new TaskNotFoundError(input.task_id);
10181
10181
  const id = uuid();
10182
- const timestamp = input.started_at || now();
10182
+ const timestamp = input.started_at || now2();
10183
10183
  if (input.claim && input.agent_id) {
10184
10184
  startTask(input.task_id, input.agent_id, d);
10185
10185
  }
@@ -10189,7 +10189,7 @@ function startTaskRun(input, db) {
10189
10189
  input.agent_id ?? null,
10190
10190
  input.title ? redactEvidenceText(input.title) : null,
10191
10191
  input.summary ? redactEvidenceText(input.summary) : null,
10192
- JSON.stringify(redactValue(input.metadata || {})),
10192
+ JSON.stringify(redactValue2(input.metadata || {})),
10193
10193
  timestamp,
10194
10194
  timestamp,
10195
10195
  timestamp
@@ -10223,14 +10223,14 @@ function addTaskRunEvent(input, db) {
10223
10223
  if (!run)
10224
10224
  throw new Error(`Run not found: ${input.run_id}`);
10225
10225
  const id = uuid();
10226
- const timestamp = input.created_at || now();
10226
+ const timestamp = input.created_at || now2();
10227
10227
  d.run("INSERT INTO task_run_events (id, run_id, task_id, event_type, message, data, agent_id, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", [
10228
10228
  id,
10229
10229
  run.id,
10230
10230
  run.task_id,
10231
10231
  input.event_type,
10232
10232
  input.message ? redactEvidenceText(input.message) : null,
10233
- JSON.stringify(redactValue(input.data || {})),
10233
+ JSON.stringify(redactValue2(input.data || {})),
10234
10234
  input.agent_id ?? run.agent_id,
10235
10235
  timestamp
10236
10236
  ]);
@@ -10247,7 +10247,7 @@ function addTaskRunCommand(input, db) {
10247
10247
  throw new Error(`Run not found: ${input.run_id}`);
10248
10248
  const id = uuid();
10249
10249
  const status = input.status || "unknown";
10250
- const timestamp = now();
10250
+ const timestamp = now2();
10251
10251
  const command = redactEvidenceText(input.command);
10252
10252
  const outputSummary = input.output_summary ? redactEvidenceText(input.output_summary) : null;
10253
10253
  const artifactPath = input.artifact_path ? redactEvidenceText(input.artifact_path) : null;
@@ -10324,10 +10324,10 @@ function addTaskRunArtifact(input, db) {
10324
10324
  if (!run)
10325
10325
  throw new Error(`Run not found: ${input.run_id}`);
10326
10326
  const id = uuid();
10327
- const timestamp = now();
10327
+ const timestamp = now2();
10328
10328
  const path = redactEvidenceText(input.path);
10329
10329
  const description = input.description ? redactEvidenceText(input.description) : null;
10330
- const metadata = redactValue(input.metadata || {});
10330
+ const metadata = redactValue2(input.metadata || {});
10331
10331
  let sizeBytes = input.size_bytes ?? null;
10332
10332
  let digest = input.sha256 ?? null;
10333
10333
  const stored = input.store_content !== false ? storeArtifactContent({ path: input.path, metadata, retention_days: input.retention_days, created_at: timestamp }) : null;
@@ -10377,7 +10377,7 @@ function finishTaskRun(input, db) {
10377
10377
  const run = getTaskRun(runId, d);
10378
10378
  if (!run)
10379
10379
  throw new Error(`Run not found: ${input.run_id}`);
10380
- const timestamp = input.completed_at || now();
10380
+ const timestamp = input.completed_at || now2();
10381
10381
  const summary = input.summary ? redactEvidenceText(input.summary) : null;
10382
10382
  d.run("UPDATE task_runs SET status = ?, summary = COALESCE(?, summary), completed_at = ?, updated_at = ? WHERE id = ?", [input.status, summary, timestamp, timestamp, run.id]);
10383
10383
  addTaskRunEvent({
@@ -10427,7 +10427,7 @@ var init_task_runs = __esm(() => {
10427
10427
  });
10428
10428
 
10429
10429
  // src/db/calendar.ts
10430
- function parseJsonObject2(value) {
10430
+ function parseJsonObject3(value) {
10431
10431
  if (!value)
10432
10432
  return {};
10433
10433
  if (typeof value === "object" && !Array.isArray(value))
@@ -10442,7 +10442,7 @@ function parseJsonObject2(value) {
10442
10442
  }
10443
10443
  }
10444
10444
  function rowToCalendarItem(row) {
10445
- return { ...row, metadata: parseJsonObject2(row.metadata) };
10445
+ return { ...row, metadata: parseJsonObject3(row.metadata) };
10446
10446
  }
10447
10447
  function eventFromLocal(item) {
10448
10448
  return {
@@ -10543,7 +10543,7 @@ function inWindow(event, query) {
10543
10543
  function createCalendarItem(input, db) {
10544
10544
  const d = db || getDatabase();
10545
10545
  const id = uuid();
10546
- const timestamp = now();
10546
+ const timestamp = now2();
10547
10547
  const kind = input.kind || "work_block";
10548
10548
  d.run(`INSERT INTO local_calendar_items (
10549
10549
  id, kind, title, description, starts_at, ends_at, timezone, project_id, task_id, plan_id, run_id,
@@ -10702,7 +10702,7 @@ function recurrenceToRrule(rule) {
10702
10702
  }
10703
10703
  function exportCalendarIcs(options = {}, db) {
10704
10704
  const events = listCalendarEvents(options, db);
10705
- const generatedAt = options.generated_at || now();
10705
+ const generatedAt = options.generated_at || now2();
10706
10706
  const lines = [
10707
10707
  "BEGIN:VCALENDAR",
10708
10708
  "VERSION:2.0",
@@ -11202,8 +11202,8 @@ function registerTaskCommands(program2) {
11202
11202
  tasks = tasks.filter((t) => t.due_at && t.due_at <= todayEnd.toISOString());
11203
11203
  }
11204
11204
  if (opts.overdue) {
11205
- const now2 = new Date().toISOString();
11206
- tasks = tasks.filter((t) => t.due_at && t.due_at < now2 && t.status !== "completed");
11205
+ const now3 = new Date().toISOString();
11206
+ tasks = tasks.filter((t) => t.due_at && t.due_at < now3 && t.status !== "completed");
11207
11207
  }
11208
11208
  if (opts.sort) {
11209
11209
  const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
@@ -11776,7 +11776,7 @@ __export(exports_builtin_templates, {
11776
11776
  BUILTIN_TEMPLATES: () => BUILTIN_TEMPLATES
11777
11777
  });
11778
11778
  import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync3 } from "fs";
11779
- import { join as join6 } from "path";
11779
+ import { join as join7 } from "path";
11780
11780
  function templateMetadata(template) {
11781
11781
  return {
11782
11782
  source: BUILTIN_TEMPLATE_LIBRARY_SOURCE,
@@ -11835,7 +11835,7 @@ function writeBuiltinTemplateFiles(directory) {
11835
11835
  mkdirSync5(directory, { recursive: true });
11836
11836
  const files = [];
11837
11837
  for (const entry of exportBuiltinTemplateFiles()) {
11838
- const path = join6(directory, entry.filename);
11838
+ const path = join7(directory, entry.filename);
11839
11839
  writeFileSync3(path, `${JSON.stringify(entry.template, null, 2)}
11840
11840
  `, "utf-8");
11841
11841
  files.push(path);
@@ -12560,7 +12560,7 @@ function setTaskLocalFields(taskId, input, db) {
12560
12560
  throw new TaskNotFoundError(taskId);
12561
12561
  const currentFields = getTaskLocalFields(taskId, d);
12562
12562
  const labels = input.labels !== undefined ? normalizeList(input.labels) : currentFields.labels;
12563
- const custom = input.custom !== undefined ? redactValue(input.merge_custom === false ? input.custom : { ...currentFields.custom, ...input.custom }) : currentFields.custom;
12563
+ const custom = input.custom !== undefined ? redactValue2(input.merge_custom === false ? input.custom : { ...currentFields.custom, ...input.custom }) : currentFields.custom;
12564
12564
  const nextFields = {
12565
12565
  labels,
12566
12566
  priority: input.priority || task.priority,
@@ -12804,7 +12804,7 @@ function likePattern(query) {
12804
12804
  return null;
12805
12805
  return `%${trimmed}%`;
12806
12806
  }
12807
- function parseJsonObject3(value) {
12807
+ function parseJsonObject4(value) {
12808
12808
  if (!value)
12809
12809
  return {};
12810
12810
  if (typeof value === "object" && !Array.isArray(value))
@@ -12819,7 +12819,7 @@ function parseJsonObject3(value) {
12819
12819
  }
12820
12820
  }
12821
12821
  function rowToTaskRun(row) {
12822
- return { ...row, metadata: parseJsonObject3(row.metadata) };
12822
+ return { ...row, metadata: parseJsonObject4(row.metadata) };
12823
12823
  }
12824
12824
  function taskMatchesSavedFilters(task, filters, db) {
12825
12825
  if (filters.plan_id && task.plan_id !== filters.plan_id)
@@ -13020,7 +13020,7 @@ function runSavedSearch(filters = {}, scope = "tasks", db) {
13020
13020
  function saveSearchView(input, db) {
13021
13021
  const d = db || getDatabase();
13022
13022
  const name = normalizeName(input.name);
13023
- const timestamp = now();
13023
+ const timestamp = now2();
13024
13024
  const existing = getSearchView(name, d);
13025
13025
  if (existing) {
13026
13026
  d.run(`UPDATE saved_search_views
@@ -13077,16 +13077,16 @@ var init_saved_search_views = __esm(() => {
13077
13077
  });
13078
13078
 
13079
13079
  // src/lib/claude-tasks.ts
13080
- import { existsSync as existsSync7, readFileSync as readFileSync4, readdirSync as readdirSync2, writeFileSync as writeFileSync4 } from "fs";
13081
- import { join as join7 } from "path";
13080
+ import { existsSync as existsSync8, readFileSync as readFileSync4, readdirSync as readdirSync2, writeFileSync as writeFileSync4 } from "fs";
13081
+ import { join as join8 } from "path";
13082
13082
  function getTaskListDir(taskListId) {
13083
- return join7(HOME, ".claude", "tasks", taskListId);
13083
+ return join8(HOME, ".claude", "tasks", taskListId);
13084
13084
  }
13085
13085
  function readClaudeTask(dir, filename) {
13086
- return readJsonFile(join7(dir, filename));
13086
+ return readJsonFile(join8(dir, filename));
13087
13087
  }
13088
13088
  function writeClaudeTask(dir, task) {
13089
- writeJsonFile(join7(dir, `${task.id}.json`), task);
13089
+ writeJsonFile(join8(dir, `${task.id}.json`), task);
13090
13090
  }
13091
13091
  function toClaudeStatus(status) {
13092
13092
  if (status === "pending" || status === "in_progress" || status === "completed") {
@@ -13098,14 +13098,14 @@ function toSqliteStatus(status) {
13098
13098
  return status;
13099
13099
  }
13100
13100
  function readPrefixCounter(dir) {
13101
- const path = join7(dir, ".prefix-counter");
13102
- if (!existsSync7(path))
13101
+ const path = join8(dir, ".prefix-counter");
13102
+ if (!existsSync8(path))
13103
13103
  return 0;
13104
13104
  const val = parseInt(readFileSync4(path, "utf-8").trim(), 10);
13105
13105
  return isNaN(val) ? 0 : val;
13106
13106
  }
13107
13107
  function writePrefixCounter(dir, value) {
13108
- writeFileSync4(join7(dir, ".prefix-counter"), String(value));
13108
+ writeFileSync4(join8(dir, ".prefix-counter"), String(value));
13109
13109
  }
13110
13110
  function formatPrefixedSubject(title, prefix, counter) {
13111
13111
  const padded = String(counter).padStart(5, "0");
@@ -13132,7 +13132,7 @@ function taskToClaudeTask(task, claudeTaskId, existingMeta) {
13132
13132
  }
13133
13133
  function pushToClaudeTaskList(taskListId, projectId, options = {}) {
13134
13134
  const dir = getTaskListDir(taskListId);
13135
- if (!existsSync7(dir))
13135
+ if (!existsSync8(dir))
13136
13136
  ensureDir2(dir);
13137
13137
  const filter = {};
13138
13138
  if (projectId)
@@ -13141,7 +13141,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
13141
13141
  const existingByTodosId = new Map;
13142
13142
  const files = listJsonFiles(dir);
13143
13143
  for (const f of files) {
13144
- const path = join7(dir, f);
13144
+ const path = join8(dir, f);
13145
13145
  const ct = readClaudeTask(dir, f);
13146
13146
  if (ct?.metadata?.["todos_id"]) {
13147
13147
  existingByTodosId.set(ct.metadata["todos_id"], { task: ct, mtimeMs: getFileMtimeMs(path) });
@@ -13228,7 +13228,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
13228
13228
  }
13229
13229
  function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
13230
13230
  const dir = getTaskListDir(taskListId);
13231
- if (!existsSync7(dir)) {
13231
+ if (!existsSync8(dir)) {
13232
13232
  return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
13233
13233
  }
13234
13234
  const files = readdirSync2(dir).filter((f) => f.endsWith(".json"));
@@ -13248,7 +13248,7 @@ function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
13248
13248
  }
13249
13249
  for (const f of files) {
13250
13250
  try {
13251
- const filePath = join7(dir, f);
13251
+ const filePath = join8(dir, f);
13252
13252
  const ct = readClaudeTask(dir, f);
13253
13253
  if (!ct)
13254
13254
  continue;
@@ -13321,20 +13321,20 @@ var init_claude_tasks = __esm(() => {
13321
13321
  });
13322
13322
 
13323
13323
  // src/lib/agent-tasks.ts
13324
- import { existsSync as existsSync8 } from "fs";
13325
- import { join as join8 } from "path";
13324
+ import { existsSync as existsSync9 } from "fs";
13325
+ import { join as join9 } from "path";
13326
13326
  function agentBaseDir(agent) {
13327
13327
  const key = `TODOS_${agent.toUpperCase()}_TASKS_DIR`;
13328
- return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join8(getTodosGlobalDir(), "agents");
13328
+ return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join9(getTodosGlobalDir(), "agents");
13329
13329
  }
13330
13330
  function getTaskListDir2(agent, taskListId) {
13331
- return join8(agentBaseDir(agent), agent, taskListId);
13331
+ return join9(agentBaseDir(agent), agent, taskListId);
13332
13332
  }
13333
13333
  function readAgentTask(dir, filename) {
13334
- return readJsonFile(join8(dir, filename));
13334
+ return readJsonFile(join9(dir, filename));
13335
13335
  }
13336
13336
  function writeAgentTask(dir, task) {
13337
- writeJsonFile(join8(dir, `${task.id}.json`), task);
13337
+ writeJsonFile(join9(dir, `${task.id}.json`), task);
13338
13338
  }
13339
13339
  function taskToAgentTask(task, externalId, existingMeta) {
13340
13340
  return {
@@ -13359,7 +13359,7 @@ function metadataKey(agent) {
13359
13359
  }
13360
13360
  function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
13361
13361
  const dir = getTaskListDir2(agent, taskListId);
13362
- if (!existsSync8(dir))
13362
+ if (!existsSync9(dir))
13363
13363
  ensureDir2(dir);
13364
13364
  const filter = {};
13365
13365
  if (projectId)
@@ -13368,7 +13368,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
13368
13368
  const existingByTodosId = new Map;
13369
13369
  const files = listJsonFiles(dir);
13370
13370
  for (const f of files) {
13371
- const path = join8(dir, f);
13371
+ const path = join9(dir, f);
13372
13372
  const at = readAgentTask(dir, f);
13373
13373
  if (at?.metadata?.["todos_id"]) {
13374
13374
  existingByTodosId.set(at.metadata["todos_id"], { task: at, mtimeMs: getFileMtimeMs(path) });
@@ -13442,7 +13442,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
13442
13442
  }
13443
13443
  function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
13444
13444
  const dir = getTaskListDir2(agent, taskListId);
13445
- if (!existsSync8(dir)) {
13445
+ if (!existsSync9(dir)) {
13446
13446
  return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
13447
13447
  }
13448
13448
  const files = listJsonFiles(dir);
@@ -13461,7 +13461,7 @@ function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
13461
13461
  }
13462
13462
  for (const f of files) {
13463
13463
  try {
13464
- const filePath = join8(dir, f);
13464
+ const filePath = join9(dir, f);
13465
13465
  const at = readAgentTask(dir, f);
13466
13466
  if (!at)
13467
13467
  continue;
@@ -13618,7 +13618,7 @@ function rowToTaskList(row) {
13618
13618
  function createTaskList(input, db) {
13619
13619
  const d = db || getDatabase();
13620
13620
  const id = uuid();
13621
- const timestamp = now();
13621
+ const timestamp = now2();
13622
13622
  const slug = input.slug || slugify(input.name);
13623
13623
  if (!input.project_id) {
13624
13624
  const existing = d.query("SELECT id FROM task_lists WHERE project_id IS NULL AND slug = ?").get(slug);
@@ -13658,7 +13658,7 @@ function updateTaskList(id, input, db) {
13658
13658
  if (!existing)
13659
13659
  throw new TaskListNotFoundError(id);
13660
13660
  const sets = ["updated_at = ?"];
13661
- const params = [now()];
13661
+ const params = [now2()];
13662
13662
  if (input.name !== undefined) {
13663
13663
  sets.push("name = ?");
13664
13664
  params.push(input.name);
@@ -13698,7 +13698,7 @@ __export(exports_project_bootstrap, {
13698
13698
  discoverProjectWorkspace: () => discoverProjectWorkspace,
13699
13699
  bootstrapProject: () => bootstrapProject
13700
13700
  });
13701
- import { existsSync as existsSync9, readFileSync as readFileSync5, statSync as statSync3 } from "fs";
13701
+ import { existsSync as existsSync10, readFileSync as readFileSync5, statSync as statSync3 } from "fs";
13702
13702
  import { basename as basename4, dirname as dirname6, resolve as resolve9 } from "path";
13703
13703
  function safeStat(path) {
13704
13704
  try {
@@ -13717,7 +13717,7 @@ function canonicalPath(input) {
13717
13717
  function findUp(start, marker) {
13718
13718
  let current = canonicalPath(start);
13719
13719
  while (true) {
13720
- if (existsSync9(resolve9(current, marker)))
13720
+ if (existsSync10(resolve9(current, marker)))
13721
13721
  return current;
13722
13722
  const parent = dirname6(current);
13723
13723
  if (parent === current)
@@ -13729,7 +13729,7 @@ function readPackageJson(path) {
13729
13729
  if (!path)
13730
13730
  return null;
13731
13731
  const file = resolve9(path, "package.json");
13732
- if (!existsSync9(file))
13732
+ if (!existsSync10(file))
13733
13733
  return null;
13734
13734
  try {
13735
13735
  const parsed = JSON.parse(readFileSync5(file, "utf-8"));
@@ -13751,7 +13751,7 @@ function workspaceMarker(root, rootPackage) {
13751
13751
  if (rootPackage?.workspaces)
13752
13752
  markers.push("package.json#workspaces");
13753
13753
  for (const marker of ["pnpm-workspace.yaml", "turbo.json", "nx.json", "lerna.json", "rush.json", "bun.lock", "bun.lockb"]) {
13754
- if (existsSync9(resolve9(root, marker)))
13754
+ if (existsSync10(resolve9(root, marker)))
13755
13755
  markers.push(marker);
13756
13756
  }
13757
13757
  const kind = markers.find((marker) => marker !== "bun.lock" && marker !== "bun.lockb") ?? null;
@@ -13873,9 +13873,9 @@ __export(exports_extract, {
13873
13873
  buildCodebaseIndex: () => buildCodebaseIndex,
13874
13874
  EXTRACT_TAGS: () => EXTRACT_TAGS
13875
13875
  });
13876
- import { existsSync as existsSync10, readFileSync as readFileSync6, statSync as statSync4 } from "fs";
13876
+ import { existsSync as existsSync11, readFileSync as readFileSync6, statSync as statSync4 } from "fs";
13877
13877
  import { createHash as createHash3 } from "crypto";
13878
- import { relative as relative3, resolve as resolve10, join as join9 } from "path";
13878
+ import { relative as relative3, resolve as resolve10, join as join10 } from "path";
13879
13879
  function stableHash(value) {
13880
13880
  return createHash3("sha256").update(value).digest("hex");
13881
13881
  }
@@ -13884,8 +13884,8 @@ function normalizePathForMatch(value) {
13884
13884
  }
13885
13885
  function readGitignorePatterns(basePath) {
13886
13886
  const root = statSync4(basePath).isFile() ? resolve10(basePath, "..") : basePath;
13887
- const gitignorePath = join9(root, ".gitignore");
13888
- if (!existsSync10(gitignorePath))
13887
+ const gitignorePath = join10(root, ".gitignore");
13888
+ if (!existsSync11(gitignorePath))
13889
13889
  return [];
13890
13890
  try {
13891
13891
  return readFileSync6(gitignorePath, "utf-8").split(`
@@ -14027,7 +14027,7 @@ function buildCodebaseIndex(options) {
14027
14027
  const files = collectFiles(basePath, extensions, excludes, respectGitignore);
14028
14028
  const indexed = [];
14029
14029
  for (const file of files) {
14030
- const fullPath = statSync4(basePath).isFile() ? basePath : join9(basePath, file);
14030
+ const fullPath = statSync4(basePath).isFile() ? basePath : join10(basePath, file);
14031
14031
  try {
14032
14032
  const source = readFileSync6(fullPath, "utf-8");
14033
14033
  const relPath = statSync4(basePath).isFile() ? relative3(resolve10(basePath, ".."), fullPath) : file;
@@ -14058,7 +14058,7 @@ function extractTodos(options, db) {
14058
14058
  const files = collectFiles(basePath, extensions, excludes, respectGitignore);
14059
14059
  const allComments = [];
14060
14060
  for (const file of files) {
14061
- const fullPath = statSync4(basePath).isFile() ? basePath : join9(basePath, file);
14061
+ const fullPath = statSync4(basePath).isFile() ? basePath : join10(basePath, file);
14062
14062
  try {
14063
14063
  const source = readFileSync6(fullPath, "utf-8");
14064
14064
  const relPath = statSync4(basePath).isFile() ? relative3(resolve10(basePath, ".."), fullPath) : file;
@@ -14266,7 +14266,7 @@ function packageSource(version) {
14266
14266
  function emptyCounts() {
14267
14267
  return Object.fromEntries(dataKeys.map((key) => [key, 0]));
14268
14268
  }
14269
- function parseJsonObject4(value) {
14269
+ function parseJsonObject5(value) {
14270
14270
  if (!value)
14271
14271
  return {};
14272
14272
  if (typeof value === "object" && !Array.isArray(value))
@@ -14312,34 +14312,34 @@ function rowToTask3(row) {
14312
14312
  return {
14313
14313
  ...row,
14314
14314
  tags: parseJsonArray2(row.tags),
14315
- metadata: parseJsonObject4(row.metadata),
14315
+ metadata: parseJsonObject5(row.metadata),
14316
14316
  requires_approval: Boolean(row.requires_approval)
14317
14317
  };
14318
14318
  }
14319
14319
  function rowToTaskList2(row) {
14320
- return { ...row, metadata: parseJsonObject4(row.metadata) };
14320
+ return { ...row, metadata: parseJsonObject5(row.metadata) };
14321
14321
  }
14322
14322
  function rowWithMetadata(row) {
14323
- return { ...row, metadata: parseJsonObject4(row.metadata) };
14323
+ return { ...row, metadata: parseJsonObject5(row.metadata) };
14324
14324
  }
14325
14325
  function rowToRunEvent(row) {
14326
- return { ...row, data: parseJsonObject4(row.data) };
14326
+ return { ...row, data: parseJsonObject5(row.data) };
14327
14327
  }
14328
14328
  function rowToCommit2(row) {
14329
14329
  return { ...row, files_changed: row.files_changed ? parseJsonArray2(row.files_changed) : null };
14330
14330
  }
14331
14331
  function rowToSavedView(row) {
14332
- return { ...row, filters: parseJsonObject4(row.filters) };
14332
+ return { ...row, filters: parseJsonObject5(row.filters) };
14333
14333
  }
14334
14334
  function rowToTaskBoard2(row) {
14335
14335
  return {
14336
14336
  ...row,
14337
14337
  lanes: parseJsonArray2(row.lanes),
14338
- filters: parseJsonObject4(row.filters)
14338
+ filters: parseJsonObject5(row.filters)
14339
14339
  };
14340
14340
  }
14341
14341
  function rowToCalendarItem2(row) {
14342
- return { ...row, metadata: parseJsonObject4(row.metadata) };
14342
+ return { ...row, metadata: parseJsonObject5(row.metadata) };
14343
14343
  }
14344
14344
  function bridgeStats(data) {
14345
14345
  return Object.fromEntries(dataKeys.map((key) => [key, data[key].length]));
@@ -14350,7 +14350,7 @@ function createLocalBridgeBundle(options = {}, db) {
14350
14350
  const runRows = queryByTaskIds(d, "SELECT * FROM task_runs WHERE task_id IN (__TASK_IDS__) ORDER BY started_at, created_at", taskIds);
14351
14351
  const runIds = runRows.map((row) => String(row.id));
14352
14352
  const project = options.project_id ? d.query("SELECT * FROM projects WHERE id = ?").get(options.project_id) : null;
14353
- const data = redactValue({
14353
+ const data = redactValue2({
14354
14354
  projects: options.project_id ? project ? [project] : [] : d.query("SELECT * FROM projects ORDER BY name").all(),
14355
14355
  task_lists: (options.project_id ? d.query("SELECT * FROM task_lists WHERE project_id = ? ORDER BY name").all(options.project_id) : d.query("SELECT * FROM task_lists ORDER BY name").all()).map(rowToTaskList2),
14356
14356
  plans: options.project_id ? d.query("SELECT * FROM plans WHERE project_id = ? ORDER BY created_at").all(options.project_id) : d.query("SELECT * FROM plans ORDER BY created_at").all(),
@@ -14379,7 +14379,7 @@ function createLocalBridgeBundle(options = {}, db) {
14379
14379
  return {
14380
14380
  schemaVersion: TODOS_LOCAL_BRIDGE_SCHEMA_VERSION,
14381
14381
  kind: TODOS_LOCAL_BRIDGE_KIND,
14382
- exportedAt: options.generatedAt ?? now(),
14382
+ exportedAt: options.generatedAt ?? now2(),
14383
14383
  package: packageSource(options.version ?? getPackageVersion(import.meta.url)),
14384
14384
  source: {
14385
14385
  project_id: options.project_id ?? null,
@@ -14565,7 +14565,7 @@ function safeMergeTask(db, incoming, options) {
14565
14565
  prefer: "local",
14566
14566
  local_updated_at: current.updated_at,
14567
14567
  remote_updated_at: incoming.updated_at,
14568
- detected_at: now(),
14568
+ detected_at: now2(),
14569
14569
  notes: buildDivergenceNotes(unresolvedFields)
14570
14570
  }, 10);
14571
14571
  }
@@ -14798,8 +14798,8 @@ __export(exports_local_encryption, {
14798
14798
  DEFAULT_ENCRYPTION_PROFILE: () => DEFAULT_ENCRYPTION_PROFILE,
14799
14799
  DEFAULT_ENCRYPTION_KEY_ENV: () => DEFAULT_ENCRYPTION_KEY_ENV
14800
14800
  });
14801
- import { createCipheriv, createDecipheriv, createHash as createHash4, randomBytes, scryptSync, timingSafeEqual } from "crypto";
14802
- function now2() {
14801
+ import { createCipheriv, createDecipheriv, createHash as createHash4, randomBytes, scryptSync, timingSafeEqual as timingSafeEqual2 } from "crypto";
14802
+ function now3() {
14803
14803
  return new Date().toISOString();
14804
14804
  }
14805
14805
  function sha2562(value) {
@@ -14836,7 +14836,7 @@ function upsertEncryptionProfile(input) {
14836
14836
  const name = normalizeProfileName(input.name);
14837
14837
  const config = loadConfig();
14838
14838
  const existing = config.encryption_profiles?.[name];
14839
- const timestamp = now2();
14839
+ const timestamp = now3();
14840
14840
  const profile = {
14841
14841
  name,
14842
14842
  algorithm: "aes-256-gcm",
@@ -14871,7 +14871,7 @@ function removeEncryptionProfile(name) {
14871
14871
  function encryptionProfileStatus(name = DEFAULT_ENCRYPTION_PROFILE, env = process.env) {
14872
14872
  const profile = ensureEncryptionProfile(name);
14873
14873
  return {
14874
- profile: redactValue(profile),
14874
+ profile: redactValue2(profile),
14875
14875
  locked: !env[profile.key_env],
14876
14876
  key_env: profile.key_env,
14877
14877
  key_present: Boolean(env[profile.key_env])
@@ -14893,7 +14893,7 @@ function encryptString(plaintext, options = {}) {
14893
14893
  return {
14894
14894
  schemaVersion: TODOS_ENCRYPTION_SCHEMA_VERSION,
14895
14895
  kind: TODOS_ENCRYPTED_VALUE_KIND,
14896
- encryptedAt: options.encryptedAt ?? now2(),
14896
+ encryptedAt: options.encryptedAt ?? now3(),
14897
14897
  profile: profile.name,
14898
14898
  key_env: profile.key_env,
14899
14899
  algorithm: "aes-256-gcm",
@@ -14928,7 +14928,7 @@ function decryptString(envelope, env = process.env) {
14928
14928
  ]).toString("utf8");
14929
14929
  const expected = Buffer.from(envelope.plaintext_sha256, "hex");
14930
14930
  const actual = Buffer.from(sha2562(plaintext), "hex");
14931
- if (expected.length !== actual.length || !timingSafeEqual(expected, actual)) {
14931
+ if (expected.length !== actual.length || !timingSafeEqual2(expected, actual)) {
14932
14932
  throw new EncryptedPayloadError("decrypted payload checksum mismatch");
14933
14933
  }
14934
14934
  return plaintext;
@@ -15028,7 +15028,7 @@ function applyExportProfile(data, options = {}) {
15028
15028
  if (profile === "encrypted") {
15029
15029
  return { profile, data: encryptSensitiveFields(data, { profile: DEFAULT_ENCRYPTION_PROFILE, env: options.env }), warnings };
15030
15030
  }
15031
- return { profile, data: redactValue(data), warnings };
15031
+ return { profile, data: redactValue2(data), warnings };
15032
15032
  }
15033
15033
  var TODOS_ENCRYPTED_VALUE_KIND = "hasna.todos.encrypted-value", TODOS_ENCRYPTED_BRIDGE_KIND = "hasna.todos.encrypted-bridge", TODOS_ENCRYPTION_SCHEMA_VERSION = 1, DEFAULT_ENCRYPTION_PROFILE = "default", DEFAULT_ENCRYPTION_KEY_ENV = "TODOS_ENCRYPTION_KEY", EncryptionKeyUnavailableError, EncryptedPayloadError;
15034
15034
  var init_local_encryption = __esm(() => {
@@ -15279,7 +15279,7 @@ function importTodosMarkdown(markdown, options = {}, db) {
15279
15279
  assigned_to: item.assigned_to,
15280
15280
  project_id: project?.id,
15281
15281
  plan_id: item.planName ? planByName.get(item.planName) : undefined,
15282
- metadata: { imported_from: TODOS_MARKDOWN_SCHEMA, imported_at: now() }
15282
+ metadata: { imported_from: TODOS_MARKDOWN_SCHEMA, imported_at: now2() }
15283
15283
  }, d);
15284
15284
  taskByTitle.set(item.title, task.id);
15285
15285
  inserted.tasks++;
@@ -16166,7 +16166,7 @@ function normalizeGeneratedAgentNames(db) {
16166
16166
  }
16167
16167
  existing.delete(oldName);
16168
16168
  existing.add(replacement);
16169
- db.run("UPDATE agents SET name = ?, last_seen_at = ? WHERE id = ?", [replacement, now(), agent.id]);
16169
+ db.run("UPDATE agents SET name = ?, last_seen_at = ? WHERE id = ?", [replacement, now2(), agent.id]);
16170
16170
  const referenceUpdates = updateReferences(db, oldName, replacement);
16171
16171
  renamed.push({
16172
16172
  id: agent.id,
@@ -16475,7 +16475,7 @@ function registerAgent(input, db) {
16475
16475
  }
16476
16476
  }
16477
16477
  const updates = ["last_seen_at = ?", "status = 'active'"];
16478
- const params = [now()];
16478
+ const params = [now2()];
16479
16479
  if (input.session_id && !sameSession) {
16480
16480
  updates.push("session_id = ?");
16481
16481
  params.push(input.session_id);
@@ -16497,7 +16497,7 @@ function registerAgent(input, db) {
16497
16497
  return getAgent(existing.id, d);
16498
16498
  }
16499
16499
  const id = shortUuid();
16500
- const timestamp = now();
16500
+ const timestamp = now2();
16501
16501
  d.run(`INSERT INTO agents (id, name, description, role, title, level, permissions, capabilities, reports_to, org_id, metadata, created_at, last_seen_at, session_id, working_dir, active_project_id)
16502
16502
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
16503
16503
  id,
@@ -16576,7 +16576,7 @@ function listAgents(opts, db) {
16576
16576
  }
16577
16577
  function updateAgentActivity(id, db) {
16578
16578
  const d = db || getDatabase();
16579
- d.run("UPDATE agents SET last_seen_at = ? WHERE id = ?", [now(), id]);
16579
+ d.run("UPDATE agents SET last_seen_at = ? WHERE id = ?", [now2(), id]);
16580
16580
  }
16581
16581
  function updateAgent(id, input, db) {
16582
16582
  const d = db || getDatabase();
@@ -16584,7 +16584,7 @@ function updateAgent(id, input, db) {
16584
16584
  if (!agent)
16585
16585
  throw new Error(`Agent not found: ${id}`);
16586
16586
  const sets = ["last_seen_at = ?"];
16587
- const params = [now()];
16587
+ const params = [now2()];
16588
16588
  if (input.name !== undefined) {
16589
16589
  const existingNames = d.query("SELECT name FROM agents WHERE id != ?").all(id).map((row) => row.name);
16590
16590
  const newName = validateAgentName(input.name, existingNames);
@@ -16643,16 +16643,16 @@ function updateAgent(id, input, db) {
16643
16643
  }
16644
16644
  function deleteAgent(id, db) {
16645
16645
  const d = db || getDatabase();
16646
- return d.run("UPDATE agents SET status = 'archived', last_seen_at = ? WHERE id = ?", [now(), id]).changes > 0;
16646
+ return d.run("UPDATE agents SET status = 'archived', last_seen_at = ? WHERE id = ?", [now2(), id]).changes > 0;
16647
16647
  }
16648
16648
  function archiveAgent(id, db) {
16649
16649
  const d = db || getDatabase();
16650
- d.run("UPDATE agents SET status = 'archived', last_seen_at = ? WHERE id = ?", [now(), id]);
16650
+ d.run("UPDATE agents SET status = 'archived', last_seen_at = ? WHERE id = ?", [now2(), id]);
16651
16651
  return getAgent(id, d);
16652
16652
  }
16653
16653
  function unarchiveAgent(id, db) {
16654
16654
  const d = db || getDatabase();
16655
- d.run("UPDATE agents SET status = 'active', last_seen_at = ? WHERE id = ?", [now(), id]);
16655
+ d.run("UPDATE agents SET status = 'active', last_seen_at = ? WHERE id = ?", [now2(), id]);
16656
16656
  return getAgent(id, d);
16657
16657
  }
16658
16658
  function getDirectReports(agentId, db) {
@@ -17078,7 +17078,7 @@ __export(exports_retention_cleanup, {
17078
17078
  applyRetentionCleanup: () => applyRetentionCleanup,
17079
17079
  RETENTION_CLEANUP_CONFIRMATION: () => RETENTION_CLEANUP_CONFIRMATION
17080
17080
  });
17081
- import { existsSync as existsSync11, unlinkSync } from "fs";
17081
+ import { existsSync as existsSync12, unlinkSync } from "fs";
17082
17082
  function normalizeScopes(scopes) {
17083
17083
  if (!scopes || scopes.length === 0)
17084
17084
  return [...ALL_SCOPES];
@@ -17281,7 +17281,7 @@ function applyRetentionCleanup(input, db) {
17281
17281
  for (const artifact of report.candidates.artifact_files) {
17282
17282
  try {
17283
17283
  const path = artifactStorePath(artifact.relative_path);
17284
- if (!existsSync11(path)) {
17284
+ if (!existsSync12(path)) {
17285
17285
  report.warnings.push(`stored artifact already missing: ${artifact.relative_path}`);
17286
17286
  continue;
17287
17287
  }
@@ -17948,8 +17948,8 @@ __export(exports_local_extensions, {
17948
17948
  discoverLocalExtensions: () => discoverLocalExtensions
17949
17949
  });
17950
17950
  import { createHash as createHash5, createVerify } from "crypto";
17951
- import { existsSync as existsSync12, readdirSync as readdirSync3, readFileSync as readFileSync7, statSync as statSync5 } from "fs";
17952
- import { basename as basename6, join as join10, resolve as resolve12 } from "path";
17951
+ import { existsSync as existsSync13, readdirSync as readdirSync3, readFileSync as readFileSync7, statSync as statSync5 } from "fs";
17952
+ import { basename as basename6, join as join11, resolve as resolve12 } from "path";
17953
17953
  function isObject(value) {
17954
17954
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
17955
17955
  }
@@ -18208,10 +18208,10 @@ function verifyExtensionSignature(input) {
18208
18208
  }
18209
18209
  function inspectExtensionSource(source2) {
18210
18210
  const resolved = resolve12(source2);
18211
- if (!existsSync12(resolved))
18211
+ if (!existsSync13(resolved))
18212
18212
  throw new Error(`extension source not found: ${source2}`);
18213
18213
  const stat = statSync5(resolved);
18214
- const manifestPath = stat.isDirectory() ? [join10(resolved, "todos.extension.json"), join10(resolved, "extension.json")].find(existsSync12) : resolved;
18214
+ const manifestPath = stat.isDirectory() ? [join11(resolved, "todos.extension.json"), join11(resolved, "extension.json")].find(existsSync13) : resolved;
18215
18215
  if (!manifestPath)
18216
18216
  throw new Error(`extension directory ${source2} is missing todos.extension.json`);
18217
18217
  const raw = readFileSync7(manifestPath);
@@ -18307,20 +18307,20 @@ function projectExtensionSources(projectPath) {
18307
18307
  return [];
18308
18308
  const root = resolve12(projectPath);
18309
18309
  const candidates = [
18310
- join10(root, "todos.extension.json"),
18311
- join10(root, ".todos", "todos.extension.json")
18310
+ join11(root, "todos.extension.json"),
18311
+ join11(root, ".todos", "todos.extension.json")
18312
18312
  ];
18313
- const extensionDir = join10(root, ".todos", "extensions");
18314
- if (existsSync12(extensionDir)) {
18313
+ const extensionDir = join11(root, ".todos", "extensions");
18314
+ if (existsSync13(extensionDir)) {
18315
18315
  for (const entry of readdirSync3(extensionDir)) {
18316
18316
  if (entry.startsWith("."))
18317
18317
  continue;
18318
- const full = join10(extensionDir, entry);
18318
+ const full = join11(extensionDir, entry);
18319
18319
  if (statSync5(full).isDirectory() || entry.endsWith(".json"))
18320
18320
  candidates.push(full);
18321
18321
  }
18322
18322
  }
18323
- return candidates.filter(existsSync12);
18323
+ return candidates.filter(existsSync13);
18324
18324
  }
18325
18325
  function discoverLocalExtensions(options = {}) {
18326
18326
  const config = loadConfig();
@@ -18374,7 +18374,7 @@ function installLocalExtension(input) {
18374
18374
  version: inspected.manifest.version,
18375
18375
  source: inspected.source,
18376
18376
  source_type: inspected.source_type,
18377
- manifest: redactValue(inspected.manifest),
18377
+ manifest: redactValue2(inspected.manifest),
18378
18378
  checksum: inspected.checksum,
18379
18379
  signature_verified: signatureVerified,
18380
18380
  trusted,
@@ -18856,7 +18856,7 @@ var init_policy_packs = __esm(() => {
18856
18856
  // src/db/checkpoints.ts
18857
18857
  function upsertCheckpoint(task_id, step, updates, db) {
18858
18858
  const d = db || getDatabase();
18859
- const timestamp = now();
18859
+ const timestamp = now2();
18860
18860
  const existing = d.query("SELECT id FROM task_checkpoints WHERE task_id = ? AND step = ?").get(task_id, step);
18861
18861
  const id = existing?.id ?? uuid();
18862
18862
  const agentId = updates.agent_id ?? null;
@@ -19016,7 +19016,7 @@ function writeGate(input, status, decision, db) {
19016
19016
  const step = stepForGate(input.gate);
19017
19017
  const existing = getCheckpoint(input.task_id, step, d);
19018
19018
  const existingData = existing?.data || {};
19019
- const timestamp = decision?.decided_at || now();
19019
+ const timestamp = decision?.decided_at || now2();
19020
19020
  const existingRunId = typeof existingData["run_id"] === "string" ? existingData["run_id"] : undefined;
19021
19021
  const runId = input.run_id ? resolveTaskRunId(input.run_id, d) : existingRunId;
19022
19022
  const data = {
@@ -19077,7 +19077,7 @@ function approveApprovalGate(input, db) {
19077
19077
  plan_id: existing.plan_id || undefined,
19078
19078
  run_id: existing.run_id || undefined,
19079
19079
  expires_at: existing.expires_at || undefined
19080
- }, "approved", { decided_by: input.reviewer, decided_at: now(), note: input.note }, d);
19080
+ }, "approved", { decided_by: input.reviewer, decided_at: now2(), note: input.note }, d);
19081
19081
  logApprovalEvent(input.task_id, "approved", gate, input.reviewer, d);
19082
19082
  return gate;
19083
19083
  }
@@ -19097,7 +19097,7 @@ function rejectApprovalGate(input, db) {
19097
19097
  plan_id: existing.plan_id || undefined,
19098
19098
  run_id: existing.run_id || undefined,
19099
19099
  expires_at: existing.expires_at || undefined
19100
- }, "rejected", { decided_by: input.reviewer, decided_at: now(), note: input.note, reason: input.reason || input.note }, d);
19100
+ }, "rejected", { decided_by: input.reviewer, decided_at: now2(), note: input.note, reason: input.reason || input.note }, d);
19101
19101
  logApprovalEvent(input.task_id, "rejected", gate, input.reviewer, d);
19102
19102
  return gate;
19103
19103
  }
@@ -19117,7 +19117,7 @@ function expireApprovalGate(input, db) {
19117
19117
  plan_id: existing.plan_id || undefined,
19118
19118
  run_id: existing.run_id || undefined,
19119
19119
  expires_at: existing.expires_at || undefined
19120
- }, "expired", { decided_by: input.reviewer, decided_at: now(), reason: input.reason || "expired" }, d);
19120
+ }, "expired", { decided_by: input.reviewer, decided_at: now2(), reason: input.reason || "expired" }, d);
19121
19121
  logApprovalEvent(input.task_id, "expired", gate, input.reviewer, d);
19122
19122
  return gate;
19123
19123
  }
@@ -19302,7 +19302,7 @@ function removeTerminalNotificationRule(name) {
19302
19302
  }
19303
19303
  function evaluateTerminalWatchRules(input, rules = listTerminalNotificationRules()) {
19304
19304
  const timestamp = input.timestamp || new Date().toISOString();
19305
- const payload = redactValue(input.payload || {});
19305
+ const payload = redactValue2(input.payload || {});
19306
19306
  return rules.map((rule) => {
19307
19307
  const skipped = [];
19308
19308
  const severity = eventSeverity(input.type);
@@ -19388,7 +19388,7 @@ var init_terminal_notifications = __esm(() => {
19388
19388
  });
19389
19389
 
19390
19390
  // src/db/api-keys.ts
19391
- import { createHash as createHash6, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "crypto";
19391
+ import { createHash as createHash6, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual3 } from "crypto";
19392
19392
  function rowToRecord(row) {
19393
19393
  return {
19394
19394
  id: row.id,
@@ -19407,7 +19407,7 @@ function hashApiKey(key) {
19407
19407
  function safeEqualHex(a, b) {
19408
19408
  if (a.length !== b.length)
19409
19409
  return false;
19410
- return timingSafeEqual2(Buffer.from(a, "hex"), Buffer.from(b, "hex"));
19410
+ return timingSafeEqual3(Buffer.from(a, "hex"), Buffer.from(b, "hex"));
19411
19411
  }
19412
19412
  function generatePlaintextKey() {
19413
19413
  return `tdos_${randomBytes2(32).toString("base64url")}`;
@@ -19418,7 +19418,7 @@ function createApiKey(input, db) {
19418
19418
  if (!name)
19419
19419
  throw new Error("API key name is required");
19420
19420
  const key = generatePlaintextKey();
19421
- const timestamp = now();
19421
+ const timestamp = now2();
19422
19422
  const id = uuid();
19423
19423
  const prefix = key.slice(0, 12);
19424
19424
  d.run(`INSERT INTO api_keys (id, name, key_hash, prefix, permissions, created_at, expires_at)
@@ -19442,18 +19442,18 @@ function listApiKeys(opts, db) {
19442
19442
  }
19443
19443
  function hasActiveApiKeys(db) {
19444
19444
  const d = db || getDatabase();
19445
- const row = d.query("SELECT COUNT(*) AS count FROM api_keys WHERE revoked_at IS NULL AND (expires_at IS NULL OR expires_at > ?)").get(now());
19445
+ const row = d.query("SELECT COUNT(*) AS count FROM api_keys WHERE revoked_at IS NULL AND (expires_at IS NULL OR expires_at > ?)").get(now2());
19446
19446
  return (row?.count ?? 0) > 0;
19447
19447
  }
19448
19448
  function verifyApiKey(key, db) {
19449
19449
  const d = db || getDatabase();
19450
19450
  const candidateHash = hashApiKey(key);
19451
- const rows = d.query("SELECT * FROM api_keys WHERE revoked_at IS NULL AND (expires_at IS NULL OR expires_at > ?)").all(now());
19451
+ const rows = d.query("SELECT * FROM api_keys WHERE revoked_at IS NULL AND (expires_at IS NULL OR expires_at > ?)").all(now2());
19452
19452
  for (const row of rows) {
19453
19453
  if (!safeEqualHex(candidateHash, row.key_hash))
19454
19454
  continue;
19455
- d.run("UPDATE api_keys SET last_used_at = ? WHERE id = ?", [now(), row.id]);
19456
- return rowToRecord({ ...row, last_used_at: now() });
19455
+ d.run("UPDATE api_keys SET last_used_at = ? WHERE id = ?", [now2(), row.id]);
19456
+ return rowToRecord({ ...row, last_used_at: now2() });
19457
19457
  }
19458
19458
  return null;
19459
19459
  }
@@ -19463,7 +19463,7 @@ function revokeApiKey(idOrPrefix, db) {
19463
19463
  const row = d.query("SELECT * FROM api_keys WHERE id = ? OR prefix = ?").get(identifier, identifier);
19464
19464
  if (!row)
19465
19465
  return null;
19466
- d.run("UPDATE api_keys SET revoked_at = ? WHERE id = ?", [now(), row.id]);
19466
+ d.run("UPDATE api_keys SET revoked_at = ? WHERE id = ?", [now2(), row.id]);
19467
19467
  const updated = d.query("SELECT * FROM api_keys WHERE id = ?").get(row.id);
19468
19468
  return rowToRecord(updated);
19469
19469
  }
@@ -19478,7 +19478,7 @@ function rowToOrg(row) {
19478
19478
  function createOrg(input, db) {
19479
19479
  const d = db || getDatabase();
19480
19480
  const id = uuid();
19481
- const timestamp = now();
19481
+ const timestamp = now2();
19482
19482
  d.run(`INSERT INTO orgs (id, name, description, metadata, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)`, [id, input.name, input.description || null, JSON.stringify(input.metadata || {}), timestamp, timestamp]);
19483
19483
  return getOrg(id, d);
19484
19484
  }
@@ -19497,7 +19497,7 @@ function updateOrg(id, input, db) {
19497
19497
  if (!org)
19498
19498
  throw new Error(`Org not found: ${id}`);
19499
19499
  const sets = ["updated_at = ?"];
19500
- const params = [now()];
19500
+ const params = [now2()];
19501
19501
  if (input.name !== undefined) {
19502
19502
  sets.push("name = ?");
19503
19503
  params.push(input.name);
@@ -19613,8 +19613,8 @@ var exports_doctor = {};
19613
19613
  __export(exports_doctor, {
19614
19614
  runTodosDoctor: () => runTodosDoctor
19615
19615
  });
19616
- import { chmodSync, copyFileSync, existsSync as existsSync13, mkdirSync as mkdirSync6, statSync as statSync6 } from "fs";
19617
- import { basename as basename7, dirname as dirname7, join as join11 } from "path";
19616
+ import { chmodSync, copyFileSync, existsSync as existsSync14, mkdirSync as mkdirSync6, statSync as statSync6 } from "fs";
19617
+ import { basename as basename7, dirname as dirname7, join as join12 } from "path";
19618
19618
  function tableExists(db, table) {
19619
19619
  return Boolean(db.query("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(table));
19620
19620
  }
@@ -19708,7 +19708,7 @@ function findMissingProjectRoots(db) {
19708
19708
  continue;
19709
19709
  if (!row.path.startsWith("/"))
19710
19710
  continue;
19711
- if (!existsSync13(row.path))
19711
+ if (!existsSync14(row.path))
19712
19712
  missing++;
19713
19713
  }
19714
19714
  return missing;
@@ -19768,16 +19768,16 @@ function databasePermissionsAreUnsafe(dbPath) {
19768
19768
  function createBackup(dbPath) {
19769
19769
  if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
19770
19770
  return;
19771
- if (!existsSync13(dbPath))
19771
+ if (!existsSync14(dbPath))
19772
19772
  return;
19773
- const stamp = now().replace(/[:.]/g, "-");
19774
- const backupDir = join11(dirname7(dbPath), `${basename7(dbPath)}.backup-${stamp}`);
19773
+ const stamp = now2().replace(/[:.]/g, "-");
19774
+ const backupDir = join12(dirname7(dbPath), `${basename7(dbPath)}.backup-${stamp}`);
19775
19775
  const files = [];
19776
19776
  mkdirSync6(backupDir, { recursive: true });
19777
19777
  for (const source2 of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
19778
- if (!existsSync13(source2))
19778
+ if (!existsSync14(source2))
19779
19779
  continue;
19780
- const target = join11(backupDir, basename7(source2));
19780
+ const target = join12(backupDir, basename7(source2));
19781
19781
  copyFileSync(source2, target);
19782
19782
  files.push(target);
19783
19783
  }
@@ -20003,7 +20003,7 @@ var init_doctor = __esm(() => {
20003
20003
  });
20004
20004
 
20005
20005
  // src/server/routes.ts
20006
- import { join as join12, resolve as resolve14, sep } from "path";
20006
+ import { join as join13, resolve as resolve14, sep } from "path";
20007
20007
  function parseFieldsParam(url) {
20008
20008
  const fieldsParam = url.searchParams.get("fields");
20009
20009
  return fieldsParam ? fieldsParam.split(",").map((f) => f.trim()).filter(Boolean) : undefined;
@@ -20707,7 +20707,7 @@ function handleStaticFiles(path, method, ctx, json2, serveStaticFile2) {
20707
20707
  if (!ctx.dashboardExists || method !== "GET" && method !== "HEAD")
20708
20708
  return null;
20709
20709
  if (path !== "/") {
20710
- const filePath = join12(ctx.dashboardDir, path);
20710
+ const filePath = join13(ctx.dashboardDir, path);
20711
20711
  const resolvedFile = resolve14(filePath);
20712
20712
  const resolvedBase = resolve14(ctx.dashboardDir);
20713
20713
  if (!resolvedFile.startsWith(resolvedBase + sep) && resolvedFile !== resolvedBase) {
@@ -20717,7 +20717,7 @@ function handleStaticFiles(path, method, ctx, json2, serveStaticFile2) {
20717
20717
  if (res2)
20718
20718
  return res2;
20719
20719
  }
20720
- const indexPath = join12(ctx.dashboardDir, "index.html");
20720
+ const indexPath = join13(ctx.dashboardDir, "index.html");
20721
20721
  const res = serveStaticFile2(indexPath);
20722
20722
  if (res)
20723
20723
  return res;
@@ -24745,7 +24745,7 @@ function createDispatch(input, db) {
24745
24745
  input.message ?? null,
24746
24746
  input.delay_ms ?? null,
24747
24747
  input.scheduled_at ?? null,
24748
- now()
24748
+ now2()
24749
24749
  ]);
24750
24750
  const row = _db2.query("SELECT * FROM dispatches WHERE id = ?").get(id);
24751
24751
  return rowToDispatch(row);
@@ -24788,7 +24788,7 @@ function updateDispatchStatus(id, status, opts = {}, db) {
24788
24788
  function createDispatchLog(log, db) {
24789
24789
  const _db2 = db ?? getDatabase();
24790
24790
  const id = uuid();
24791
- const created_at = now();
24791
+ const created_at = now2();
24792
24792
  _db2.run(`INSERT INTO dispatch_logs (id, dispatch_id, target_window, message, delay_ms, status, error, created_at)
24793
24793
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [id, log.dispatch_id, log.target_window, log.message, log.delay_ms, log.status, log.error ?? null, created_at]);
24794
24794
  return { ...log, id, created_at };
@@ -24802,7 +24802,7 @@ function getDueDispatches(db) {
24802
24802
  const rows = _db2.query(`SELECT * FROM dispatches
24803
24803
  WHERE status = 'pending'
24804
24804
  AND (scheduled_at IS NULL OR scheduled_at <= ?)
24805
- ORDER BY created_at ASC`).all(now());
24805
+ ORDER BY created_at ASC`).all(now2());
24806
24806
  return rows.map(rowToDispatch);
24807
24807
  }
24808
24808
  var init_dispatches = __esm(() => {
@@ -24926,7 +24926,7 @@ async function executeDispatch(dispatch, opts = {}, db) {
24926
24926
  error: null
24927
24927
  }, _db2);
24928
24928
  if (!opts.dryRun) {
24929
- updateDispatchStatus(dispatch.id, "sent", { sent_at: now() }, _db2);
24929
+ updateDispatchStatus(dispatch.id, "sent", { sent_at: now2() }, _db2);
24930
24930
  }
24931
24931
  } catch (err) {
24932
24932
  const error = err instanceof Error ? err.message : String(err);
@@ -25394,7 +25394,7 @@ function normalizeName3(name) {
25394
25394
  function createLabel(input, db) {
25395
25395
  const d = db || getDatabase();
25396
25396
  const id = uuid();
25397
- const ts = now();
25397
+ const ts = now2();
25398
25398
  d.run(`INSERT INTO labels (id, project_id, name, color, description, created_at, updated_at)
25399
25399
  VALUES (?, ?, ?, ?, ?, ?, ?)`, [id, input.project_id ?? null, input.name.trim(), input.color ?? null, input.description ?? null, ts, ts]);
25400
25400
  return rowToLabel(d.query("SELECT * FROM labels WHERE id = ?").get(id));
@@ -25419,7 +25419,7 @@ function updateLabel(idOrName, input, db) {
25419
25419
  const existing = getLabel(idOrName, d);
25420
25420
  if (!existing)
25421
25421
  throw new Error(`Label not found: ${idOrName}`);
25422
- const ts = now();
25422
+ const ts = now2();
25423
25423
  d.run(`UPDATE labels SET
25424
25424
  name = COALESCE(?, name),
25425
25425
  color = COALESCE(?, color),
@@ -25480,7 +25480,7 @@ function getTagRow(idOrName, db) {
25480
25480
  function updateTaskTagJson(oldName, newName, db) {
25481
25481
  const rows = db.query("SELECT id, tags FROM tasks WHERE tags IS NOT NULL AND tags != '[]'").all();
25482
25482
  const update = db.prepare("UPDATE tasks SET tags = ?, updated_at = ? WHERE id = ?");
25483
- const ts = now();
25483
+ const ts = now2();
25484
25484
  for (const row of rows) {
25485
25485
  if (!row.tags)
25486
25486
  continue;
@@ -25509,7 +25509,7 @@ function createTag(input, db) {
25509
25509
  if (!name)
25510
25510
  throw new Error("Tag name is required");
25511
25511
  const id = uuid();
25512
- const ts = now();
25512
+ const ts = now2();
25513
25513
  d.run(`INSERT INTO tags (id, name, color, description, created_at, updated_at)
25514
25514
  VALUES (?, ?, ?, ?, ?, ?)`, [id, name, input.color ?? null, input.description ?? null, ts, ts]);
25515
25515
  return rowToTag(d.query("SELECT * FROM tags WHERE id = ?").get(id), d);
@@ -25555,7 +25555,7 @@ function updateTag(idOrName, input, db) {
25555
25555
  renameTaskTagRows(stored.name, nextName, d);
25556
25556
  updateTaskTagJson(stored.name, nextName, d);
25557
25557
  }
25558
- d.run(`UPDATE tags SET name = ?, color = COALESCE(?, color), description = COALESCE(?, description), updated_at = ? WHERE id = ?`, [nextName, input.color ?? null, input.description ?? null, now(), stored.id]);
25558
+ d.run(`UPDATE tags SET name = ?, color = COALESCE(?, color), description = COALESCE(?, description), updated_at = ? WHERE id = ?`, [nextName, input.color ?? null, input.description ?? null, now2(), stored.id]);
25559
25559
  return getTag(stored.id, d);
25560
25560
  }
25561
25561
  function deleteTag(idOrName, db) {
@@ -25577,8 +25577,8 @@ var exports_mention_resolver = {};
25577
25577
  __export(exports_mention_resolver, {
25578
25578
  resolveMentions: () => resolveMentions
25579
25579
  });
25580
- import { existsSync as existsSync14, readdirSync as readdirSync4, readFileSync as readFileSync8, statSync as statSync7 } from "fs";
25581
- import { basename as basename8, isAbsolute, join as join13, relative as relative5, resolve as resolve15, sep as sep2 } from "path";
25580
+ import { existsSync as existsSync15, readdirSync as readdirSync4, readFileSync as readFileSync8, statSync as statSync7 } from "fs";
25581
+ import { basename as basename8, isAbsolute, join as join14, relative as relative5, resolve as resolve15, sep as sep2 } from "path";
25582
25582
  function blankResolution(parsed) {
25583
25583
  return {
25584
25584
  input: parsed.input,
@@ -25676,7 +25676,7 @@ function resolveFile(parsed, workspace) {
25676
25676
  return resolution;
25677
25677
  }
25678
25678
  resolution.path = relPath;
25679
- if (!existsSync14(absolutePath)) {
25679
+ if (!existsSync15(absolutePath)) {
25680
25680
  resolution.warnings.push("file does not exist in the local workspace");
25681
25681
  return resolution;
25682
25682
  }
@@ -25709,7 +25709,7 @@ function walkSourceFiles(root, current = root, files = []) {
25709
25709
  if (SKIP_DIRS2.has(entry.name))
25710
25710
  continue;
25711
25711
  }
25712
- const absolutePath = join13(current, entry.name);
25712
+ const absolutePath = join14(current, entry.name);
25713
25713
  if (entry.isDirectory()) {
25714
25714
  if (!SKIP_DIRS2.has(entry.name))
25715
25715
  walkSourceFiles(root, absolutePath, files);
@@ -26052,7 +26052,7 @@ function alertId(kind, id, suffix = "") {
26052
26052
  return `${kind}:${id}${suffix ? `:${suffix}` : ""}`;
26053
26053
  }
26054
26054
  function taskPayload(task, extra = {}) {
26055
- return redactValue({
26055
+ return redactValue2({
26056
26056
  id: task.id,
26057
26057
  task_id: task.id,
26058
26058
  title: task.title,
@@ -26098,7 +26098,7 @@ function calendarAlert(event, triggeredAt, quieted) {
26098
26098
  due_at: event.starts_at,
26099
26099
  triggered_at: triggeredAt,
26100
26100
  quieted,
26101
- payload: redactValue({ ...event, severity: event.kind === "milestone" ? "warning" : "info" })
26101
+ payload: redactValue2({ ...event, severity: event.kind === "milestone" ? "warning" : "info" })
26102
26102
  };
26103
26103
  }
26104
26104
  function runAlerts(input, db, checkedAt, quieted) {
@@ -26126,7 +26126,7 @@ function runAlerts(input, db, checkedAt, quieted) {
26126
26126
  due_at: null,
26127
26127
  triggered_at: run.completed_at || checkedAt,
26128
26128
  quieted,
26129
- payload: redactValue({ ...run, task_title: task?.title, project_id: task?.project_id, severity: failed ? "critical" : "info" })
26129
+ payload: redactValue2({ ...run, task_title: task?.title, project_id: task?.project_id, severity: failed ? "critical" : "info" })
26130
26130
  };
26131
26131
  }).filter((alert) => alert !== null);
26132
26132
  }
@@ -26146,7 +26146,7 @@ function countAlerts(alerts) {
26146
26146
  }
26147
26147
  async function checkLocalNotifications(input = {}, db) {
26148
26148
  const d = db || getDatabase();
26149
- const checkedAt = input.now || now();
26149
+ const checkedAt = input.now || now2();
26150
26150
  const checkedMs = Date.parse(checkedAt);
26151
26151
  const dueWithin = minutes(input.due_within_minutes, 60);
26152
26152
  const staleMinutes = minutes(input.stale_minutes, 30);
@@ -26265,7 +26265,7 @@ function toEntry(row) {
26265
26265
  created_at: row.created_at,
26266
26266
  title: redactEvidenceText(row.title),
26267
26267
  message: row.message ? redactEvidenceText(row.message) : null,
26268
- metadata: redactValue(parseMetadata2(row.metadata_json))
26268
+ metadata: redactValue2(parseMetadata2(row.metadata_json))
26269
26269
  };
26270
26270
  }
26271
26271
  function sourceRank(source2) {
@@ -27022,7 +27022,7 @@ function rowToRelationship(row) {
27022
27022
  function addTaskRelationship(input, db) {
27023
27023
  const d = db || getDatabase();
27024
27024
  const id = uuid();
27025
- const timestamp = now();
27025
+ const timestamp = now2();
27026
27026
  if (input.source_task_id === input.target_task_id) {
27027
27027
  throw new Error("Cannot create a relationship between a task and itself");
27028
27028
  }
@@ -27345,10 +27345,10 @@ function moveFiles(db, primaryId, duplicateId) {
27345
27345
  if (existing) {
27346
27346
  const note = [existing.note, row.note].filter(Boolean).join(`
27347
27347
  `);
27348
- db.run("UPDATE task_files SET status = ?, agent_id = COALESCE(?, agent_id), note = ?, updated_at = ? WHERE id = ?", [row.status, row.agent_id, note || null, now(), existing.id]);
27348
+ db.run("UPDATE task_files SET status = ?, agent_id = COALESCE(?, agent_id), note = ?, updated_at = ? WHERE id = ?", [row.status, row.agent_id, note || null, now2(), existing.id]);
27349
27349
  db.run("DELETE FROM task_files WHERE id = ?", [row.id]);
27350
27350
  } else {
27351
- db.run("UPDATE task_files SET task_id = ?, updated_at = ? WHERE id = ?", [primaryId, now(), row.id]);
27351
+ db.run("UPDATE task_files SET task_id = ?, updated_at = ? WHERE id = ?", [primaryId, now2(), row.id]);
27352
27352
  }
27353
27353
  moved++;
27354
27354
  }
@@ -27381,7 +27381,7 @@ function moveGitRefs(db, primaryId, duplicateId) {
27381
27381
  const exists = db.query("SELECT id FROM task_git_refs WHERE task_id = ? AND ref_type = ? AND name = ?").get(primaryId, row.ref_type, row.name);
27382
27382
  if (exists)
27383
27383
  continue;
27384
- db.run("UPDATE task_git_refs SET task_id = ?, updated_at = ? WHERE id = ?", [primaryId, now(), row.id]);
27384
+ db.run("UPDATE task_git_refs SET task_id = ?, updated_at = ? WHERE id = ?", [primaryId, now2(), row.id]);
27385
27385
  moved++;
27386
27386
  }
27387
27387
  return moved;
@@ -27391,7 +27391,7 @@ function moveChecklists(db, primaryId, duplicateId) {
27391
27391
  const rows = db.query("SELECT id, position FROM task_checklists WHERE task_id = ? ORDER BY position, created_at").all(duplicateId);
27392
27392
  let moved = 0;
27393
27393
  for (const [index, row] of rows.entries()) {
27394
- db.run("UPDATE task_checklists SET task_id = ?, position = ?, updated_at = ? WHERE id = ?", [primaryId, max.position + index + 1, now(), row.id]);
27394
+ db.run("UPDATE task_checklists SET task_id = ?, position = ?, updated_at = ? WHERE id = ?", [primaryId, max.position + index + 1, now2(), row.id]);
27395
27395
  moved++;
27396
27396
  }
27397
27397
  return moved;
@@ -27441,7 +27441,7 @@ function mergeDuplicateTask(input, db) {
27441
27441
  throw new Error(`Primary task not found: ${input.primary_task_id}`);
27442
27442
  if (!duplicate)
27443
27443
  throw new Error(`Duplicate task not found: ${input.duplicate_task_id}`);
27444
- const mergedAt = now();
27444
+ const mergedAt = now2();
27445
27445
  const moved = {
27446
27446
  comments: 0,
27447
27447
  dependencies: 0,
@@ -27668,7 +27668,7 @@ function createRoadmap(input) {
27668
27668
  if (!name)
27669
27669
  throw new Error("Roadmap name is required");
27670
27670
  const store = readStore();
27671
- const now3 = timestamp();
27671
+ const now4 = timestamp();
27672
27672
  const roadmap = {
27673
27673
  id: newId("roadmap"),
27674
27674
  name,
@@ -27679,8 +27679,8 @@ function createRoadmap(input) {
27679
27679
  agent_id: cleanString(input.agent_id),
27680
27680
  release: cleanString(input.release),
27681
27681
  milestone_ids: [],
27682
- created_at: now3,
27683
- updated_at: now3
27682
+ created_at: now4,
27683
+ updated_at: now4
27684
27684
  };
27685
27685
  store.roadmaps[roadmap.id] = roadmap;
27686
27686
  writeStore(store);
@@ -27740,7 +27740,7 @@ function createMilestone(input) {
27740
27740
  const title = input.title.trim();
27741
27741
  if (!title)
27742
27742
  throw new Error("Milestone title is required");
27743
- const now3 = timestamp();
27743
+ const now4 = timestamp();
27744
27744
  const milestone = {
27745
27745
  id: newId("milestone"),
27746
27746
  roadmap_id: roadmapId,
@@ -27755,11 +27755,11 @@ function createMilestone(input) {
27755
27755
  run_ids: cleanList(input.run_ids),
27756
27756
  release: cleanString(input.release ?? roadmap.release ?? undefined),
27757
27757
  tags: cleanList(input.tags),
27758
- created_at: now3,
27759
- updated_at: now3
27758
+ created_at: now4,
27759
+ updated_at: now4
27760
27760
  };
27761
27761
  store.milestones[milestone.id] = milestone;
27762
- store.roadmaps[roadmapId] = { ...roadmap, milestone_ids: cleanList([...roadmap.milestone_ids, milestone.id]), updated_at: now3 };
27762
+ store.roadmaps[roadmapId] = { ...roadmap, milestone_ids: cleanList([...roadmap.milestone_ids, milestone.id]), updated_at: now4 };
27763
27763
  writeStore(store);
27764
27764
  return milestone;
27765
27765
  }
@@ -27819,7 +27819,7 @@ function upsertReleaseGroup(input) {
27819
27819
  throw new Error("Release group name is required");
27820
27820
  const key = releaseKey(roadmapId, name);
27821
27821
  const existing = store.releases[key];
27822
- const now3 = timestamp();
27822
+ const now4 = timestamp();
27823
27823
  const release = {
27824
27824
  name,
27825
27825
  version: input.version === undefined ? existing?.version ?? null : cleanString(input.version),
@@ -27830,8 +27830,8 @@ function upsertReleaseGroup(input) {
27830
27830
  plan_ids: input.plan_ids === undefined ? existing?.plan_ids ?? [] : cleanList(input.plan_ids),
27831
27831
  run_ids: input.run_ids === undefined ? existing?.run_ids ?? [] : cleanList(input.run_ids),
27832
27832
  notes: input.notes === undefined ? existing?.notes ?? null : cleanString(input.notes),
27833
- created_at: existing?.created_at ?? now3,
27834
- updated_at: now3
27833
+ created_at: existing?.created_at ?? now4,
27834
+ updated_at: now4
27835
27835
  };
27836
27836
  store.releases[key] = release;
27837
27837
  writeStore(store);
@@ -28039,7 +28039,7 @@ function upsertCapacityProfile(input) {
28039
28039
  const store = readStore2();
28040
28040
  const key = profileKey(agentId, projectId);
28041
28041
  const existing = store.profiles[key];
28042
- const now3 = timestamp2();
28042
+ const now4 = timestamp2();
28043
28043
  const profile = {
28044
28044
  id: existing?.id ?? key,
28045
28045
  agent_id: agentId,
@@ -28047,8 +28047,8 @@ function upsertCapacityProfile(input) {
28047
28047
  minutes_per_day: assertMinutes(input.minutes_per_day),
28048
28048
  working_days: normalizeWorkingDays(input.working_days),
28049
28049
  effective_from: cleanString2(input.effective_from),
28050
- created_at: existing?.created_at ?? now3,
28051
- updated_at: now3
28050
+ created_at: existing?.created_at ?? now4,
28051
+ updated_at: now4
28052
28052
  };
28053
28053
  store.profiles[key] = profile;
28054
28054
  writeStore2(store);
@@ -28201,7 +28201,7 @@ function parsePayload(value) {
28201
28201
  return {};
28202
28202
  try {
28203
28203
  const parsed = JSON.parse(value);
28204
- return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? redactValue(parsed) : {};
28204
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? redactValue2(parsed) : {};
28205
28205
  } catch {
28206
28206
  return {};
28207
28207
  }
@@ -28372,7 +28372,7 @@ function getLocalAuditLedger(input = {}, db) {
28372
28372
  first_entry_hash: entries[0]?.chain_hash ?? null,
28373
28373
  last_entry_hash: entries.at(-1)?.chain_hash ?? null,
28374
28374
  source_counts: sourceCounts,
28375
- generated_at: now(),
28375
+ generated_at: now2(),
28376
28376
  ...input.include_entries === false ? {} : { entries }
28377
28377
  };
28378
28378
  }
@@ -28393,7 +28393,7 @@ function sealLocalAuditLedger(input, db) {
28393
28393
  first_entry_hash: ledger.first_entry_hash,
28394
28394
  last_entry_hash: ledger.last_entry_hash,
28395
28395
  source_counts: ledger.source_counts,
28396
- created_at: now()
28396
+ created_at: now2()
28397
28397
  };
28398
28398
  saveConfig({
28399
28399
  ...config,
@@ -28474,7 +28474,7 @@ __export(exports_release_compatibility, {
28474
28474
  LOCAL_RELEASE_COMPATIBILITY_SCHEMA_VERSION: () => LOCAL_RELEASE_COMPATIBILITY_SCHEMA_VERSION
28475
28475
  });
28476
28476
  import { readFileSync as readFileSync9 } from "fs";
28477
- import { join as join14, resolve as resolve16 } from "path";
28477
+ import { join as join15, resolve as resolve16 } from "path";
28478
28478
  import { Database as Database2 } from "bun:sqlite";
28479
28479
  function pass(id, message, details) {
28480
28480
  return { id, status: "passed", message, details };
@@ -28486,7 +28486,7 @@ function warn(id, message, details) {
28486
28486
  return { id, status: "warning", message, details };
28487
28487
  }
28488
28488
  function readPackageJson2(root) {
28489
- return JSON.parse(readFileSync9(join14(root, "package.json"), "utf8"));
28489
+ return JSON.parse(readFileSync9(join15(root, "package.json"), "utf8"));
28490
28490
  }
28491
28491
  function sortedKeys(value) {
28492
28492
  return Object.keys(value ?? {}).sort((left, right) => left.localeCompare(right));
@@ -30942,7 +30942,7 @@ __export(exports_handoffs, {
30942
30942
  function createHandoff(input, db) {
30943
30943
  const d = db || getDatabase();
30944
30944
  const id = uuid();
30945
- const timestamp3 = now();
30945
+ const timestamp3 = now2();
30946
30946
  d.run(`INSERT INTO handoffs (id, agent_id, project_id, session_id, summary, completed, in_progress, blockers, next_steps, task_ids, relevant_files, run_ids, created_at)
30947
30947
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
30948
30948
  id,
@@ -31081,7 +31081,7 @@ function importHandoffBundle(bundle, options = {}, db) {
31081
31081
  ]);
31082
31082
  }
31083
31083
  for (const agentId of handoff.acknowledged_by ?? []) {
31084
- d.run("INSERT OR REPLACE INTO handoff_acknowledgements (handoff_id, agent_id, acknowledged_at) VALUES (?, ?, ?)", [handoff.id, agentId, now()]);
31084
+ d.run("INSERT OR REPLACE INTO handoff_acknowledgements (handoff_id, agent_id, acknowledged_at) VALUES (?, ?, ?)", [handoff.id, agentId, now2()]);
31085
31085
  }
31086
31086
  return {
31087
31087
  applied: true,
@@ -31157,7 +31157,7 @@ function acknowledgeHandoff(id, agentId, db) {
31157
31157
  const handoff = getHandoff(id, d);
31158
31158
  if (!handoff)
31159
31159
  throw new Error(`Handoff not found: ${id}`);
31160
- d.run("INSERT OR REPLACE INTO handoff_acknowledgements (handoff_id, agent_id, acknowledged_at) VALUES (?, ?, ?)", [handoff.id, agentId, now()]);
31160
+ d.run("INSERT OR REPLACE INTO handoff_acknowledgements (handoff_id, agent_id, acknowledged_at) VALUES (?, ?, ?)", [handoff.id, agentId, now2()]);
31161
31161
  return getHandoff(handoff.id, d);
31162
31162
  }
31163
31163
  function getLatestHandoff(agentId, projectId, db) {
@@ -31467,7 +31467,7 @@ function registerTaskWorkflowTools(server, ctx) {
31467
31467
  const globalRole = n.agent.role ? ` [${n.agent.role}]` : "";
31468
31468
  const lead = n.is_lead ? " \u2605" : "";
31469
31469
  const lastSeen = new Date(n.agent.last_seen_at).getTime();
31470
- const active = now3 - lastSeen < ACTIVE_MS ? " \u25CF" : " \u25CB";
31470
+ const active = now4 - lastSeen < ACTIVE_MS ? " \u25CF" : " \u25CB";
31471
31471
  const line = `${prefix}${active} ${n.agent.name}${title}${globalRole}${lead}`;
31472
31472
  const children = n.reports.length > 0 ? `
31473
31473
  ` + render(n.reports, indent + 1) : "";
@@ -31480,7 +31480,7 @@ function registerTaskWorkflowTools(server, ctx) {
31480
31480
  if (format === "json") {
31481
31481
  return { content: [{ type: "text", text: JSON.stringify(tree, null, 2) }] };
31482
31482
  }
31483
- const now3 = Date.now();
31483
+ const now4 = Date.now();
31484
31484
  const ACTIVE_MS = 30 * 60 * 1000;
31485
31485
  const text = tree.length > 0 ? render(tree) : "No agents in org chart.";
31486
31486
  return { content: [{ type: "text", text }] };
@@ -31676,14 +31676,14 @@ function registerTaskAutoTools(server, ctx) {
31676
31676
  return { content: [{ type: "text", text: "No agent_id provided and no agent focus is active." }], isError: true };
31677
31677
  }
31678
31678
  const assigned = listTasks3({ assigned_to: effectiveAgentId, limit: 500 }, undefined);
31679
- const now3 = Date.now();
31680
- const dueSoonCutoff = now3 + 24 * 60 * 60 * 1000;
31679
+ const now4 = Date.now();
31680
+ const dueSoonCutoff = now4 + 24 * 60 * 60 * 1000;
31681
31681
  const blocked = getBlockedTasks2().filter((t) => t.assigned_to === effectiveAgentId);
31682
31682
  const workload = {
31683
31683
  in_progress: assigned.filter((t) => t.status === "in_progress").length,
31684
31684
  pending: assigned.filter((t) => t.status === "pending").length,
31685
- completed_recent: assigned.filter((t) => t.status === "completed" && t.completed_at && now3 - new Date(t.completed_at).getTime() <= 7 * 24 * 60 * 60 * 1000).length,
31686
- due_soon: assigned.filter((t) => t.due_at && new Date(t.due_at).getTime() <= dueSoonCutoff && new Date(t.due_at).getTime() >= now3 && !["completed", "cancelled", "failed"].includes(t.status)).length,
31685
+ completed_recent: assigned.filter((t) => t.status === "completed" && t.completed_at && now4 - new Date(t.completed_at).getTime() <= 7 * 24 * 60 * 60 * 1000).length,
31686
+ due_soon: assigned.filter((t) => t.due_at && new Date(t.due_at).getTime() <= dueSoonCutoff && new Date(t.due_at).getTime() >= now4 && !["completed", "cancelled", "failed"].includes(t.status)).length,
31687
31687
  blocked: blocked.length
31688
31688
  };
31689
31689
  const lines = [
@@ -31910,7 +31910,7 @@ function limits(input) {
31910
31910
  stale_after_hours: clamp(input.stale_after_hours, DEFAULT_LIMITS.stale_after_hours, 24 * 365)
31911
31911
  };
31912
31912
  }
31913
- function truncate(value, max) {
31913
+ function truncate2(value, max) {
31914
31914
  if (!value)
31915
31915
  return value ?? null;
31916
31916
  const redacted = redactEvidenceText(value);
@@ -31931,9 +31931,9 @@ function acceptanceCriteria(task, maxText) {
31931
31931
  const metadata = task.metadata || {};
31932
31932
  const raw = metadata["acceptance_criteria"] ?? metadata["acceptanceCriteria"] ?? metadata["criteria"];
31933
31933
  if (Array.isArray(raw))
31934
- return raw.map((item) => truncate(String(item), maxText)).filter((item) => Boolean(item));
31934
+ return raw.map((item) => truncate2(String(item), maxText)).filter((item) => Boolean(item));
31935
31935
  if (typeof raw === "string") {
31936
- return raw.split(/\r?\n/).map((line) => line.replace(/^[-*]\s*/, "").trim()).filter(Boolean).map((line) => truncate(line, maxText)).filter((item) => Boolean(item));
31936
+ return raw.split(/\r?\n/).map((line) => line.replace(/^[-*]\s*/, "").trim()).filter(Boolean).map((line) => truncate2(line, maxText)).filter((item) => Boolean(item));
31937
31937
  }
31938
31938
  return [];
31939
31939
  }
@@ -31956,7 +31956,7 @@ function addFile(files, path, source2, base) {
31956
31956
  path,
31957
31957
  status: base?.status || "active",
31958
31958
  agent_id: base?.agent_id ?? null,
31959
- note: truncate(base?.note, 240),
31959
+ note: truncate2(base?.note, 240),
31960
31960
  updated_at: base?.updated_at || "",
31961
31961
  sources: [source2]
31962
31962
  });
@@ -32014,7 +32014,7 @@ function estimateTokens(value) {
32014
32014
  return Math.max(1, Math.ceil((text || "").length / 4));
32015
32015
  }
32016
32016
  function summarizeStrings(values, maxChars) {
32017
- return truncate(values.filter(Boolean).join("; "), maxChars) || "No local details were available before this section was omitted.";
32017
+ return truncate2(values.filter(Boolean).join("; "), maxChars) || "No local details were available before this section was omitted.";
32018
32018
  }
32019
32019
  function summarizeSection(pack, section, maxChars) {
32020
32020
  if (section === "project")
@@ -32205,8 +32205,8 @@ function createAgentContextPack(input, db) {
32205
32205
  ...taskFiles.map((file) => file.updated_at)
32206
32206
  ], task.updated_at);
32207
32207
  const warnings = [];
32208
- const now3 = input.now ? new Date(input.now) : new Date;
32209
- if (Date.parse(task.updated_at) < now3.getTime() - limit.stale_after_hours * 60 * 60 * 1000) {
32208
+ const now4 = input.now ? new Date(input.now) : new Date;
32209
+ if (Date.parse(task.updated_at) < now4.getTime() - limit.stale_after_hours * 60 * 60 * 1000) {
32210
32210
  warnings.push(`task state is older than ${limit.stale_after_hours} hours`);
32211
32211
  }
32212
32212
  if (comments.length > recentComments.length)
@@ -32221,7 +32221,7 @@ function createAgentContextPack(input, db) {
32221
32221
  id: task.id,
32222
32222
  short_id: task.short_id,
32223
32223
  title: redactEvidenceText(task.title),
32224
- description: truncate(task.description, limit.max_text_chars),
32224
+ description: truncate2(task.description, limit.max_text_chars),
32225
32225
  status: task.status,
32226
32226
  priority: task.priority,
32227
32227
  assigned_to: task.assigned_to,
@@ -32245,7 +32245,7 @@ function createAgentContextPack(input, db) {
32245
32245
  plan: plan ? {
32246
32246
  id: plan.id,
32247
32247
  name: plan.name,
32248
- description: truncate(plan.description, limit.max_text_chars),
32248
+ description: truncate2(plan.description, limit.max_text_chars),
32249
32249
  status: plan.status,
32250
32250
  agent_id: plan.agent_id,
32251
32251
  tasks: planTasks.slice(0, limit.plan_task_limit).map(taskSummary).filter((item) => Boolean(item)),
@@ -32264,7 +32264,7 @@ function createAgentContextPack(input, db) {
32264
32264
  type: comment.type,
32265
32265
  progress_pct: comment.progress_pct,
32266
32266
  created_at: comment.created_at,
32267
- content: truncate(comment.content, limit.max_text_chars) || ""
32267
+ content: truncate2(comment.content, limit.max_text_chars) || ""
32268
32268
  })),
32269
32269
  omitted: Math.max(0, comments.length - recentComments.length)
32270
32270
  },
@@ -32272,7 +32272,7 @@ function createAgentContextPack(input, db) {
32272
32272
  traceability: {
32273
32273
  commits: traceability.commits.map((commit) => ({
32274
32274
  sha: commit.sha,
32275
- message: truncate(commit.message, 240),
32275
+ message: truncate2(commit.message, 240),
32276
32276
  files_changed: commit.files_changed,
32277
32277
  committed_at: commit.committed_at
32278
32278
  })),
@@ -32280,7 +32280,7 @@ function createAgentContextPack(input, db) {
32280
32280
  verifications: verifications.map((verification) => ({
32281
32281
  command: verification.command,
32282
32282
  status: verification.status,
32283
- output_summary: truncate(verification.output_summary, limit.max_text_chars),
32283
+ output_summary: truncate2(verification.output_summary, limit.max_text_chars),
32284
32284
  artifact_path: verification.artifact_path,
32285
32285
  run_at: verification.run_at
32286
32286
  })),
@@ -32291,14 +32291,14 @@ function createAgentContextPack(input, db) {
32291
32291
  id: ledger.run.id,
32292
32292
  title: ledger.run.title,
32293
32293
  status: ledger.run.status,
32294
- summary: truncate(ledger.run.summary, limit.max_text_chars),
32294
+ summary: truncate2(ledger.run.summary, limit.max_text_chars),
32295
32295
  agent_id: ledger.run.agent_id,
32296
32296
  started_at: ledger.run.started_at,
32297
32297
  completed_at: ledger.run.completed_at,
32298
- events: ledger.events.map((event) => ({ event_type: event.event_type, message: truncate(event.message, 500), created_at: event.created_at })),
32299
- commands: ledger.commands.map((command) => ({ command: command.command, status: command.status, output_summary: truncate(command.output_summary, limit.max_text_chars), artifact_path: command.artifact_path })),
32300
- files: ledger.files.map((file) => ({ path: file.path, status: file.status, note: truncate(file.note, 240) })),
32301
- artifacts: ledger.artifacts.map((artifact) => ({ path: artifact.path, artifact_type: artifact.artifact_type, description: truncate(artifact.description, 240), sha256: artifact.sha256 }))
32298
+ events: ledger.events.map((event) => ({ event_type: event.event_type, message: truncate2(event.message, 500), created_at: event.created_at })),
32299
+ commands: ledger.commands.map((command) => ({ command: command.command, status: command.status, output_summary: truncate2(command.output_summary, limit.max_text_chars), artifact_path: command.artifact_path })),
32300
+ files: ledger.files.map((file) => ({ path: file.path, status: file.status, note: truncate2(file.note, 240) })),
32301
+ artifacts: ledger.artifacts.map((artifact) => ({ path: artifact.path, artifact_type: artifact.artifact_type, description: truncate2(artifact.description, 240), sha256: artifact.sha256 }))
32302
32302
  })),
32303
32303
  omitted: Math.max(0, runs.length - selectedRuns.length)
32304
32304
  },
@@ -32330,7 +32330,7 @@ function createAgentContextPack(input, db) {
32330
32330
  }))
32331
32331
  };
32332
32332
  const { context_budget: _contextBudget, ...withoutContextBudget } = budgeted;
32333
- const redacted = redactValue(withoutContextBudget);
32333
+ const redacted = redactValue2(withoutContextBudget);
32334
32334
  redacted.context_budget = contextBudget;
32335
32335
  return redacted;
32336
32336
  }
@@ -32403,7 +32403,7 @@ function renderAgentContextPackCompactMarkdown(pack) {
32403
32403
  const lines = [
32404
32404
  `# Context: ${pack.task.title}`,
32405
32405
  `${pack.task.status} | ${pack.task.priority} | ${pack.task.short_id || pack.task.id.slice(0, 8)}`,
32406
- pack.task.description ? truncate(pack.task.description, Math.min(pack.limits.summary_char_limit, 700)) : null,
32406
+ pack.task.description ? truncate2(pack.task.description, Math.min(pack.limits.summary_char_limit, 700)) : null,
32407
32407
  "",
32408
32408
  "## Must Know",
32409
32409
  bullet([
@@ -32518,7 +32518,7 @@ function emptyContract(taskId) {
32518
32518
  relevant_files: [],
32519
32519
  risk_level: null,
32520
32520
  done_definition: [],
32521
- updated_at: now()
32521
+ updated_at: now2()
32522
32522
  };
32523
32523
  }
32524
32524
  function emptyReview(taskId) {
@@ -32544,7 +32544,7 @@ function readContract(taskId, metadata) {
32544
32544
  relevant_files: cleanList2(raw.relevant_files),
32545
32545
  risk_level: cleanRisk(raw.risk_level),
32546
32546
  done_definition: cleanList2(raw.done_definition),
32547
- updated_at: typeof raw.updated_at === "string" ? raw.updated_at : now()
32547
+ updated_at: typeof raw.updated_at === "string" ? raw.updated_at : now2()
32548
32548
  };
32549
32549
  }
32550
32550
  function readReview(taskId, metadata) {
@@ -32557,7 +32557,7 @@ function readReview(taskId, metadata) {
32557
32557
  actor: typeof item.actor === "string" ? item.actor : "unknown",
32558
32558
  notes: typeof item.notes === "string" ? item.notes : null,
32559
32559
  changes_requested: cleanList2(item.changes_requested),
32560
- at: typeof item.at === "string" ? item.at : now()
32560
+ at: typeof item.at === "string" ? item.at : now2()
32561
32561
  };
32562
32562
  }) : [];
32563
32563
  return {
@@ -32587,7 +32587,7 @@ function setTaskContract(input, db) {
32587
32587
  relevant_files: input.relevant_files === undefined ? current.relevant_files : cleanList2(input.relevant_files),
32588
32588
  risk_level: input.risk_level === undefined ? current.risk_level : cleanRisk(input.risk_level),
32589
32589
  done_definition: input.done_definition === undefined ? current.done_definition : cleanList2(input.done_definition),
32590
- updated_at: now()
32590
+ updated_at: now2()
32591
32591
  };
32592
32592
  const metadata = {
32593
32593
  ...task.metadata,
@@ -32606,7 +32606,7 @@ function getTaskContract(taskId, db) {
32606
32606
  }
32607
32607
  function requestTaskReview(input, db) {
32608
32608
  const task = taskOrThrow(input.task_id, db);
32609
- const timestamp3 = now();
32609
+ const timestamp3 = now2();
32610
32610
  const previous = readReview(task.id, task.metadata);
32611
32611
  const entry = {
32612
32612
  state: "requested",
@@ -32631,7 +32631,7 @@ function requestTaskReview(input, db) {
32631
32631
  }
32632
32632
  function recordTaskReview(input, db) {
32633
32633
  const task = taskOrThrow(input.task_id, db);
32634
- const timestamp3 = now();
32634
+ const timestamp3 = now2();
32635
32635
  const previous = readReview(task.id, task.metadata);
32636
32636
  const changes = cleanList2(input.changes_requested);
32637
32637
  const entry = {
@@ -33492,11 +33492,11 @@ function updateDispatcherMetadata(runId, dispatcher, db) {
33492
33492
  const run = getTaskRun(resolveTaskRunId(runId, d), d);
33493
33493
  if (!run)
33494
33494
  throw new Error(`Run not found: ${runId}`);
33495
- const metadata = redactValue({
33495
+ const metadata = redactValue2({
33496
33496
  ...run.metadata,
33497
33497
  agent_run_dispatcher: dispatcher
33498
33498
  });
33499
- d.run("UPDATE task_runs SET metadata = ?, updated_at = ? WHERE id = ?", [JSON.stringify(metadata), now(), run.id]);
33499
+ d.run("UPDATE task_runs SET metadata = ?, updated_at = ? WHERE id = ?", [JSON.stringify(metadata), now2(), run.id]);
33500
33500
  return getTaskRun(run.id, d);
33501
33501
  }
33502
33502
  function resolveAdapter(adapter) {
@@ -33735,7 +33735,7 @@ function claimNextAgentRun(agentId, options = {}, db) {
33735
33735
  const dispatcher = { ...next.dispatcher, state: "running", started_at: new Date().toISOString() };
33736
33736
  const updated = updateDispatcherMetadata(next.run.id, dispatcher, d);
33737
33737
  if (agentId)
33738
- d.run("UPDATE task_runs SET agent_id = ?, updated_at = ? WHERE id = ?", [agentId, now(), next.run.id]);
33738
+ d.run("UPDATE task_runs SET agent_id = ?, updated_at = ? WHERE id = ?", [agentId, now2(), next.run.id]);
33739
33739
  const reread = getTaskRun(next.run.id, d) ?? updated;
33740
33740
  return toAgentRun({ run: reread, dispatcher });
33741
33741
  }
@@ -33805,7 +33805,7 @@ __export(exports_verification_providers, {
33805
33805
  getVerificationRecord: () => getVerificationRecord,
33806
33806
  discoverVerificationProviderCapabilities: () => discoverVerificationProviderCapabilities
33807
33807
  });
33808
- import { existsSync as existsSync15, readFileSync as readFileSync10 } from "fs";
33808
+ import { existsSync as existsSync16, readFileSync as readFileSync10 } from "fs";
33809
33809
  function normalizeName6(name) {
33810
33810
  const normalized = name.trim().toLowerCase();
33811
33811
  if (!/^[a-z0-9][a-z0-9_-]{0,63}$/.test(normalized)) {
@@ -33838,7 +33838,7 @@ function upsertVerificationProvider(input) {
33838
33838
  kind: input.kind,
33839
33839
  command: input.command ?? existing?.command,
33840
33840
  cwd: input.cwd ?? existing?.cwd,
33841
- env: input.env ? redactValue(input.env) : existing?.env,
33841
+ env: input.env ? redactValue2(input.env) : existing?.env,
33842
33842
  capabilities: input.capabilities ?? existing?.capabilities,
33843
33843
  retry: input.retry ? retryConfig(input.retry) : existing?.retry,
33844
33844
  timeout_ms: timeoutMs(input.timeout_ms ?? existing?.timeout_ms),
@@ -33957,7 +33957,7 @@ Timed out after ${provider.timeout_ms}ms`);
33957
33957
  };
33958
33958
  }
33959
33959
  function runCiLogProvider(input) {
33960
- const text = input.log_text ?? (input.log_path && existsSync15(input.log_path) ? readFileSync10(input.log_path, "utf-8") : "");
33960
+ const text = input.log_text ?? (input.log_path && existsSync16(input.log_path) ? readFileSync10(input.log_path, "utf-8") : "");
33961
33961
  return {
33962
33962
  status: classifyLog(text),
33963
33963
  attempts: 1,
@@ -33969,7 +33969,7 @@ function runBrowserProvider(input) {
33969
33969
  if (!input.artifact_path) {
33970
33970
  return { status: "unknown", attempts: 1, exit_code: null, output_summary: "browser provider needs a screenshot or artifact path" };
33971
33971
  }
33972
- if (!existsSync15(input.artifact_path)) {
33972
+ if (!existsSync16(input.artifact_path)) {
33973
33973
  return { status: "failed", attempts: 1, exit_code: null, output_summary: `artifact not found: ${input.artifact_path}` };
33974
33974
  }
33975
33975
  return {
@@ -33997,9 +33997,9 @@ async function runVerificationProvider(input, db) {
33997
33997
  exit_code: partial.exit_code,
33998
33998
  output_summary: partial.output_summary ? redactEvidenceText(partial.output_summary) : null,
33999
33999
  artifact_path: input.artifact_path || null,
34000
- run_at: now(),
34000
+ run_at: now2(),
34001
34001
  task_id: input.task_id || null,
34002
- metadata: redactValue({
34002
+ metadata: redactValue2({
34003
34003
  ...input.metadata || {},
34004
34004
  provider_kind: provider.kind,
34005
34005
  command_template: command,
@@ -34246,7 +34246,7 @@ function generateReleaseNotes(input = {}, db) {
34246
34246
  warnings.push("no completed tasks matched the release-note scope");
34247
34247
  return {
34248
34248
  schema_version: 1,
34249
- generated_at: input.generated_at || now(),
34249
+ generated_at: input.generated_at || now2(),
34250
34250
  title: input.title || "Release Notes",
34251
34251
  version: input.version || null,
34252
34252
  local_only: true,
@@ -34341,7 +34341,7 @@ var init_release_notes = __esm(() => {
34341
34341
  function saveSnapshot(input, db) {
34342
34342
  const d = db || getDatabase();
34343
34343
  const id = uuid();
34344
- const timestamp3 = now();
34344
+ const timestamp3 = now2();
34345
34345
  d.run(`INSERT INTO context_snapshots (id, agent_id, task_id, project_id, snapshot_type, plan_summary, files_open, attempts, blockers, next_steps, metadata, created_at)
34346
34346
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
34347
34347
  id,
@@ -34426,7 +34426,7 @@ function rowToKnowledgeRecord(row) {
34426
34426
  agent_id: row.agent_id,
34427
34427
  snapshot_id: row.snapshot_id,
34428
34428
  tags: parseArray2(row.tags),
34429
- metadata: redactValue(parseObject2(row.metadata)),
34429
+ metadata: redactValue2(parseObject2(row.metadata)),
34430
34430
  created_at: row.created_at,
34431
34431
  updated_at: row.updated_at
34432
34432
  };
@@ -34442,7 +34442,7 @@ function createKnowledgeRecord(input, db) {
34442
34442
  if (!title)
34443
34443
  throw new Error("Knowledge record title is required");
34444
34444
  const d = db || getDatabase();
34445
- const timestamp3 = now();
34445
+ const timestamp3 = now2();
34446
34446
  const id = uuid();
34447
34447
  d.run(`INSERT INTO project_knowledge_records (
34448
34448
  id, record_type, title, content, decision, rationale, alternatives,
@@ -34578,7 +34578,7 @@ function createKnowledgeExportReport(options, db) {
34578
34578
  schema_version: 1,
34579
34579
  local_only: true,
34580
34580
  no_network: true,
34581
- generated_at: now(),
34581
+ generated_at: now2(),
34582
34582
  filters: { ...filters, query: options.query || null },
34583
34583
  count: records.length,
34584
34584
  records
@@ -34694,7 +34694,7 @@ function rowToRisk(row) {
34694
34694
  plan_id: row.plan_id,
34695
34695
  task_id: row.task_id,
34696
34696
  tags: parseArray3(row.tags),
34697
- metadata: redactValue(parseObject3(row.metadata)),
34697
+ metadata: redactValue2(parseObject3(row.metadata)),
34698
34698
  created_at: row.created_at,
34699
34699
  updated_at: row.updated_at,
34700
34700
  closed_at: row.closed_at
@@ -34716,7 +34716,7 @@ function createRisk(input, db) {
34716
34716
  assertSeverity(severity);
34717
34717
  assertProbability(probability);
34718
34718
  const d = db || getDatabase();
34719
- const timestamp3 = now();
34719
+ const timestamp3 = now2();
34720
34720
  const id = uuid();
34721
34721
  const closedAt = status === "resolved" || status === "accepted" ? timestamp3 : null;
34722
34722
  d.run(`INSERT INTO project_risks (
@@ -34756,7 +34756,7 @@ function updateRisk(id, input, db) {
34756
34756
  throw new Error(`Risk not found: ${id}`);
34757
34757
  const resolved = current.id;
34758
34758
  const sets = ["updated_at = ?"];
34759
- const params = [now()];
34759
+ const params = [now2()];
34760
34760
  if (input.title !== undefined) {
34761
34761
  const title = input.title.trim();
34762
34762
  if (!title)
@@ -34773,7 +34773,7 @@ function updateRisk(id, input, db) {
34773
34773
  sets.push("status = ?");
34774
34774
  params.push(input.status);
34775
34775
  sets.push("closed_at = ?");
34776
- params.push(input.status === "resolved" || input.status === "accepted" ? now() : null);
34776
+ params.push(input.status === "resolved" || input.status === "accepted" ? now2() : null);
34777
34777
  }
34778
34778
  if (input.severity !== undefined) {
34779
34779
  assertSeverity(input.severity);
@@ -34911,7 +34911,7 @@ function calculateDependencyDepth(taskIds, db) {
34911
34911
  }
34912
34912
  function scoreHealth(scope, scopeId, db) {
34913
34913
  const d = db || getDatabase();
34914
- const generatedAt = now();
34914
+ const generatedAt = now2();
34915
34915
  const scopeInfo = scopeCondition(scope, scopeId, d);
34916
34916
  const tasks = d.query(`SELECT id, short_id, title, status, due_at FROM tasks WHERE ${scopeInfo.where}`).all(scopeInfo.id);
34917
34917
  const taskIds = new Set(tasks.map((task) => task.id));
@@ -35008,7 +35008,7 @@ function createRiskRegisterExport(options = {}, db) {
35008
35008
  schema_version: 1,
35009
35009
  local_only: true,
35010
35010
  no_network: true,
35011
- generated_at: now(),
35011
+ generated_at: now2(),
35012
35012
  filters,
35013
35013
  count: risks.length,
35014
35014
  risks
@@ -35157,8 +35157,8 @@ function scoreTask(taskId, score, reviewerId, db) {
35157
35157
  metadata._review_score = score;
35158
35158
  if (reviewerId)
35159
35159
  metadata._reviewed_by = reviewerId;
35160
- metadata._reviewed_at = now();
35161
- d.run("UPDATE tasks SET metadata = ?, updated_at = ? WHERE id = ?", [JSON.stringify(metadata), now(), taskId]);
35160
+ metadata._reviewed_at = now2();
35161
+ d.run("UPDATE tasks SET metadata = ?, updated_at = ? WHERE id = ?", [JSON.stringify(metadata), now2(), taskId]);
35162
35162
  }
35163
35163
  function clampScore(value) {
35164
35164
  if (!Number.isFinite(value))
@@ -35238,7 +35238,7 @@ function getAgentReliabilityScorecard(agentId, options = {}, db) {
35238
35238
  const agent = resolveAgent2(agentId, d);
35239
35239
  if (!agent)
35240
35240
  return null;
35241
- const generatedAt = now();
35241
+ const generatedAt = now2();
35242
35242
  const staleAfterHours = Number.isFinite(options.stale_after_hours) && options.stale_after_hours > 0 ? Math.min(Math.floor(options.stale_after_hours), 24 * 30) : 24;
35243
35243
  const staleCutoff = new Date(Date.now() - staleAfterHours * 60 * 60 * 1000).toISOString();
35244
35244
  const taskFilter = agentTaskWhere(agent, options, d);
@@ -35417,7 +35417,7 @@ function createAgentReliabilityExport(options = {}, db) {
35417
35417
  schema_version: 1,
35418
35418
  local_only: true,
35419
35419
  no_network: true,
35420
- generated_at: now(),
35420
+ generated_at: now2(),
35421
35421
  filters: {
35422
35422
  agent_id: options.agent_id || null,
35423
35423
  project_id: options.project_id || null,
@@ -35545,7 +35545,7 @@ function extractUsage(value) {
35545
35545
  }
35546
35546
  return own;
35547
35547
  }
35548
- function parseJsonObject5(value) {
35548
+ function parseJsonObject6(value) {
35549
35549
  if (!value)
35550
35550
  return {};
35551
35551
  try {
@@ -35717,7 +35717,7 @@ function createLocalUsageLedger(options = {}, db) {
35717
35717
  completedRunMs += millisBetween(run.started_at, run.completed_at);
35718
35718
  else
35719
35719
  openRunMs += millisBetween(run.started_at, generatedAt);
35720
- const usage = extractUsage(parseJsonObject5(run.metadata));
35720
+ const usage = extractUsage(parseJsonObject6(run.metadata));
35721
35721
  metadataUsage.tokens += usage.tokens;
35722
35722
  metadataUsage.cost_usd += usage.cost_usd;
35723
35723
  metadataUsage.duration_ms += usage.duration_ms;
@@ -35729,7 +35729,7 @@ function createLocalUsageLedger(options = {}, db) {
35729
35729
  JOIN tasks t ON t.id = e.task_id
35730
35730
  ${runClause}`, runParams);
35731
35731
  for (const event of eventRows) {
35732
- const usage = extractUsage(parseJsonObject5(event.data));
35732
+ const usage = extractUsage(parseJsonObject6(event.data));
35733
35733
  metadataUsage.tokens += usage.tokens;
35734
35734
  metadataUsage.cost_usd += usage.cost_usd;
35735
35735
  metadataUsage.duration_ms += usage.duration_ms;
@@ -35881,12 +35881,12 @@ function summarizeTask(task) {
35881
35881
  };
35882
35882
  }
35883
35883
  function overdueTasks(tasks, nowIso) {
35884
- const now3 = Date.parse(nowIso);
35884
+ const now4 = Date.parse(nowIso);
35885
35885
  return tasks.filter((task) => {
35886
35886
  if (isTerminal(task) || !task.due_at)
35887
35887
  return false;
35888
35888
  const due = Date.parse(task.due_at);
35889
- return Number.isFinite(due) && due < now3;
35889
+ return Number.isFinite(due) && due < now4;
35890
35890
  });
35891
35891
  }
35892
35892
  function isReady(task, db) {
@@ -36299,7 +36299,7 @@ function asRecord(value) {
36299
36299
  }
36300
36300
  function createLocalBackup(options = {}, db) {
36301
36301
  const d = db || getDatabase();
36302
- const createdAt = options.generated_at ?? now();
36302
+ const createdAt = options.generated_at ?? now2();
36303
36303
  const bridge = createLocalBridgeBundle({
36304
36304
  project_id: options.project_id,
36305
36305
  generatedAt: createdAt,
@@ -36364,7 +36364,7 @@ function readLocalBackupFile(path) {
36364
36364
  return JSON.parse(readFileSync11(resolve17(path), "utf-8"));
36365
36365
  }
36366
36366
  function verifyLocalBackup(value, options = {}, db) {
36367
- const verifiedAt = options.verified_at ?? now();
36367
+ const verifiedAt = options.verified_at ?? now2();
36368
36368
  const record = asRecord(value);
36369
36369
  const issues = [];
36370
36370
  const warnings = [];
@@ -36470,7 +36470,7 @@ function restoreLocalBackup(backup, options = {}, db) {
36470
36470
  kind: "hasna.todos.local-backup-restore",
36471
36471
  local_only: true,
36472
36472
  no_network: true,
36473
- restored_at: options.verified_at ?? now(),
36473
+ restored_at: options.verified_at ?? now2(),
36474
36474
  dry_run: !options.apply,
36475
36475
  ok: verification.ok && Boolean(importResult?.ok),
36476
36476
  verification,
@@ -36528,7 +36528,7 @@ function checkLocalIntegrity(options = {}, db) {
36528
36528
  kind: TODOS_LOCAL_INTEGRITY_KIND,
36529
36529
  local_only: true,
36530
36530
  no_network: true,
36531
- generated_at: options.generated_at ?? now(),
36531
+ generated_at: options.generated_at ?? now2(),
36532
36532
  database_path: getDatabasePath(),
36533
36533
  sqlite,
36534
36534
  bridge_validation: bridgeValidation,
@@ -36558,7 +36558,7 @@ __export(exports_onboarding_fixtures, {
36558
36558
  TODOS_ONBOARDING_FIXTURE_LIBRARY_VERSION: () => TODOS_ONBOARDING_FIXTURE_LIBRARY_VERSION
36559
36559
  });
36560
36560
  import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync6 } from "fs";
36561
- import { join as join15 } from "path";
36561
+ import { join as join16 } from "path";
36562
36562
  function emptyData() {
36563
36563
  return {
36564
36564
  projects: [],
@@ -36891,7 +36891,7 @@ function writeOnboardingFixtureFiles(directory) {
36891
36891
  mkdirSync8(directory, { recursive: true });
36892
36892
  const files = [];
36893
36893
  for (const fixture of allFixtures()) {
36894
- const path = join15(directory, `${fixture.summary.name}.bridge.json`);
36894
+ const path = join16(directory, `${fixture.summary.name}.bridge.json`);
36895
36895
  writeFileSync6(path, `${JSON.stringify(fixture.bundle, null, 2)}
36896
36896
  `, "utf-8");
36897
36897
  files.push(path);
@@ -37121,7 +37121,7 @@ function getLocalSnapshot(options, db) {
37121
37121
  if (!ALL_TYPES.includes(options.type)) {
37122
37122
  throw new Error(`Unknown local snapshot type: ${options.type}`);
37123
37123
  }
37124
- const generatedAt = options.generatedAt ?? now();
37124
+ const generatedAt = options.generatedAt ?? now2();
37125
37125
  const limit = normalizeLimit2(options.limit);
37126
37126
  const items = snapshotItems({ ...options, generatedAt, limit }, db);
37127
37127
  const cursor = latestTimestamp2(items, generatedAt);
@@ -37157,7 +37157,7 @@ function getLocalSnapshot(options, db) {
37157
37157
  };
37158
37158
  }
37159
37159
  function pollLocalSnapshots(options = {}, db) {
37160
- const generatedAt = options.generatedAt ?? now();
37160
+ const generatedAt = options.generatedAt ?? now2();
37161
37161
  const types2 = options.types?.length ? options.types : ALL_TYPES;
37162
37162
  const snapshots = types2.map((type) => getLocalSnapshot({
37163
37163
  type,
@@ -37282,7 +37282,7 @@ function rowToRetrospective(row) {
37282
37282
  project_id: row.project_id,
37283
37283
  plan_id: row.plan_id,
37284
37284
  agent_id: row.agent_id,
37285
- report: redactValue(report),
37285
+ report: redactValue2(report),
37286
37286
  created_at: row.created_at,
37287
37287
  updated_at: row.updated_at
37288
37288
  };
@@ -37347,7 +37347,7 @@ function buildFollowUps(report) {
37347
37347
  }
37348
37348
  function buildReport2(input, db) {
37349
37349
  const scope = scopeFromInput(input, db);
37350
- const generatedAt = now();
37350
+ const generatedAt = now2();
37351
37351
  const title = input.title?.trim() || `${scope.scope === "plan" ? "Plan" : "Project"} retrospective ${scope.scopeId.slice(0, 8)}`;
37352
37352
  const tasks = db.query(`SELECT id, short_id, title, status, estimated_minutes, actual_minutes
37353
37353
  FROM tasks WHERE ${scope.where}`).all(scope.scopeId);
@@ -37431,7 +37431,7 @@ function createRetrospective(input, db) {
37431
37431
  const d = db || getDatabase();
37432
37432
  const report = buildReport2(input, d);
37433
37433
  const scope = scopeFromInput(input, d);
37434
- const timestamp3 = now();
37434
+ const timestamp3 = now2();
37435
37435
  if (input.create_followups) {
37436
37436
  for (const followUp of report.follow_up_tasks) {
37437
37437
  const task2 = createTask({
@@ -37485,7 +37485,7 @@ function createRetrospectiveExport(options = {}, db) {
37485
37485
  schema_version: 1,
37486
37486
  local_only: true,
37487
37487
  no_network: true,
37488
- generated_at: now(),
37488
+ generated_at: now2(),
37489
37489
  filters,
37490
37490
  count: retrospectives.length,
37491
37491
  retrospectives
@@ -37603,7 +37603,7 @@ function approvalsFromFixture(fixture, runs) {
37603
37603
  return [...explicit, ...fromEvents];
37604
37604
  }
37605
37605
  function simulateAgentReplay(input, options = {}) {
37606
- const fixture = redactValue(unpackFixture(input));
37606
+ const fixture = redactValue2(unpackFixture(input));
37607
37607
  const task2 = isObject2(fixture["task"]) ? fixture["task"] : {};
37608
37608
  const plan = isObject2(fixture["plan"]) ? fixture["plan"] : null;
37609
37609
  const runsContainer = isObject2(fixture["runs"]) ? fixture["runs"] : {};
@@ -37953,7 +37953,7 @@ function createInboxItem(input, db) {
37953
37953
  const item = rowToInboxItem(existing);
37954
37954
  return { item, task: item.task_id ? getTask(item.task_id, d) : null, duplicate: true };
37955
37955
  }
37956
- const timestamp3 = now();
37956
+ const timestamp3 = now2();
37957
37957
  let task2 = null;
37958
37958
  const metadata = {
37959
37959
  ...input.metadata || {},
@@ -38127,7 +38127,7 @@ function githubRecord(input, fallback) {
38127
38127
  labels,
38128
38128
  assignee: asString3(asObject2(input["assignee"])["login"]) || asString3(input["assignee"]),
38129
38129
  priority: priorityFromLabels(labels, fallback),
38130
- metadata: redactValue(input)
38130
+ metadata: redactValue2(input)
38131
38131
  };
38132
38132
  }
38133
38133
  function linearRecord(input, fallback) {
@@ -38146,7 +38146,7 @@ function linearRecord(input, fallback) {
38146
38146
  labels,
38147
38147
  assignee: asString3(asObject2(input["assignee"])["name"]) || asString3(asObject2(input["assignee"])["displayName"]) || asString3(input["assignee"]),
38148
38148
  priority,
38149
- metadata: redactValue(input)
38149
+ metadata: redactValue2(input)
38150
38150
  };
38151
38151
  }
38152
38152
  function jiraDescription(value) {
@@ -38174,7 +38174,7 @@ function jiraRecord(input, fallback) {
38174
38174
  labels,
38175
38175
  assignee: asString3(asObject2(fields["assignee"])["displayName"]) || asString3(input["assignee"]),
38176
38176
  priority,
38177
- metadata: redactValue(input)
38177
+ metadata: redactValue2(input)
38178
38178
  };
38179
38179
  }
38180
38180
  function urlRecord(url, title, body, fallback = "medium") {
@@ -38357,7 +38357,7 @@ function createTaskFromIssue(issue, input, db) {
38357
38357
  key: issue.key,
38358
38358
  url: issue.url,
38359
38359
  state: issue.state,
38360
- imported_at: now()
38360
+ imported_at: now2()
38361
38361
  },
38362
38362
  ...parsedGitHub ? {
38363
38363
  github_url: issue.url,
@@ -38371,7 +38371,7 @@ function createTaskFromIssue(issue, input, db) {
38371
38371
  description: taskDescription(issue).slice(0, 4000),
38372
38372
  priority: issue.priority || input.default_priority || "medium",
38373
38373
  tags: Array.from(new Set(["external-issue", issue.provider, ...issue.labels])).slice(0, 10),
38374
- metadata: redactValue(metadata),
38374
+ metadata: redactValue2(metadata),
38375
38375
  project_id: input.project_id,
38376
38376
  task_list_id: input.task_list_id,
38377
38377
  agent_id: input.agent_id,
@@ -38421,7 +38421,7 @@ function importExternalIssues(input, db) {
38421
38421
  external_id: stableId(issue.provider, issue.key, issue.url, issue.title),
38422
38422
  body: issue.body ? redactEvidenceText(issue.body) : null,
38423
38423
  title: redactEvidenceText(issue.title),
38424
- metadata: redactValue(issue.metadata)
38424
+ metadata: redactValue2(issue.metadata)
38425
38425
  }));
38426
38426
  const createdTasks = [];
38427
38427
  const inboxItems = [];
@@ -38467,7 +38467,7 @@ function importExternalIssues(input, db) {
38467
38467
  local_only: true,
38468
38468
  network_used: networkUsed,
38469
38469
  dry_run: !input.apply,
38470
- imported_at: now(),
38470
+ imported_at: now2(),
38471
38471
  source: {
38472
38472
  provider,
38473
38473
  source_url: input.source_url || null,
@@ -38512,14 +38512,14 @@ function expiresAt(ttlSeconds) {
38512
38512
  }
38513
38513
  function cleanExpiredFileLocks(db) {
38514
38514
  const d = db || getDatabase();
38515
- const result = d.run("DELETE FROM file_locks WHERE expires_at <= ?", [now()]);
38515
+ const result = d.run("DELETE FROM file_locks WHERE expires_at <= ?", [now2()]);
38516
38516
  return result.changes;
38517
38517
  }
38518
38518
  function lockFile(input, db) {
38519
38519
  const d = db || getDatabase();
38520
38520
  const ttl = input.ttl_seconds ?? FILE_LOCK_DEFAULT_TTL_SECONDS;
38521
38521
  const expiry = expiresAt(ttl);
38522
- const timestamp3 = now();
38522
+ const timestamp3 = now2();
38523
38523
  cleanExpiredFileLocks(d);
38524
38524
  const existing = d.query("SELECT * FROM file_locks WHERE path = ?").get(input.path);
38525
38525
  if (existing) {
@@ -40047,7 +40047,7 @@ function syncKgEdges(db) {
40047
40047
  function upsertEdge(d, sourceId, sourceType, targetId, targetType, relationType, weight = 1) {
40048
40048
  try {
40049
40049
  d.run(`INSERT OR IGNORE INTO kg_edges (id, source_id, source_type, target_id, target_type, relation_type, weight, metadata, created_at)
40050
- VALUES (?, ?, ?, ?, ?, ?, ?, '{}', ?)`, [uuid(), sourceId, sourceType, targetId, targetType, relationType, weight, now()]);
40050
+ VALUES (?, ?, ?, ?, ?, ?, ?, '{}', ?)`, [uuid(), sourceId, sourceType, targetId, targetType, relationType, weight, now2()]);
40051
40051
  return 1;
40052
40052
  } catch {
40053
40053
  return 0;
@@ -40202,7 +40202,7 @@ function getCriticalPath(opts, db) {
40202
40202
  function addKgEdge(sourceId, sourceType, targetId, targetType, relationType, weight = 1, metadata, db) {
40203
40203
  const d = db || getDatabase();
40204
40204
  const id = uuid();
40205
- const timestamp3 = now();
40205
+ const timestamp3 = now2();
40206
40206
  d.run(`INSERT OR IGNORE INTO kg_edges (id, source_id, source_type, target_id, target_type, relation_type, weight, metadata, created_at)
40207
40207
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [id, sourceId, sourceType, targetId, targetType, relationType, weight, JSON.stringify(metadata || {}), timestamp3]);
40208
40208
  return { id, source_id: sourceId, source_type: sourceType, target_id: targetId, target_type: targetType, relation_type: relationType, weight, metadata: metadata || {}, created_at: timestamp3 };
@@ -40238,7 +40238,7 @@ function setProjectAgentRole(projectId, agentId, role, isLead = false, db) {
40238
40238
  return rowToRole(d.query("SELECT * FROM project_agent_roles WHERE id = ?").get(existing.id));
40239
40239
  }
40240
40240
  const id = uuid();
40241
- d.run("INSERT INTO project_agent_roles (id, project_id, agent_id, role, is_lead, created_at) VALUES (?, ?, ?, ?, ?, ?)", [id, projectId, agentId, role, isLead ? 1 : 0, now()]);
40241
+ d.run("INSERT INTO project_agent_roles (id, project_id, agent_id, role, is_lead, created_at) VALUES (?, ?, ?, ?, ?, ?)", [id, projectId, agentId, role, isLead ? 1 : 0, now2()]);
40242
40242
  return rowToRole(d.query("SELECT * FROM project_agent_roles WHERE id = ?").get(id));
40243
40243
  }
40244
40244
  function removeProjectAgentRole(projectId, agentId, role, db) {
@@ -40442,7 +40442,7 @@ function taskOrThrow2(taskId, db) {
40442
40442
  return task2;
40443
40443
  }
40444
40444
  function normalizeRule2(input, existing) {
40445
- const timestamp3 = now();
40445
+ const timestamp3 = now2();
40446
40446
  const name = input.name.trim();
40447
40447
  if (!name)
40448
40448
  throw new Error("Review routing rule name is required");
@@ -40477,7 +40477,7 @@ function readQueue(task2) {
40477
40477
  requested_at: typeof raw.requested_at === "string" ? raw.requested_at : null,
40478
40478
  claimed_at: typeof raw.claimed_at === "string" ? raw.claimed_at : null,
40479
40479
  decided_at: typeof raw.decided_at === "string" ? raw.decided_at : null,
40480
- updated_at: typeof raw.updated_at === "string" ? raw.updated_at : now(),
40480
+ updated_at: typeof raw.updated_at === "string" ? raw.updated_at : now2(),
40481
40481
  history: Array.isArray(raw.history) ? raw.history.map((entry) => {
40482
40482
  const item = typeof entry === "object" && entry !== null ? entry : {};
40483
40483
  const entryState = typeof item.state === "string" && STATES.has(item.state) ? item.state : state;
@@ -40485,7 +40485,7 @@ function readQueue(task2) {
40485
40485
  state: entryState,
40486
40486
  actor: typeof item.actor === "string" ? item.actor : "unknown",
40487
40487
  note: typeof item.note === "string" ? item.note : null,
40488
- at: typeof item.at === "string" ? item.at : now()
40488
+ at: typeof item.at === "string" ? item.at : now2()
40489
40489
  };
40490
40490
  }) : []
40491
40491
  };
@@ -40527,7 +40527,7 @@ function writeQueue(task2, queue, actor, action, db) {
40527
40527
  return itemFromTask(taskOrThrow2(task2.id, d), queue, d);
40528
40528
  }
40529
40529
  function appendHistory(queue, state, actor, note) {
40530
- return [...queue.history, { state, actor, note: note ?? null, at: now() }];
40530
+ return [...queue.history, { state, actor, note: note ?? null, at: now2() }];
40531
40531
  }
40532
40532
  function itemFromTask(task2, queue, db) {
40533
40533
  return {
@@ -40662,7 +40662,7 @@ function requestReviewQueue(input, db) {
40662
40662
  notes: input.notes ?? input.reason
40663
40663
  }, d);
40664
40664
  const updatedTask = taskOrThrow2(task2.id, d);
40665
- const timestamp3 = now();
40665
+ const timestamp3 = now2();
40666
40666
  const previous = readQueue(updatedTask);
40667
40667
  const queue = {
40668
40668
  schema_version: 1,
@@ -40705,7 +40705,7 @@ function claimReviewItem(input, db) {
40705
40705
  const previous = derivedQueue(task2, d);
40706
40706
  if (!previous)
40707
40707
  throw new Error(`Task is not in a review queue: ${task2.id}`);
40708
- const timestamp3 = now();
40708
+ const timestamp3 = now2();
40709
40709
  const queue = {
40710
40710
  ...previous,
40711
40711
  state: "claimed",
@@ -40725,7 +40725,7 @@ function approveReviewItem(input, db) {
40725
40725
  throw new Error(`Task is not in a review queue: ${task2.id}`);
40726
40726
  recordTaskReview({ task_id: task2.id, state: "approved", reviewer: input.reviewer, notes: input.note }, d);
40727
40727
  const updatedTask = taskOrThrow2(task2.id, d);
40728
- const timestamp3 = now();
40728
+ const timestamp3 = now2();
40729
40729
  const queue = {
40730
40730
  ...previous,
40731
40731
  state: "approved",
@@ -40753,7 +40753,7 @@ function returnReviewItem(input, db) {
40753
40753
  changes_requested: changes
40754
40754
  }, d);
40755
40755
  const updatedTask = taskOrThrow2(task2.id, d);
40756
- const timestamp3 = now();
40756
+ const timestamp3 = now2();
40757
40757
  const queue = {
40758
40758
  ...previous,
40759
40759
  state: "returned",
@@ -40774,7 +40774,7 @@ function reopenReviewItem(input, db) {
40774
40774
  throw new Error(`Task is not in a review queue: ${task2.id}`);
40775
40775
  recordTaskReview({ task_id: task2.id, state: "reopened", reviewer: input.reviewer, notes: input.note }, d);
40776
40776
  const updatedTask = taskOrThrow2(task2.id, d);
40777
- const timestamp3 = now();
40777
+ const timestamp3 = now2();
40778
40778
  const queue = {
40779
40779
  ...previous,
40780
40780
  state: "reopened",
@@ -41217,7 +41217,7 @@ ${lines.join(`
41217
41217
  const projectRoles = n.project_roles.length > 0 ? ` <${n.project_roles.join(", ")}>` : "";
41218
41218
  const lead = n.is_project_lead ? " \u2605" : "";
41219
41219
  const lastSeen = new Date(n.agent.last_seen_at).getTime();
41220
- const active = now3 - lastSeen < ACTIVE_MS ? " \u25CF" : " \u25CB";
41220
+ const active = now4 - lastSeen < ACTIVE_MS ? " \u25CF" : " \u25CB";
41221
41221
  const line = `${prefix}${active} ${n.agent.name}${title}${globalRole}${projectRoles}${lead}`;
41222
41222
  const children = n.reports.length > 0 ? `
41223
41223
  ` + render(n.reports, indent + 1) : "";
@@ -41231,7 +41231,7 @@ ${lines.join(`
41231
41231
  if (format === "json") {
41232
41232
  return { content: [{ type: "text", text: JSON.stringify(tree, null, 2) }] };
41233
41233
  }
41234
- const now3 = Date.now();
41234
+ const now4 = Date.now();
41235
41235
  const ACTIVE_MS = 30 * 60 * 1000;
41236
41236
  const text2 = tree.length > 0 ? render(tree) : "No agents in this project's org chart.";
41237
41237
  return { content: [{ type: "text", text: text2 }] };
@@ -41781,10 +41781,10 @@ ${lines.join(`
41781
41781
  });
41782
41782
  }
41783
41783
  if (shouldRegisterTool("get_idle_focus_prompts")) {
41784
- server.tool("get_idle_focus_prompts", "Return local idle prompts for active focus sessions.", { agent_id: exports_external.string().optional(), now: exports_external.string().optional() }, async ({ agent_id, now: now3 }) => {
41784
+ server.tool("get_idle_focus_prompts", "Return local idle prompts for active focus sessions.", { agent_id: exports_external.string().optional(), now: exports_external.string().optional() }, async ({ agent_id, now: now4 }) => {
41785
41785
  try {
41786
41786
  const { getIdleFocusSessionPrompts: getIdleFocusSessionPrompts2 } = (init_tasks(), __toCommonJS(exports_tasks));
41787
- return { content: [{ type: "text", text: JSON.stringify(getIdleFocusSessionPrompts2({ agent_id, now: now3 }), null, 2) }] };
41787
+ return { content: [{ type: "text", text: JSON.stringify(getIdleFocusSessionPrompts2({ agent_id, now: now4 }), null, 2) }] };
41788
41788
  } catch (e) {
41789
41789
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
41790
41790
  }
@@ -42922,16 +42922,16 @@ __export(exports_environment_snapshots, {
42922
42922
  captureEnvironmentSnapshot: () => captureEnvironmentSnapshot
42923
42923
  });
42924
42924
  import { createHash as createHash12 } from "crypto";
42925
- import { existsSync as existsSync16, readFileSync as readFileSync13, statSync as statSync8 } from "fs";
42925
+ import { existsSync as existsSync17, readFileSync as readFileSync13, statSync as statSync8 } from "fs";
42926
42926
  import { hostname as hostname2, platform, arch } from "os";
42927
- import { dirname as dirname9, join as join16, resolve as resolve18 } from "path";
42927
+ import { dirname as dirname9, join as join17, resolve as resolve18 } from "path";
42928
42928
  import { tmpdir as tmpdir2 } from "os";
42929
42929
  function sha2566(value) {
42930
42930
  return createHash12("sha256").update(value).digest("hex");
42931
42931
  }
42932
42932
  function fileRecord(root, relativePath) {
42933
- const path = join16(root, relativePath);
42934
- if (!existsSync16(path))
42933
+ const path = join17(root, relativePath);
42934
+ if (!existsSync17(path))
42935
42935
  return null;
42936
42936
  const stat = statSync8(path);
42937
42937
  if (!stat.isFile())
@@ -42943,10 +42943,10 @@ function manifestRecord(root, relativePath) {
42943
42943
  const base = fileRecord(root, relativePath);
42944
42944
  if (!base)
42945
42945
  return null;
42946
- const parsed = readJsonFile(join16(root, relativePath));
42946
+ const parsed = readJsonFile(join17(root, relativePath));
42947
42947
  if (!parsed)
42948
42948
  return { ...base, redacted: {} };
42949
- const redacted = redactValue({
42949
+ const redacted = redactValue2({
42950
42950
  name: parsed["name"] ?? null,
42951
42951
  version: parsed["version"] ?? null,
42952
42952
  packageManager: parsed["packageManager"] ?? null,
@@ -43038,8 +43038,8 @@ function commandEnv(env, includeValues) {
43038
43038
  function defaultSnapshotDir() {
43039
43039
  const dbPath = getDatabasePath();
43040
43040
  if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
43041
- return join16(tmpdir2(), "hasna-todos", "environment-snapshots");
43042
- return join16(dirname9(resolve18(dbPath)), "environment-snapshots");
43041
+ return join17(tmpdir2(), "hasna-todos", "environment-snapshots");
43042
+ return join17(dirname9(resolve18(dbPath)), "environment-snapshots");
43043
43043
  }
43044
43044
  function snapshotWithId(snapshot) {
43045
43045
  const digest = sha2566(JSON.stringify(snapshot)).slice(0, 24);
@@ -43086,7 +43086,7 @@ function captureEnvironmentSnapshot(input = {}) {
43086
43086
  });
43087
43087
  }
43088
43088
  function writeEnvironmentSnapshot(snapshot, outputPath) {
43089
- const path = outputPath ? resolve18(outputPath) : join16(defaultSnapshotDir(), `${snapshot.id}.json`);
43089
+ const path = outputPath ? resolve18(outputPath) : join17(defaultSnapshotDir(), `${snapshot.id}.json`);
43090
43090
  ensureDir2(dirname9(path));
43091
43091
  writeJsonFile(path, snapshot);
43092
43092
  return path;
@@ -43617,27 +43617,27 @@ __export(exports_serve, {
43617
43617
  SECURITY_HEADERS: () => SECURITY_HEADERS,
43618
43618
  MIME_TYPES: () => MIME_TYPES
43619
43619
  });
43620
- import { existsSync as existsSync17 } from "fs";
43621
- import { join as join17, dirname as dirname10, extname } from "path";
43620
+ import { existsSync as existsSync18 } from "fs";
43621
+ import { join as join18, dirname as dirname10, extname } from "path";
43622
43622
  import { fileURLToPath as fileURLToPath2 } from "url";
43623
43623
  function resolveDashboardDir() {
43624
43624
  const candidates = [];
43625
43625
  try {
43626
43626
  const scriptDir = dirname10(fileURLToPath2(import.meta.url));
43627
- candidates.push(join17(scriptDir, "..", "dashboard", "dist"));
43628
- candidates.push(join17(scriptDir, "..", "..", "dashboard", "dist"));
43627
+ candidates.push(join18(scriptDir, "..", "dashboard", "dist"));
43628
+ candidates.push(join18(scriptDir, "..", "..", "dashboard", "dist"));
43629
43629
  } catch {}
43630
43630
  if (process.argv[1]) {
43631
43631
  const mainDir = dirname10(process.argv[1]);
43632
- candidates.push(join17(mainDir, "..", "dashboard", "dist"));
43633
- candidates.push(join17(mainDir, "..", "..", "dashboard", "dist"));
43632
+ candidates.push(join18(mainDir, "..", "dashboard", "dist"));
43633
+ candidates.push(join18(mainDir, "..", "..", "dashboard", "dist"));
43634
43634
  }
43635
- candidates.push(join17(process.cwd(), "dashboard", "dist"));
43635
+ candidates.push(join18(process.cwd(), "dashboard", "dist"));
43636
43636
  for (const candidate of candidates) {
43637
- if (existsSync17(candidate))
43637
+ if (existsSync18(candidate))
43638
43638
  return candidate;
43639
43639
  }
43640
- return join17(process.cwd(), "dashboard", "dist");
43640
+ return join18(process.cwd(), "dashboard", "dist");
43641
43641
  }
43642
43642
  function getProvidedApiKey(req) {
43643
43643
  const headerKey = req.headers.get("x-api-key");
@@ -43664,15 +43664,15 @@ function checkAuth(req, apiKey) {
43664
43664
  return null;
43665
43665
  }
43666
43666
  function checkRateLimit(ip) {
43667
- const now3 = Date.now();
43667
+ const now4 = Date.now();
43668
43668
  const entry = rateLimitMap.get(ip);
43669
- if (!entry || now3 > entry.resetAt) {
43670
- rateLimitMap.set(ip, { count: 1, resetAt: now3 + RATE_LIMIT_WINDOW_MS });
43669
+ if (!entry || now4 > entry.resetAt) {
43670
+ rateLimitMap.set(ip, { count: 1, resetAt: now4 + RATE_LIMIT_WINDOW_MS });
43671
43671
  return { allowed: true };
43672
43672
  }
43673
43673
  entry.count++;
43674
43674
  if (entry.count > RATE_LIMIT_MAX) {
43675
- return { allowed: false, retryAfter: Math.ceil((entry.resetAt - now3) / 1000) };
43675
+ return { allowed: false, retryAfter: Math.ceil((entry.resetAt - now4) / 1000) };
43676
43676
  }
43677
43677
  return { allowed: true };
43678
43678
  }
@@ -43687,7 +43687,7 @@ function json(data, status = 200, headers) {
43687
43687
  });
43688
43688
  }
43689
43689
  function serveStaticFile(filePath) {
43690
- if (!existsSync17(filePath))
43690
+ if (!existsSync18(filePath))
43691
43691
  return null;
43692
43692
  const ext = extname(filePath);
43693
43693
  const contentType = MIME_TYPES[ext] || "application/octet-stream";
@@ -43766,7 +43766,7 @@ data: ${data}
43766
43766
  filteredSseClients.delete(client);
43767
43767
  }
43768
43768
  const dashboardDir = resolveDashboardDir();
43769
- const dashboardExists = existsSync17(dashboardDir);
43769
+ const dashboardExists = existsSync18(dashboardDir);
43770
43770
  if (!dashboardExists) {
43771
43771
  console.error(`
43772
43772
  Dashboard not found at: ${dashboardDir}`);
@@ -45592,12 +45592,12 @@ __export(exports_config_serve_commands, {
45592
45592
  registerConfigServeCommands: () => registerConfigServeCommands
45593
45593
  });
45594
45594
  import chalk6 from "chalk";
45595
- import { existsSync as existsSync18, mkdirSync as mkdirSync9, readFileSync as readFileSync14, writeFileSync as writeFileSync7 } from "fs";
45596
- import { dirname as dirname11, join as join18 } from "path";
45595
+ import { existsSync as existsSync19, mkdirSync as mkdirSync9, readFileSync as readFileSync14, writeFileSync as writeFileSync7 } from "fs";
45596
+ import { dirname as dirname11, join as join19 } from "path";
45597
45597
  function registerConfigServeCommands(program2) {
45598
45598
  program2.command("config").description("View or update configuration").option("--get <key>", "Get a config value").option("--set <key=value>", "Set a config value (e.g. completion_guard.enabled=true)").action((opts) => {
45599
45599
  const globalOpts = program2.opts();
45600
- const configPath = join18(getTodosGlobalDir(), "config.json");
45600
+ const configPath = join19(getTodosGlobalDir(), "config.json");
45601
45601
  if (opts.get) {
45602
45602
  const config2 = loadConfig();
45603
45603
  const keys = opts.get.split(".");
@@ -45634,7 +45634,7 @@ function registerConfigServeCommands(program2) {
45634
45634
  }
45635
45635
  obj[keys[keys.length - 1]] = parsedValue;
45636
45636
  const dir = dirname11(configPath);
45637
- if (!existsSync18(dir))
45637
+ if (!existsSync19(dir))
45638
45638
  mkdirSync9(dir, { recursive: true });
45639
45639
  writeFileSync7(configPath, JSON.stringify(config2, null, 2));
45640
45640
  if (globalOpts.json) {
@@ -46496,8 +46496,8 @@ function registerConfigServeCommands(program2) {
46496
46496
  for (const t of all)
46497
46497
  counts[t.status] = (counts[t.status] || 0) + 1;
46498
46498
  process.stdout.write("\x1B[2J\x1B[0f");
46499
- const now3 = new Date().toLocaleTimeString();
46500
- console.log(chalk6.bold(`todos watch`) + chalk6.dim(` \u2014 ${now3} \u2014 refreshing every ${opts.interval}s \u2014 Ctrl+C to stop
46499
+ const now4 = new Date().toLocaleTimeString();
46500
+ console.log(chalk6.bold(`todos watch`) + chalk6.dim(` \u2014 ${now4} \u2014 refreshing every ${opts.interval}s \u2014 Ctrl+C to stop
46501
46501
  `));
46502
46502
  const parts = [
46503
46503
  `total: ${chalk6.bold(String(all.length))}`,
@@ -47331,9 +47331,9 @@ Repairs`));
47331
47331
  const db = getDatabase();
47332
47332
  const row = db.query("SELECT COUNT(*) as count FROM tasks").get();
47333
47333
  const { statSync: statSync9 } = await import("fs");
47334
- const { join: join19 } = await import("path");
47334
+ const { join: join20 } = await import("path");
47335
47335
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
47336
- const dbPath = process.env["HASNA_TODOS_DB_PATH"] || process.env["TODOS_DB_PATH"] || join19(home, ".hasna", "todos", "todos.db");
47336
+ const dbPath = process.env["HASNA_TODOS_DB_PATH"] || process.env["TODOS_DB_PATH"] || join20(home, ".hasna", "todos", "todos.db");
47337
47337
  let size = "unknown";
47338
47338
  try {
47339
47339
  size = `${(statSync9(dbPath).size / 1024 / 1024).toFixed(1)} MB`;
@@ -47641,14 +47641,14 @@ Repairs`));
47641
47641
  const globalOpts = program2.opts();
47642
47642
  const db = getDatabase();
47643
47643
  const { getTasksChangedSince: getTasksChangedSince2 } = await Promise.resolve().then(() => (init_tasks(), exports_tasks));
47644
- const now3 = new Date;
47645
- const start = new Date(now3);
47644
+ const now4 = new Date;
47645
+ const start = new Date(now4);
47646
47646
  start.setDate(start.getDate() - 7);
47647
47647
  start.setHours(0, 0, 0, 0);
47648
47648
  const tasks = getTasksChangedSince2(start.toISOString(), undefined, db);
47649
47649
  const days = {};
47650
47650
  for (let i = 0;i < 7; i++) {
47651
- const d = new Date(now3);
47651
+ const d = new Date(now4);
47652
47652
  d.setDate(d.getDate() - i);
47653
47653
  days[d.toISOString().slice(0, 10)] = { completed: [], started: [], other: [] };
47654
47654
  }
@@ -47664,12 +47664,12 @@ Repairs`));
47664
47664
  days[day].other.push(t);
47665
47665
  }
47666
47666
  if (opts.json || globalOpts.json) {
47667
- console.log(JSON.stringify({ from: start.toISOString().slice(0, 10), to: now3.toISOString().slice(0, 10), days }));
47667
+ console.log(JSON.stringify({ from: start.toISOString().slice(0, 10), to: now4.toISOString().slice(0, 10), days }));
47668
47668
  return;
47669
47669
  }
47670
47670
  const totalCompleted = tasks.filter((t) => t.status === "completed").length;
47671
47671
  const totalStarted = tasks.filter((t) => t.status === "in_progress").length;
47672
- console.log(chalk7.bold(`Week \u2014 ${start.toISOString().slice(0, 10)} to ${now3.toISOString().slice(0, 10)}`));
47672
+ console.log(chalk7.bold(`Week \u2014 ${start.toISOString().slice(0, 10)} to ${now4.toISOString().slice(0, 10)}`));
47673
47673
  console.log(chalk7.dim(` ${totalCompleted} completed, ${totalStarted} in progress, ${tasks.length} total changes
47674
47674
  `));
47675
47675
  const sortedDays = Object.keys(days).sort().reverse();
@@ -47696,10 +47696,10 @@ Repairs`));
47696
47696
  const { getRecentActivity: getRecentActivity2 } = await Promise.resolve().then(() => (init_audit(), exports_audit));
47697
47697
  const numDays = parseInt(opts.days, 10);
47698
47698
  const entries = getRecentActivity2(5000, db);
47699
- const now3 = new Date;
47699
+ const now4 = new Date;
47700
47700
  const dayStats = [];
47701
47701
  for (let i = numDays - 1;i >= 0; i--) {
47702
- const d = new Date(now3);
47702
+ const d = new Date(now4);
47703
47703
  d.setDate(d.getDate() - i);
47704
47704
  const dateStr = d.toISOString().slice(0, 10);
47705
47705
  const dayEntries = entries.filter((e) => e.created_at.slice(0, 10) === dateStr);
@@ -49090,21 +49090,21 @@ __export(exports_mcp_hooks_commands, {
49090
49090
  });
49091
49091
  import chalk8 from "chalk";
49092
49092
  import { execSync as execSync3 } from "child_process";
49093
- import { existsSync as existsSync19, readFileSync as readFileSync16, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10, chmodSync as chmodSync2 } from "fs";
49094
- import { dirname as dirname12, join as join19 } from "path";
49093
+ import { existsSync as existsSync20, readFileSync as readFileSync16, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10, chmodSync as chmodSync2 } from "fs";
49094
+ import { dirname as dirname12, join as join20 } from "path";
49095
49095
  function getMcpBinaryPath() {
49096
49096
  try {
49097
49097
  const p = execSync3("which todos-mcp", { encoding: "utf-8" }).trim();
49098
49098
  if (p)
49099
49099
  return p;
49100
49100
  } catch {}
49101
- const bunBin = join19(HOME2, ".bun", "bin", "todos-mcp");
49102
- if (existsSync19(bunBin))
49101
+ const bunBin = join20(HOME2, ".bun", "bin", "todos-mcp");
49102
+ if (existsSync20(bunBin))
49103
49103
  return bunBin;
49104
49104
  return "todos-mcp";
49105
49105
  }
49106
49106
  function readJsonFile2(path) {
49107
- if (!existsSync19(path))
49107
+ if (!existsSync20(path))
49108
49108
  return {};
49109
49109
  try {
49110
49110
  return JSON.parse(readFileSync16(path, "utf-8"));
@@ -49114,19 +49114,19 @@ function readJsonFile2(path) {
49114
49114
  }
49115
49115
  function writeJsonFile2(path, data) {
49116
49116
  const dir = dirname12(path);
49117
- if (!existsSync19(dir))
49117
+ if (!existsSync20(dir))
49118
49118
  mkdirSync10(dir, { recursive: true });
49119
49119
  writeFileSync9(path, JSON.stringify(data, null, 2) + `
49120
49120
  `);
49121
49121
  }
49122
49122
  function readTomlFile(path) {
49123
- if (!existsSync19(path))
49123
+ if (!existsSync20(path))
49124
49124
  return "";
49125
49125
  return readFileSync16(path, "utf-8");
49126
49126
  }
49127
49127
  function writeTomlFile(path, content) {
49128
49128
  const dir = dirname12(path);
49129
- if (!existsSync19(dir))
49129
+ if (!existsSync20(dir))
49130
49130
  mkdirSync10(dir, { recursive: true });
49131
49131
  writeFileSync9(path, content);
49132
49132
  }
@@ -49192,7 +49192,7 @@ function unregisterClaude(_global) {
49192
49192
  }
49193
49193
  }
49194
49194
  function registerCodex(binPath) {
49195
- const configPath = join19(HOME2, ".codex", "config.toml");
49195
+ const configPath = join20(HOME2, ".codex", "config.toml");
49196
49196
  let content = readTomlFile(configPath);
49197
49197
  content = removeTomlBlock(content, "mcp_servers.todos");
49198
49198
  const block = `
@@ -49206,7 +49206,7 @@ args = []
49206
49206
  console.log(chalk8.green(`Codex CLI: registered in ${configPath}`));
49207
49207
  }
49208
49208
  function unregisterCodex() {
49209
- const configPath = join19(HOME2, ".codex", "config.toml");
49209
+ const configPath = join20(HOME2, ".codex", "config.toml");
49210
49210
  let content = readTomlFile(configPath);
49211
49211
  if (!content.includes("[mcp_servers.todos]")) {
49212
49212
  console.log(chalk8.dim(`Codex CLI: todos not found in ${configPath}`));
@@ -49218,7 +49218,7 @@ function unregisterCodex() {
49218
49218
  console.log(chalk8.green(`Codex CLI: unregistered from ${configPath}`));
49219
49219
  }
49220
49220
  function registerGemini(binPath) {
49221
- const configPath = join19(HOME2, ".gemini", "settings.json");
49221
+ const configPath = join20(HOME2, ".gemini", "settings.json");
49222
49222
  const config = readJsonFile2(configPath);
49223
49223
  if (!config["mcpServers"]) {
49224
49224
  config["mcpServers"] = {};
@@ -49232,7 +49232,7 @@ function registerGemini(binPath) {
49232
49232
  console.log(chalk8.green(`Gemini CLI: registered in ${configPath}`));
49233
49233
  }
49234
49234
  function unregisterGemini() {
49235
- const configPath = join19(HOME2, ".gemini", "settings.json");
49235
+ const configPath = join20(HOME2, ".gemini", "settings.json");
49236
49236
  const config = readJsonFile2(configPath);
49237
49237
  const servers = config["mcpServers"];
49238
49238
  if (!servers || !("todos" in servers)) {
@@ -49289,8 +49289,8 @@ function registerMcpHooksCommands(program2) {
49289
49289
  if (p)
49290
49290
  todosBin = p;
49291
49291
  } catch {}
49292
- const hooksDir = join19(process.cwd(), ".claude", "hooks");
49293
- if (!existsSync19(hooksDir))
49292
+ const hooksDir = join20(process.cwd(), ".claude", "hooks");
49293
+ if (!existsSync20(hooksDir))
49294
49294
  mkdirSync10(hooksDir, { recursive: true });
49295
49295
  const hookScript = `#!/usr/bin/env bash
49296
49296
  # Auto-generated by: todos hooks install
@@ -49315,11 +49315,11 @@ esac
49315
49315
 
49316
49316
  exit 0
49317
49317
  `;
49318
- const hookPath = join19(hooksDir, "todos-sync.sh");
49318
+ const hookPath = join20(hooksDir, "todos-sync.sh");
49319
49319
  writeFileSync9(hookPath, hookScript);
49320
49320
  execSync3(`chmod +x "${hookPath}"`);
49321
49321
  console.log(chalk8.green(`Hook script created: ${hookPath}`));
49322
- const settingsPath = join19(process.cwd(), ".claude", "settings.json");
49322
+ const settingsPath = join20(process.cwd(), ".claude", "settings.json");
49323
49323
  const settings = readJsonFile2(settingsPath);
49324
49324
  if (!settings["hooks"]) {
49325
49325
  settings["hooks"] = {};
@@ -50122,7 +50122,7 @@ Artifacts:`));
50122
50122
  const gitDir = execSync3("git rev-parse --git-dir", { encoding: "utf-8" }).trim();
50123
50123
  const hookPath = `${gitDir}/hooks/post-commit`;
50124
50124
  const marker = "# todos-auto-link";
50125
- if (existsSync19(hookPath)) {
50125
+ if (existsSync20(hookPath)) {
50126
50126
  const existing = readFileSync16(hookPath, "utf-8");
50127
50127
  if (existing.includes(marker)) {
50128
50128
  console.log(chalk8.yellow("Hook already installed."));
@@ -50150,7 +50150,7 @@ $(dirname "$0")/../../scripts/post-commit-hook.sh
50150
50150
  const gitDir = execSync3("git rev-parse --git-dir", { encoding: "utf-8" }).trim();
50151
50151
  const hookPath = `${gitDir}/hooks/post-commit`;
50152
50152
  const marker = "# todos-auto-link";
50153
- if (!existsSync19(hookPath)) {
50153
+ if (!existsSync20(hookPath)) {
50154
50154
  console.log(chalk8.dim("No post-commit hook found."));
50155
50155
  return;
50156
50156
  }
@@ -50332,7 +50332,7 @@ import chalk10 from "chalk";
50332
50332
  import { execSync as execSync4 } from "child_process";
50333
50333
  import { readFileSync as readFileSync17, unlinkSync as unlinkSync2, writeFileSync as writeFileSync10 } from "fs";
50334
50334
  import { tmpdir as tmpdir3 } from "os";
50335
- import { join as join20 } from "path";
50335
+ import { join as join21 } from "path";
50336
50336
  function getOrCreateLocalMachineName() {
50337
50337
  return process.env["TODOS_MACHINE_NAME"] || __require("os").hostname() || "unknown";
50338
50338
  }
@@ -50370,7 +50370,7 @@ function remoteTempPath(sshAddress) {
50370
50370
  }
50371
50371
  function readRemoteBridgeBundle(sshAddress) {
50372
50372
  const remotePath = remoteTempPath(sshAddress);
50373
- const localPath = join20(tmpdir3(), `todos-bridge-pull-${uuid()}.json`);
50373
+ const localPath = join21(tmpdir3(), `todos-bridge-pull-${uuid()}.json`);
50374
50374
  try {
50375
50375
  runSsh(sshAddress, `todos export --format bridge --allow-plaintext-sensitive --output ${shellQuote(remotePath)}`, 120000);
50376
50376
  scpFromRemote(sshAddress, remotePath, localPath);
@@ -50385,7 +50385,7 @@ function readRemoteBridgeBundle(sshAddress) {
50385
50385
  }
50386
50386
  }
50387
50387
  function writeLocalBridgeBundle() {
50388
- const localPath = join20(tmpdir3(), `todos-bridge-push-${uuid()}.json`);
50388
+ const localPath = join21(tmpdir3(), `todos-bridge-push-${uuid()}.json`);
50389
50389
  writeFileSync10(localPath, JSON.stringify(createLocalBridgeBundle(), null, 2));
50390
50390
  return localPath;
50391
50391
  }
@@ -50908,7 +50908,7 @@ function parseRecordType(value) {
50908
50908
  console.error(chalk13.red(`type must be one of: ${RECORD_TYPES.join(", ")}`));
50909
50909
  process.exit(1);
50910
50910
  }
50911
- function parseJsonObject6(value, label) {
50911
+ function parseJsonObject7(value, label) {
50912
50912
  if (!value)
50913
50913
  return;
50914
50914
  try {
@@ -50968,7 +50968,7 @@ function registerKnowledgeCommands(program2) {
50968
50968
  plan_id: opts.plan,
50969
50969
  agent_id: opts.agent || globalOpts.agent,
50970
50970
  tags: tagsFromOption(opts.tag),
50971
- metadata: parseJsonObject6(opts.metadataJson, "--metadata-json")
50971
+ metadata: parseJsonObject7(opts.metadataJson, "--metadata-json")
50972
50972
  }, getDatabase());
50973
50973
  if (opts.json || globalOpts.json)
50974
50974
  output(record, true);
@@ -50993,7 +50993,7 @@ function registerKnowledgeCommands(program2) {
50993
50993
  blockers: opts.blocker,
50994
50994
  next_steps: opts.next,
50995
50995
  tags: tagsFromOption(opts.tag),
50996
- metadata: parseJsonObject6(opts.metadataJson, "--metadata-json")
50996
+ metadata: parseJsonObject7(opts.metadataJson, "--metadata-json")
50997
50997
  }, getDatabase());
50998
50998
  if (opts.json || globalOpts.json)
50999
50999
  output(result, true);
@@ -51079,7 +51079,7 @@ function parseChoice(value, choices, label) {
51079
51079
  console.error(chalk14.red(`${label} must be one of: ${choices.join(", ")}`));
51080
51080
  process.exit(1);
51081
51081
  }
51082
- function parseJsonObject7(value, label) {
51082
+ function parseJsonObject8(value, label) {
51083
51083
  if (!value)
51084
51084
  return;
51085
51085
  try {
@@ -51144,7 +51144,7 @@ function registerRiskCommands(program2) {
51144
51144
  plan_id: opts.plan,
51145
51145
  task_id: opts.task,
51146
51146
  tags: tagsFromOption2(opts.tag),
51147
- metadata: parseJsonObject7(opts.metadataJson, "--metadata-json")
51147
+ metadata: parseJsonObject8(opts.metadataJson, "--metadata-json")
51148
51148
  }, getDatabase());
51149
51149
  if (opts.json || globalOpts.json)
51150
51150
  output(risk, true);
@@ -51196,7 +51196,7 @@ function registerRiskCommands(program2) {
51196
51196
  plan_id: opts.plan,
51197
51197
  task_id: opts.task,
51198
51198
  tags: opts.tag.length > 0 ? tagsFromOption2(opts.tag) : undefined,
51199
- metadata: parseJsonObject7(opts.metadataJson, "--metadata-json")
51199
+ metadata: parseJsonObject8(opts.metadataJson, "--metadata-json")
51200
51200
  }, getDatabase());
51201
51201
  if (opts.json || globalOpts.json)
51202
51202
  output(risk, true);
@@ -51360,7 +51360,7 @@ __export(exports_agent_reliability_commands, {
51360
51360
  registerAgentReliabilityCommands: () => registerAgentReliabilityCommands
51361
51361
  });
51362
51362
  import chalk16 from "chalk";
51363
- function parseNumber(value, fallback) {
51363
+ function parseNumber2(value, fallback) {
51364
51364
  if (!value)
51365
51365
  return fallback;
51366
51366
  const parsed = Number.parseInt(value, 10);
@@ -51370,7 +51370,7 @@ function commonOptions(opts) {
51370
51370
  return {
51371
51371
  project_id: opts.project,
51372
51372
  since: opts.since,
51373
- stale_after_hours: parseNumber(opts.staleAfterHours, 24)
51373
+ stale_after_hours: parseNumber2(opts.staleAfterHours, 24)
51374
51374
  };
51375
51375
  }
51376
51376
  function printScorecard(scorecard) {
@@ -51407,7 +51407,7 @@ function registerAgentReliabilityCommands(program2) {
51407
51407
  const report = createAgentReliabilityExport({
51408
51408
  ...commonOptions(opts),
51409
51409
  agent_id: opts.agent,
51410
- limit: parseNumber(opts.limit, 50)
51410
+ limit: parseNumber2(opts.limit, 50)
51411
51411
  }, getDatabase());
51412
51412
  const globalOpts = program2.opts();
51413
51413
  if (opts.json || globalOpts.json)
@@ -51423,7 +51423,7 @@ function registerAgentReliabilityCommands(program2) {
51423
51423
  const report = createAgentReliabilityExport({
51424
51424
  ...commonOptions(opts),
51425
51425
  agent_id: opts.agent,
51426
- limit: parseNumber(opts.limit, 100)
51426
+ limit: parseNumber2(opts.limit, 100)
51427
51427
  }, getDatabase());
51428
51428
  if (opts.format === "markdown") {
51429
51429
  console.log(renderAgentReliabilityMarkdown(report));
@@ -54767,7 +54767,7 @@ __export(exports_sdk_integration_fixtures, {
54767
54767
  TODOS_SDK_INTEGRATION_FIXTURE_GENERATED_AT: () => TODOS_SDK_INTEGRATION_FIXTURE_GENERATED_AT
54768
54768
  });
54769
54769
  import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
54770
- import { join as join21 } from "path";
54770
+ import { join as join22 } from "path";
54771
54771
  function source5(version) {
54772
54772
  return {
54773
54773
  packageName: "@hasna/todos",
@@ -54874,7 +54874,7 @@ function writeSdkIntegrationFixtures(directory, options = {}) {
54874
54874
  ];
54875
54875
  const written = [];
54876
54876
  for (const [name, payload] of files) {
54877
- const file = join21(directory, name);
54877
+ const file = join22(directory, name);
54878
54878
  writeFileSync11(file, `${JSON.stringify(payload, null, 2)}
54879
54879
  `, "utf-8");
54880
54880
  written.push(file);
@@ -56596,7 +56596,7 @@ var init_hybrid = __esm(() => {
56596
56596
  });
56597
56597
 
56598
56598
  // src/storage/postgres-adapter.ts
56599
- import { randomUUID as randomUUID2 } from "crypto";
56599
+ import { randomUUID as randomUUID5 } from "crypto";
56600
56600
  function createPostgresTodosStorageAdapter(options) {
56601
56601
  const store = new PostgresJsonRecordStore(options);
56602
56602
  const adapter = {
@@ -56779,7 +56779,7 @@ async function createTask3(input, store, context) {
56779
56779
  const timestamp3 = new Date().toISOString();
56780
56780
  const shortId = input.project_id ? await nextTaskShortId2(input.project_id, store, context) : null;
56781
56781
  const task2 = {
56782
- id: randomUUID2(),
56782
+ id: randomUUID5(),
56783
56783
  short_id: shortId,
56784
56784
  project_id: input.project_id ?? context?.projectId ?? null,
56785
56785
  parent_id: input.parent_id ?? null,
@@ -56946,7 +56946,7 @@ async function getChangedSince(since, filters, store) {
56946
56946
  async function createProject2(input, store, context) {
56947
56947
  const timestamp3 = new Date().toISOString();
56948
56948
  const project = {
56949
- id: randomUUID2(),
56949
+ id: randomUUID5(),
56950
56950
  name: input.name,
56951
56951
  path: input.path,
56952
56952
  description: input.description ?? null,
@@ -56966,7 +56966,7 @@ async function updateProject2(id, input, store) {
56966
56966
  async function createPlan2(input, store, context) {
56967
56967
  const timestamp3 = new Date().toISOString();
56968
56968
  return store.upsert("plans", {
56969
- id: randomUUID2(),
56969
+ id: randomUUID5(),
56970
56970
  project_id: input.project_id ?? context?.projectId ?? null,
56971
56971
  task_list_id: input.task_list_id ?? context?.taskListId ?? null,
56972
56972
  agent_id: input.agent_id ?? context?.agentId ?? null,
@@ -56988,7 +56988,7 @@ async function registerAgent2(input, store, context) {
56988
56988
  }
56989
56989
  const timestamp3 = new Date().toISOString();
56990
56990
  const agent = {
56991
- id: existing?.id ?? randomUUID2().slice(0, 8),
56991
+ id: existing?.id ?? randomUUID5().slice(0, 8),
56992
56992
  name: input.name,
56993
56993
  description: input.description ?? existing?.description ?? null,
56994
56994
  role: input.role ?? existing?.role ?? null,
@@ -57024,7 +57024,7 @@ async function updateAgent2(id, input, store) {
57024
57024
  async function createTaskList2(input, store, context) {
57025
57025
  const timestamp3 = new Date().toISOString();
57026
57026
  return store.upsert("task_lists", {
57027
- id: randomUUID2(),
57027
+ id: randomUUID5(),
57028
57028
  project_id: input.project_id ?? context?.projectId ?? null,
57029
57029
  slug: input.slug ?? slugify2(input.name),
57030
57030
  name: input.name,
@@ -57046,7 +57046,7 @@ async function updateTaskList2(id, input, store) {
57046
57046
  async function createTemplate2(input, store, context) {
57047
57047
  const timestamp3 = new Date().toISOString();
57048
57048
  return store.upsert("templates", {
57049
- id: randomUUID2(),
57049
+ id: randomUUID5(),
57050
57050
  name: input.name,
57051
57051
  title_pattern: input.title_pattern,
57052
57052
  description: input.description ?? null,
@@ -57075,7 +57075,7 @@ async function updateTemplate2(id, input, store) {
57075
57075
  }
57076
57076
  async function logTaskChange2(taskId, action, field2, oldValue, newValue, agentId, store, context) {
57077
57077
  const entry2 = {
57078
- id: randomUUID2(),
57078
+ id: randomUUID5(),
57079
57079
  task_id: taskId,
57080
57080
  action,
57081
57081
  field: field2 ?? null,
@@ -57088,7 +57088,7 @@ async function logTaskChange2(taskId, action, field2, oldValue, newValue, agentI
57088
57088
  }
57089
57089
  async function addComment2(input, store, context) {
57090
57090
  const comment = {
57091
- id: randomUUID2(),
57091
+ id: randomUUID5(),
57092
57092
  task_id: input.task_id,
57093
57093
  agent_id: input.agent_id ?? context?.agentId ?? null,
57094
57094
  session_id: input.session_id ?? context?.sessionId ?? null,
@@ -57271,10 +57271,10 @@ var init_factory = __esm(() => {
57271
57271
  });
57272
57272
 
57273
57273
  // src/storage/s3-artifacts.ts
57274
- import { createHash as createHash13, createHmac } from "crypto";
57274
+ import { createHash as createHash13, createHmac as createHmac2 } from "crypto";
57275
57275
  function createTodosS3ArtifactStore(options) {
57276
57276
  const requestFetch = options.fetch ?? fetch;
57277
- const now3 = options.now ?? (() => new Date);
57277
+ const now4 = options.now ?? (() => new Date);
57278
57278
  return {
57279
57279
  objectKey: (relativePath) => buildS3ObjectKey(options.config, relativePath),
57280
57280
  objectUrl: (relativePath) => buildS3ObjectUrl(options.config, buildS3ObjectKey(options.config, relativePath)),
@@ -57296,7 +57296,7 @@ function createTodosS3ArtifactStore(options) {
57296
57296
  headers,
57297
57297
  body,
57298
57298
  credentials: options.credentials,
57299
- now: now3()
57299
+ now: now4()
57300
57300
  });
57301
57301
  const response = await requestFetch(url, { method: "PUT", headers: signed.headers, body });
57302
57302
  if (!response.ok)
@@ -57317,7 +57317,7 @@ function createTodosS3ArtifactStore(options) {
57317
57317
  service: "s3",
57318
57318
  headers: {},
57319
57319
  credentials: options.credentials,
57320
- now: now3()
57320
+ now: now4()
57321
57321
  });
57322
57322
  const response = await requestFetch(url, { method: "GET", headers: signed.headers });
57323
57323
  if (!response.ok)
@@ -57333,7 +57333,7 @@ function createTodosS3ArtifactStore(options) {
57333
57333
  service: "s3",
57334
57334
  headers: {},
57335
57335
  credentials: options.credentials,
57336
- now: now3()
57336
+ now: now4()
57337
57337
  });
57338
57338
  const response = await requestFetch(url, { method: "DELETE", headers: signed.headers });
57339
57339
  if (!response.ok && response.status !== 404)
@@ -57446,10 +57446,10 @@ function sha256Hex(value) {
57446
57446
  return createHash13("sha256").update(value).digest("hex");
57447
57447
  }
57448
57448
  function hmac(key, value) {
57449
- return createHmac("sha256", key).update(value).digest();
57449
+ return createHmac2("sha256", key).update(value).digest();
57450
57450
  }
57451
57451
  function hmacHex(key, value) {
57452
- return createHmac("sha256", key).update(value).digest("hex");
57452
+ return createHmac2("sha256", key).update(value).digest("hex");
57453
57453
  }
57454
57454
  function getSigningKey(secretAccessKey, dateStamp, region, service) {
57455
57455
  const dateKey = hmac(`AWS4${secretAccessKey}`, dateStamp);
@@ -57462,7 +57462,7 @@ var init_s3_artifacts = () => {};
57462
57462
  // src/storage/s3-artifact-sync.ts
57463
57463
  async function uploadRunArtifactsToS3(options) {
57464
57464
  const db = options.db ?? getDatabase();
57465
- const now3 = options.now ?? (() => new Date);
57465
+ const now4 = options.now ?? (() => new Date);
57466
57466
  const result = emptyResult();
57467
57467
  for (const artifact of listRunArtifacts(db, options.filter)) {
57468
57468
  try {
@@ -57501,7 +57501,7 @@ async function uploadRunArtifactsToS3(options) {
57501
57501
  url: ref.url,
57502
57502
  sha256: content.sha256,
57503
57503
  size_bytes: content.size_bytes,
57504
- uploaded_at: now3().toISOString()
57504
+ uploaded_at: now4().toISOString()
57505
57505
  };
57506
57506
  updateArtifactMetadata(db, artifact.id, {
57507
57507
  ...metadata,
@@ -57576,7 +57576,7 @@ function planRunArtifactsS3Sync(options) {
57576
57576
  }
57577
57577
  async function downloadRunArtifactsFromS3(options) {
57578
57578
  const db = options.db ?? getDatabase();
57579
- const now3 = options.now ?? (() => new Date);
57579
+ const now4 = options.now ?? (() => new Date);
57580
57580
  const result = emptyResult();
57581
57581
  for (const artifact of listRunArtifacts(db, options.filter)) {
57582
57582
  try {
@@ -57612,7 +57612,7 @@ async function downloadRunArtifactsFromS3(options) {
57612
57612
  ...metadata,
57613
57613
  remote_artifact_store: {
57614
57614
  ...remote,
57615
- downloaded_at: now3().toISOString()
57615
+ downloaded_at: now4().toISOString()
57616
57616
  }
57617
57617
  });
57618
57618
  result.downloaded += 1;
@@ -58675,6 +58675,686 @@ var init_help_commands = __esm(() => {
58675
58675
 
58676
58676
  // src/cli/index.tsx
58677
58677
  init_esm();
58678
+
58679
+ // node_modules/.bun/@hasna+events@0.1.3/node_modules/@hasna/events/dist/commander.js
58680
+ import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
58681
+ import { existsSync } from "fs";
58682
+ import { homedir } from "os";
58683
+ import { join } from "path";
58684
+ import { createHmac, timingSafeEqual } from "crypto";
58685
+ import { randomUUID } from "crypto";
58686
+ import { spawn } from "child_process";
58687
+ import { randomUUID as randomUUID2 } from "crypto";
58688
+ function getPathValue(input, path) {
58689
+ return path.split(".").reduce((value, part) => {
58690
+ if (value && typeof value === "object" && part in value) {
58691
+ return value[part];
58692
+ }
58693
+ return;
58694
+ }, input);
58695
+ }
58696
+ function wildcardToRegExp(pattern) {
58697
+ const escaped = pattern.replace(/[|\\{}()[\]^$+?.]/g, "\\$&").replace(/\*/g, ".*");
58698
+ return new RegExp(`^${escaped}$`);
58699
+ }
58700
+ function matchString(value, matcher) {
58701
+ if (matcher === undefined)
58702
+ return true;
58703
+ if (value === undefined)
58704
+ return false;
58705
+ const matchers = Array.isArray(matcher) ? matcher : [matcher];
58706
+ return matchers.some((item) => wildcardToRegExp(item).test(value));
58707
+ }
58708
+ function matchRecord(input, matcher) {
58709
+ if (!matcher)
58710
+ return true;
58711
+ return Object.entries(matcher).every(([path, expected]) => {
58712
+ const actual = getPathValue(input, path);
58713
+ if (typeof expected === "string" || Array.isArray(expected)) {
58714
+ return matchString(actual === undefined ? undefined : String(actual), expected);
58715
+ }
58716
+ return actual === expected;
58717
+ });
58718
+ }
58719
+ function eventMatchesFilter(event, filter) {
58720
+ return matchString(event.source, filter.source) && matchString(event.type, filter.type) && matchString(event.subject, filter.subject) && matchString(event.severity, filter.severity) && matchRecord(event.data, filter.data) && matchRecord(event.metadata, filter.metadata);
58721
+ }
58722
+ function channelMatchesEvent(channel, event) {
58723
+ if (!channel.enabled)
58724
+ return false;
58725
+ if (!channel.filters || channel.filters.length === 0)
58726
+ return true;
58727
+ return channel.filters.some((filter) => eventMatchesFilter(event, filter));
58728
+ }
58729
+ var HASNA_EVENTS_DIR_ENV = "HASNA_EVENTS_DIR";
58730
+ var HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME";
58731
+ function getEventsDataDir(override) {
58732
+ return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join(homedir(), ".hasna", "events");
58733
+ }
58734
+
58735
+ class JsonEventsStore {
58736
+ dataDir;
58737
+ channelsPath;
58738
+ eventsPath;
58739
+ deliveriesPath;
58740
+ constructor(dataDir = getEventsDataDir()) {
58741
+ this.dataDir = dataDir;
58742
+ this.channelsPath = join(dataDir, "channels.json");
58743
+ this.eventsPath = join(dataDir, "events.json");
58744
+ this.deliveriesPath = join(dataDir, "deliveries.json");
58745
+ }
58746
+ async init() {
58747
+ await mkdir(this.dataDir, { recursive: true, mode: 448 });
58748
+ await chmod(this.dataDir, 448).catch(() => {
58749
+ return;
58750
+ });
58751
+ await this.ensureArrayFile(this.channelsPath);
58752
+ await this.ensureArrayFile(this.eventsPath);
58753
+ await this.ensureArrayFile(this.deliveriesPath);
58754
+ }
58755
+ async addChannel(channel) {
58756
+ await this.init();
58757
+ const channels = await this.readJson(this.channelsPath, []);
58758
+ const index = channels.findIndex((item) => item.id === channel.id);
58759
+ if (index >= 0) {
58760
+ channels[index] = { ...channel, createdAt: channels[index].createdAt, updatedAt: new Date().toISOString() };
58761
+ } else {
58762
+ channels.push(channel);
58763
+ }
58764
+ await this.writeJson(this.channelsPath, channels);
58765
+ return index >= 0 ? channels[index] : channel;
58766
+ }
58767
+ async listChannels() {
58768
+ await this.init();
58769
+ return this.readJson(this.channelsPath, []);
58770
+ }
58771
+ async getChannel(id) {
58772
+ const channels = await this.listChannels();
58773
+ return channels.find((channel) => channel.id === id);
58774
+ }
58775
+ async removeChannel(id) {
58776
+ await this.init();
58777
+ const channels = await this.readJson(this.channelsPath, []);
58778
+ const next = channels.filter((channel) => channel.id !== id);
58779
+ await this.writeJson(this.channelsPath, next);
58780
+ return next.length !== channels.length;
58781
+ }
58782
+ async appendEvent(event) {
58783
+ await this.init();
58784
+ const events = await this.readJson(this.eventsPath, []);
58785
+ events.push(event);
58786
+ await this.writeJson(this.eventsPath, events);
58787
+ return event;
58788
+ }
58789
+ async listEvents() {
58790
+ await this.init();
58791
+ return this.readJson(this.eventsPath, []);
58792
+ }
58793
+ async findEventByIdentity(identity) {
58794
+ const events = await this.listEvents();
58795
+ return events.find((event) => identity.id !== undefined && event.id === identity.id || identity.dedupeKey !== undefined && event.dedupeKey === identity.dedupeKey);
58796
+ }
58797
+ async appendDelivery(result) {
58798
+ await this.init();
58799
+ const deliveries = await this.readJson(this.deliveriesPath, []);
58800
+ deliveries.push(result);
58801
+ await this.writeJson(this.deliveriesPath, deliveries);
58802
+ return result;
58803
+ }
58804
+ async listDeliveries() {
58805
+ await this.init();
58806
+ return this.readJson(this.deliveriesPath, []);
58807
+ }
58808
+ async exportData() {
58809
+ return {
58810
+ channels: await this.listChannels(),
58811
+ events: await this.listEvents(),
58812
+ deliveries: await this.listDeliveries()
58813
+ };
58814
+ }
58815
+ async ensureArrayFile(path) {
58816
+ if (!existsSync(path)) {
58817
+ await writeFile(path, `[]
58818
+ `, { encoding: "utf-8", mode: 384 });
58819
+ }
58820
+ await chmod(path, 384).catch(() => {
58821
+ return;
58822
+ });
58823
+ }
58824
+ async readJson(path, fallback) {
58825
+ try {
58826
+ const raw = await readFile(path, "utf-8");
58827
+ if (!raw.trim())
58828
+ return fallback;
58829
+ return JSON.parse(raw);
58830
+ } catch (error) {
58831
+ if (error.code === "ENOENT")
58832
+ return fallback;
58833
+ throw error;
58834
+ }
58835
+ }
58836
+ async writeJson(path, value) {
58837
+ const tempPath = `${path}.${process.pid}.${Date.now()}.tmp`;
58838
+ await writeFile(tempPath, `${JSON.stringify(value, null, 2)}
58839
+ `, { encoding: "utf-8", mode: 384 });
58840
+ await rename(tempPath, path);
58841
+ await chmod(path, 384).catch(() => {
58842
+ return;
58843
+ });
58844
+ }
58845
+ }
58846
+ var DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1000;
58847
+ function buildSignatureBase(timestamp, body) {
58848
+ return `${timestamp}.${body}`;
58849
+ }
58850
+ function signPayload(secret, timestamp, body) {
58851
+ const digest = createHmac("sha256", secret).update(buildSignatureBase(timestamp, body)).digest("hex");
58852
+ return `sha256=${digest}`;
58853
+ }
58854
+ function now() {
58855
+ return new Date().toISOString();
58856
+ }
58857
+ function truncate(value, max = 4096) {
58858
+ return value.length > max ? `${value.slice(0, max)}...` : value;
58859
+ }
58860
+ function buildWebhookRequest(event, channel) {
58861
+ if (!channel.webhook)
58862
+ throw new Error(`Channel ${channel.id} has no webhook config`);
58863
+ const body = JSON.stringify(event);
58864
+ const timestamp = event.time;
58865
+ const headers = {
58866
+ "Content-Type": "application/json",
58867
+ "User-Agent": "@hasna/events",
58868
+ "X-Hasna-Event-Id": event.id,
58869
+ "X-Hasna-Event-Type": event.type,
58870
+ "X-Hasna-Timestamp": timestamp,
58871
+ ...channel.webhook.headers
58872
+ };
58873
+ if (channel.webhook.secret) {
58874
+ headers["X-Hasna-Signature"] = signPayload(channel.webhook.secret, timestamp, body);
58875
+ }
58876
+ return { body, headers };
58877
+ }
58878
+ async function dispatchWebhook(event, channel, options = {}) {
58879
+ if (!channel.webhook)
58880
+ throw new Error(`Channel ${channel.id} has no webhook config`);
58881
+ const startedAt = now();
58882
+ const { body, headers } = buildWebhookRequest(event, channel);
58883
+ const controller = new AbortController;
58884
+ const timeout = setTimeout(() => controller.abort(), channel.webhook.timeoutMs ?? 15000);
58885
+ try {
58886
+ const response = await (options.fetchImpl ?? fetch)(channel.webhook.url, {
58887
+ method: "POST",
58888
+ headers,
58889
+ body,
58890
+ signal: controller.signal
58891
+ });
58892
+ const responseBody = truncate(await response.text());
58893
+ return {
58894
+ attempt: 1,
58895
+ status: response.ok ? "success" : "failed",
58896
+ startedAt,
58897
+ completedAt: now(),
58898
+ responseStatus: response.status,
58899
+ responseBody,
58900
+ error: response.ok ? undefined : `Webhook returned HTTP ${response.status}`
58901
+ };
58902
+ } catch (error) {
58903
+ return {
58904
+ attempt: 1,
58905
+ status: "failed",
58906
+ startedAt,
58907
+ completedAt: now(),
58908
+ error: error instanceof Error ? error.message : String(error)
58909
+ };
58910
+ } finally {
58911
+ clearTimeout(timeout);
58912
+ }
58913
+ }
58914
+ async function dispatchCommand(event, channel) {
58915
+ if (!channel.command)
58916
+ throw new Error(`Channel ${channel.id} has no command config`);
58917
+ const startedAt = now();
58918
+ const eventJson = JSON.stringify(event);
58919
+ const env = {
58920
+ ...process.env,
58921
+ ...channel.command.env,
58922
+ HASNA_CHANNEL_ID: channel.id,
58923
+ HASNA_EVENT_ID: event.id,
58924
+ HASNA_EVENT_TYPE: event.type,
58925
+ HASNA_EVENT_SOURCE: event.source,
58926
+ HASNA_EVENT_SUBJECT: event.subject ?? "",
58927
+ HASNA_EVENT_SEVERITY: event.severity,
58928
+ HASNA_EVENT_TIME: event.time,
58929
+ HASNA_EVENT_DEDUPE_KEY: event.dedupeKey ?? "",
58930
+ HASNA_EVENT_SCHEMA_VERSION: event.schemaVersion,
58931
+ HASNA_EVENT_JSON: eventJson
58932
+ };
58933
+ return new Promise((resolve) => {
58934
+ const child = spawn(channel.command.command, channel.command.args ?? [], {
58935
+ cwd: channel.command.cwd,
58936
+ env,
58937
+ stdio: ["pipe", "pipe", "pipe"]
58938
+ });
58939
+ let stdout = "";
58940
+ let stderr = "";
58941
+ const timeout = setTimeout(() => child.kill("SIGTERM"), channel.command.timeoutMs ?? 15000);
58942
+ child.stdin.end(eventJson);
58943
+ child.stdout.on("data", (chunk) => {
58944
+ stdout += chunk.toString();
58945
+ });
58946
+ child.stderr.on("data", (chunk) => {
58947
+ stderr += chunk.toString();
58948
+ });
58949
+ child.on("error", (error) => {
58950
+ clearTimeout(timeout);
58951
+ resolve({
58952
+ attempt: 1,
58953
+ status: "failed",
58954
+ startedAt,
58955
+ completedAt: now(),
58956
+ stdout: truncate(stdout),
58957
+ stderr: truncate(stderr),
58958
+ error: error.message
58959
+ });
58960
+ });
58961
+ child.on("close", (code, signal) => {
58962
+ clearTimeout(timeout);
58963
+ const success = code === 0;
58964
+ resolve({
58965
+ attempt: 1,
58966
+ status: success ? "success" : "failed",
58967
+ startedAt,
58968
+ completedAt: now(),
58969
+ stdout: truncate(stdout),
58970
+ stderr: truncate(stderr),
58971
+ error: success ? undefined : `Command exited with ${signal ? `signal ${signal}` : `code ${code}`}`
58972
+ });
58973
+ });
58974
+ });
58975
+ }
58976
+ async function dispatchChannel(event, channel, options = {}) {
58977
+ if (channel.transport === "webhook")
58978
+ return dispatchWebhook(event, channel, options);
58979
+ if (channel.transport === "command")
58980
+ return dispatchCommand(event, channel);
58981
+ return {
58982
+ attempt: 1,
58983
+ status: "skipped",
58984
+ startedAt: now(),
58985
+ completedAt: now(),
58986
+ error: `Unsupported transport: ${channel.transport}`
58987
+ };
58988
+ }
58989
+ function createDeliveryResult(event, channel, attempts) {
58990
+ const status = attempts.some((attempt) => attempt.status === "success") ? "success" : attempts.every((attempt) => attempt.status === "skipped") ? "skipped" : "failed";
58991
+ return {
58992
+ id: randomUUID(),
58993
+ eventId: event.id,
58994
+ channelId: channel.id,
58995
+ transport: channel.transport,
58996
+ status,
58997
+ attempts,
58998
+ createdAt: attempts[0]?.startedAt ?? now(),
58999
+ completedAt: attempts.at(-1)?.completedAt ?? now()
59000
+ };
59001
+ }
59002
+ function createEvent(input) {
59003
+ return {
59004
+ id: input.id ?? randomUUID2(),
59005
+ source: input.source,
59006
+ type: input.type,
59007
+ time: normalizeTime(input.time),
59008
+ subject: input.subject,
59009
+ severity: input.severity ?? "info",
59010
+ data: input.data ?? {},
59011
+ message: input.message,
59012
+ dedupeKey: input.dedupeKey,
59013
+ schemaVersion: input.schemaVersion ?? "1.0",
59014
+ metadata: input.metadata ?? {}
59015
+ };
59016
+ }
59017
+
59018
+ class EventsClient {
59019
+ store;
59020
+ redactors;
59021
+ transportOptions;
59022
+ constructor(options = {}) {
59023
+ this.store = options.store ?? new JsonEventsStore(options.dataDir);
59024
+ this.redactors = options.redactors ?? [];
59025
+ this.transportOptions = { fetchImpl: options.fetchImpl };
59026
+ }
59027
+ async addChannel(input) {
59028
+ const timestamp = new Date().toISOString();
59029
+ return this.store.addChannel({
59030
+ ...input,
59031
+ createdAt: input.createdAt ?? timestamp,
59032
+ updatedAt: input.updatedAt ?? timestamp
59033
+ });
59034
+ }
59035
+ async listChannels() {
59036
+ return this.store.listChannels();
59037
+ }
59038
+ async removeChannel(id) {
59039
+ return this.store.removeChannel(id);
59040
+ }
59041
+ async emit(input, options = {}) {
59042
+ const event = options.redactSensitiveData === false ? createEvent(input) : redactSensitiveKeys(createEvent(input));
59043
+ if (options.dedupe !== false) {
59044
+ const existing = await this.store.findEventByIdentity({ id: input.id, dedupeKey: event.dedupeKey });
59045
+ if (existing) {
59046
+ return { event: existing, deliveries: [], deduped: true };
59047
+ }
59048
+ }
59049
+ await this.store.appendEvent(event);
59050
+ const deliveries = options.deliver === false ? [] : await this.deliver(event);
59051
+ return { event, deliveries, deduped: false };
59052
+ }
59053
+ async listEvents() {
59054
+ return this.store.listEvents();
59055
+ }
59056
+ async listDeliveries() {
59057
+ return this.store.listDeliveries();
59058
+ }
59059
+ async deliver(event) {
59060
+ const channels = await this.store.listChannels();
59061
+ const selected = channels.filter((channel) => channelMatchesEvent(channel, event));
59062
+ const deliveries = [];
59063
+ for (const channel of selected) {
59064
+ const eventForChannel = await this.applyRedaction(event, channel);
59065
+ const result = await this.deliverWithRetry(eventForChannel, channel);
59066
+ await this.store.appendDelivery(result);
59067
+ deliveries.push(result);
59068
+ }
59069
+ return deliveries;
59070
+ }
59071
+ async testChannel(id, input = {}) {
59072
+ const channel = await this.store.getChannel(id);
59073
+ if (!channel)
59074
+ throw new Error(`Channel not found: ${id}`);
59075
+ const event = createEvent({
59076
+ source: input.source ?? "hasna.events",
59077
+ type: input.type ?? "events.test",
59078
+ subject: input.subject ?? id,
59079
+ severity: input.severity ?? "info",
59080
+ data: input.data ?? { test: true },
59081
+ message: input.message ?? "Hasna events test delivery",
59082
+ dedupeKey: input.dedupeKey,
59083
+ schemaVersion: input.schemaVersion,
59084
+ metadata: input.metadata,
59085
+ time: input.time,
59086
+ id: input.id
59087
+ });
59088
+ const eventForChannel = await this.applyRedaction(event, channel);
59089
+ const result = await this.deliverWithRetry(eventForChannel, channel);
59090
+ await this.store.appendDelivery(result);
59091
+ return result;
59092
+ }
59093
+ async replay(options = {}) {
59094
+ const events = (await this.store.listEvents()).filter((event) => {
59095
+ if (options.eventId && event.id !== options.eventId)
59096
+ return false;
59097
+ if (options.source && event.source !== options.source)
59098
+ return false;
59099
+ if (options.type && event.type !== options.type)
59100
+ return false;
59101
+ return true;
59102
+ });
59103
+ if (options.dryRun)
59104
+ return { events, deliveries: [] };
59105
+ const deliveries = [];
59106
+ for (const event of events) {
59107
+ deliveries.push(...await this.deliver(event));
59108
+ }
59109
+ return { events, deliveries };
59110
+ }
59111
+ async applyRedaction(event, channel) {
59112
+ let next = redactPaths(event, channel.redact?.paths ?? [], channel.redact?.replacement ?? "[REDACTED]");
59113
+ for (const redactor of this.redactors) {
59114
+ next = await redactor(next, channel);
59115
+ }
59116
+ return next;
59117
+ }
59118
+ async deliverWithRetry(event, channel) {
59119
+ const policy = normalizeRetryPolicy(channel.retry);
59120
+ const attempts = [];
59121
+ for (let index = 0;index < policy.maxAttempts; index += 1) {
59122
+ const attempt = await dispatchChannel(event, channel, this.transportOptions);
59123
+ attempt.attempt = index + 1;
59124
+ if (attempt.status === "failed" && index + 1 < policy.maxAttempts) {
59125
+ attempt.nextBackoffMs = Math.round(policy.backoffMs * policy.multiplier ** index);
59126
+ }
59127
+ attempts.push(attempt);
59128
+ if (attempt.status !== "failed")
59129
+ break;
59130
+ if (attempt.nextBackoffMs)
59131
+ await Bun.sleep(attempt.nextBackoffMs);
59132
+ }
59133
+ return createDeliveryResult(event, channel, attempts);
59134
+ }
59135
+ }
59136
+ function redactPaths(event, paths, replacement = "[REDACTED]") {
59137
+ if (paths.length === 0)
59138
+ return event;
59139
+ const copy = structuredClone(event);
59140
+ for (const path of paths) {
59141
+ setPath(copy, path, replacement);
59142
+ }
59143
+ return copy;
59144
+ }
59145
+ function sanitizeChannelForOutput(channel) {
59146
+ const copy = structuredClone(channel);
59147
+ if (copy.webhook?.secret)
59148
+ copy.webhook.secret = "[REDACTED]";
59149
+ if (copy.command?.env) {
59150
+ copy.command.env = Object.fromEntries(Object.entries(copy.command.env).map(([key, value]) => [key, shouldRedactKey(key) ? "[REDACTED]" : value]));
59151
+ }
59152
+ return copy;
59153
+ }
59154
+ function sanitizeChannelsForOutput(channels) {
59155
+ return channels.map(sanitizeChannelForOutput);
59156
+ }
59157
+ function redactSensitiveKeys(event, replacement = "[REDACTED]") {
59158
+ return redactValue(event, replacement);
59159
+ }
59160
+ function shouldRedactKey(key) {
59161
+ return /secret|token|password|api[_-]?key|authorization/i.test(key);
59162
+ }
59163
+ function redactValue(value, replacement) {
59164
+ if (Array.isArray(value))
59165
+ return value.map((item) => redactValue(item, replacement));
59166
+ if (!value || typeof value !== "object")
59167
+ return value;
59168
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [
59169
+ key,
59170
+ shouldRedactKey(key) ? replacement : redactValue(item, replacement)
59171
+ ]));
59172
+ }
59173
+ function setPath(input, path, replacement) {
59174
+ const parts = path.split(".");
59175
+ let cursor = input;
59176
+ for (const part of parts.slice(0, -1)) {
59177
+ const next = cursor[part];
59178
+ if (!next || typeof next !== "object")
59179
+ return;
59180
+ cursor = next;
59181
+ }
59182
+ const last = parts.at(-1);
59183
+ if (last && last in cursor)
59184
+ cursor[last] = replacement;
59185
+ }
59186
+ function normalizeTime(value) {
59187
+ if (!value)
59188
+ return new Date().toISOString();
59189
+ return value instanceof Date ? value.toISOString() : value;
59190
+ }
59191
+ function normalizeRetryPolicy(policy) {
59192
+ return {
59193
+ maxAttempts: Math.max(1, policy?.maxAttempts ?? 1),
59194
+ backoffMs: Math.max(0, policy?.backoffMs ?? 250),
59195
+ multiplier: Math.max(1, policy?.multiplier ?? 2)
59196
+ };
59197
+ }
59198
+ function parseJsonObject(value, fallback) {
59199
+ if (!value)
59200
+ return fallback;
59201
+ const parsed = JSON.parse(value);
59202
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
59203
+ throw new Error("Expected a JSON object");
59204
+ }
59205
+ return parsed;
59206
+ }
59207
+ function parseHeaders(values) {
59208
+ if (!values?.length)
59209
+ return;
59210
+ const headers = {};
59211
+ for (const value of values) {
59212
+ const separator = value.indexOf("=");
59213
+ if (separator === -1)
59214
+ throw new Error(`Invalid header, expected name=value: ${value}`);
59215
+ headers[value.slice(0, separator)] = value.slice(separator + 1);
59216
+ }
59217
+ return headers;
59218
+ }
59219
+ function parseFilter(options) {
59220
+ const filter2 = {};
59221
+ if (options.source)
59222
+ filter2.source = options.source;
59223
+ if (options.type)
59224
+ filter2.type = options.type;
59225
+ if (options.subject)
59226
+ filter2.subject = options.subject;
59227
+ if (options.severity)
59228
+ filter2.severity = options.severity;
59229
+ return Object.keys(filter2).length > 0 ? [filter2] : undefined;
59230
+ }
59231
+ function createClient(options) {
59232
+ if (options.createClient)
59233
+ return options.createClient();
59234
+ return new EventsClient({ store: new JsonEventsStore(options.dataDir) });
59235
+ }
59236
+ function print(value, json, text) {
59237
+ if (json)
59238
+ console.log(JSON.stringify(value, null, 2));
59239
+ else
59240
+ console.log(text);
59241
+ }
59242
+ function registerWebhookCommands(program2, options) {
59243
+ const webhooks = program2.command(options.webhooksCommandName ?? "webhooks").description("Manage Hasna event webhook subscriptions");
59244
+ webhooks.command("add").description("Add or replace a webhook or command subscription").argument("<target>", "Webhook URL or command binary").requiredOption("--id <id>", "Subscription/channel identifier").option("--transport <kind>", "Transport kind: webhook or command", "webhook").option("--name <name>", "Display name").option("--type <pattern>", "Event type filter, e.g. todos.task.*").option("--source <pattern>", "Event source filter").option("--subject <pattern>", "Event subject filter").option("--severity <pattern>", "Event severity filter").option("--secret <secret>", "Webhook HMAC secret").option("--header <name=value...>", "Webhook header", collectValues, []).option("--arg <arg...>", "Command argument", collectValues, []).option("--timeout-ms <ms>", "Transport timeout in milliseconds", parseNumber).option("--retry-attempts <n>", "Maximum delivery attempts", parseNumber).option("--retry-backoff-ms <ms>", "Initial retry backoff in milliseconds", parseNumber).option("--redact <path...>", "Event field path to redact before delivery", collectValues, []).option("--disabled", "Create channel disabled", false).option("-j, --json", "Print JSON output", false).action(async (target, actionOptions) => {
59245
+ const timestamp = new Date().toISOString();
59246
+ const channel = {
59247
+ id: actionOptions.id,
59248
+ name: actionOptions.name,
59249
+ enabled: !actionOptions.disabled,
59250
+ transport: actionOptions.transport,
59251
+ filters: parseFilter(actionOptions),
59252
+ retry: actionOptions.retryAttempts || actionOptions.retryBackoffMs ? { maxAttempts: actionOptions.retryAttempts, backoffMs: actionOptions.retryBackoffMs } : undefined,
59253
+ redact: actionOptions.redact?.length ? { paths: actionOptions.redact } : undefined,
59254
+ createdAt: timestamp,
59255
+ updatedAt: timestamp
59256
+ };
59257
+ if (actionOptions.transport === "webhook") {
59258
+ channel.webhook = { url: target, secret: actionOptions.secret, headers: parseHeaders(actionOptions.header), timeoutMs: actionOptions.timeoutMs };
59259
+ } else if (actionOptions.transport === "command") {
59260
+ channel.command = { command: target, args: actionOptions.arg ?? [], timeoutMs: actionOptions.timeoutMs };
59261
+ } else {
59262
+ throw new Error(`Transport ${actionOptions.transport} is reserved for future use and cannot be added yet`);
59263
+ }
59264
+ const saved = await createClient(options).addChannel(channel);
59265
+ print(sanitizeChannelForOutput(saved), Boolean(actionOptions.json), `Added ${saved.transport} channel ${saved.id}`);
59266
+ });
59267
+ webhooks.command("list").description("List configured subscriptions").option("-j, --json", "Print JSON output", false).action(async (actionOptions) => {
59268
+ const channels = await createClient(options).listChannels();
59269
+ if (actionOptions.json) {
59270
+ console.log(JSON.stringify(sanitizeChannelsForOutput(channels), null, 2));
59271
+ return;
59272
+ }
59273
+ if (!channels.length) {
59274
+ console.log("No channels configured.");
59275
+ return;
59276
+ }
59277
+ for (const channel of channels) {
59278
+ console.log(`${channel.id} ${channel.enabled ? "enabled" : "disabled"} ${channel.transport} ${channel.webhook?.url ?? channel.command?.command ?? channel.transport}`);
59279
+ }
59280
+ });
59281
+ webhooks.command("remove").description("Remove a subscription").argument("<id>", "Subscription/channel identifier").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions) => {
59282
+ const removed = await createClient(options).removeChannel(id);
59283
+ print({ removed }, Boolean(actionOptions.json), removed ? `Removed ${id}` : `Channel not found: ${id}`);
59284
+ });
59285
+ webhooks.command("test").description("Send a test event to one subscription").argument("<id>", "Subscription/channel identifier").option("--type <type>", "Event type", "events.test").option("--subject <subject>", "Event subject").option("--message <message>", "Event message", "Hasna events test delivery").option("--data <json>", "Event data JSON object").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions) => {
59286
+ const result = await createClient(options).testChannel(id, {
59287
+ source: options.source,
59288
+ type: actionOptions.type,
59289
+ subject: actionOptions.subject ?? id,
59290
+ message: actionOptions.message,
59291
+ data: parseJsonObject(actionOptions.data, { test: true })
59292
+ });
59293
+ print(result, Boolean(actionOptions.json), `${result.status}: ${result.channelId}`);
59294
+ });
59295
+ return webhooks;
59296
+ }
59297
+ function registerEventCommands(program2, options) {
59298
+ const events = program2.command(options.eventsCommandName ?? "events").description("Emit, list, and replay Hasna events");
59299
+ events.command("emit").description("Emit an event from this app").argument("<type>", "Event type").option("--source <source>", "Event source override").option("--subject <subject>", "Event subject").option("--severity <severity>", "Event severity", "info").option("--message <message>", "Event message").option("--dedupe-key <key>", "Dedupe key").option("--data <json>", "Event data JSON object").option("--metadata <json>", "Event metadata JSON object").option("--no-deliver", "Record without delivering").option("--no-dedupe", "Allow duplicate id/dedupeKey events").option("-j, --json", "Print JSON output", false).action(async (type, actionOptions) => {
59300
+ const result = await createClient(options).emit({
59301
+ source: actionOptions.source ?? options.source,
59302
+ type,
59303
+ subject: actionOptions.subject,
59304
+ severity: actionOptions.severity,
59305
+ message: actionOptions.message,
59306
+ dedupeKey: actionOptions.dedupeKey,
59307
+ data: parseJsonObject(actionOptions.data, {}),
59308
+ metadata: parseJsonObject(actionOptions.metadata, {})
59309
+ }, { deliver: actionOptions.deliver, dedupe: actionOptions.dedupe });
59310
+ print(result, Boolean(actionOptions.json), `${result.deduped ? "Deduped" : "Emitted"} ${result.event.id} to ${result.deliveries.length} channel(s)`);
59311
+ });
59312
+ events.command("list").description("List recorded events").option("--source <source>", "Filter by source").option("--type <type>", "Filter by type").option("--limit <n>", "Limit results", parseNumber).option("-j, --json", "Print JSON output", false).action(async (actionOptions) => {
59313
+ let rows = await createClient(options).listEvents();
59314
+ if (actionOptions.source)
59315
+ rows = rows.filter((event) => event.source === actionOptions.source);
59316
+ if (actionOptions.type)
59317
+ rows = rows.filter((event) => event.type === actionOptions.type);
59318
+ if (actionOptions.limit)
59319
+ rows = rows.slice(-actionOptions.limit);
59320
+ if (actionOptions.json) {
59321
+ console.log(JSON.stringify(rows, null, 2));
59322
+ return;
59323
+ }
59324
+ if (!rows.length) {
59325
+ console.log("No events recorded.");
59326
+ return;
59327
+ }
59328
+ for (const event of rows)
59329
+ console.log(`${event.time} ${event.id} ${event.source} ${event.type} ${event.severity}`);
59330
+ });
59331
+ events.command("replay").description("Replay recorded events").option("--id <id>", "Replay one event id").option("--source <source>", "Filter by source").option("--type <type>", "Filter by type").option("--dry-run", "Preview without delivery", false).option("-j, --json", "Print JSON output", false).action(async (actionOptions) => {
59332
+ const result = await createClient(options).replay({
59333
+ eventId: actionOptions.id,
59334
+ source: actionOptions.source,
59335
+ type: actionOptions.type,
59336
+ dryRun: actionOptions.dryRun
59337
+ });
59338
+ print(result, Boolean(actionOptions.json), `Replayed ${result.events.length} event(s), ${result.deliveries.length} delivery result(s)`);
59339
+ });
59340
+ return events;
59341
+ }
59342
+ function registerEventsCommands(program2, options) {
59343
+ registerWebhookCommands(program2, options);
59344
+ registerEventCommands(program2, options);
59345
+ }
59346
+ function parseNumber(value) {
59347
+ const parsed = Number(value);
59348
+ if (!Number.isFinite(parsed))
59349
+ throw new Error(`Expected a number, got ${value}`);
59350
+ return parsed;
59351
+ }
59352
+ function collectValues(value, previous) {
59353
+ previous.push(value);
59354
+ return previous;
59355
+ }
59356
+
59357
+ // src/cli/index.tsx
58678
59358
  init_package_version();
58679
59359
  var program2 = new Command;
58680
59360
  program2.name("todos").description("Universal task management for AI coding agents").version(getPackageVersion()).option("--project <path>", "Project path").option("-j, --json", "Output as JSON").option("--agent <name>", "Agent name").option("--session <id>", "Session ID");
@@ -58764,5 +59444,6 @@ registerUsageLedgerCommands2(program2);
58764
59444
  registerLocalBackupCommands2(program2);
58765
59445
  registerStorageCommands2(program2);
58766
59446
  registerScaleHardeningCommands2(program2);
59447
+ registerEventsCommands(program2, { source: "todos" });
58767
59448
  registerHelpCommands2(program2);
58768
59449
  program2.parse();