@hasna/todos 0.15.50 → 0.15.52

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.
@@ -70,7 +70,7 @@ var package_default;
70
70
  var init_package = __esm(() => {
71
71
  package_default = {
72
72
  name: "@hasna/todos",
73
- version: "0.15.50",
73
+ version: "0.15.52",
74
74
  description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
75
75
  type: "module",
76
76
  main: "dist/index.js",
@@ -129,6 +129,7 @@ var init_package = __esm(() => {
129
129
  files: [
130
130
  "dist",
131
131
  "dashboard/dist",
132
+ "postinstall.js",
132
133
  "LICENSE",
133
134
  "README.md"
134
135
  ],
@@ -155,7 +156,7 @@ var init_package = __esm(() => {
155
156
  "test:attested-container-compatibility-vector": "bun test scripts/attested-container-compatibility-vector.test.ts",
156
157
  "issue:release-review": "bun run scripts/issue-npm-release-agent-review.ts",
157
158
  prepublishOnly: "bun run scripts/verify-public-release.ts --mode=publish",
158
- postinstall: "mkdir -p $HOME/.hasna/todos $HOME/.hasna/todos/training 2>/dev/null || true"
159
+ postinstall: "node postinstall.js"
159
160
  },
160
161
  keywords: [
161
162
  "todos",
@@ -189,13 +190,15 @@ var init_package = __esm(() => {
189
190
  author: "Andrei Hasna <andrei@hasna.com>",
190
191
  license: "Apache-2.0",
191
192
  dependencies: {
192
- "@hasna/contracts": "0.14.0",
193
+ "@hasna/contracts": "0.14.2",
193
194
  "@hasna/events": "^0.1.11",
195
+ "@hasna/paths": "0.1.0",
194
196
  "@modelcontextprotocol/sdk": "^1.12.1",
195
197
  chalk: "^5.4.1",
196
198
  commander: "^13.1.0",
197
199
  ink: "^5.2.0",
198
200
  react: "^18.3.1",
201
+ "signal-exit": "3.0.7",
199
202
  zod: "3.25.76"
200
203
  },
201
204
  overrides: {
@@ -204,7 +207,7 @@ var init_package = __esm(() => {
204
207
  zod: "3.25.76"
205
208
  },
206
209
  devDependencies: {
207
- "@types/bun": "^1.2.4",
210
+ "@types/bun": "1.3.14",
208
211
  "@types/react": "^18.3.18",
209
212
  "bun-types": "1.3.9",
210
213
  "hasna-deployment-contracts": "npm:@hasna/contracts@0.10.4",
@@ -225,7 +228,7 @@ var init_package_version = __esm(() => {
225
228
  init_package();
226
229
  });
227
230
 
228
- // node_modules/.bun/@hasna+contracts@0.14.0+619f74e7b30eeaf4/node_modules/@hasna/contracts/dist/auth/index.js
231
+ // node_modules/.bun/@hasna+contracts@0.14.2+a5fb9613d5af3331/node_modules/@hasna/contracts/dist/auth/index.js
229
232
  import { createHash, createHmac, randomBytes, timingSafeEqual } from "crypto";
230
233
  function isValidTenantId(value) {
231
234
  return typeof value === "string" && TENANT_ID_PATTERN.test(value);
@@ -1308,18 +1311,112 @@ function normalizeAgentNameInput(name) {
1308
1311
  return name.trim().toLowerCase();
1309
1312
  }
1310
1313
 
1311
- // src/lib/sync-utils.ts
1312
- import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
1314
+ // node_modules/.bun/@hasna+paths@0.1.0/node_modules/@hasna/paths/dist/index.js
1313
1315
  import { homedir } from "os";
1314
1316
  import { join } from "path";
1317
+ function assertApp(app) {
1318
+ if (typeof app !== "string" || app.length === 0) {
1319
+ throw new TypeError("paths: app must be a non-empty string");
1320
+ }
1321
+ if (!APP_SLUG_RE.test(app)) {
1322
+ throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
1323
+ }
1324
+ }
1325
+ function envOf(options) {
1326
+ return options.env ?? process.env;
1327
+ }
1328
+ function envValue(options, kind) {
1329
+ const value = envOf(options)[KIND_ENV[kind]];
1330
+ return typeof value === "string" && value.length > 0 ? value : undefined;
1331
+ }
1332
+ function isMacOS(platform) {
1333
+ return platform === "darwin";
1334
+ }
1335
+ function baseDir(kind, options) {
1336
+ const override = envValue(options, kind);
1337
+ if (override)
1338
+ return override;
1339
+ const home = options.home ?? homedir();
1340
+ const platform = options.platform ?? process.platform;
1341
+ if (isMacOS(platform)) {
1342
+ switch (kind) {
1343
+ case "config":
1344
+ case "data":
1345
+ return join(home, "Library", "Application Support", "Hasna");
1346
+ case "cache":
1347
+ return join(home, "Library", "Caches", "Hasna");
1348
+ case "state":
1349
+ return join(home, "Library", "Logs", "Hasna");
1350
+ }
1351
+ }
1352
+ switch (kind) {
1353
+ case "config":
1354
+ return join(home, ".config", "hasna");
1355
+ case "data":
1356
+ return join(home, ".local", "share", "hasna");
1357
+ case "state":
1358
+ return join(home, ".local", "state", "hasna");
1359
+ case "cache":
1360
+ return join(home, ".cache", "hasna");
1361
+ }
1362
+ }
1363
+ function resolvePath(kind, options) {
1364
+ assertApp(options.app);
1365
+ const appSegment = options.internal === true ? join("internal", options.app) : options.app;
1366
+ return join(baseDir(kind, options), appSegment);
1367
+ }
1368
+ function dataDir(options) {
1369
+ return resolvePath("data", options);
1370
+ }
1371
+ var KIND_ENV, APP_SLUG_RE;
1372
+ var init_dist = __esm(() => {
1373
+ KIND_ENV = {
1374
+ config: "HASNA_CONFIG_HOME",
1375
+ data: "HASNA_DATA_HOME",
1376
+ state: "HASNA_STATE_HOME",
1377
+ cache: "HASNA_CACHE_HOME"
1378
+ };
1379
+ APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
1380
+ });
1381
+
1382
+ // src/lib/paths.ts
1383
+ import { existsSync } from "fs";
1384
+ import { homedir as homedir2 } from "os";
1385
+ import { join as join2, resolve } from "path";
1386
+ function effectiveHome(env = process.env) {
1387
+ return env.HOME || env.USERPROFILE || homedir2();
1388
+ }
1389
+ function legacyHomeDir(env = process.env) {
1390
+ return join2(effectiveHome(env), ".hasna", "todos");
1391
+ }
1392
+ function resolverHome(env = process.env) {
1393
+ return dataDir({ app: "todos", home: effectiveHome(env), env });
1394
+ }
1395
+ function adoptResolverHome(resolved, env = process.env) {
1396
+ const dataOverride = env.HASNA_DATA_HOME;
1397
+ if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
1398
+ return true;
1399
+ return existsSync(join2(resolved, "todos.db")) || existsSync(join2(resolved, "config.json"));
1400
+ }
1401
+ function getTodosDir(env = process.env) {
1402
+ const resolved = resolverHome(env);
1403
+ return resolve(adoptResolverHome(resolved, env) ? resolved : legacyHomeDir(env));
1404
+ }
1405
+ var init_paths = __esm(() => {
1406
+ init_dist();
1407
+ });
1408
+
1409
+ // src/lib/sync-utils.ts
1410
+ import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
1411
+ import { homedir as homedir3 } from "os";
1315
1412
  function getHomeDir() {
1316
- return process.env["HOME"] || process.env["USERPROFILE"] || homedir();
1413
+ return process.env["HOME"] || process.env["USERPROFILE"] || homedir3();
1317
1414
  }
1318
1415
  function getTodosGlobalDir() {
1319
- return join(getHomeDir(), ".hasna", "todos");
1416
+ return getTodosDir();
1320
1417
  }
1321
1418
  function ensureDir(dir) {
1322
- if (!existsSync(dir))
1419
+ if (!existsSync2(dir))
1323
1420
  mkdirSync(dir, { recursive: true });
1324
1421
  }
1325
1422
  function readJsonFile(path) {
@@ -1340,18 +1437,19 @@ function appendSyncConflict(metadata, conflict, limit = 5) {
1340
1437
  }
1341
1438
  var HOME;
1342
1439
  var init_sync_utils = __esm(() => {
1440
+ init_paths();
1343
1441
  HOME = getHomeDir();
1344
1442
  });
1345
1443
 
1346
1444
  // src/lib/creator-identity.ts
1347
- import { existsSync as existsSync2, rmSync } from "fs";
1348
- import { join as join2 } from "path";
1445
+ import { existsSync as existsSync3, rmSync } from "fs";
1446
+ import { join as join3 } from "path";
1349
1447
  function identityFilePath() {
1350
- return join2(getTodosGlobalDir(), "identity.json");
1448
+ return join3(getTodosGlobalDir(), "identity.json");
1351
1449
  }
1352
1450
  function readPersistedIdentity() {
1353
1451
  const path = identityFilePath();
1354
- if (!existsSync2(path))
1452
+ if (!existsSync3(path))
1355
1453
  return null;
1356
1454
  const parsed = readJsonFile(path);
1357
1455
  if (!parsed || typeof parsed.agent_id !== "string" || !parsed.agent_id.trim())
@@ -1499,15 +1597,15 @@ var init_plan_project_link_contract = __esm(() => {
1499
1597
  });
1500
1598
 
1501
1599
  // src/lib/config.ts
1502
- import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
1503
- import { dirname, join as join3 } from "path";
1600
+ import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
1601
+ import { dirname, join as join4 } from "path";
1504
1602
  function getConfigPath() {
1505
- return join3(getTodosGlobalDir(), "config.json");
1603
+ return join4(getTodosGlobalDir(), "config.json");
1506
1604
  }
1507
1605
  function loadConfig() {
1508
1606
  if (cached)
1509
1607
  return cached;
1510
- if (!existsSync3(getConfigPath())) {
1608
+ if (!existsSync4(getConfigPath())) {
1511
1609
  cached = {};
1512
1610
  return cached;
1513
1611
  }
@@ -5357,7 +5455,7 @@ async function retryOnTransientPostgresError(fn, attempts = 2, delayMs = 150) {
5357
5455
  lastError = error;
5358
5456
  if (!isTransientPostgresError(error) || attempt === attempts)
5359
5457
  throw error;
5360
- await new Promise((resolve) => setTimeout(resolve, delayMs * attempt));
5458
+ await new Promise((resolve2) => setTimeout(resolve2, delayMs * attempt));
5361
5459
  }
5362
5460
  }
5363
5461
  throw lastError;
@@ -11134,9 +11232,9 @@ var init_schema = __esm(() => {
11134
11232
  });
11135
11233
 
11136
11234
  // src/db/machines.ts
11137
- import { existsSync as existsSync4 } from "fs";
11235
+ import { existsSync as existsSync5 } from "fs";
11138
11236
  import { hostname as osHostname, platform as osPlatform, arch as osArch } from "os";
11139
- import { resolve } from "path";
11237
+ import { resolve as resolve2 } from "path";
11140
11238
  import { spawnSync } from "child_process";
11141
11239
  function parseMetadata(value) {
11142
11240
  if (!value)
@@ -11167,7 +11265,7 @@ function discoverGitRoot(workspacePath) {
11167
11265
  }
11168
11266
  function topologyMetadata(input, existing = {}) {
11169
11267
  const next = { ...existing };
11170
- const workspacePath = input.workspace_path ? resolve(input.workspace_path) : undefined;
11268
+ const workspacePath = input.workspace_path ? resolve2(input.workspace_path) : undefined;
11171
11269
  const entries = {
11172
11270
  tailscale_name: input.tailscale_name,
11173
11271
  tailscale_ip: input.tailscale_ip,
@@ -11341,7 +11439,7 @@ function getMachineTopologyDiagnostics(opts = {}, db, at = new Date) {
11341
11439
  message: `${project.name} has ${distinctPaths.length} different machine-local paths`
11342
11440
  });
11343
11441
  }
11344
- if (localRow && !existsSync4(localRow.path)) {
11442
+ if (localRow && !existsSync5(localRow.path)) {
11345
11443
  pathIssues.push({
11346
11444
  type: "path_missing",
11347
11445
  project_id: project.id,
@@ -11352,7 +11450,7 @@ function getMachineTopologyDiagnostics(opts = {}, db, at = new Date) {
11352
11450
  message: `Local path does not exist on this machine: ${localRow.path}`
11353
11451
  });
11354
11452
  }
11355
- if (!localRow && project.path && machineById.has(localMachine.id) && !existsSync4(project.path)) {
11453
+ if (!localRow && project.path && machineById.has(localMachine.id) && !existsSync5(project.path)) {
11356
11454
  pathIssues.push({
11357
11455
  type: "path_missing",
11358
11456
  project_id: project.id,
@@ -11729,18 +11827,18 @@ __export(exports_database, {
11729
11827
  LOCK_EXPIRY_MINUTES: () => LOCK_EXPIRY_MINUTES
11730
11828
  });
11731
11829
  import { Database } from "bun:sqlite";
11732
- import { existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
11733
- import { dirname as dirname2, join as join4, resolve as resolve2 } from "path";
11830
+ import { existsSync as existsSync6, mkdirSync as mkdirSync2 } from "fs";
11831
+ import { dirname as dirname2, join as join5, resolve as resolve3 } from "path";
11734
11832
  function isInMemoryDb(path) {
11735
11833
  return path === ":memory:" || path.startsWith("file::memory:");
11736
11834
  }
11737
11835
  function findNearestProjectDb(startDir) {
11738
11836
  const gitRoot = findGitRoot(startDir);
11739
- const stopAt = gitRoot ? resolve2(gitRoot) : resolve2(startDir);
11740
- let dir = resolve2(startDir);
11837
+ const stopAt = gitRoot ? resolve3(gitRoot) : resolve3(startDir);
11838
+ let dir = resolve3(startDir);
11741
11839
  while (true) {
11742
- const candidate = join4(dir, ".hasna", "todos", "todos.db");
11743
- if (existsSync5(candidate))
11840
+ const candidate = join5(dir, ".hasna", "todos", "todos.db");
11841
+ if (existsSync6(candidate))
11744
11842
  return candidate;
11745
11843
  if (dir === stopAt)
11746
11844
  break;
@@ -11752,9 +11850,9 @@ function findNearestProjectDb(startDir) {
11752
11850
  return null;
11753
11851
  }
11754
11852
  function findGitRoot(startDir) {
11755
- let dir = resolve2(startDir);
11853
+ let dir = resolve3(startDir);
11756
11854
  while (true) {
11757
- if (existsSync5(join4(dir, ".git")))
11855
+ if (existsSync6(join5(dir, ".git")))
11758
11856
  return dir;
11759
11857
  const parent = dirname2(dir);
11760
11858
  if (parent === dir)
@@ -11764,7 +11862,7 @@ function findGitRoot(startDir) {
11764
11862
  return null;
11765
11863
  }
11766
11864
  function getGlobalDbPath() {
11767
- return join4(getHomeDir(), ".hasna", "todos", "todos.db");
11865
+ return join5(getTodosGlobalDir(), "todos.db");
11768
11866
  }
11769
11867
  function hasExplicitProjectArg(args = process.argv.slice(2)) {
11770
11868
  return args.some((arg) => arg === "--project" || arg.startsWith("--project="));
@@ -11802,7 +11900,7 @@ function getDbPath() {
11802
11900
  if (process.env["TODOS_DB_SCOPE"] === "project") {
11803
11901
  const gitRoot = findGitRoot(cwd);
11804
11902
  if (gitRoot && canCreateScopedProjectDb()) {
11805
- return join4(gitRoot, ".hasna", "todos", "todos.db");
11903
+ return join5(gitRoot, ".hasna", "todos", "todos.db");
11806
11904
  }
11807
11905
  }
11808
11906
  return getGlobalDbPath();
@@ -11813,8 +11911,8 @@ function getDatabasePath() {
11813
11911
  function ensureDir2(filePath) {
11814
11912
  if (isInMemoryDb(filePath))
11815
11913
  return;
11816
- const dir = dirname2(resolve2(filePath));
11817
- if (!existsSync5(dir)) {
11914
+ const dir = dirname2(resolve3(filePath));
11915
+ if (!existsSync6(dir)) {
11818
11916
  mkdirSync2(dir, { recursive: true });
11819
11917
  }
11820
11918
  }
@@ -12653,14 +12751,14 @@ var init_completion_guard = __esm(() => {
12653
12751
 
12654
12752
  // src/lib/event-emission-safety.ts
12655
12753
  import { tmpdir } from "os";
12656
- import { resolve as resolve3, sep } from "path";
12754
+ import { resolve as resolve4, sep } from "path";
12657
12755
  function envFlag(name) {
12658
12756
  const value = process.env[name]?.trim().toLowerCase();
12659
12757
  return value === "1" || value === "true" || value === "yes" || value === "on";
12660
12758
  }
12661
12759
  function isUnder(parent, child) {
12662
- const normalizedParent = resolve3(parent);
12663
- const normalizedChild = resolve3(child);
12760
+ const normalizedParent = resolve4(parent);
12761
+ const normalizedChild = resolve4(child);
12664
12762
  return normalizedChild === normalizedParent || normalizedChild.startsWith(`${normalizedParent}${sep}`);
12665
12763
  }
12666
12764
  function databasePathFromDatabase(db) {
@@ -12703,9 +12801,9 @@ var init_event_emission_safety = __esm(() => {
12703
12801
  });
12704
12802
 
12705
12803
  // src/lib/workspace-trust.ts
12706
- import { relative, resolve as resolve4 } from "path";
12804
+ import { relative, resolve as resolve5 } from "path";
12707
12805
  function normalizePath(path) {
12708
- return resolve4(path);
12806
+ return resolve5(path);
12709
12807
  }
12710
12808
  function unique2(values) {
12711
12809
  return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
@@ -12887,9 +12985,9 @@ var init_workspace_trust = __esm(() => {
12887
12985
  });
12888
12986
 
12889
12987
  // src/lib/runner-sandbox.ts
12890
- import { relative as relative2, resolve as resolve5 } from "path";
12988
+ import { relative as relative2, resolve as resolve6 } from "path";
12891
12989
  function normalizePath2(path) {
12892
- return resolve5(path);
12990
+ return resolve6(path);
12893
12991
  }
12894
12992
  function unique3(values) {
12895
12993
  return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
@@ -13079,7 +13177,7 @@ var init_runner_sandbox = __esm(() => {
13079
13177
  // src/lib/event-hooks.ts
13080
13178
  import { createHash as createHash5, randomUUID as randomUUID2 } from "crypto";
13081
13179
  import { appendFileSync, mkdirSync as mkdirSync3 } from "fs";
13082
- import { dirname as dirname3, resolve as resolve6 } from "path";
13180
+ import { dirname as dirname3, resolve as resolve7 } from "path";
13083
13181
  import { createConnection } from "net";
13084
13182
  function safeName(name) {
13085
13183
  const trimmed = name.trim();
@@ -13217,7 +13315,7 @@ async function deliverHook(hook, envelope) {
13217
13315
  if (hook.target === "stdout") {
13218
13316
  output = line.trim();
13219
13317
  } else if (hook.target === "file") {
13220
- const filePath = resolve6(hook.file_path);
13318
+ const filePath = resolve7(hook.file_path);
13221
13319
  mkdirSync3(dirname3(filePath), { recursive: true });
13222
13320
  appendFileSync(filePath, line);
13223
13321
  } else if (hook.target === "socket") {
@@ -13338,9 +13436,9 @@ var init_event_hooks = __esm(() => {
13338
13436
  // node_modules/.bun/@hasna+events@0.1.16/node_modules/@hasna/events/dist/index.js
13339
13437
  import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
13340
13438
  import { Buffer as Buffer2 } from "buffer";
13341
- import { existsSync as existsSync6 } from "fs";
13342
- import { homedir as homedir2 } from "os";
13343
- import { join as join5 } from "path";
13439
+ import { existsSync as existsSync7 } from "fs";
13440
+ import { homedir as homedir4 } from "os";
13441
+ import { join as join6 } from "path";
13344
13442
  import { createHmac as createHmac2, timingSafeEqual as timingSafeEqual2 } from "crypto";
13345
13443
  import { randomUUID as randomUUID3 } from "crypto";
13346
13444
  import { spawn } from "child_process";
@@ -13441,7 +13539,7 @@ function channelMatchesEvent(channel, event) {
13441
13539
  return channel.filters.some((filter) => eventMatchesFilter(event, filter));
13442
13540
  }
13443
13541
  function getEventsDataDir(override) {
13444
- return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join5(homedir2(), ".hasna", "events");
13542
+ return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join6(homedir4(), ".hasna", "events");
13445
13543
  }
13446
13544
 
13447
13545
  class JsonEventsStore {
@@ -13450,12 +13548,12 @@ class JsonEventsStore {
13450
13548
  channelsPath;
13451
13549
  eventsPath;
13452
13550
  deliveriesPath;
13453
- constructor(dataDir = getEventsDataDir()) {
13454
- this.dataDir = dataDir;
13455
- this.runtime = localJsonRuntime(dataDir);
13456
- this.channelsPath = join5(dataDir, "channels.json");
13457
- this.eventsPath = join5(dataDir, "events.json");
13458
- this.deliveriesPath = join5(dataDir, "deliveries.json");
13551
+ constructor(dataDir2 = getEventsDataDir()) {
13552
+ this.dataDir = dataDir2;
13553
+ this.runtime = localJsonRuntime(dataDir2);
13554
+ this.channelsPath = join6(dataDir2, "channels.json");
13555
+ this.eventsPath = join6(dataDir2, "events.json");
13556
+ this.deliveriesPath = join6(dataDir2, "deliveries.json");
13459
13557
  }
13460
13558
  async init() {
13461
13559
  await mkdir(this.dataDir, { recursive: true, mode: 448 });
@@ -13572,7 +13670,7 @@ class JsonEventsStore {
13572
13670
  };
13573
13671
  }
13574
13672
  async ensureArrayFile(path) {
13575
- if (!existsSync6(path)) {
13673
+ if (!existsSync7(path)) {
13576
13674
  await writeFile(path, `[]
13577
13675
  `, { encoding: "utf-8", mode: 384 });
13578
13676
  }
@@ -13602,7 +13700,7 @@ class JsonEventsStore {
13602
13700
  });
13603
13701
  }
13604
13702
  }
13605
- function localJsonRuntime(dataDir = getEventsDataDir()) {
13703
+ function localJsonRuntime(dataDir2 = getEventsDataDir()) {
13606
13704
  return {
13607
13705
  mode: "local-files",
13608
13706
  name: "json-events-store",
@@ -13615,7 +13713,7 @@ function localJsonRuntime(dataDir = getEventsDataDir()) {
13615
13713
  durable: true,
13616
13714
  idempotency: "best-effort-local",
13617
13715
  replayCursors: true,
13618
- description: `Local JSON files in ${dataDir}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
13716
+ description: `Local JSON files in ${dataDir2}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
13619
13717
  };
13620
13718
  }
13621
13719
  function encodeLocalJsonEventCursor(offset, options = {}) {
@@ -13794,7 +13892,7 @@ async function dispatchCommand(event, channel) {
13794
13892
  HASNA_EVENT_SCHEMA_VERSION: event.schemaVersion,
13795
13893
  HASNA_EVENT_JSON: eventJson
13796
13894
  };
13797
- return new Promise((resolve7) => {
13895
+ return new Promise((resolve8) => {
13798
13896
  const child = spawn(channel.command.command, channel.command.args ?? [], {
13799
13897
  cwd: channel.command.cwd,
13800
13898
  env,
@@ -13812,7 +13910,7 @@ async function dispatchCommand(event, channel) {
13812
13910
  });
13813
13911
  child.on("error", (error) => {
13814
13912
  clearTimeout(timeout);
13815
- resolve7({
13913
+ resolve8({
13816
13914
  attempt: 1,
13817
13915
  status: "failed",
13818
13916
  startedAt,
@@ -13825,7 +13923,7 @@ async function dispatchCommand(event, channel) {
13825
13923
  child.on("close", (code, signal) => {
13826
13924
  clearTimeout(timeout);
13827
13925
  const success = code === 0;
13828
- resolve7({
13926
+ resolve8({
13829
13927
  attempt: 1,
13830
13928
  status: success ? "success" : "failed",
13831
13929
  startedAt,
@@ -14167,7 +14265,7 @@ function normalizeRetryPolicy(policy) {
14167
14265
  };
14168
14266
  }
14169
14267
  var HASNA_EVENTS_DIR_ENV = "HASNA_EVENTS_DIR", HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME", LOCAL_JSON_EVENT_CURSOR_PREFIX = "local-json-v1:", DEFAULT_EVENT_PAGE_LIMIT = 100, MAX_EVENT_PAGE_LIMIT = 1000, DEFAULT_SIGNATURE_TOLERANCE_MS, EventValidationError, defaultEventTypeCatalog, APP_EVENT_V1_MAX_DATA_BYTES;
14170
- var init_dist = __esm(() => {
14268
+ var init_dist2 = __esm(() => {
14171
14269
  DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1000;
14172
14270
  EventValidationError = class EventValidationError extends Error {
14173
14271
  eventType;
@@ -14587,7 +14685,7 @@ function emitSharedTaskEventQuiet(input) {
14587
14685
  }
14588
14686
  var SOURCE = "todos";
14589
14687
  var init_shared_events = __esm(() => {
14590
- init_dist();
14688
+ init_dist2();
14591
14689
  init_database();
14592
14690
  init_projects();
14593
14691
  init_task_lists();
@@ -16449,17 +16547,17 @@ function sanitizeCreateTaskInput(input) {
16449
16547
  return {
16450
16548
  ...input,
16451
16549
  title: sanitizePreWriteText(input.title, "task.title"),
16452
- description: input.description !== undefined ? sanitizePreWriteText(input.description, "task.description") : undefined,
16550
+ description: input.description == null ? input.description : sanitizePreWriteText(input.description, "task.description"),
16453
16551
  tags: input.tags !== undefined ? sanitizePreWriteValue(input.tags, "task.tags") : undefined,
16454
16552
  metadata: input.metadata !== undefined ? sanitizePreWriteValue(input.metadata, "task.metadata") : undefined,
16455
- reason: input.reason !== undefined ? sanitizePreWriteText(input.reason, "task.reason") : undefined
16553
+ reason: input.reason == null ? input.reason : sanitizePreWriteText(input.reason, "task.reason")
16456
16554
  };
16457
16555
  }
16458
16556
  function sanitizeUpdateTaskInput(input) {
16459
16557
  return {
16460
16558
  ...input,
16461
16559
  title: input.title !== undefined ? sanitizePreWriteText(input.title, "task.title") : undefined,
16462
- description: input.description !== undefined ? sanitizePreWriteText(input.description, "task.description") : undefined,
16560
+ description: input.description == null ? input.description : sanitizePreWriteText(input.description, "task.description"),
16463
16561
  tags: input.tags !== undefined ? sanitizePreWriteValue(input.tags, "task.tags") : undefined,
16464
16562
  metadata: input.metadata !== undefined ? sanitizePreWriteValue(input.metadata, "task.metadata") : undefined
16465
16563
  };
@@ -18456,28 +18554,28 @@ var init_boards = __esm(() => {
18456
18554
 
18457
18555
  // src/lib/artifact-store.ts
18458
18556
  import { createHash as createHash6 } from "crypto";
18459
- import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync3, rmSync as rmSync2, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
18460
- import { basename, dirname as dirname4, join as join6, resolve as resolve7 } from "path";
18557
+ import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync3, rmSync as rmSync2, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
18558
+ import { basename, dirname as dirname4, join as join7, resolve as resolve8 } from "path";
18461
18559
  import { tmpdir as tmpdir2 } from "os";
18462
18560
  function isInMemoryDb2(path) {
18463
18561
  return path === ":memory:" || path.startsWith("file::memory:");
18464
18562
  }
18465
18563
  function artifactStoreRoot() {
18466
18564
  if (process.env["HASNA_TODOS_ARTIFACTS_DIR"])
18467
- return resolve7(process.env["HASNA_TODOS_ARTIFACTS_DIR"]);
18565
+ return resolve8(process.env["HASNA_TODOS_ARTIFACTS_DIR"]);
18468
18566
  if (process.env["TODOS_ARTIFACTS_DIR"])
18469
- return resolve7(process.env["TODOS_ARTIFACTS_DIR"]);
18567
+ return resolve8(process.env["TODOS_ARTIFACTS_DIR"]);
18470
18568
  const dbPath = getDatabasePath();
18471
18569
  if (isInMemoryDb2(dbPath))
18472
- return join6(tmpdir2(), "hasna-todos-artifacts");
18473
- return join6(dirname4(resolve7(dbPath)), "artifacts");
18570
+ return join7(tmpdir2(), "hasna-todos-artifacts");
18571
+ return join7(dirname4(resolve8(dbPath)), "artifacts");
18474
18572
  }
18475
18573
  function artifactStorePath(relativePath) {
18476
18574
  const normalized = relativePath.replace(/\\/g, "/");
18477
18575
  if (normalized.includes("..") || normalized.startsWith("/") || normalized.length === 0) {
18478
18576
  throw new Error("Invalid artifact store path");
18479
18577
  }
18480
- return join6(artifactStoreRoot(), normalized);
18578
+ return join7(artifactStoreRoot(), normalized);
18481
18579
  }
18482
18580
  function sha2562(buffer) {
18483
18581
  return createHash6("sha256").update(buffer).digest("hex");
@@ -18517,8 +18615,8 @@ function mediaTypeFor(path, textLike) {
18517
18615
  return "application/octet-stream";
18518
18616
  }
18519
18617
  function storeArtifactContent(input) {
18520
- const sourcePath = resolve7(input.path);
18521
- if (!existsSync7(sourcePath))
18618
+ const sourcePath = resolve8(input.path);
18619
+ if (!existsSync8(sourcePath))
18522
18620
  return null;
18523
18621
  const sourceStat = statSync2(sourcePath);
18524
18622
  if (!sourceStat.isFile())
@@ -18535,9 +18633,9 @@ function storeArtifactContent(input) {
18535
18633
  redactionStatus = "redacted";
18536
18634
  }
18537
18635
  const storedSha = sha2562(storedBuffer);
18538
- const relativePath = join6("sha256", storedSha.slice(0, 2), storedSha).replace(/\\/g, "/");
18636
+ const relativePath = join7("sha256", storedSha.slice(0, 2), storedSha).replace(/\\/g, "/");
18539
18637
  const destination = artifactStorePath(relativePath);
18540
- if (!existsSync7(destination)) {
18638
+ if (!existsSync8(destination)) {
18541
18639
  mkdirSync4(dirname4(destination), { recursive: true });
18542
18640
  writeFileSync2(destination, storedBuffer);
18543
18641
  }
@@ -18597,7 +18695,7 @@ function verifyStoredArtifact(input) {
18597
18695
  };
18598
18696
  }
18599
18697
  const storedPath = artifactStorePath(store.relative_path);
18600
- if (!existsSync7(storedPath)) {
18698
+ if (!existsSync8(storedPath)) {
18601
18699
  return {
18602
18700
  id: input.id,
18603
18701
  path: input.path,
@@ -31161,8 +31259,8 @@ var exports_doctor = {};
31161
31259
  __export(exports_doctor, {
31162
31260
  runTodosDoctor: () => runTodosDoctor
31163
31261
  });
31164
- import { chmodSync, copyFileSync, existsSync as existsSync8, mkdirSync as mkdirSync5, statSync as statSync3 } from "fs";
31165
- import { basename as basename2, dirname as dirname5, join as join7 } from "path";
31262
+ import { chmodSync, copyFileSync, existsSync as existsSync9, mkdirSync as mkdirSync5, statSync as statSync3 } from "fs";
31263
+ import { basename as basename2, dirname as dirname5, join as join8 } from "path";
31166
31264
  function tableExists2(db, table) {
31167
31265
  return Boolean(db.query("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(table));
31168
31266
  }
@@ -31256,7 +31354,7 @@ function findMissingProjectRoots(db) {
31256
31354
  continue;
31257
31355
  if (!row.path.startsWith("/"))
31258
31356
  continue;
31259
- if (!existsSync8(row.path))
31357
+ if (!existsSync9(row.path))
31260
31358
  missing++;
31261
31359
  }
31262
31360
  return missing;
@@ -31316,16 +31414,16 @@ function databasePermissionsAreUnsafe(dbPath) {
31316
31414
  function createBackup(dbPath) {
31317
31415
  if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
31318
31416
  return;
31319
- if (!existsSync8(dbPath))
31417
+ if (!existsSync9(dbPath))
31320
31418
  return;
31321
31419
  const stamp = now().replace(/[:.]/g, "-");
31322
- const backupDir = join7(dirname5(dbPath), `${basename2(dbPath)}.backup-${stamp}`);
31420
+ const backupDir = join8(dirname5(dbPath), `${basename2(dbPath)}.backup-${stamp}`);
31323
31421
  const files = [];
31324
31422
  mkdirSync5(backupDir, { recursive: true });
31325
31423
  for (const source of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
31326
- if (!existsSync8(source))
31424
+ if (!existsSync9(source))
31327
31425
  continue;
31328
- const target = join7(backupDir, basename2(source));
31426
+ const target = join8(backupDir, basename2(source));
31329
31427
  copyFileSync(source, target);
31330
31428
  files.push(target);
31331
31429
  }
@@ -31584,7 +31682,7 @@ var init_doctor = __esm(() => {
31584
31682
  });
31585
31683
 
31586
31684
  // src/server/routes.ts
31587
- import { join as join8, resolve as resolve8, sep as sep2 } from "path";
31685
+ import { join as join9, resolve as resolve9, sep as sep2 } from "path";
31588
31686
  function parseFieldsParam(url) {
31589
31687
  const fieldsParam = url.searchParams.get("fields");
31590
31688
  return fieldsParam ? fieldsParam.split(",").map((f) => f.trim()).filter(Boolean) : undefined;
@@ -32421,9 +32519,9 @@ function handleStaticFiles(path, method, ctx, json5, serveStaticFile2) {
32421
32519
  if (!ctx.dashboardExists || method !== "GET" && method !== "HEAD")
32422
32520
  return null;
32423
32521
  if (path !== "/") {
32424
- const filePath = join8(ctx.dashboardDir, path);
32425
- const resolvedFile = resolve8(filePath);
32426
- const resolvedBase = resolve8(ctx.dashboardDir);
32522
+ const filePath = join9(ctx.dashboardDir, path);
32523
+ const resolvedFile = resolve9(filePath);
32524
+ const resolvedBase = resolve9(ctx.dashboardDir);
32427
32525
  if (!resolvedFile.startsWith(resolvedBase + sep2) && resolvedFile !== resolvedBase) {
32428
32526
  return json5({ error: "Forbidden" }, 403);
32429
32527
  }
@@ -32431,7 +32529,7 @@ function handleStaticFiles(path, method, ctx, json5, serveStaticFile2) {
32431
32529
  if (res2)
32432
32530
  return res2;
32433
32531
  }
32434
- const indexPath = join8(ctx.dashboardDir, "index.html");
32532
+ const indexPath = join9(ctx.dashboardDir, "index.html");
32435
32533
  const res = serveStaticFile2(indexPath);
32436
32534
  if (res)
32437
32535
  return res;
@@ -32538,7 +32636,7 @@ class TodosShadowOutbox {
32538
32636
  const remaining = deadline - Date.now();
32539
32637
  if (remaining <= 0)
32540
32638
  break;
32541
- await new Promise((resolve9) => setTimeout(resolve9, Math.min(200, remaining)));
32639
+ await new Promise((resolve10) => setTimeout(resolve10, Math.min(200, remaining)));
32542
32640
  }
32543
32641
  }
32544
32642
  return this.getStats();
@@ -44573,9 +44671,9 @@ data:
44573
44671
  const initRequest = messages.find((m) => isInitializeRequest(m));
44574
44672
  const clientProtocolVersion = initRequest ? initRequest.params.protocolVersion : req.headers.get("mcp-protocol-version") ?? DEFAULT_NEGOTIATED_PROTOCOL_VERSION;
44575
44673
  if (this._enableJsonResponse) {
44576
- return new Promise((resolve9) => {
44674
+ return new Promise((resolve10) => {
44577
44675
  this._streamMapping.set(streamId, {
44578
- resolveJson: resolve9,
44676
+ resolveJson: resolve10,
44579
44677
  cleanup: () => {
44580
44678
  this._streamMapping.delete(streamId);
44581
44679
  }
@@ -47002,7 +47100,7 @@ class Protocol {
47002
47100
  return;
47003
47101
  }
47004
47102
  const pollInterval = task3.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1000;
47005
- await new Promise((resolve9) => setTimeout(resolve9, pollInterval));
47103
+ await new Promise((resolve10) => setTimeout(resolve10, pollInterval));
47006
47104
  options?.signal?.throwIfAborted();
47007
47105
  }
47008
47106
  } catch (error3) {
@@ -47014,7 +47112,7 @@ class Protocol {
47014
47112
  }
47015
47113
  request(request, resultSchema, options) {
47016
47114
  const { relatedRequestId, resumptionToken, onresumptiontoken, task: task2, relatedTask } = options ?? {};
47017
- return new Promise((resolve9, reject) => {
47115
+ return new Promise((resolve10, reject) => {
47018
47116
  const earlyReject = (error3) => {
47019
47117
  reject(error3);
47020
47118
  };
@@ -47092,7 +47190,7 @@ class Protocol {
47092
47190
  if (!parseResult.success) {
47093
47191
  reject(parseResult.error);
47094
47192
  } else {
47095
- resolve9(parseResult.data);
47193
+ resolve10(parseResult.data);
47096
47194
  }
47097
47195
  } catch (error3) {
47098
47196
  reject(error3);
@@ -47283,12 +47381,12 @@ class Protocol {
47283
47381
  interval = task2.pollInterval;
47284
47382
  }
47285
47383
  } catch {}
47286
- return new Promise((resolve9, reject) => {
47384
+ return new Promise((resolve10, reject) => {
47287
47385
  if (signal.aborted) {
47288
47386
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
47289
47387
  return;
47290
47388
  }
47291
- const timeoutId = setTimeout(resolve9, interval);
47389
+ const timeoutId = setTimeout(resolve10, interval);
47292
47390
  signal.addEventListener("abort", () => {
47293
47391
  clearTimeout(timeoutId);
47294
47392
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -50273,7 +50371,7 @@ var require_compile = __commonJS((exports) => {
50273
50371
  const schOrFunc = root.refs[ref];
50274
50372
  if (schOrFunc)
50275
50373
  return schOrFunc;
50276
- let _sch = resolve9.call(this, root, ref);
50374
+ let _sch = resolve10.call(this, root, ref);
50277
50375
  if (_sch === undefined) {
50278
50376
  const schema2 = (_a = root.localRefs) === null || _a === undefined ? undefined : _a[ref];
50279
50377
  const { schemaId } = this.opts;
@@ -50300,7 +50398,7 @@ var require_compile = __commonJS((exports) => {
50300
50398
  function sameSchemaEnv(s1, s2) {
50301
50399
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
50302
50400
  }
50303
- function resolve9(root, ref) {
50401
+ function resolve10(root, ref) {
50304
50402
  let sch;
50305
50403
  while (typeof (sch = this.refs[ref]) == "string")
50306
50404
  ref = sch;
@@ -50886,7 +50984,7 @@ var require_fast_uri = __commonJS((exports, module) => {
50886
50984
  }
50887
50985
  return uri;
50888
50986
  }
50889
- function resolve9(baseURI, relativeURI, options) {
50987
+ function resolve10(baseURI, relativeURI, options) {
50890
50988
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
50891
50989
  const resolved = resolveComponent(parse6(baseURI, schemelessOptions), parse6(relativeURI, schemelessOptions), schemelessOptions, true);
50892
50990
  schemelessOptions.skipEscape = true;
@@ -51145,7 +51243,7 @@ var require_fast_uri = __commonJS((exports, module) => {
51145
51243
  var fastUri = {
51146
51244
  SCHEMES,
51147
51245
  normalize: normalize2,
51148
- resolve: resolve9,
51246
+ resolve: resolve10,
51149
51247
  resolveComponent,
51150
51248
  equal,
51151
51249
  serialize,
@@ -54716,7 +54814,7 @@ class McpServer {
54716
54814
  let task2 = createTaskResult.task;
54717
54815
  const pollInterval = task2.pollInterval ?? 5000;
54718
54816
  while (task2.status !== "completed" && task2.status !== "failed" && task2.status !== "cancelled") {
54719
- await new Promise((resolve9) => setTimeout(resolve9, pollInterval));
54817
+ await new Promise((resolve10) => setTimeout(resolve10, pollInterval));
54720
54818
  const updatedTask = await extra.taskStore.getTask(taskId);
54721
54819
  if (!updatedTask) {
54722
54820
  throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
@@ -55361,12 +55459,12 @@ class StdioServerTransport {
55361
55459
  this.onclose?.();
55362
55460
  }
55363
55461
  send(message) {
55364
- return new Promise((resolve9) => {
55462
+ return new Promise((resolve10) => {
55365
55463
  const json7 = serializeMessage(message);
55366
55464
  if (this._stdout.write(json7)) {
55367
- resolve9();
55465
+ resolve10();
55368
55466
  } else {
55369
- this._stdout.once("drain", resolve9);
55467
+ this._stdout.once("drain", resolve10);
55370
55468
  }
55371
55469
  });
55372
55470
  }
@@ -56515,10 +56613,10 @@ var init_token_utils = __esm(() => {
56515
56613
 
56516
56614
  // src/lib/assignee-validation.ts
56517
56615
  import { readFileSync as readFileSync4 } from "fs";
56518
- import { homedir as homedir3 } from "os";
56519
- import { join as join9 } from "path";
56616
+ import { homedir as homedir5 } from "os";
56617
+ import { join as join10 } from "path";
56520
56618
  function defaultSeatRosterPath() {
56521
- return process.env["TODOS_SEAT_ROSTER_PATH"] || join9(homedir3(), ".hasna", "identities", "hasna-seats.roster.json");
56619
+ return process.env["TODOS_SEAT_ROSTER_PATH"] || join10(homedir5(), ".hasna", "identities", "hasna-seats.roster.json");
56522
56620
  }
56523
56621
  function loadSeatSlugs(path = defaultSeatRosterPath()) {
56524
56622
  try {
@@ -56608,10 +56706,11 @@ var init_assignee_context = __esm(() => {
56608
56706
  init_assignee_validation();
56609
56707
  });
56610
56708
 
56611
- // node_modules/.bun/@hasna+contracts@0.14.0+619f74e7b30eeaf4/node_modules/@hasna/contracts/dist/client/storage.js
56709
+ // node_modules/.bun/@hasna+contracts@0.14.2+a5fb9613d5af3331/node_modules/@hasna/contracts/dist/client/storage.js
56612
56710
  import { isIP } from "net";
56613
56711
  import { readFileSync as readFileSync5, statSync as statSync4 } from "fs";
56614
- import { join as join10 } from "path";
56712
+ import { createRequire } from "module";
56713
+ import { join as join11 } from "path";
56615
56714
  function envToken(name) {
56616
56715
  return name.toUpperCase().replace(/-/g, "_");
56617
56716
  }
@@ -56625,24 +56724,48 @@ function clientTransportEnvKeys(name) {
56625
56724
  function credentialOverrideEnvKey(name) {
56626
56725
  return `HASNA_${envToken(name)}_API_KEY_OVERRIDE`;
56627
56726
  }
56727
+ function credentialPointerEnvKey(name) {
56728
+ return `HASNA_${envToken(name)}_API_KEY_REF`;
56729
+ }
56628
56730
  function homeDir(env) {
56629
56731
  const home = env.HOME?.trim();
56630
56732
  return home ? home : null;
56631
56733
  }
56632
- function credentialDiskSources(name, env) {
56633
- return profileDiskSources(name, env, null);
56634
- }
56635
- function profileDiskSources(name, env, profile) {
56734
+ function credentialDiskSourceList(name, env, profile = null) {
56636
56735
  const home = homeDir(env);
56637
56736
  if (!home || !SAFE_APP_SLUG.test(name))
56638
56737
  return [];
56639
56738
  const stem = profile ? `${name}.${profile}` : name;
56640
56739
  const configStem = profile ? `${name}-${profile}` : name;
56641
56740
  return [
56642
- join10(home, HASNA_STATE_DIR, FLEET_CREDENTIAL_DIR, `${stem}.env`),
56643
- join10(home, CONFIG_DIR, CONFIG_NAMESPACE, `${configStem}-cloud.env`)
56741
+ {
56742
+ path: join11(home, HASNA_STATE_DIR, FLEET_CREDENTIAL_DIR, `${stem}.env`),
56743
+ tier: "fleet-env",
56744
+ deprecated: false
56745
+ },
56746
+ {
56747
+ path: join11(home, HASNA_STATE_DIR, LEGACY_CLOUD_DIR, `${stem}.env`),
56748
+ tier: "legacy-cloud",
56749
+ deprecated: true
56750
+ },
56751
+ {
56752
+ path: join11(home, CONFIG_DIR, CONFIG_NAMESPACE, `${configStem}.env`),
56753
+ tier: "config",
56754
+ deprecated: false
56755
+ },
56756
+ {
56757
+ path: join11(home, CONFIG_DIR, CONFIG_NAMESPACE, `${configStem}-cloud.env`),
56758
+ tier: "config-legacy",
56759
+ deprecated: true
56760
+ }
56644
56761
  ];
56645
56762
  }
56763
+ function credentialDiskSources(name, env) {
56764
+ return credentialDiskSourceList(name, env, null).map((s) => s.path);
56765
+ }
56766
+ function profileDiskSources(name, env, profile) {
56767
+ return credentialDiskSourceList(name, env, profile).map((s) => s.path);
56768
+ }
56646
56769
  function parseEnvFile(text) {
56647
56770
  const values = new Map;
56648
56771
  for (const rawLine of text.split(/\r?\n/)) {
@@ -56709,6 +56832,9 @@ function appConfigDiskValue(name, env, keys) {
56709
56832
  return null;
56710
56833
  }
56711
56834
  function assertUsableCredential(appName, source, value) {
56835
+ if (VAULT_POINTER_SHAPE.test(value)) {
56836
+ throw new CredentialResolutionError(appName, `The credential from ${source} looks like a secrets-vault pointer (a path-shaped reference like ` + `'namespace/app/live/api_key'). A vault path is NEVER accepted as a literal API key. ` + `Use ${credentialPointerEnvKey(appName)} to resolve the key through the vault, or provide the actual key value.`, [source]);
56837
+ }
56712
56838
  if (!ILLEGAL_IN_HEADER_VALUE.test(value))
56713
56839
  return;
56714
56840
  throw new CredentialResolutionError(appName, `The credential from ${source} contains characters that cannot be sent in an HTTP header ` + `(a control character or non-ASCII byte). A file written with CR-only line endings is the usual ` + `cause. Rewrite that credential file with one LF-terminated KEY=value line. ` + `The value is not shown here, and is deliberately never logged.`, [source]);
@@ -56730,6 +56856,14 @@ function sealCredential(fields) {
56730
56856
  writable: false,
56731
56857
  configurable: false
56732
56858
  });
56859
+ if (fields.pointerVaultKey !== undefined) {
56860
+ Object.defineProperty(sealed, "pointerVaultKey", {
56861
+ value: fields.pointerVaultKey,
56862
+ enumerable: false,
56863
+ writable: false,
56864
+ configurable: false
56865
+ });
56866
+ }
56733
56867
  Object.defineProperty(sealed, INSPECT_CUSTOM, {
56734
56868
  value: () => ({ ...visible, apiKey: "[redacted]" }),
56735
56869
  enumerable: false,
@@ -56781,7 +56915,8 @@ function validateAndSealResolvedCredential(appName, credential) {
56781
56915
  deliberate: credential.deliberate,
56782
56916
  deprecated: credential.deprecated,
56783
56917
  diskCandidates: credential.diskCandidates,
56784
- warning: credential.warning
56918
+ warning: credential.warning,
56919
+ ...credential.pointerVaultKey !== undefined ? { pointerVaultKey: credential.pointerVaultKey } : {}
56785
56920
  });
56786
56921
  }
56787
56922
  function firstEnvValue(env, keys) {
@@ -56841,6 +56976,27 @@ function resolveCredential(name, env, options = {}) {
56841
56976
  warning: null
56842
56977
  });
56843
56978
  }
56979
+ const pointerKeyName = credentialPointerEnvKey(name);
56980
+ const pointerRaw = env[pointerKeyName];
56981
+ if (pointerRaw !== undefined) {
56982
+ const pointer = pointerRaw.trim();
56983
+ if (!pointer) {
56984
+ throw new CredentialResolutionError(name, `${pointerKeyName} is set but empty. It is a deliberate vault pointer, so it is not resolved around: ` + `either give it a vault item key or unset it to fall back to the credential on disk.`, [pointerKeyName]);
56985
+ }
56986
+ if (!VAULT_POINTER_SHAPE.test(pointer)) {
56987
+ throw new CredentialResolutionError(name, `${pointerKeyName} must name a vault ITEM KEY (a path-shaped reference like ` + `'namespace/app/live/api_key'), not a credential value. A pointer that carries a literal is refused.`, [pointerKeyName]);
56988
+ }
56989
+ return sealCredential({
56990
+ apiKey: "",
56991
+ pointerVaultKey: pointer,
56992
+ tier: "pointer",
56993
+ source: pointerKeyName,
56994
+ deliberate: true,
56995
+ deprecated: false,
56996
+ diskCandidates: diskPaths,
56997
+ warning: null
56998
+ });
56999
+ }
56844
57000
  const profile = options.profile?.trim() || env[CREDENTIAL_PROFILE_ENV_KEY]?.trim();
56845
57001
  if (profile) {
56846
57002
  const profileSource = options.profile?.trim() ? "explicit profile argument" : CREDENTIAL_PROFILE_ENV_KEY;
@@ -56865,26 +57021,42 @@ function resolveCredential(name, env, options = {}) {
56865
57021
  }
56866
57022
  throw new CredentialResolutionError(name, `Profile '${profile}' (from ${profileSource}) has no ${apiKeyKeys[0]} for '${name}'. ` + `Looked in: ${paths.join(", ") || "<no HOME in this environment>"}. ` + `A profile names WHICH identity to use, so it is never resolved around \u2014 ` + `create the profile's credential file or unset ${CREDENTIAL_PROFILE_ENV_KEY}.`, paths);
56867
57023
  }
56868
- const diskHits = diskPaths.map((path) => ({ path, value: readCredentialFile(path, apiKeyKeys) })).filter((hit) => hit.value !== null);
57024
+ const diskSourceList = credentialDiskSourceList(name, env, null);
57025
+ const diskHits = diskSourceList.map((src) => ({ src, value: readCredentialFile(src.path, apiKeyKeys) })).filter((hit) => hit.value !== null);
56869
57026
  if (diskHits.length > 0) {
56870
57027
  const winner = diskHits[0];
56871
- assertUsableCredential(name, winner.path, winner.value);
57028
+ assertUsableCredential(name, winner.src.path, winner.value);
56872
57029
  const divergentSources = [
56873
- ...diskHits.slice(1).filter((hit) => hit.value !== winner.value).map((hit) => hit.path),
57030
+ ...diskHits.slice(1).filter((hit) => hit.value !== winner.value).map((hit) => hit.src.path),
56874
57031
  ...(() => {
56875
57032
  const legacyHit = firstEnvValue(env, apiKeyKeys);
56876
57033
  return legacyHit && legacyHit.value !== winner.value ? [legacyHit.key] : [];
56877
57034
  })()
56878
57035
  ];
56879
- const warning = divergentSources.length > 0 ? `Credential sources disagree for '${name}': ${winner.path} and ` + `${divergentSources.join(", ")} hold different keys. ${winner.path} wins, because a file on ` + `disk is re-read on every call while an environment variable is a snapshot. Reconcile them \u2014 ` + `a rotation that updated only one leaves the other to fail 401 wherever it is loaded first.` : null;
57036
+ const warning = divergentSources.length > 0 ? `Credential sources disagree for '${name}': ${winner.src.path} and ` + `${divergentSources.join(", ")} hold different keys. ${winner.src.path} wins, because a file on ` + `disk is re-read on every call while an environment variable is a snapshot. Reconcile them \u2014 ` + `a rotation that updated only one leaves the other to fail 401 wherever it is loaded first.` : null;
57037
+ let deprecated = winner.src.deprecated;
57038
+ let finalWarning = warning;
57039
+ if (winner.src.deprecated) {
57040
+ deprecated = true;
57041
+ const sink = options.onDeprecation ?? defaultDeprecationSink;
57042
+ const notified = deprecationNotified();
57043
+ const noticeKey = `${name}:${winner.src.path}`;
57044
+ if (!notified.has(noticeKey)) {
57045
+ notified.add(noticeKey);
57046
+ const target = diskSourceList[0]?.path ?? "<none>";
57047
+ const message = `[${name}] DEPRECATED: the API key came from ${winner.src.path} \u2014 a legacy credential location. ` + `The primary location is ${target} (~/.hasna/fleet-env/<app>.env). The legacy 'cloud' tiers are ` + `removed after ${LEGACY_CLOUD_REMOVAL_DEADLINE}. Migrate the key to the primary location.`;
57048
+ sink(message);
57049
+ }
57050
+ finalWarning = [warning, `Legacy credential source: ${winner.src.path}. Removed after ${LEGACY_CLOUD_REMOVAL_DEADLINE}.`].filter(Boolean).join(" ") || null;
57051
+ }
56880
57052
  return sealCredential({
56881
57053
  apiKey: winner.value,
56882
- tier: "disk",
56883
- source: winner.path,
57054
+ tier: winner.src.tier,
57055
+ source: winner.src.path,
56884
57056
  deliberate: false,
56885
- deprecated: false,
57057
+ deprecated,
56886
57058
  diskCandidates: diskPaths,
56887
- warning
57059
+ warning: finalWarning
56888
57060
  });
56889
57061
  }
56890
57062
  const legacy = firstEnvValue(env, apiKeyKeys);
@@ -56910,6 +57082,45 @@ function resolveCredential(name, env, options = {}) {
56910
57082
  }
56911
57083
  return null;
56912
57084
  }
57085
+ async function completePointerCredential(name, pointerResolution, env = process.env) {
57086
+ const vaultKey = pointerResolution.pointerVaultKey;
57087
+ const pointerEnvKey = pointerResolution.source;
57088
+ if (!vaultKey) {
57089
+ throw new CredentialResolutionError(name, `Pointer resolution from ${pointerEnvKey} carries no vault item key; this is a defect in the resolver.`, [pointerEnvKey]);
57090
+ }
57091
+ let secretsSdk;
57092
+ try {
57093
+ secretsSdk = requireSecretsSdk(SECRETS_PACKAGE_SPECIFIER);
57094
+ } catch {
57095
+ throw new CredentialResolutionError(name, `${pointerEnvKey} names vault item '${vaultKey}', but the secrets SDK (@hasna/secrets) is not installed ` + `in this process. A vault pointer is TERMINAL: install @hasna/secrets to resolve it, or unset ${pointerEnvKey}.`, [pointerEnvKey]);
57096
+ }
57097
+ let client;
57098
+ try {
57099
+ client = secretsSdk.createSecretsClientFromEnv(env);
57100
+ } catch {
57101
+ throw new CredentialResolutionError(name, `${pointerEnvKey} names vault item '${vaultKey}', but the secrets client could not be configured from this ` + `environment (the secrets service URL and key env are missing or invalid). A vault pointer is TERMINAL and ` + `never falls through to a literal or disk credential.`, [pointerEnvKey]);
57102
+ }
57103
+ let secret;
57104
+ try {
57105
+ secret = await client.getSecret({ key: vaultKey });
57106
+ } catch {
57107
+ throw new CredentialResolutionError(name, `${pointerEnvKey} names vault item '${vaultKey}', but the vault could not be reached or the item is ` + `unavailable. A vault pointer is TERMINAL and never falls through to a literal or disk credential.`, [pointerEnvKey]);
57108
+ }
57109
+ const value = secret.value;
57110
+ if (!value) {
57111
+ throw new CredentialResolutionError(name, `${pointerEnvKey} resolved vault item '${vaultKey}', but it holds no value. A vault pointer is TERMINAL.`, [pointerEnvKey]);
57112
+ }
57113
+ assertUsableCredential(name, `${pointerEnvKey} -> vault:${vaultKey}`, value);
57114
+ return sealCredential({
57115
+ apiKey: value,
57116
+ tier: "pointer",
57117
+ source: `${pointerEnvKey} -> vault:${vaultKey}`,
57118
+ deliberate: true,
57119
+ deprecated: false,
57120
+ diskCandidates: pointerResolution.diskCandidates,
57121
+ warning: null
57122
+ });
57123
+ }
56913
57124
  function isValidDnsDomain(value) {
56914
57125
  if (value.length === 0 || value.length > 253 || ASCII_CONTROL_PATTERN.test(value) || /[^\x00-\x7f]/.test(value)) {
56915
57126
  return false;
@@ -57133,6 +57344,13 @@ function currentCredential(name, apiKey) {
57133
57344
  }
57134
57345
  return explicitCredential(name, apiKey);
57135
57346
  }
57347
+ async function resolveRequestCredential(name, apiKey, env = process.env) {
57348
+ const resolved = currentCredential(name, apiKey);
57349
+ if (resolved.tier === "pointer") {
57350
+ return completePointerCredential(name, resolved, env);
57351
+ }
57352
+ return resolved;
57353
+ }
57136
57354
  function authFailureGuidance(credential) {
57137
57355
  const origin = `The API key for this request came from ${credential.source}`;
57138
57356
  if (credential.deliberate) {
@@ -57278,7 +57496,7 @@ function createHasnaHttpTransport(options) {
57278
57496
  const retry = resolveRetry(opts.retry);
57279
57497
  const methodRetryable = IDEMPOTENT_METHODS.has(upper) || Boolean(opts.idempotencyKey);
57280
57498
  const maxAttempts = retry && methodRetryable ? retry.retries + 1 : 1;
57281
- const credential = currentCredential(options.name, options.apiKey);
57499
+ const credential = await resolveRequestCredential(options.name, options.apiKey);
57282
57500
  let last = null;
57283
57501
  for (let attempt = 1;attempt <= maxAttempts; attempt++) {
57284
57502
  const result = await once(upper, rel, url, body2, opts, credential);
@@ -57441,7 +57659,7 @@ function resolveStorageClient(name, env = process.env, overrides) {
57441
57659
  }
57442
57660
  return { transport: "sqlite", client: null };
57443
57661
  }
57444
- var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE", CredentialResolutionError, HASNA_STATE_DIR = ".hasna", FLEET_CREDENTIAL_DIR = "cloud", CONFIG_DIR = ".config", CONFIG_NAMESPACE = "hasna", MAX_CREDENTIAL_FILE_BYTES, SAFE_APP_SLUG, SAFE_PROFILE, ILLEGAL_IN_HEADER_VALUE, CREDENTIAL_SHAPED_KEY, INSPECT_CUSTOM, CREDENTIAL_SEAL, CALLER_SUPPLIED_CREDENTIAL_PROVIDER_SOURCE = "caller-supplied CredentialProvider", DEPRECATION_REGISTRY, ASCII_CONTROL_PATTERN, DNS_LABEL_PATTERN, HasnaHttpError, DEFAULT_RETRY_STATUSES, IDEMPOTENT_METHODS, AUTHORITY_OVERRIDE_HEADERS, defaultSleep = (ms) => new Promise((resolve9) => setTimeout(resolve9, ms));
57662
+ var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE", CredentialResolutionError, HASNA_STATE_DIR = ".hasna", FLEET_CREDENTIAL_DIR = "fleet-env", LEGACY_CLOUD_DIR = "cloud", CONFIG_DIR = ".config", CONFIG_NAMESPACE = "hasna", LEGACY_CLOUD_REMOVAL_DEADLINE = "2026-10-01", MAX_CREDENTIAL_FILE_BYTES, SAFE_APP_SLUG, SAFE_PROFILE, ILLEGAL_IN_HEADER_VALUE, VAULT_POINTER_SHAPE, CREDENTIAL_SHAPED_KEY, INSPECT_CUSTOM, CREDENTIAL_SEAL, CALLER_SUPPLIED_CREDENTIAL_PROVIDER_SOURCE = "caller-supplied CredentialProvider", DEPRECATION_REGISTRY, SECRETS_PACKAGE_SPECIFIER, requireSecretsSdk, ASCII_CONTROL_PATTERN, DNS_LABEL_PATTERN, HasnaHttpError, DEFAULT_RETRY_STATUSES, IDEMPOTENT_METHODS, AUTHORITY_OVERRIDE_HEADERS, defaultSleep = (ms) => new Promise((resolve10) => setTimeout(resolve10, ms));
57445
57663
  var init_storage = __esm(() => {
57446
57664
  CredentialResolutionError = class CredentialResolutionError extends Error {
57447
57665
  appName;
@@ -57457,10 +57675,13 @@ var init_storage = __esm(() => {
57457
57675
  SAFE_APP_SLUG = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
57458
57676
  SAFE_PROFILE = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
57459
57677
  ILLEGAL_IN_HEADER_VALUE = /[^\t\x20-\x7e]/;
57678
+ VAULT_POINTER_SHAPE = /^[a-z0-9][a-z0-9-]*(?:\/[a-z0-9][a-z0-9-_.]*){2,}$/;
57460
57679
  CREDENTIAL_SHAPED_KEY = /(?:^|_)(?:API_KEY|KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|AUTH)(?:_|$)/;
57461
57680
  INSPECT_CUSTOM = Symbol.for("nodejs.util.inspect.custom");
57462
57681
  CREDENTIAL_SEAL = Symbol.for("hasna:contracts:sealedCredential");
57463
57682
  DEPRECATION_REGISTRY = Symbol.for("hasna:contracts:credentialDeprecationNotices");
57683
+ SECRETS_PACKAGE_SPECIFIER = "@hasna/" + "secrets";
57684
+ requireSecretsSdk = createRequire(import.meta.url);
57464
57685
  ASCII_CONTROL_PATTERN = /[\u0000-\u001f\u007f]/;
57465
57686
  DNS_LABEL_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
57466
57687
  HasnaHttpError = class HasnaHttpError extends Error {
@@ -58339,7 +58560,7 @@ var init_page_validation = __esm(() => {
58339
58560
 
58340
58561
  // src/cli/cloud-router.ts
58341
58562
  import { randomUUID as randomUUID4 } from "crypto";
58342
- import { resolve as resolvePath } from "path";
58563
+ import { resolve as resolvePath2 } from "path";
58343
58564
  function emitTodosLocalFallbackNotice(env) {
58344
58565
  if (todosLocalFallbackNoticeEmitted)
58345
58566
  return;
@@ -58399,15 +58620,23 @@ function normalizeRemoteAuthorityUrl(value) {
58399
58620
  if (url.search || url.hash) {
58400
58621
  throw new Error("REMOTE_API_URL_INVALID: HASNA_TODOS_API_URL must not contain a query or fragment; local SQLite fallback is disabled");
58401
58622
  }
58402
- if (url.pathname !== "/" && url.pathname !== "/v1" && url.pathname !== "/v1/") {
58403
- throw new Error("REMOTE_API_URL_INVALID: HASNA_TODOS_API_URL must be an authority root or end in /v1, not /api/v1 or another path; " + "local SQLite fallback is disabled");
58623
+ const path = url.pathname.replace(/\/+$/, "");
58624
+ const segments = path.split("/").filter(Boolean);
58625
+ const reservedGatewaySegments = new Set(["api", "v1"]);
58626
+ const isRoot = path === "";
58627
+ const isV1Root = segments.length === 1 && segments[0] === "v1";
58628
+ const isAppRoot = segments.length === 1 && !reservedGatewaySegments.has(segments[0].toLowerCase());
58629
+ const isAppV1Root = segments.length === 2 && segments[1] === "v1" && !reservedGatewaySegments.has(segments[0].toLowerCase());
58630
+ if (!isRoot && !isV1Root && !isAppRoot && !isAppV1Root) {
58631
+ throw new Error("REMOTE_API_URL_INVALID: HASNA_TODOS_API_URL must be an authority root, /v1, or <app>[/v1], not /api/v1 or another path; " + "local SQLite fallback is disabled");
58404
58632
  }
58405
58633
  const hostname3 = url.hostname.toLowerCase();
58406
58634
  const loopback = hostname3 === "localhost" || hostname3 === "::1" || hostname3 === "[::1]" || /^127(?:\.\d{1,3}){3}$/.test(hostname3);
58407
58635
  if (url.protocol === "http:" && !loopback) {
58408
58636
  throw new Error("REMOTE_API_URL_INVALID: plaintext HTTP is allowed only for loopback Todos authorities; local SQLite fallback is disabled");
58409
58637
  }
58410
- return url.origin;
58638
+ const rootPath = isV1Root || isAppV1Root ? path.slice(0, -"/v1".length) : path;
58639
+ return rootPath ? `${url.origin}${rootPath}` : url.origin;
58411
58640
  }
58412
58641
  function getTodosRemoteAuthorityConfigStatus(env = process.env) {
58413
58642
  let resolution;
@@ -58905,11 +59134,11 @@ function resolveCloudProjectRef(projects, ref) {
58905
59134
  const input = ref.trim();
58906
59135
  const normalizedRef = input.toLowerCase();
58907
59136
  const pathLike = input.startsWith(".") || input.includes("/") || input.includes("\\");
58908
- const normalizedPath = pathLike ? resolvePath(input) : undefined;
59137
+ const normalizedPath = pathLike ? resolvePath2(input) : undefined;
58909
59138
  const slug = cloudProjectSlug(pathLike ? cloudProjectPathBasename(input) : input);
58910
59139
  const matchGroups = [
58911
59140
  uniqueProjectMatches(projects, (project) => project.id.toLowerCase() === normalizedRef),
58912
- uniqueProjectMatches(projects, (project) => project.path === input || normalizedPath !== undefined && resolvePath(project.path) === normalizedPath),
59141
+ uniqueProjectMatches(projects, (project) => project.path === input || normalizedPath !== undefined && resolvePath2(project.path) === normalizedPath),
58913
59142
  uniqueProjectMatches(projects, (project) => project.name.toLowerCase() === normalizedRef),
58914
59143
  uniqueProjectMatches(projects, (project) => project.task_list_id === input || cloudProjectSlug(project.name) === slug || cloudProjectSlug(cloudProjectPathBasename(project.path)) === slug),
58915
59144
  uniqueProjectMatches(projects, (project) => project.id.toLowerCase().startsWith(normalizedRef))
@@ -59493,8 +59722,8 @@ var init_task_crud2 = __esm(() => {
59493
59722
  });
59494
59723
 
59495
59724
  // src/lib/project-bootstrap.ts
59496
- import { existsSync as existsSync9, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
59497
- import { basename as basename3, dirname as dirname6, resolve as resolve9 } from "path";
59725
+ import { existsSync as existsSync10, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
59726
+ import { basename as basename3, dirname as dirname6, resolve as resolve10 } from "path";
59498
59727
  function safeStat(path) {
59499
59728
  try {
59500
59729
  return statSync5(path);
@@ -59503,7 +59732,7 @@ function safeStat(path) {
59503
59732
  }
59504
59733
  }
59505
59734
  function canonicalPath(input) {
59506
- const resolved = resolve9(input);
59735
+ const resolved = resolve10(input);
59507
59736
  const stats = safeStat(resolved);
59508
59737
  if (stats?.isFile())
59509
59738
  return dirname6(resolved);
@@ -59512,7 +59741,7 @@ function canonicalPath(input) {
59512
59741
  function findUp(start, marker) {
59513
59742
  let current = canonicalPath(start);
59514
59743
  while (true) {
59515
- if (existsSync9(resolve9(current, marker)))
59744
+ if (existsSync10(resolve10(current, marker)))
59516
59745
  return current;
59517
59746
  const parent = dirname6(current);
59518
59747
  if (parent === current)
@@ -59523,8 +59752,8 @@ function findUp(start, marker) {
59523
59752
  function readPackageJson(path) {
59524
59753
  if (!path)
59525
59754
  return null;
59526
- const file = resolve9(path, "package.json");
59527
- if (!existsSync9(file))
59755
+ const file = resolve10(path, "package.json");
59756
+ if (!existsSync10(file))
59528
59757
  return null;
59529
59758
  try {
59530
59759
  const parsed = JSON.parse(readFileSync6(file, "utf-8"));
@@ -59546,7 +59775,7 @@ function workspaceMarker(root, rootPackage) {
59546
59775
  if (rootPackage?.workspaces)
59547
59776
  markers.push("package.json#workspaces");
59548
59777
  for (const marker of ["pnpm-workspace.yaml", "turbo.json", "nx.json", "lerna.json", "rush.json", "bun.lock", "bun.lockb"]) {
59549
- if (existsSync9(resolve9(root, marker)))
59778
+ if (existsSync10(resolve10(root, marker)))
59550
59779
  markers.push(marker);
59551
59780
  }
59552
59781
  const kind = markers.find((marker) => marker !== "bun.lock" && marker !== "bun.lockb") ?? null;
@@ -59859,7 +60088,7 @@ var init_tags = __esm(() => {
59859
60088
  });
59860
60089
 
59861
60090
  // src/lib/retention-cleanup.ts
59862
- import { existsSync as existsSync10, unlinkSync } from "fs";
60091
+ import { existsSync as existsSync11, unlinkSync } from "fs";
59863
60092
  function normalizeScopes(scopes) {
59864
60093
  if (!scopes || scopes.length === 0)
59865
60094
  return [...ALL_SCOPES];
@@ -60062,7 +60291,7 @@ function applyRetentionCleanup(input, db) {
60062
60291
  for (const artifact of report.candidates.artifact_files) {
60063
60292
  try {
60064
60293
  const path = artifactStorePath(artifact.relative_path);
60065
- if (!existsSync10(path)) {
60294
+ if (!existsSync11(path)) {
60066
60295
  report.warnings.push(`stored artifact already missing: ${artifact.relative_path}`);
60067
60296
  continue;
60068
60297
  }
@@ -60089,8 +60318,8 @@ var init_retention_cleanup = __esm(() => {
60089
60318
  });
60090
60319
 
60091
60320
  // src/lib/mention-resolver.ts
60092
- import { existsSync as existsSync11, readdirSync as readdirSync2, readFileSync as readFileSync7, statSync as statSync6 } from "fs";
60093
- import { basename as basename4, isAbsolute, join as join11, relative as relative3, resolve as resolve10, sep as sep3 } from "path";
60321
+ import { existsSync as existsSync12, readdirSync as readdirSync2, readFileSync as readFileSync7, statSync as statSync6 } from "fs";
60322
+ import { basename as basename4, isAbsolute, join as join12, relative as relative3, resolve as resolve11, sep as sep3 } from "path";
60094
60323
  function blankResolution(parsed) {
60095
60324
  return {
60096
60325
  input: parsed.input,
@@ -60113,7 +60342,7 @@ function backlink(kind, key2, label, target = key2) {
60113
60342
  return { kind, key: key2, label, target };
60114
60343
  }
60115
60344
  function normalizeWorkspace(workspace) {
60116
- return resolve10(workspace || process.cwd());
60345
+ return resolve11(workspace || process.cwd());
60117
60346
  }
60118
60347
  function isInside(root, absolutePath) {
60119
60348
  const rel = relative3(root, absolutePath);
@@ -60181,14 +60410,14 @@ function resolveFile(parsed, workspace) {
60181
60410
  resolution.warnings.push("path is empty or escapes the workspace");
60182
60411
  return resolution;
60183
60412
  }
60184
- const absolutePath = resolve10(workspace, relPath);
60413
+ const absolutePath = resolve11(workspace, relPath);
60185
60414
  if (!isInside(workspace, absolutePath)) {
60186
60415
  resolution.path = relPath;
60187
60416
  resolution.warnings.push("path escapes the workspace");
60188
60417
  return resolution;
60189
60418
  }
60190
60419
  resolution.path = relPath;
60191
- if (!existsSync11(absolutePath)) {
60420
+ if (!existsSync12(absolutePath)) {
60192
60421
  resolution.warnings.push("file does not exist in the local workspace");
60193
60422
  return resolution;
60194
60423
  }
@@ -60221,7 +60450,7 @@ function walkSourceFiles(root, current = root, files = []) {
60221
60450
  if (SKIP_DIRS.has(entry2.name))
60222
60451
  continue;
60223
60452
  }
60224
- const absolutePath = join11(current, entry2.name);
60453
+ const absolutePath = join12(current, entry2.name);
60225
60454
  if (entry2.isDirectory()) {
60226
60455
  if (!SKIP_DIRS.has(entry2.name))
60227
60456
  walkSourceFiles(root, absolutePath, files);
@@ -60526,9 +60755,9 @@ var init_mention_resolver = __esm(() => {
60526
60755
  });
60527
60756
 
60528
60757
  // src/lib/policy-packs.ts
60529
- import { relative as relative4, resolve as resolve11 } from "path";
60758
+ import { relative as relative4, resolve as resolve12 } from "path";
60530
60759
  function normalizePath3(path) {
60531
- return resolve11(path);
60760
+ return resolve12(path);
60532
60761
  }
60533
60762
  function unique4(values) {
60534
60763
  return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
@@ -60583,7 +60812,7 @@ function commandMatches(commands, pattern) {
60583
60812
  }
60584
60813
  function pathMatches(paths, pattern, root) {
60585
60814
  return paths.filter((path) => {
60586
- const candidate = path.startsWith("/") ? path : resolve11(root, path);
60815
+ const candidate = path.startsWith("/") ? path : resolve12(root, path);
60587
60816
  if (!isPathInside3(root, candidate))
60588
60817
  return matchesPattern3(path, pattern);
60589
60818
  return matchesPattern3(path, pattern) || matchesPattern3(relative4(root, candidate), pattern);
@@ -63962,7 +64191,7 @@ var init_audit_ledger = __esm(() => {
63962
64191
 
63963
64192
  // src/lib/release-compatibility.ts
63964
64193
  import { readFileSync as readFileSync8 } from "fs";
63965
- import { join as join12, resolve as resolve12 } from "path";
64194
+ import { join as join13, resolve as resolve13 } from "path";
63966
64195
  import { Database as Database2 } from "bun:sqlite";
63967
64196
  function pass(id, message, details) {
63968
64197
  return { id, status: "passed", message, details };
@@ -63974,7 +64203,7 @@ function warn(id, message, details) {
63974
64203
  return { id, status: "warning", message, details };
63975
64204
  }
63976
64205
  function readPackageJson2(root) {
63977
- return JSON.parse(readFileSync8(join12(root, "package.json"), "utf8"));
64206
+ return JSON.parse(readFileSync8(join13(root, "package.json"), "utf8"));
63978
64207
  }
63979
64208
  function sortedKeys(value) {
63980
64209
  return Object.keys(value ?? {}).sort((left, right) => left.localeCompare(right));
@@ -64070,7 +64299,7 @@ function checkChangelog() {
64070
64299
  ];
64071
64300
  }
64072
64301
  function createReleaseCompatibilityReport(options = {}) {
64073
- const root = resolve12(options.root ?? process.cwd());
64302
+ const root = resolve13(options.root ?? process.cwd());
64074
64303
  const packageJson = readPackageJson2(root);
64075
64304
  const simulatedLevels = options.simulated_levels ?? defaultSimulationLevels();
64076
64305
  const checks4 = [
@@ -91181,7 +91410,7 @@ var require_protocol = __commonJS((exports) => {
91181
91410
  return;
91182
91411
  }
91183
91412
  const pollInterval = task3.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1000;
91184
- await new Promise((resolve13) => setTimeout(resolve13, pollInterval));
91413
+ await new Promise((resolve14) => setTimeout(resolve14, pollInterval));
91185
91414
  options?.signal?.throwIfAborted();
91186
91415
  }
91187
91416
  } catch (error3) {
@@ -91193,7 +91422,7 @@ var require_protocol = __commonJS((exports) => {
91193
91422
  }
91194
91423
  request(request, resultSchema, options) {
91195
91424
  const { relatedRequestId, resumptionToken, onresumptiontoken, task: task2, relatedTask } = options ?? {};
91196
- return new Promise((resolve13, reject) => {
91425
+ return new Promise((resolve14, reject) => {
91197
91426
  const earlyReject = (error3) => {
91198
91427
  reject(error3);
91199
91428
  };
@@ -91271,7 +91500,7 @@ var require_protocol = __commonJS((exports) => {
91271
91500
  if (!parseResult.success) {
91272
91501
  reject(parseResult.error);
91273
91502
  } else {
91274
- resolve13(parseResult.data);
91503
+ resolve14(parseResult.data);
91275
91504
  }
91276
91505
  } catch (error3) {
91277
91506
  reject(error3);
@@ -91462,12 +91691,12 @@ var require_protocol = __commonJS((exports) => {
91462
91691
  interval = task2.pollInterval;
91463
91692
  }
91464
91693
  } catch {}
91465
- return new Promise((resolve13, reject) => {
91694
+ return new Promise((resolve14, reject) => {
91466
91695
  if (signal.aborted) {
91467
91696
  reject(new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest, "Request cancelled"));
91468
91697
  return;
91469
91698
  }
91470
- const timeoutId = setTimeout(resolve13, interval);
91699
+ const timeoutId = setTimeout(resolve14, interval);
91471
91700
  signal.addEventListener("abort", () => {
91472
91701
  clearTimeout(timeoutId);
91473
91702
  reject(new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest, "Request cancelled"));
@@ -92661,7 +92890,7 @@ var require_mcp = __commonJS((exports) => {
92661
92890
  let task2 = createTaskResult.task;
92662
92891
  const pollInterval = task2.pollInterval ?? 5000;
92663
92892
  while (task2.status !== "completed" && task2.status !== "failed" && task2.status !== "cancelled") {
92664
- await new Promise((resolve13) => setTimeout(resolve13, pollInterval));
92893
+ await new Promise((resolve14) => setTimeout(resolve14, pollInterval));
92665
92894
  const updatedTask = await extra.taskStore.getTask(taskId);
92666
92895
  if (!updatedTask) {
92667
92896
  throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Task ${taskId} not found during polling`);
@@ -93980,7 +94209,7 @@ var init_agent_run_dispatcher = __esm(() => {
93980
94209
  });
93981
94210
 
93982
94211
  // src/lib/verification-providers.ts
93983
- import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
94212
+ import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
93984
94213
  function normalizeName5(name) {
93985
94214
  const normalized = name.trim().toLowerCase();
93986
94215
  if (!/^[a-z0-9][a-z0-9_-]{0,63}$/.test(normalized)) {
@@ -94077,7 +94306,7 @@ function classifyLog(text) {
94077
94306
  async function sleep2(ms) {
94078
94307
  if (ms <= 0)
94079
94308
  return;
94080
- await new Promise((resolve13) => setTimeout(resolve13, ms));
94309
+ await new Promise((resolve14) => setTimeout(resolve14, ms));
94081
94310
  }
94082
94311
  async function runCommandProvider(provider, input) {
94083
94312
  const commandTemplate = input.command || provider.command;
@@ -94132,7 +94361,7 @@ Timed out after ${provider.timeout_ms}ms`);
94132
94361
  };
94133
94362
  }
94134
94363
  function runCiLogProvider(input) {
94135
- const text = input.log_text ?? (input.log_path && existsSync12(input.log_path) ? readFileSync9(input.log_path, "utf-8") : "");
94364
+ const text = input.log_text ?? (input.log_path && existsSync13(input.log_path) ? readFileSync9(input.log_path, "utf-8") : "");
94136
94365
  return {
94137
94366
  status: classifyLog(text),
94138
94367
  attempts: 1,
@@ -94144,7 +94373,7 @@ function runBrowserProvider(input) {
94144
94373
  if (!input.artifact_path) {
94145
94374
  return { status: "unknown", attempts: 1, exit_code: null, output_summary: "browser provider needs a screenshot or artifact path" };
94146
94375
  }
94147
- if (!existsSync12(input.artifact_path)) {
94376
+ if (!existsSync13(input.artifact_path)) {
94148
94377
  return { status: "failed", attempts: 1, exit_code: null, output_summary: `artifact not found: ${input.artifact_path}` };
94149
94378
  }
94150
94379
  return {
@@ -96874,7 +97103,7 @@ var init_local_bridge = __esm(() => {
96874
97103
  // src/lib/local-backups.ts
96875
97104
  import { createHash as createHash12 } from "crypto";
96876
97105
  import { readFileSync as readFileSync10, writeFileSync as writeFileSync3 } from "fs";
96877
- import { dirname as dirname7, resolve as resolve13 } from "path";
97106
+ import { dirname as dirname7, resolve as resolve14 } from "path";
96878
97107
  import { mkdirSync as mkdirSync6 } from "fs";
96879
97108
  function stableJson2(value) {
96880
97109
  if (value === null || typeof value !== "object")
@@ -96976,14 +97205,14 @@ function createLocalBackup(options = {}, db) {
96976
97205
  return backup;
96977
97206
  }
96978
97207
  function writeLocalBackupFile(backup, outputPath) {
96979
- const path = resolve13(outputPath);
97208
+ const path = resolve14(outputPath);
96980
97209
  mkdirSync6(dirname7(path), { recursive: true });
96981
97210
  writeFileSync3(path, `${JSON.stringify(backup, null, 2)}
96982
97211
  `);
96983
97212
  return path;
96984
97213
  }
96985
97214
  function readLocalBackupFile(path) {
96986
- return JSON.parse(readFileSync10(resolve13(path), "utf-8"));
97215
+ return JSON.parse(readFileSync10(resolve14(path), "utf-8"));
96987
97216
  }
96988
97217
  function verifyLocalBackup(value, options = {}, db) {
96989
97218
  const verifiedAt = options.verified_at ?? now();
@@ -98435,8 +98664,8 @@ __export(exports_local_extensions, {
98435
98664
  discoverLocalExtensions: () => discoverLocalExtensions
98436
98665
  });
98437
98666
  import { createHash as createHash15, createVerify } from "crypto";
98438
- import { existsSync as existsSync13, readdirSync as readdirSync3, readFileSync as readFileSync11, statSync as statSync7 } from "fs";
98439
- import { basename as basename5, join as join13, resolve as resolve14 } from "path";
98667
+ import { existsSync as existsSync14, readdirSync as readdirSync3, readFileSync as readFileSync11, statSync as statSync7 } from "fs";
98668
+ import { basename as basename5, join as join14, resolve as resolve15 } from "path";
98440
98669
  function isObject3(value) {
98441
98670
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
98442
98671
  }
@@ -98694,11 +98923,11 @@ function verifyExtensionSignature(input) {
98694
98923
  return verifier.verify(input.public_key, decodeSignature(input.signature));
98695
98924
  }
98696
98925
  function inspectExtensionSource(source3) {
98697
- const resolved = resolve14(source3);
98698
- if (!existsSync13(resolved))
98926
+ const resolved = resolve15(source3);
98927
+ if (!existsSync14(resolved))
98699
98928
  throw new Error(`extension source not found: ${source3}`);
98700
98929
  const stat = statSync7(resolved);
98701
- const manifestPath = stat.isDirectory() ? [join13(resolved, "todos.extension.json"), join13(resolved, "extension.json")].find(existsSync13) : resolved;
98930
+ const manifestPath = stat.isDirectory() ? [join14(resolved, "todos.extension.json"), join14(resolved, "extension.json")].find(existsSync14) : resolved;
98702
98931
  if (!manifestPath)
98703
98932
  throw new Error(`extension directory ${source3} is missing todos.extension.json`);
98704
98933
  const raw = readFileSync11(manifestPath);
@@ -98792,26 +99021,26 @@ function testExtensionCompatibility(sourceOrManifest) {
98792
99021
  function projectExtensionSources(projectPath) {
98793
99022
  if (!projectPath)
98794
99023
  return [];
98795
- const root = resolve14(projectPath);
99024
+ const root = resolve15(projectPath);
98796
99025
  const candidates = [
98797
- join13(root, "todos.extension.json"),
98798
- join13(root, ".todos", "todos.extension.json")
99026
+ join14(root, "todos.extension.json"),
99027
+ join14(root, ".todos", "todos.extension.json")
98799
99028
  ];
98800
- const extensionDir = join13(root, ".todos", "extensions");
98801
- if (existsSync13(extensionDir)) {
99029
+ const extensionDir = join14(root, ".todos", "extensions");
99030
+ if (existsSync14(extensionDir)) {
98802
99031
  for (const entry2 of readdirSync3(extensionDir)) {
98803
99032
  if (entry2.startsWith("."))
98804
99033
  continue;
98805
- const full = join13(extensionDir, entry2);
99034
+ const full = join14(extensionDir, entry2);
98806
99035
  if (statSync7(full).isDirectory() || entry2.endsWith(".json"))
98807
99036
  candidates.push(full);
98808
99037
  }
98809
99038
  }
98810
- return candidates.filter(existsSync13);
99039
+ return candidates.filter(existsSync14);
98811
99040
  }
98812
99041
  function discoverLocalExtensions(options = {}) {
98813
99042
  const config2 = loadConfig();
98814
- const projectPath = options.project_path ? resolve14(options.project_path) : null;
99043
+ const projectPath = options.project_path ? resolve15(options.project_path) : null;
98815
99044
  const configuredSources = [
98816
99045
  ...config2.extension_sources || [],
98817
99046
  ...projectPath ? config2.project_overrides?.[projectPath]?.extension_sources || [] : []
@@ -98819,7 +99048,7 @@ function discoverLocalExtensions(options = {}) {
98819
99048
  const sources = Array.from(new Set([
98820
99049
  ...configuredSources,
98821
99050
  ...projectExtensionSources(projectPath || undefined)
98822
- ])).map((source3) => projectPath && !source3.startsWith("/") ? resolve14(projectPath, source3) : resolve14(source3));
99051
+ ])).map((source3) => projectPath && !source3.startsWith("/") ? resolve15(projectPath, source3) : resolve15(source3));
98823
99052
  const warnings = [];
98824
99053
  const discovered = [];
98825
99054
  for (const source3 of sources) {
@@ -103214,9 +103443,9 @@ __export(exports_extract, {
103214
103443
  buildCodebaseIndex: () => buildCodebaseIndex,
103215
103444
  EXTRACT_TAGS: () => EXTRACT_TAGS
103216
103445
  });
103217
- import { existsSync as existsSync14, readFileSync as readFileSync12, statSync as statSync8 } from "fs";
103446
+ import { existsSync as existsSync15, readFileSync as readFileSync12, statSync as statSync8 } from "fs";
103218
103447
  import { createHash as createHash17 } from "crypto";
103219
- import { relative as relative5, resolve as resolve15, join as join14 } from "path";
103448
+ import { relative as relative5, resolve as resolve16, join as join15 } from "path";
103220
103449
  function stableHash(value) {
103221
103450
  return createHash17("sha256").update(value).digest("hex");
103222
103451
  }
@@ -103224,9 +103453,9 @@ function normalizePathForMatch(value) {
103224
103453
  return value.replace(/\\/g, "/").replace(/^\.\//, "");
103225
103454
  }
103226
103455
  function readGitignorePatterns(basePath) {
103227
- const root = statSync8(basePath).isFile() ? resolve15(basePath, "..") : basePath;
103228
- const gitignorePath = join14(root, ".gitignore");
103229
- if (!existsSync14(gitignorePath))
103456
+ const root = statSync8(basePath).isFile() ? resolve16(basePath, "..") : basePath;
103457
+ const gitignorePath = join15(root, ".gitignore");
103458
+ if (!existsSync15(gitignorePath))
103230
103459
  return [];
103231
103460
  try {
103232
103461
  return readFileSync12(gitignorePath, "utf-8").split(`
@@ -103360,7 +103589,7 @@ function collectFiles(basePath, extensions, excludes, respectGitignore) {
103360
103589
  return files.sort();
103361
103590
  }
103362
103591
  function buildCodebaseIndex(options) {
103363
- const basePath = resolve15(options.path);
103592
+ const basePath = resolve16(options.path);
103364
103593
  const tags = options.patterns || [...EXTRACT_TAGS];
103365
103594
  const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
103366
103595
  const excludes = options.exclude || [];
@@ -103368,10 +103597,10 @@ function buildCodebaseIndex(options) {
103368
103597
  const files = collectFiles(basePath, extensions, excludes, respectGitignore);
103369
103598
  const indexed = [];
103370
103599
  for (const file of files) {
103371
- const fullPath = statSync8(basePath).isFile() ? basePath : join14(basePath, file);
103600
+ const fullPath = statSync8(basePath).isFile() ? basePath : join15(basePath, file);
103372
103601
  try {
103373
103602
  const source3 = readFileSync12(fullPath, "utf-8");
103374
- const relPath = statSync8(basePath).isFile() ? relative5(resolve15(basePath, ".."), fullPath) : file;
103603
+ const relPath = statSync8(basePath).isFile() ? relative5(resolve16(basePath, ".."), fullPath) : file;
103375
103604
  indexed.push({
103376
103605
  file: relPath,
103377
103606
  checksum: stableHash(source3).slice(0, 24),
@@ -103391,7 +103620,7 @@ function buildCodebaseIndex(options) {
103391
103620
  };
103392
103621
  }
103393
103622
  function extractTodos(options, db) {
103394
- const basePath = resolve15(options.path);
103623
+ const basePath = resolve16(options.path);
103395
103624
  const tags = options.patterns || [...EXTRACT_TAGS];
103396
103625
  const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
103397
103626
  const excludes = options.exclude || [];
@@ -103399,10 +103628,10 @@ function extractTodos(options, db) {
103399
103628
  const files = collectFiles(basePath, extensions, excludes, respectGitignore);
103400
103629
  const allComments = [];
103401
103630
  for (const file of files) {
103402
- const fullPath = statSync8(basePath).isFile() ? basePath : join14(basePath, file);
103631
+ const fullPath = statSync8(basePath).isFile() ? basePath : join15(basePath, file);
103403
103632
  try {
103404
103633
  const source3 = readFileSync12(fullPath, "utf-8");
103405
- const relPath = statSync8(basePath).isFile() ? relative5(resolve15(basePath, ".."), fullPath) : file;
103634
+ const relPath = statSync8(basePath).isFile() ? relative5(resolve16(basePath, ".."), fullPath) : file;
103406
103635
  const comments = extractFromSource(source3, relPath, tags);
103407
103636
  allComments.push(...comments);
103408
103637
  } catch {}
@@ -103496,7 +103725,7 @@ async function watchSourceTodos(options, onRun) {
103496
103725
  const interval = Math.max(100, options.interval_ms || 2000);
103497
103726
  const once = options.once !== false && (!options.max_runs || options.max_runs <= 1);
103498
103727
  const maxRuns = options.max_runs ?? (once ? 1 : Number.POSITIVE_INFINITY);
103499
- const root = resolve15(options.path);
103728
+ const root = resolve16(options.path);
103500
103729
  const runs = [];
103501
103730
  let previous = new Map;
103502
103731
  for (let runNumber = 1;runNumber <= maxRuns; runNumber++) {
@@ -104055,7 +104284,7 @@ Last seen: ${agent.last_seen_at}`
104055
104284
  `Suggested names: ${suggestions.slice(0, 8).join(", ")}`,
104056
104285
  allActive.length > 0 ? `Active agents (avoid these names): ${allActive.map((a) => `${a.name} (seen ${Math.round((Date.now() - new Date(a.last_seen_at).getTime()) / 60000)}m ago)`).join(", ")}` : "No active agents.",
104057
104286
  `
104058
- To restrict names, configure agent_pool or project_pools in ~/.hasna/todos/config.json`
104287
+ To restrict names, configure agent_pool or project_pools in the todos data home config file (default <data home>/config.json)`
104059
104288
  ];
104060
104289
  return { content: [{ type: "text", text: lines2.join(`
104061
104290
  `) }] };
@@ -104358,7 +104587,7 @@ __export(exports_builtin_templates, {
104358
104587
  BUILTIN_TEMPLATES: () => BUILTIN_TEMPLATES
104359
104588
  });
104360
104589
  import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync4 } from "fs";
104361
- import { join as join15 } from "path";
104590
+ import { join as join16 } from "path";
104362
104591
  function templateMetadata(template) {
104363
104592
  return {
104364
104593
  source: BUILTIN_TEMPLATE_LIBRARY_SOURCE,
@@ -104417,7 +104646,7 @@ function writeBuiltinTemplateFiles(directory) {
104417
104646
  mkdirSync7(directory, { recursive: true });
104418
104647
  const files = [];
104419
104648
  for (const entry2 of exportBuiltinTemplateFiles()) {
104420
- const path = join15(directory, entry2.filename);
104649
+ const path = join16(directory, entry2.filename);
104421
104650
  writeFileSync4(path, `${JSON.stringify(entry2.template, null, 2)}
104422
104651
  `, "utf-8");
104423
104652
  files.push(path);
@@ -104943,16 +105172,16 @@ __export(exports_environment_snapshots, {
104943
105172
  captureEnvironmentSnapshot: () => captureEnvironmentSnapshot
104944
105173
  });
104945
105174
  import { createHash as createHash18 } from "crypto";
104946
- import { existsSync as existsSync15, readFileSync as readFileSync13, statSync as statSync9 } from "fs";
105175
+ import { existsSync as existsSync16, readFileSync as readFileSync13, statSync as statSync9 } from "fs";
104947
105176
  import { hostname as hostname3, platform, arch } from "os";
104948
- import { dirname as dirname8, join as join16, resolve as resolve16 } from "path";
105177
+ import { dirname as dirname8, join as join17, resolve as resolve17 } from "path";
104949
105178
  import { tmpdir as tmpdir3 } from "os";
104950
105179
  function sha2567(value) {
104951
105180
  return createHash18("sha256").update(value).digest("hex");
104952
105181
  }
104953
105182
  function fileRecord(root, relativePath) {
104954
- const path = join16(root, relativePath);
104955
- if (!existsSync15(path))
105183
+ const path = join17(root, relativePath);
105184
+ if (!existsSync16(path))
104956
105185
  return null;
104957
105186
  const stat = statSync9(path);
104958
105187
  if (!stat.isFile())
@@ -104964,7 +105193,7 @@ function manifestRecord(root, relativePath) {
104964
105193
  const base = fileRecord(root, relativePath);
104965
105194
  if (!base)
104966
105195
  return null;
104967
- const parsed = readJsonFile(join16(root, relativePath));
105196
+ const parsed = readJsonFile(join17(root, relativePath));
104968
105197
  if (!parsed)
104969
105198
  return { ...base, redacted: {} };
104970
105199
  const redacted = redactValue({
@@ -105059,15 +105288,15 @@ function commandEnv(env, includeValues) {
105059
105288
  function defaultSnapshotDir() {
105060
105289
  const dbPath = getDatabasePath();
105061
105290
  if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
105062
- return join16(tmpdir3(), "hasna-todos", "environment-snapshots");
105063
- return join16(dirname8(resolve16(dbPath)), "environment-snapshots");
105291
+ return join17(tmpdir3(), "hasna-todos", "environment-snapshots");
105292
+ return join17(dirname8(resolve17(dbPath)), "environment-snapshots");
105064
105293
  }
105065
105294
  function snapshotWithId(snapshot) {
105066
105295
  const digest4 = sha2567(JSON.stringify(snapshot)).slice(0, 24);
105067
105296
  return { id: `env_${digest4}`, ...snapshot };
105068
105297
  }
105069
105298
  function captureEnvironmentSnapshot(input = {}) {
105070
- const root = resolve16(input.root || process.cwd());
105299
+ const root = resolve17(input.root || process.cwd());
105071
105300
  const env = input.env || process.env;
105072
105301
  const warnings = [];
105073
105302
  const manifests = MANIFEST_FILES.map((file) => manifestRecord(root, file)).filter((file) => Boolean(file));
@@ -105107,13 +105336,13 @@ function captureEnvironmentSnapshot(input = {}) {
105107
105336
  });
105108
105337
  }
105109
105338
  function writeEnvironmentSnapshot(snapshot, outputPath) {
105110
- const path = outputPath ? resolve16(outputPath) : join16(defaultSnapshotDir(), `${snapshot.id}.json`);
105339
+ const path = outputPath ? resolve17(outputPath) : join17(defaultSnapshotDir(), `${snapshot.id}.json`);
105111
105340
  ensureDir(dirname8(path));
105112
105341
  writeJsonFile(path, snapshot);
105113
105342
  return path;
105114
105343
  }
105115
105344
  function readEnvironmentSnapshot(path) {
105116
- const snapshot = readJsonFile(resolve16(path));
105345
+ const snapshot = readJsonFile(resolve17(path));
105117
105346
  if (!snapshot || snapshot.schema_version !== 1 || typeof snapshot.id !== "string") {
105118
105347
  throw new Error(`Invalid environment snapshot: ${path}`);
105119
105348
  }
@@ -105939,8 +106168,8 @@ class SqlitePrGroupLedgerPersistence {
105939
106168
  async transaction(fn) {
105940
106169
  const previous = sqliteTransactionTails2.get(this.db) ?? Promise.resolve();
105941
106170
  let release;
105942
- const current = new Promise((resolve17) => {
105943
- release = resolve17;
106171
+ const current = new Promise((resolve18) => {
106172
+ release = resolve18;
105944
106173
  });
105945
106174
  sqliteTransactionTails2.set(this.db, current);
105946
106175
  await previous;
@@ -106038,27 +106267,27 @@ __export(exports_serve, {
106038
106267
  SECURITY_HEADERS: () => SECURITY_HEADERS,
106039
106268
  MIME_TYPES: () => MIME_TYPES
106040
106269
  });
106041
- import { existsSync as existsSync16 } from "fs";
106042
- import { join as join17, dirname as dirname9, extname } from "path";
106270
+ import { existsSync as existsSync17 } from "fs";
106271
+ import { join as join18, dirname as dirname9, extname } from "path";
106043
106272
  import { fileURLToPath } from "url";
106044
106273
  function resolveDashboardDir() {
106045
106274
  const candidates = [];
106046
106275
  try {
106047
106276
  const scriptDir = dirname9(fileURLToPath(import.meta.url));
106048
- candidates.push(join17(scriptDir, "..", "dashboard", "dist"));
106049
- candidates.push(join17(scriptDir, "..", "..", "dashboard", "dist"));
106277
+ candidates.push(join18(scriptDir, "..", "dashboard", "dist"));
106278
+ candidates.push(join18(scriptDir, "..", "..", "dashboard", "dist"));
106050
106279
  } catch {}
106051
106280
  if (process.argv[1]) {
106052
106281
  const mainDir = dirname9(process.argv[1]);
106053
- candidates.push(join17(mainDir, "..", "dashboard", "dist"));
106054
- candidates.push(join17(mainDir, "..", "..", "dashboard", "dist"));
106282
+ candidates.push(join18(mainDir, "..", "dashboard", "dist"));
106283
+ candidates.push(join18(mainDir, "..", "..", "dashboard", "dist"));
106055
106284
  }
106056
- candidates.push(join17(process.cwd(), "dashboard", "dist"));
106285
+ candidates.push(join18(process.cwd(), "dashboard", "dist"));
106057
106286
  for (const candidate of candidates) {
106058
- if (existsSync16(candidate))
106287
+ if (existsSync17(candidate))
106059
106288
  return candidate;
106060
106289
  }
106061
- return join17(process.cwd(), "dashboard", "dist");
106290
+ return join18(process.cwd(), "dashboard", "dist");
106062
106291
  }
106063
106292
  function getProvidedApiKey(req) {
106064
106293
  const headerKey = req.headers.get("x-api-key");
@@ -106130,7 +106359,7 @@ function json4(data, status3 = 200, headers) {
106130
106359
  });
106131
106360
  }
106132
106361
  function serveStaticFile(filePath) {
106133
- if (!existsSync16(filePath))
106362
+ if (!existsSync17(filePath))
106134
106363
  return null;
106135
106364
  const ext = extname(filePath);
106136
106365
  const contentType2 = MIME_TYPES[ext] || "application/octet-stream";
@@ -106231,7 +106460,7 @@ data: ${data}
106231
106460
  filteredSseClients.delete(client);
106232
106461
  }
106233
106462
  const dashboardDir = resolveDashboardDir();
106234
- const dashboardExists = existsSync16(dashboardDir);
106463
+ const dashboardExists = existsSync17(dashboardDir);
106235
106464
  if (!dashboardExists) {
106236
106465
  console.error(`
106237
106466
  Dashboard not found at: ${dashboardDir}`);