@hasna/todos 0.11.71 → 0.11.72

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -8031,8 +8031,6 @@ function routeEnabledForTask(task, taskList) {
8031
8031
  const explicit = booleanField(task.metadata.route_enabled);
8032
8032
  if (explicit !== undefined)
8033
8033
  return explicit;
8034
- if (task.tags.includes("auto:route") || task.tags.includes("route:enabled"))
8035
- return true;
8036
8034
  const taskListDefault = taskList ? booleanField(taskList.metadata.route_enabled) : undefined;
8037
8035
  if (taskListDefault !== undefined)
8038
8036
  return taskListDefault;
@@ -8054,8 +8052,26 @@ function workflowPointersFromMetadata(metadata) {
8054
8052
  function compactWorkflowPointers(pointers) {
8055
8053
  return Object.fromEntries(Object.entries(pointers).filter(([, value]) => typeof value === "string" && value.length > 0));
8056
8054
  }
8057
- function classifyProjectKind(path) {
8058
- return path.includes("/hasna/opensource/") ? "open-source" : "unknown";
8055
+ function metadataStringField(record, keys) {
8056
+ if (!record)
8057
+ return;
8058
+ for (const key of keys) {
8059
+ const value = record[key];
8060
+ if (typeof value === "string" && value.trim())
8061
+ return value.trim();
8062
+ }
8063
+ return;
8064
+ }
8065
+ function projectKindFromMetadata(...records) {
8066
+ for (const record of records) {
8067
+ const value = metadataStringField(record ?? undefined, ["project_kind", "projectKind", "source_kind", "sourceKind"]);
8068
+ if (value)
8069
+ return value;
8070
+ }
8071
+ return null;
8072
+ }
8073
+ function classifyProjectKind(_path, metadata) {
8074
+ return projectKindFromMetadata(metadata);
8059
8075
  }
8060
8076
  function isWorktreePath(path) {
8061
8077
  return path.includes("/.codewith/worktrees/") || path.includes("/.worktrees/");
@@ -8128,7 +8144,6 @@ function taskEventMetadata(task) {
8128
8144
  metadata.project_canonical_path = projectPath;
8129
8145
  }
8130
8146
  if (projectPath) {
8131
- metadata.project_kind = classifyProjectKind(projectPath);
8132
8147
  metadata.project_is_worktree = isWorktreePath(projectPath);
8133
8148
  metadata.working_dir = task.working_dir ?? projectPath;
8134
8149
  }
@@ -8140,6 +8155,10 @@ function taskEventMetadata(task) {
8140
8155
  metadata.task_list_project_id = taskList.project_id;
8141
8156
  metadata.task_list_is_project_default = Boolean(project?.task_list_id && taskList.slug === project.task_list_id);
8142
8157
  }
8158
+ const projectKind = projectKindFromMetadata(task.metadata, taskList?.metadata);
8159
+ if (projectKind) {
8160
+ metadata.project_kind = classifyProjectKind(projectPath ?? "", { project_kind: projectKind });
8161
+ }
8143
8162
  const routeEnabled = routeEnabledForTask(task, taskList);
8144
8163
  if (routeEnabled !== undefined) {
8145
8164
  metadata.route_enabled = routeEnabled;
@@ -25004,6 +25023,496 @@ function clean2(value) {
25004
25023
  const trimmed = value?.trim();
25005
25024
  return trimmed ? trimmed : undefined;
25006
25025
  }
25026
+ // src/lib/task-route-sources.ts
25027
+ init_database();
25028
+ import { Database as Database3 } from "bun:sqlite";
25029
+ import { createHash as createHash10 } from "crypto";
25030
+ import { existsSync as existsSync9, readdirSync as readdirSync2, statSync as statSync3 } from "fs";
25031
+ import { basename as basename2, dirname as dirname7, join as join10, resolve as resolve10 } from "path";
25032
+ init_redaction();
25033
+
25034
+ // src/lib/task-routing.ts
25035
+ init_database();
25036
+ function machineLocalPath(project, db) {
25037
+ const machineId = process.env["TODOS_MACHINE_ID"];
25038
+ if (!machineId)
25039
+ return null;
25040
+ try {
25041
+ const row = db.query("SELECT path FROM project_machine_paths WHERE project_id = ? AND machine_id = ?").get(project.id, machineId);
25042
+ return row?.path ?? null;
25043
+ } catch {
25044
+ return null;
25045
+ }
25046
+ }
25047
+ function resolveProject(task2, db) {
25048
+ const project = task2.project_id ? getProject(task2.project_id, db) : null;
25049
+ const projectPath = project ? machineLocalPath(project, db) ?? project.path : task2.working_dir;
25050
+ return { project, projectPath: projectPath ?? null };
25051
+ }
25052
+ function resolveTaskList(task2, project, db) {
25053
+ if (task2.task_list_id) {
25054
+ return getTaskList(task2.task_list_id, db) ?? (project ? getTaskListBySlug(task2.task_list_id, project.id, db) : null);
25055
+ }
25056
+ if (project?.task_list_id) {
25057
+ return getTaskListBySlug(project.task_list_id, project.id, db);
25058
+ }
25059
+ return null;
25060
+ }
25061
+ function isTerminal2(status) {
25062
+ return status === "completed" || status === "cancelled" || status === "failed";
25063
+ }
25064
+ function routeConcurrencyKey(task2, project, taskList, projectPath) {
25065
+ if (project?.id)
25066
+ return `project:${project.id}`;
25067
+ if (taskList?.id)
25068
+ return `task-list:${taskList.id}`;
25069
+ if (projectPath)
25070
+ return `path:${projectPath}`;
25071
+ return `task:${task2.id}`;
25072
+ }
25073
+ function getTaskRouteState(taskOrId, db) {
25074
+ const d = db || getDatabase();
25075
+ const task2 = typeof taskOrId === "string" ? getTask(taskOrId, d) : taskOrId;
25076
+ if (!task2)
25077
+ throw new Error(`Task not found: ${taskOrId}`);
25078
+ const { project, projectPath } = resolveProject(task2, d);
25079
+ const taskList = resolveTaskList(task2, project, d);
25080
+ const automation = routingAutomationMetadata(task2, taskList) ?? {};
25081
+ const routeEnabled = routeEnabledForTask(task2, taskList) === true;
25082
+ const tagOptIn = task2.tags.includes("auto:route") || task2.tags.includes("route:enabled");
25083
+ const projectKind = projectKindFromMetadata(task2.metadata, taskList?.metadata);
25084
+ const locked = Boolean(task2.locked_by && !isLockExpired(task2.locked_at));
25085
+ const blockers = getBlockingDeps(task2.id, d);
25086
+ const blocked = blockers.length > 0;
25087
+ const terminal = isTerminal2(task2.status);
25088
+ const requiresApproval = automation.requires_approval === true || task2.requires_approval === true;
25089
+ const approvalRequired = automation.approval_required === true;
25090
+ const approved = Boolean(task2.approved_by);
25091
+ const gates = {
25092
+ route_enabled: routeEnabled,
25093
+ tag_opt_in: tagOptIn,
25094
+ no_auto: automation.no_auto === true,
25095
+ manual: automation.manual === true,
25096
+ manual_required: automation.manual_required === true,
25097
+ requires_approval: requiresApproval,
25098
+ approval_required: approvalRequired,
25099
+ approved,
25100
+ locked,
25101
+ blocked,
25102
+ terminal
25103
+ };
25104
+ const reasons = [];
25105
+ if (task2.status !== "pending")
25106
+ reasons.push("task_not_pending");
25107
+ if (terminal)
25108
+ reasons.push("task_terminal");
25109
+ if (!routeEnabled)
25110
+ reasons.push("route_not_enabled");
25111
+ if (locked)
25112
+ reasons.push("task_locked");
25113
+ if (blocked)
25114
+ reasons.push("task_blocked");
25115
+ if (gates.no_auto)
25116
+ reasons.push("no_auto");
25117
+ if (gates.manual)
25118
+ reasons.push("manual");
25119
+ if (gates.manual_required)
25120
+ reasons.push("manual_required");
25121
+ if (requiresApproval && !approved)
25122
+ reasons.push("requires_approval");
25123
+ if (approvalRequired && !approved)
25124
+ reasons.push("approval_required");
25125
+ if (automation.allowed === false)
25126
+ reasons.push("automation_disallowed");
25127
+ return {
25128
+ schema_version: TODOS_TASK_ROUTE_STATE_SCHEMA_VERSION,
25129
+ task_id: task2.id,
25130
+ task_short_id: task2.short_id,
25131
+ status: task2.status,
25132
+ eligible: reasons.length === 0,
25133
+ reasons,
25134
+ blockers: blockers.map((blocker) => ({
25135
+ id: blocker.id,
25136
+ short_id: blocker.short_id,
25137
+ title: blocker.title,
25138
+ status: blocker.status
25139
+ })),
25140
+ gates,
25141
+ automation: Object.keys(automation).length > 0 ? automation : null,
25142
+ route: {
25143
+ project_id: project?.id ?? task2.project_id,
25144
+ project_path: projectPath,
25145
+ working_dir: task2.working_dir ?? projectPath,
25146
+ project_kind: projectKind,
25147
+ task_list_id: taskList?.id ?? task2.task_list_id,
25148
+ task_list_slug: taskList?.slug ?? null,
25149
+ task_list_name: taskList?.name ?? null,
25150
+ concurrency_key: routeConcurrencyKey(task2, project, taskList, projectPath)
25151
+ },
25152
+ pointers: workflowPointersFromMetadata(task2.metadata)
25153
+ };
25154
+ }
25155
+ function setTaskWorkflowPointers(taskId, input, db) {
25156
+ const d = db || getDatabase();
25157
+ const task2 = getTask(taskId, d);
25158
+ if (!task2)
25159
+ throw new Error(`Task not found: ${taskId}`);
25160
+ const previous = workflowPointersFromMetadata(task2.metadata);
25161
+ const next = compactWorkflowPointers({
25162
+ current_workflow_invocation_id: pointerPatch(previous.current_workflow_invocation_id, input, "current_workflow_invocation_id"),
25163
+ current_run_id: pointerPatch(previous.current_run_id, input, "current_run_id"),
25164
+ latest_manifest_path: pointerPatch(previous.latest_manifest_path, input, "latest_manifest_path"),
25165
+ latest_evaluation_path: pointerPatch(previous.latest_evaluation_path, input, "latest_evaluation_path"),
25166
+ workflow_state: pointerPatch(previous.workflow_state, input, "workflow_state")
25167
+ });
25168
+ const timestamp2 = now();
25169
+ const {
25170
+ current_workflow_invocation_id,
25171
+ current_run_id,
25172
+ latest_manifest_path,
25173
+ latest_evaluation_path,
25174
+ workflow_state,
25175
+ workflow_invocation,
25176
+ ...baseMetadata
25177
+ } = task2.metadata;
25178
+ const metadata = {
25179
+ ...baseMetadata,
25180
+ ...next,
25181
+ workflow_invocation: {
25182
+ schema_version: TASK_WORKFLOW_POINTER_SCHEMA_VERSION,
25183
+ ...next,
25184
+ updated_at: timestamp2,
25185
+ updated_by: input.actor ?? null
25186
+ }
25187
+ };
25188
+ return updateTask(task2.id, { version: task2.version, metadata }, d);
25189
+ }
25190
+ function pointerPatch(previous, input, key) {
25191
+ if (!Object.prototype.hasOwnProperty.call(input, key))
25192
+ return previous;
25193
+ const value = input[key];
25194
+ if (value === undefined)
25195
+ return previous;
25196
+ return typeof value === "string" && value.trim() ? value : undefined;
25197
+ }
25198
+
25199
+ // src/lib/task-route-sources.ts
25200
+ var TASK_ROUTE_SOURCE_DISCOVERY_SCHEMA_VERSION = "todos.task_route_sources.v1";
25201
+ var TODO_STORE_RELATIVE_PATH = join10(".hasna", "todos", "todos.db");
25202
+ var ROOT_SCAN_MAX_DEPTH = 5;
25203
+ var SKIPPED_SCAN_DIRS = new Set([
25204
+ ".git",
25205
+ ".hg",
25206
+ ".svn",
25207
+ "node_modules",
25208
+ "dist",
25209
+ "build",
25210
+ ".next",
25211
+ ".turbo",
25212
+ ".cache"
25213
+ ]);
25214
+ function normalizePath3(input) {
25215
+ return resolve10(input);
25216
+ }
25217
+ function sourceStoreId(sourceDbPath) {
25218
+ const digest = createHash10("sha256").update(sourceDbPath).digest("hex").slice(0, 16);
25219
+ return `sqlite:${digest}`;
25220
+ }
25221
+ function inferSourceRepoPath(sourceDbPath) {
25222
+ const normalized = normalizePath3(sourceDbPath);
25223
+ if (normalized.endsWith(TODO_STORE_RELATIVE_PATH)) {
25224
+ return dirname7(dirname7(dirname7(normalized)));
25225
+ }
25226
+ return dirname7(normalized);
25227
+ }
25228
+ function createStoreRef(sourceDbPath) {
25229
+ const normalized = normalizePath3(sourceDbPath);
25230
+ return {
25231
+ source_store_id: sourceStoreId(normalized),
25232
+ source_repo_path: inferSourceRepoPath(normalized),
25233
+ source_db_path: normalized
25234
+ };
25235
+ }
25236
+ function normalizePatterns(patterns) {
25237
+ return (patterns ?? []).map((pattern) => pattern.trim()).filter(Boolean);
25238
+ }
25239
+ function escapeRegExp(value) {
25240
+ return value.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
25241
+ }
25242
+ function globPatternToRegExp(pattern) {
25243
+ let source9 = "";
25244
+ for (const char of pattern) {
25245
+ if (char === "*")
25246
+ source9 += ".*";
25247
+ else if (char === "?")
25248
+ source9 += ".";
25249
+ else
25250
+ source9 += escapeRegExp(char);
25251
+ }
25252
+ return new RegExp(`^${source9}$`);
25253
+ }
25254
+ function matchesPattern3(value, pattern) {
25255
+ const normalizedValue = value.replace(/\\/g, "/");
25256
+ const normalizedPattern = pattern.replace(/\\/g, "/");
25257
+ if (normalizedPattern.includes("*") || normalizedPattern.includes("?")) {
25258
+ return globPatternToRegExp(normalizedPattern).test(normalizedValue);
25259
+ }
25260
+ return normalizedValue.includes(normalizedPattern);
25261
+ }
25262
+ function storeMatchesAny(ref, patterns) {
25263
+ if (patterns.length === 0)
25264
+ return false;
25265
+ const paths = [ref.source_db_path, ref.source_repo_path].filter((value) => Boolean(value));
25266
+ const values = paths.flatMap((value) => [value, basename2(value)]);
25267
+ return patterns.some((pattern) => values.some((value) => matchesPattern3(value, pattern)));
25268
+ }
25269
+ function shouldIncludeStore(ref, include, exclude) {
25270
+ const included = include.length === 0 || storeMatchesAny(ref, include);
25271
+ return included && !storeMatchesAny(ref, exclude);
25272
+ }
25273
+ function discoverStoresUnderRoot(sourceRoot) {
25274
+ const rootPath = normalizePath3(sourceRoot);
25275
+ const errors = [];
25276
+ const stores = [];
25277
+ if (!existsSync9(rootPath)) {
25278
+ const ref = createStoreRef(join10(rootPath, TODO_STORE_RELATIVE_PATH));
25279
+ errors.push({
25280
+ ...ref,
25281
+ code: "SOURCE_ROOT_MISSING",
25282
+ message: `Source root does not exist: ${rootPath}`
25283
+ });
25284
+ return { stores, errors };
25285
+ }
25286
+ let rootStat;
25287
+ try {
25288
+ rootStat = statSync3(rootPath);
25289
+ } catch (error) {
25290
+ const ref = createStoreRef(join10(rootPath, TODO_STORE_RELATIVE_PATH));
25291
+ errors.push({
25292
+ ...ref,
25293
+ code: "SOURCE_ROOT_UNREADABLE",
25294
+ message: error instanceof Error ? error.message : `Unable to read source root: ${rootPath}`
25295
+ });
25296
+ return { stores, errors };
25297
+ }
25298
+ if (rootStat.isFile()) {
25299
+ stores.push(createStoreRef(rootPath));
25300
+ return { stores, errors };
25301
+ }
25302
+ function scanDirectory(dir, depth) {
25303
+ const candidate = join10(dir, TODO_STORE_RELATIVE_PATH);
25304
+ if (existsSync9(candidate)) {
25305
+ stores.push(createStoreRef(candidate));
25306
+ }
25307
+ if (depth >= ROOT_SCAN_MAX_DEPTH)
25308
+ return;
25309
+ let entries;
25310
+ try {
25311
+ entries = readdirSync2(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
25312
+ } catch (error) {
25313
+ const ref = createStoreRef(candidate);
25314
+ errors.push({
25315
+ ...ref,
25316
+ code: "SOURCE_ROOT_UNREADABLE",
25317
+ message: error instanceof Error ? error.message : `Unable to read source root: ${dir}`
25318
+ });
25319
+ return;
25320
+ }
25321
+ for (const entry2 of entries) {
25322
+ if (!entry2.isDirectory() || SKIPPED_SCAN_DIRS.has(entry2.name))
25323
+ continue;
25324
+ scanDirectory(join10(dir, entry2.name), depth + 1);
25325
+ }
25326
+ }
25327
+ scanDirectory(rootPath, 0);
25328
+ return { stores, errors };
25329
+ }
25330
+ function collectStoreRefs(input) {
25331
+ const byPath = new Map;
25332
+ const errors = [];
25333
+ for (const storePath of input.sourceStores ?? []) {
25334
+ const ref = createStoreRef(storePath);
25335
+ byPath.set(ref.source_db_path, ref);
25336
+ }
25337
+ for (const sourceRoot of input.sourceRoots ?? []) {
25338
+ const discovered = discoverStoresUnderRoot(sourceRoot);
25339
+ for (const ref of discovered.stores) {
25340
+ byPath.set(ref.source_db_path, ref);
25341
+ }
25342
+ errors.push(...discovered.errors);
25343
+ }
25344
+ return {
25345
+ stores: [...byPath.values()].sort((a, b) => a.source_db_path.localeCompare(b.source_db_path)),
25346
+ errors: errors.sort((a, b) => a.source_db_path.localeCompare(b.source_db_path))
25347
+ };
25348
+ }
25349
+ function openReadonlyStore(ref) {
25350
+ if (!existsSync9(ref.source_db_path)) {
25351
+ throw Object.assign(new Error(`Store does not exist: ${ref.source_db_path}`), { code: "STORE_MISSING" });
25352
+ }
25353
+ return new Database3(ref.source_db_path, { readonly: true, create: false });
25354
+ }
25355
+ function hasTable2(db, tableName) {
25356
+ const row = db.query("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?").get(tableName);
25357
+ return Boolean(row);
25358
+ }
25359
+ function tableColumns2(db, tableName) {
25360
+ const rows = db.query(`PRAGMA table_info(${tableName})`).all();
25361
+ return new Set(rows.map((row) => row.name));
25362
+ }
25363
+ function listPendingTasksReadonly(db) {
25364
+ if (!hasTable2(db, "tasks")) {
25365
+ throw Object.assign(new Error("Store does not contain a tasks table"), { code: "STORE_INVALID" });
25366
+ }
25367
+ const columns = tableColumns2(db, "tasks");
25368
+ const conditions = ["status = 'pending'"];
25369
+ if (columns.has("archived_at"))
25370
+ conditions.push("archived_at IS NULL");
25371
+ const rows = db.query(`SELECT * FROM tasks WHERE ${conditions.join(" AND ")}
25372
+ ORDER BY CASE priority WHEN 'critical' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 WHEN 'low' THEN 3 END, created_at DESC`).all();
25373
+ return rows.map(rowToTask);
25374
+ }
25375
+ function isReadyTask(task2, db) {
25376
+ if (task2.locked_by && !isLockExpired(task2.locked_at))
25377
+ return false;
25378
+ return getBlockingDeps(task2.id, db).length === 0;
25379
+ }
25380
+ function metadataFingerprint(metadata) {
25381
+ const value = metadata.fingerprint;
25382
+ if (typeof value === "string" && value.trim())
25383
+ return value;
25384
+ if (typeof value === "number" && Number.isFinite(value))
25385
+ return String(value);
25386
+ return null;
25387
+ }
25388
+ function boundedMetadataValue(value, depth = 0) {
25389
+ if (depth > 6)
25390
+ return "[TRUNCATED]";
25391
+ if (typeof value === "string") {
25392
+ return value.length > 2000 ? `${value.slice(0, 2000)}[TRUNCATED]` : value;
25393
+ }
25394
+ if (Array.isArray(value)) {
25395
+ return value.slice(0, 50).map((item) => boundedMetadataValue(item, depth + 1));
25396
+ }
25397
+ if (value && typeof value === "object") {
25398
+ const result = {};
25399
+ for (const [key, child] of Object.entries(value).slice(0, 80)) {
25400
+ const normalized = key.toLowerCase();
25401
+ if (normalized === "comment" || normalized === "comments" || normalized === "task_comments") {
25402
+ result[key] = "[REDACTED_COMMENT]";
25403
+ continue;
25404
+ }
25405
+ result[key] = boundedMetadataValue(child, depth + 1);
25406
+ }
25407
+ return result;
25408
+ }
25409
+ return value;
25410
+ }
25411
+ function discoveryMetadata(metadata) {
25412
+ return redactValue(boundedMetadataValue(metadata));
25413
+ }
25414
+ function sourceCandidate(ref, task2, db) {
25415
+ const routeState = getTaskRouteState(task2, db);
25416
+ const autoRoute = task2.tags.includes("auto:route") || task2.tags.includes("route:enabled");
25417
+ return {
25418
+ source_store_id: ref.source_store_id,
25419
+ source_repo_path: ref.source_repo_path,
25420
+ source_db_path: ref.source_db_path,
25421
+ source_task_key: `${ref.source_store_id}:${task2.id}`,
25422
+ source_selected_by_input: true,
25423
+ task_id: task2.id,
25424
+ task_short_id: task2.short_id,
25425
+ title: task2.title,
25426
+ status: task2.status,
25427
+ priority: task2.priority,
25428
+ project_path: routeState.route.project_path ?? task2.working_dir ?? ref.source_repo_path,
25429
+ task_version: task2.version,
25430
+ task_updated_at: task2.updated_at,
25431
+ task_fingerprint: metadataFingerprint(task2.metadata),
25432
+ tags: task2.tags,
25433
+ task_intent: {
25434
+ auto_route: autoRoute
25435
+ },
25436
+ metadata: discoveryMetadata(task2.metadata),
25437
+ route_state: routeState
25438
+ };
25439
+ }
25440
+ function discoveryError(ref, code, error) {
25441
+ return {
25442
+ ...ref,
25443
+ code,
25444
+ message: error instanceof Error ? error.message : String(error)
25445
+ };
25446
+ }
25447
+ function errorCode(error) {
25448
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "STORE_MISSING") {
25449
+ return "STORE_MISSING";
25450
+ }
25451
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "STORE_INVALID") {
25452
+ return "STORE_INVALID";
25453
+ }
25454
+ return "STORE_UNREADABLE";
25455
+ }
25456
+ function discoverTaskRouteSources(input) {
25457
+ const include = normalizePatterns(input.include);
25458
+ const exclude = normalizePatterns(input.exclude);
25459
+ const sourceRoots = (input.sourceRoots ?? []).map(normalizePath3).sort();
25460
+ const sourceStores = (input.sourceStores ?? []).map(normalizePath3).sort();
25461
+ const limit = Number.isFinite(input.limit ?? NaN) && (input.limit ?? 0) >= 0 ? Math.floor(input.limit ?? 0) : null;
25462
+ const collected = collectStoreRefs(input);
25463
+ const stores = [];
25464
+ const errors = [...collected.errors];
25465
+ const candidates = [];
25466
+ let totalCandidateCount = 0;
25467
+ for (const ref of collected.stores) {
25468
+ if (!shouldIncludeStore(ref, include, exclude))
25469
+ continue;
25470
+ const storeErrors = [];
25471
+ let db = null;
25472
+ try {
25473
+ db = openReadonlyStore(ref);
25474
+ const readyTasks = listPendingTasksReadonly(db).filter((task2) => isReadyTask(task2, db));
25475
+ totalCandidateCount += readyTasks.length;
25476
+ const remaining = limit === null ? readyTasks.length : Math.max(0, limit - candidates.length);
25477
+ const selectedTasks = limit === null ? readyTasks : readyTasks.slice(0, remaining);
25478
+ candidates.push(...selectedTasks.map((task2) => sourceCandidate(ref, task2, db)));
25479
+ stores.push({
25480
+ ...ref,
25481
+ status: "ok",
25482
+ candidate_count: readyTasks.length,
25483
+ returned_candidate_count: selectedTasks.length,
25484
+ errors: []
25485
+ });
25486
+ } catch (error) {
25487
+ const storeError = discoveryError(ref, errorCode(error), error);
25488
+ storeErrors.push(storeError);
25489
+ errors.push(storeError);
25490
+ stores.push({
25491
+ ...ref,
25492
+ status: storeError.code === "STORE_MISSING" ? "missing" : "error",
25493
+ candidate_count: 0,
25494
+ returned_candidate_count: 0,
25495
+ errors: storeErrors
25496
+ });
25497
+ } finally {
25498
+ db?.close();
25499
+ }
25500
+ }
25501
+ return {
25502
+ schema_version: TASK_ROUTE_SOURCE_DISCOVERY_SCHEMA_VERSION,
25503
+ sourceRoots,
25504
+ sourceStores,
25505
+ include,
25506
+ exclude,
25507
+ limit,
25508
+ total_candidate_count: totalCandidateCount,
25509
+ returned_candidate_count: candidates.length,
25510
+ truncated: limit !== null && totalCandidateCount > candidates.length,
25511
+ stores,
25512
+ candidates,
25513
+ errors
25514
+ };
25515
+ }
25007
25516
 
25008
25517
  // src/index.ts
25009
25518
  init_database();
@@ -25141,8 +25650,8 @@ function listCyclesWithStats(options = {}, db) {
25141
25650
  }
25142
25651
  // src/lib/plan-artifacts.ts
25143
25652
  init_database();
25144
- import { existsSync as existsSync9, mkdirSync as mkdirSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
25145
- import { join as join10, resolve as resolve10 } from "path";
25653
+ import { existsSync as existsSync10, mkdirSync as mkdirSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
25654
+ import { join as join11, resolve as resolve11 } from "path";
25146
25655
  var PLAN_MARKDOWN_SCHEMA = "hasna.todos.plan/v1";
25147
25656
  function assertSafePathSegment(value, label) {
25148
25657
  const trimmed = value.trim();
@@ -25186,7 +25695,7 @@ function resolvePlanArtifactProject(input) {
25186
25695
  const ref = input.project_id || input.project_ref;
25187
25696
  if (!ref)
25188
25697
  throw new Error("Plan artifacts require a project id or project reference");
25189
- const byPath = getProjectByPath(resolve10(ref), db);
25698
+ const byPath = getProjectByPath(resolve11(ref), db);
25190
25699
  if (byPath)
25191
25700
  return byPath;
25192
25701
  const resolvedId = resolvePartialId(db, "projects", ref);
@@ -25203,8 +25712,8 @@ function resolvePlanArtifactProject(input) {
25203
25712
  function resolvePlanArtifactPaths(input) {
25204
25713
  const project = resolvePlanArtifactProject(input);
25205
25714
  const projectId = assertSafePathSegment(project.id, "project id");
25206
- const projectRoot = resolve10(project.path);
25207
- const directory = join10(projectRoot, ".hasna", "todos", "plans", projectId);
25715
+ const projectRoot = resolve11(project.path);
25716
+ const directory = join11(projectRoot, ".hasna", "todos", "plans", projectId);
25208
25717
  const planId = input.plan_id ? assertSafePathSegment(input.plan_id, "plan id") : null;
25209
25718
  const planSlug = input.plan_slug ? assertSafePathSegment(slugify(input.plan_slug), "plan slug") : null;
25210
25719
  const fileName = planId ? planSlug ? `${planSlug}--${planId.slice(0, 8)}.md` : `${planId}.md` : null;
@@ -25212,7 +25721,7 @@ function resolvePlanArtifactPaths(input) {
25212
25721
  project_id: project.id,
25213
25722
  project_root: projectRoot,
25214
25723
  directory,
25215
- file_path: fileName ? join10(directory, fileName) : directory
25724
+ file_path: fileName ? join11(directory, fileName) : directory
25216
25725
  };
25217
25726
  }
25218
25727
  function resolvePlanArtifactCandidatePaths(plan, db) {
@@ -25378,7 +25887,7 @@ function readPlanArtifact(plan, db) {
25378
25887
  return null;
25379
25888
  const d = db || getDatabase();
25380
25889
  const paths = resolvePlanArtifactCandidatePaths(plan, d);
25381
- const path = existsSync9(paths.primary.file_path) ? paths.primary.file_path : existsSync9(paths.legacy.file_path) ? paths.legacy.file_path : null;
25890
+ const path = existsSync10(paths.primary.file_path) ? paths.primary.file_path : existsSync10(paths.legacy.file_path) ? paths.legacy.file_path : null;
25382
25891
  if (!path)
25383
25892
  return null;
25384
25893
  const markdown = readFileSync7(path, "utf8");
@@ -25393,7 +25902,7 @@ function inspectPlanArtifact(plan, db) {
25393
25902
  return null;
25394
25903
  const d = db || getDatabase();
25395
25904
  const paths = resolvePlanArtifactCandidatePaths(plan, d);
25396
- const path = existsSync9(paths.primary.file_path) ? paths.primary.file_path : existsSync9(paths.legacy.file_path) ? paths.legacy.file_path : null;
25905
+ const path = existsSync10(paths.primary.file_path) ? paths.primary.file_path : existsSync10(paths.legacy.file_path) ? paths.legacy.file_path : null;
25397
25906
  if (!path) {
25398
25907
  return {
25399
25908
  path: paths.primary.file_path,
@@ -26479,28 +26988,28 @@ function renderRetrospectiveMarkdown(record) {
26479
26988
  }
26480
26989
  // src/lib/project-bootstrap.ts
26481
26990
  init_database();
26482
- import { existsSync as existsSync10, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
26483
- import { basename as basename2, dirname as dirname7, resolve as resolve11 } from "path";
26991
+ import { existsSync as existsSync11, readFileSync as readFileSync8, statSync as statSync4 } from "fs";
26992
+ import { basename as basename3, dirname as dirname8, resolve as resolve12 } from "path";
26484
26993
  function safeStat(path) {
26485
26994
  try {
26486
- return statSync3(path);
26995
+ return statSync4(path);
26487
26996
  } catch {
26488
26997
  return null;
26489
26998
  }
26490
26999
  }
26491
27000
  function canonicalPath(input) {
26492
- const resolved = resolve11(input);
27001
+ const resolved = resolve12(input);
26493
27002
  const stats2 = safeStat(resolved);
26494
27003
  if (stats2?.isFile())
26495
- return dirname7(resolved);
27004
+ return dirname8(resolved);
26496
27005
  return resolved;
26497
27006
  }
26498
27007
  function findUp(start, marker) {
26499
27008
  let current = canonicalPath(start);
26500
27009
  while (true) {
26501
- if (existsSync10(resolve11(current, marker)))
27010
+ if (existsSync11(resolve12(current, marker)))
26502
27011
  return current;
26503
- const parent = dirname7(current);
27012
+ const parent = dirname8(current);
26504
27013
  if (parent === current)
26505
27014
  return null;
26506
27015
  current = parent;
@@ -26509,8 +27018,8 @@ function findUp(start, marker) {
26509
27018
  function readPackageJson2(path) {
26510
27019
  if (!path)
26511
27020
  return null;
26512
- const file = resolve11(path, "package.json");
26513
- if (!existsSync10(file))
27021
+ const file = resolve12(path, "package.json");
27022
+ if (!existsSync11(file))
26514
27023
  return null;
26515
27024
  try {
26516
27025
  const parsed = JSON.parse(readFileSync8(file, "utf-8"));
@@ -26521,9 +27030,9 @@ function readPackageJson2(path) {
26521
27030
  }
26522
27031
  function packageDisplayName(name, fallbackPath) {
26523
27032
  if (!name)
26524
- return basename2(fallbackPath);
27033
+ return basename3(fallbackPath);
26525
27034
  const withoutScope = name.startsWith("@") ? name.split("/")[1] : name;
26526
- return withoutScope || basename2(fallbackPath);
27035
+ return withoutScope || basename3(fallbackPath);
26527
27036
  }
26528
27037
  function workspaceMarker(root, rootPackage) {
26529
27038
  if (!root)
@@ -26532,7 +27041,7 @@ function workspaceMarker(root, rootPackage) {
26532
27041
  if (rootPackage?.workspaces)
26533
27042
  markers.push("package.json#workspaces");
26534
27043
  for (const marker of ["pnpm-workspace.yaml", "turbo.json", "nx.json", "lerna.json", "rush.json", "bun.lock", "bun.lockb"]) {
26535
- if (existsSync10(resolve11(root, marker)))
27044
+ if (existsSync11(resolve12(root, marker)))
26536
27045
  markers.push(marker);
26537
27046
  }
26538
27047
  const kind = markers.find((marker) => marker !== "bun.lock" && marker !== "bun.lockb") ?? null;
@@ -26650,177 +27159,9 @@ function getProjectByPathForBootstrap(path, db) {
26650
27159
  WHERE pmp.path = ?`).get(path);
26651
27160
  return machineRow ?? null;
26652
27161
  }
26653
- // src/lib/task-routing.ts
26654
- init_database();
26655
- function classifyProjectKind2(path) {
26656
- if (!path)
26657
- return null;
26658
- return path.includes("/hasna/opensource/") ? "open-source" : "unknown";
26659
- }
26660
- function machineLocalPath(project, db) {
26661
- const machineId = process.env["TODOS_MACHINE_ID"];
26662
- if (!machineId)
26663
- return null;
26664
- try {
26665
- const row = db.query("SELECT path FROM project_machine_paths WHERE project_id = ? AND machine_id = ?").get(project.id, machineId);
26666
- return row?.path ?? null;
26667
- } catch {
26668
- return null;
26669
- }
26670
- }
26671
- function resolveProject(task2, db) {
26672
- const project = task2.project_id ? getProject(task2.project_id, db) : null;
26673
- const projectPath = project ? machineLocalPath(project, db) ?? project.path : task2.working_dir;
26674
- return { project, projectPath: projectPath ?? null };
26675
- }
26676
- function resolveTaskList(task2, project, db) {
26677
- if (task2.task_list_id) {
26678
- return getTaskList(task2.task_list_id, db) ?? (project ? getTaskListBySlug(task2.task_list_id, project.id, db) : null);
26679
- }
26680
- if (project?.task_list_id) {
26681
- return getTaskListBySlug(project.task_list_id, project.id, db);
26682
- }
26683
- return null;
26684
- }
26685
- function isTerminal2(status) {
26686
- return status === "completed" || status === "cancelled" || status === "failed";
26687
- }
26688
- function routeConcurrencyKey(task2, project, taskList, projectPath) {
26689
- if (project?.id)
26690
- return `project:${project.id}`;
26691
- if (taskList?.id)
26692
- return `task-list:${taskList.id}`;
26693
- if (projectPath)
26694
- return `path:${projectPath}`;
26695
- return `task:${task2.id}`;
26696
- }
26697
- function getTaskRouteState(taskOrId, db) {
26698
- const d = db || getDatabase();
26699
- const task2 = typeof taskOrId === "string" ? getTask(taskOrId, d) : taskOrId;
26700
- if (!task2)
26701
- throw new Error(`Task not found: ${taskOrId}`);
26702
- const { project, projectPath } = resolveProject(task2, d);
26703
- const taskList = resolveTaskList(task2, project, d);
26704
- const automation = routingAutomationMetadata(task2, taskList) ?? {};
26705
- const routeEnabled = routeEnabledForTask(task2, taskList) === true;
26706
- const tagOptIn = task2.tags.includes("auto:route") || task2.tags.includes("route:enabled");
26707
- const locked = Boolean(task2.locked_by && !isLockExpired(task2.locked_at));
26708
- const blockers = getBlockingDeps(task2.id, d);
26709
- const blocked = blockers.length > 0;
26710
- const terminal = isTerminal2(task2.status);
26711
- const requiresApproval = automation.requires_approval === true || task2.requires_approval === true;
26712
- const approvalRequired = automation.approval_required === true;
26713
- const approved = Boolean(task2.approved_by);
26714
- const gates = {
26715
- route_enabled: routeEnabled,
26716
- tag_opt_in: tagOptIn,
26717
- no_auto: automation.no_auto === true,
26718
- manual: automation.manual === true,
26719
- manual_required: automation.manual_required === true,
26720
- requires_approval: requiresApproval,
26721
- approval_required: approvalRequired,
26722
- approved,
26723
- locked,
26724
- blocked,
26725
- terminal
26726
- };
26727
- const reasons = [];
26728
- if (task2.status !== "pending")
26729
- reasons.push("task_not_pending");
26730
- if (terminal)
26731
- reasons.push("task_terminal");
26732
- if (!routeEnabled)
26733
- reasons.push("route_not_enabled");
26734
- if (locked)
26735
- reasons.push("task_locked");
26736
- if (blocked)
26737
- reasons.push("task_blocked");
26738
- if (gates.no_auto)
26739
- reasons.push("no_auto");
26740
- if (gates.manual)
26741
- reasons.push("manual");
26742
- if (gates.manual_required)
26743
- reasons.push("manual_required");
26744
- if (requiresApproval && !approved)
26745
- reasons.push("requires_approval");
26746
- if (approvalRequired && !approved)
26747
- reasons.push("approval_required");
26748
- if (automation.allowed === false)
26749
- reasons.push("automation_disallowed");
26750
- return {
26751
- schema_version: TODOS_TASK_ROUTE_STATE_SCHEMA_VERSION,
26752
- task_id: task2.id,
26753
- task_short_id: task2.short_id,
26754
- status: task2.status,
26755
- eligible: reasons.length === 0,
26756
- reasons,
26757
- blockers: blockers.map((blocker) => ({
26758
- id: blocker.id,
26759
- short_id: blocker.short_id,
26760
- title: blocker.title,
26761
- status: blocker.status
26762
- })),
26763
- gates,
26764
- automation: Object.keys(automation).length > 0 ? automation : null,
26765
- route: {
26766
- project_id: project?.id ?? task2.project_id,
26767
- project_path: projectPath,
26768
- working_dir: task2.working_dir ?? projectPath,
26769
- project_kind: classifyProjectKind2(projectPath),
26770
- task_list_id: taskList?.id ?? task2.task_list_id,
26771
- task_list_slug: taskList?.slug ?? null,
26772
- task_list_name: taskList?.name ?? null,
26773
- concurrency_key: routeConcurrencyKey(task2, project, taskList, projectPath)
26774
- },
26775
- pointers: workflowPointersFromMetadata(task2.metadata)
26776
- };
26777
- }
26778
- function setTaskWorkflowPointers(taskId, input, db) {
26779
- const d = db || getDatabase();
26780
- const task2 = getTask(taskId, d);
26781
- if (!task2)
26782
- throw new Error(`Task not found: ${taskId}`);
26783
- const previous = workflowPointersFromMetadata(task2.metadata);
26784
- const next = compactWorkflowPointers({
26785
- current_workflow_invocation_id: pointerPatch(previous.current_workflow_invocation_id, input, "current_workflow_invocation_id"),
26786
- current_run_id: pointerPatch(previous.current_run_id, input, "current_run_id"),
26787
- latest_manifest_path: pointerPatch(previous.latest_manifest_path, input, "latest_manifest_path"),
26788
- latest_evaluation_path: pointerPatch(previous.latest_evaluation_path, input, "latest_evaluation_path"),
26789
- workflow_state: pointerPatch(previous.workflow_state, input, "workflow_state")
26790
- });
26791
- const timestamp2 = now();
26792
- const {
26793
- current_workflow_invocation_id,
26794
- current_run_id,
26795
- latest_manifest_path,
26796
- latest_evaluation_path,
26797
- workflow_state,
26798
- workflow_invocation,
26799
- ...baseMetadata
26800
- } = task2.metadata;
26801
- const metadata = {
26802
- ...baseMetadata,
26803
- ...next,
26804
- workflow_invocation: {
26805
- schema_version: TASK_WORKFLOW_POINTER_SCHEMA_VERSION,
26806
- ...next,
26807
- updated_at: timestamp2,
26808
- updated_by: input.actor ?? null
26809
- }
26810
- };
26811
- return updateTask(task2.id, { version: task2.version, metadata }, d);
26812
- }
26813
- function pointerPatch(previous, input, key) {
26814
- if (!Object.prototype.hasOwnProperty.call(input, key))
26815
- return previous;
26816
- const value = input[key];
26817
- if (value === undefined)
26818
- return previous;
26819
- return typeof value === "string" && value.trim() ? value : undefined;
26820
- }
26821
27162
  // src/db/api-keys.ts
26822
27163
  init_database();
26823
- import { createHash as createHash10, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual3 } from "crypto";
27164
+ import { createHash as createHash11, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual3 } from "crypto";
26824
27165
  function rowToRecord(row) {
26825
27166
  return {
26826
27167
  id: row.id,
@@ -26834,7 +27175,7 @@ function rowToRecord(row) {
26834
27175
  };
26835
27176
  }
26836
27177
  function hashApiKey(key) {
26837
- return createHash10("sha256").update(key).digest("hex");
27178
+ return createHash11("sha256").update(key).digest("hex");
26838
27179
  }
26839
27180
  function safeEqualHex(a, b) {
26840
27181
  if (a.length !== b.length)
@@ -27025,18 +27366,18 @@ var gatherTrainingData = async (options = {}) => {
27025
27366
  };
27026
27367
  // src/lib/model-config.ts
27027
27368
  init_sync_utils();
27028
- import { existsSync as existsSync11, mkdirSync as mkdirSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
27029
- import { join as join11 } from "path";
27369
+ import { existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
27370
+ import { join as join12 } from "path";
27030
27371
  var DEFAULT_MODEL = "gpt-4o-mini";
27031
27372
  function getConfigDir() {
27032
27373
  return getTodosGlobalDir();
27033
27374
  }
27034
27375
  function getConfigPath2() {
27035
- return join11(getConfigDir(), "config.json");
27376
+ return join12(getConfigDir(), "config.json");
27036
27377
  }
27037
27378
  function readConfig() {
27038
27379
  const configPath = getConfigPath2();
27039
- if (!existsSync11(configPath))
27380
+ if (!existsSync12(configPath))
27040
27381
  return {};
27041
27382
  try {
27042
27383
  const raw = readFileSync9(configPath, "utf-8");
@@ -27047,7 +27388,7 @@ function readConfig() {
27047
27388
  }
27048
27389
  function writeConfig(config) {
27049
27390
  const configDir = getConfigDir();
27050
- if (!existsSync11(configDir)) {
27391
+ if (!existsSync12(configDir)) {
27051
27392
  mkdirSync9(configDir, { recursive: true });
27052
27393
  }
27053
27394
  writeFileSync7(getConfigPath2(), JSON.stringify(config, null, 2) + `
@@ -27772,7 +28113,7 @@ CLI equivalent: \`${r.equivalent_cli}\`
27772
28113
  `);
27773
28114
  }
27774
28115
  // src/lib/verification-providers.ts
27775
- import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
28116
+ import { existsSync as existsSync13, readFileSync as readFileSync10 } from "fs";
27776
28117
  init_database();
27777
28118
  init_config();
27778
28119
  init_redaction();
@@ -27883,7 +28224,7 @@ function classifyLog(text) {
27883
28224
  async function sleep2(ms) {
27884
28225
  if (ms <= 0)
27885
28226
  return;
27886
- await new Promise((resolve12) => setTimeout(resolve12, ms));
28227
+ await new Promise((resolve13) => setTimeout(resolve13, ms));
27887
28228
  }
27888
28229
  async function runCommandProvider(provider, input) {
27889
28230
  const commandTemplate = input.command || provider.command;
@@ -27938,7 +28279,7 @@ Timed out after ${provider.timeout_ms}ms`);
27938
28279
  };
27939
28280
  }
27940
28281
  function runCiLogProvider(input) {
27941
- const text = input.log_text ?? (input.log_path && existsSync12(input.log_path) ? readFileSync10(input.log_path, "utf-8") : "");
28282
+ const text = input.log_text ?? (input.log_path && existsSync13(input.log_path) ? readFileSync10(input.log_path, "utf-8") : "");
27942
28283
  return {
27943
28284
  status: classifyLog(text),
27944
28285
  attempts: 1,
@@ -27950,7 +28291,7 @@ function runBrowserProvider(input) {
27950
28291
  if (!input.artifact_path) {
27951
28292
  return { status: "unknown", attempts: 1, exit_code: null, output_summary: "browser provider needs a screenshot or artifact path" };
27952
28293
  }
27953
- if (!existsSync12(input.artifact_path)) {
28294
+ if (!existsSync13(input.artifact_path)) {
27954
28295
  return { status: "failed", attempts: 1, exit_code: null, output_summary: `artifact not found: ${input.artifact_path}` };
27955
28296
  }
27956
28297
  return {
@@ -28115,7 +28456,7 @@ function listVerificationRecords(filter = {}, db) {
28115
28456
  // src/lib/verification-evidence.ts
28116
28457
  init_database();
28117
28458
  import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync10 } from "fs";
28118
- import { dirname as dirname8 } from "path";
28459
+ import { dirname as dirname9 } from "path";
28119
28460
  var VERIFICATION_EVIDENCE_SCHEMA = "todos.verification_evidence.v1";
28120
28461
  function getMachineId3() {
28121
28462
  return process.env["TODOS_MACHINE_ID"] || __require("os").hostname();
@@ -28235,15 +28576,15 @@ function exportVerificationEvidence(filter = {}, db) {
28235
28576
  };
28236
28577
  }
28237
28578
  function writeVerificationExport(bundle, path) {
28238
- mkdirSync10(dirname8(path), { recursive: true });
28579
+ mkdirSync10(dirname9(path), { recursive: true });
28239
28580
  writeFileSync8(path, JSON.stringify(bundle, null, 2), "utf8");
28240
28581
  }
28241
28582
  // src/lib/policy-packs.ts
28242
- import { relative as relative3, resolve as resolve12 } from "path";
28583
+ import { relative as relative3, resolve as resolve13 } from "path";
28243
28584
  init_database();
28244
28585
  init_config();
28245
- function normalizePath3(path) {
28246
- return resolve12(path);
28586
+ function normalizePath4(path) {
28587
+ return resolve13(path);
28247
28588
  }
28248
28589
  function unique4(values) {
28249
28590
  return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
@@ -28253,13 +28594,13 @@ function parseStatuses(values) {
28253
28594
  return unique4(values).filter((value) => allowed.has(value));
28254
28595
  }
28255
28596
  function configuredPacks(config = loadConfig()) {
28256
- return Object.values(config.policy_packs || {}).map((pack) => ({ ...pack, root: normalizePath3(pack.root) })).sort((a, b) => a.name.localeCompare(b.name));
28597
+ return Object.values(config.policy_packs || {}).map((pack) => ({ ...pack, root: normalizePath4(pack.root) })).sort((a, b) => a.name.localeCompare(b.name));
28257
28598
  }
28258
28599
  function defaultPolicyPack(name, root) {
28259
28600
  return {
28260
28601
  name,
28261
28602
  version: 1,
28262
- root: normalizePath3(root),
28603
+ root: normalizePath4(root),
28263
28604
  required_commands: [],
28264
28605
  prohibited_commands: ["npm install -g", "git reset --hard", "git checkout --", "rm -rf"],
28265
28606
  prohibited_paths: [],
@@ -28277,7 +28618,7 @@ function isPathInside3(root, path) {
28277
28618
  const rel = relative3(root, path);
28278
28619
  return rel === "" || !rel.startsWith("..") && !rel.startsWith("/") && !/^[A-Za-z]:/.test(rel);
28279
28620
  }
28280
- function matchesPattern3(value, pattern) {
28621
+ function matchesPattern4(value, pattern) {
28281
28622
  const normalizedValue = value.toLowerCase();
28282
28623
  const normalizedPattern = pattern.toLowerCase();
28283
28624
  if (pattern.startsWith("/") && pattern.endsWith("/") && pattern.length > 2) {
@@ -28294,14 +28635,14 @@ function matchesPattern3(value, pattern) {
28294
28635
  return normalizedValue === normalizedPattern || normalizedValue.includes(normalizedPattern);
28295
28636
  }
28296
28637
  function commandMatches(commands, pattern) {
28297
- return commands.filter((command) => matchesPattern3(command, pattern));
28638
+ return commands.filter((command) => matchesPattern4(command, pattern));
28298
28639
  }
28299
28640
  function pathMatches(paths, pattern, root) {
28300
28641
  return paths.filter((path) => {
28301
- const candidate = path.startsWith("/") ? path : resolve12(root, path);
28642
+ const candidate = path.startsWith("/") ? path : resolve13(root, path);
28302
28643
  if (!isPathInside3(root, candidate))
28303
- return matchesPattern3(path, pattern);
28304
- return matchesPattern3(path, pattern) || matchesPattern3(relative3(root, candidate), pattern);
28644
+ return matchesPattern4(path, pattern);
28645
+ return matchesPattern4(path, pattern) || matchesPattern4(relative3(root, candidate), pattern);
28305
28646
  });
28306
28647
  }
28307
28648
  function finding(id, passed, message, evidence = []) {
@@ -28380,7 +28721,7 @@ function getPolicyPack(name) {
28380
28721
  function upsertPolicyPack(input) {
28381
28722
  const config = loadConfig();
28382
28723
  const existing = config.policy_packs?.[input.name];
28383
- const root = normalizePath3(input.root || existing?.root || process.cwd());
28724
+ const root = normalizePath4(input.root || existing?.root || process.cwd());
28384
28725
  const base = existing || defaultPolicyPack(input.name, root);
28385
28726
  const timestamp2 = new Date().toISOString();
28386
28727
  const pack = {
@@ -28460,7 +28801,7 @@ function validatePolicyPack(input, db) {
28460
28801
  findings.push(finding("linked-pull-request", refs.length > 0, "at least one linked pull request is required", refs.map((ref) => ref.name)));
28461
28802
  }
28462
28803
  if (pack.branch_pattern) {
28463
- const branches = evidence.gitRefs.filter((ref) => ref.ref_type === "branch" && matchesPattern3(ref.name, pack.branch_pattern));
28804
+ const branches = evidence.gitRefs.filter((ref) => ref.ref_type === "branch" && matchesPattern4(ref.name, pack.branch_pattern));
28464
28805
  findings.push(finding("branch-pattern", branches.length > 0, `at least one linked branch must match: ${pack.branch_pattern}`, branches.map((ref) => ref.name)));
28465
28806
  }
28466
28807
  if (pack.require_approval) {
@@ -28589,21 +28930,21 @@ function resourceDiagnostics() {
28589
28930
  };
28590
28931
  }
28591
28932
  // src/lib/sandbox-profiles.ts
28592
- import { existsSync as existsSync13, readFileSync as readFileSync11, writeFileSync as writeFileSync9, mkdirSync as mkdirSync11 } from "fs";
28593
- import { join as join12, dirname as dirname9 } from "path";
28933
+ import { existsSync as existsSync14, readFileSync as readFileSync11, writeFileSync as writeFileSync9, mkdirSync as mkdirSync11 } from "fs";
28934
+ import { join as join13, dirname as dirname10 } from "path";
28594
28935
  var SANDBOX_PROFILE_VERSION = "todos.sandbox-profile.v1";
28595
28936
  function getProfilesPath() {
28596
28937
  if (process.env["TODOS_SANDBOX_PROFILES_PATH"]) {
28597
28938
  return process.env["TODOS_SANDBOX_PROFILES_PATH"];
28598
28939
  }
28599
- const localDir = join12(process.cwd(), ".todos");
28600
- const local = join12(localDir, "sandbox-profiles.json");
28601
- if (existsSync13(localDir))
28940
+ const localDir = join13(process.cwd(), ".todos");
28941
+ const local = join13(localDir, "sandbox-profiles.json");
28942
+ if (existsSync14(localDir))
28602
28943
  return local;
28603
- if (existsSync13(local))
28944
+ if (existsSync14(local))
28604
28945
  return local;
28605
28946
  const home = process.env["HOME"] || "~";
28606
- return join12(home, ".hasna", "todos", "sandbox-profiles.json");
28947
+ return join13(home, ".hasna", "todos", "sandbox-profiles.json");
28607
28948
  }
28608
28949
  var cached2 = null;
28609
28950
  function resetSandboxProfileCache() {
@@ -28635,7 +28976,7 @@ function loadSandboxProfiles() {
28635
28976
  if (cached2)
28636
28977
  return cached2;
28637
28978
  const path = getProfilesPath();
28638
- if (!existsSync13(path)) {
28979
+ if (!existsSync14(path)) {
28639
28980
  cached2 = getDefaultSandboxProfiles();
28640
28981
  return cached2;
28641
28982
  }
@@ -28648,7 +28989,7 @@ function getSandboxProfile(name) {
28648
28989
  }
28649
28990
  function saveSandboxProfiles(profiles) {
28650
28991
  const path = getProfilesPath();
28651
- mkdirSync11(dirname9(path), { recursive: true });
28992
+ mkdirSync11(dirname10(path), { recursive: true });
28652
28993
  writeFileSync9(path, JSON.stringify({ schema_version: SANDBOX_PROFILE_VERSION, profiles }, null, 2));
28653
28994
  cached2 = profiles;
28654
28995
  }
@@ -29008,9 +29349,9 @@ function getDefaultAgentAdapters() {
29008
29349
  }
29009
29350
  function resetAgentAdapterCache() {}
29010
29351
  // src/lib/git-traceability.ts
29011
- import { existsSync as existsSync14, readFileSync as readFileSync12 } from "fs";
29352
+ import { existsSync as existsSync15, readFileSync as readFileSync12 } from "fs";
29012
29353
  import { spawnSync as spawnSync2 } from "child_process";
29013
- import { resolve as resolve13 } from "path";
29354
+ import { resolve as resolve14 } from "path";
29014
29355
  var GIT_TRACEABILITY_SCHEMA_VERSION = "todos.git_traceability.v1";
29015
29356
  function runGit(args, cwd) {
29016
29357
  const result = spawnSync2("git", args, { cwd, encoding: "utf8" });
@@ -29053,8 +29394,8 @@ function inspectGitCommit(sha, cwd) {
29053
29394
  };
29054
29395
  }
29055
29396
  function loadCiSnapshot(path) {
29056
- const target = path ? resolve13(path) : resolve13(process.cwd(), ".todos", "ci-snapshot.json");
29057
- if (!existsSync14(target))
29397
+ const target = path ? resolve14(path) : resolve14(process.cwd(), ".todos", "ci-snapshot.json");
29398
+ if (!existsSync15(target))
29058
29399
  return null;
29059
29400
  try {
29060
29401
  const parsed = JSON.parse(readFileSync12(target, "utf8"));
@@ -29150,8 +29491,8 @@ function formatTraceabilityReport(report) {
29150
29491
  `);
29151
29492
  }
29152
29493
  // src/lib/mention-resolver.ts
29153
- import { existsSync as existsSync15, readdirSync as readdirSync2, readFileSync as readFileSync13, statSync as statSync4 } from "fs";
29154
- import { basename as basename3, isAbsolute, join as join13, relative as relative4, resolve as resolve14, sep as sep2 } from "path";
29494
+ import { existsSync as existsSync16, readdirSync as readdirSync3, readFileSync as readFileSync13, statSync as statSync5 } from "fs";
29495
+ import { basename as basename4, isAbsolute, join as join14, relative as relative4, resolve as resolve15, sep as sep2 } from "path";
29155
29496
  init_database();
29156
29497
  var PREFIXES = {
29157
29498
  file: "file",
@@ -29227,7 +29568,7 @@ function backlink(kind, key, label, target = key) {
29227
29568
  return { kind, key, label, target };
29228
29569
  }
29229
29570
  function normalizeWorkspace(workspace) {
29230
- return resolve14(workspace || process.cwd());
29571
+ return resolve15(workspace || process.cwd());
29231
29572
  }
29232
29573
  function isInside(root, absolutePath) {
29233
29574
  const rel = relative4(root, absolutePath);
@@ -29295,18 +29636,18 @@ function resolveFile(parsed, workspace) {
29295
29636
  resolution.warnings.push("path is empty or escapes the workspace");
29296
29637
  return resolution;
29297
29638
  }
29298
- const absolutePath = resolve14(workspace, relPath);
29639
+ const absolutePath = resolve15(workspace, relPath);
29299
29640
  if (!isInside(workspace, absolutePath)) {
29300
29641
  resolution.path = relPath;
29301
29642
  resolution.warnings.push("path escapes the workspace");
29302
29643
  return resolution;
29303
29644
  }
29304
29645
  resolution.path = relPath;
29305
- if (!existsSync15(absolutePath)) {
29646
+ if (!existsSync16(absolutePath)) {
29306
29647
  resolution.warnings.push("file does not exist in the local workspace");
29307
29648
  return resolution;
29308
29649
  }
29309
- const stats2 = statSync4(absolutePath);
29650
+ const stats2 = statSync5(absolutePath);
29310
29651
  if (!stats2.isFile()) {
29311
29652
  resolution.warnings.push("path exists but is not a file");
29312
29653
  return resolution;
@@ -29330,12 +29671,12 @@ function resolveFile(parsed, workspace) {
29330
29671
  function walkSourceFiles(root, current = root, files = []) {
29331
29672
  if (files.length >= 5000)
29332
29673
  return files;
29333
- for (const entry2 of readdirSync2(current, { withFileTypes: true })) {
29674
+ for (const entry2 of readdirSync3(current, { withFileTypes: true })) {
29334
29675
  if (entry2.name.startsWith(".") && ![".github"].includes(entry2.name)) {
29335
29676
  if (SKIP_DIRS.has(entry2.name))
29336
29677
  continue;
29337
29678
  }
29338
- const absolutePath = join13(current, entry2.name);
29679
+ const absolutePath = join14(current, entry2.name);
29339
29680
  if (entry2.isDirectory()) {
29340
29681
  if (!SKIP_DIRS.has(entry2.name))
29341
29682
  walkSourceFiles(root, absolutePath, files);
@@ -29343,8 +29684,8 @@ function walkSourceFiles(root, current = root, files = []) {
29343
29684
  }
29344
29685
  if (!entry2.isFile())
29345
29686
  continue;
29346
- const extension = `.${basename3(entry2.name).split(".").pop() || ""}`;
29347
- if (SOURCE_EXTENSIONS.has(extension) && statSync4(absolutePath).size <= 512 * 1024) {
29687
+ const extension = `.${basename4(entry2.name).split(".").pop() || ""}`;
29688
+ if (SOURCE_EXTENSIONS.has(extension) && statSync5(absolutePath).size <= 512 * 1024) {
29348
29689
  files.push(absolutePath);
29349
29690
  }
29350
29691
  }
@@ -31215,9 +31556,9 @@ function getAdapterDocsFingerprint() {
31215
31556
  }
31216
31557
  // src/lib/inbox-intake.ts
31217
31558
  init_database();
31218
- import { existsSync as existsSync16, readFileSync as readFileSync14 } from "fs";
31219
- import { basename as basename4 } from "path";
31220
- import { createHash as createHash11 } from "crypto";
31559
+ import { existsSync as existsSync17, readFileSync as readFileSync14 } from "fs";
31560
+ import { basename as basename5 } from "path";
31561
+ import { createHash as createHash12 } from "crypto";
31221
31562
  init_secret_redaction();
31222
31563
  var INBOX_INTAKE_SCHEMA = "todos.inbox_intake.v1";
31223
31564
  var INTAKE_SOURCE_TYPES = [
@@ -31230,7 +31571,7 @@ var INTAKE_SOURCE_TYPES = [
31230
31571
  ];
31231
31572
  var INTAKE_TRIAGE_STATUSES = ["preview", "triaged", "duplicate", "created"];
31232
31573
  function fingerprint2(text) {
31233
- return createHash11("sha256").update(text).digest("hex").slice(0, 16);
31574
+ return createHash12("sha256").update(text).digest("hex").slice(0, 16);
31234
31575
  }
31235
31576
  function loadRawContent(input) {
31236
31577
  if (input.github_url) {
@@ -31261,15 +31602,15 @@ function loadRawContent(input) {
31261
31602
  }
31262
31603
  }
31263
31604
  if (input.file_path) {
31264
- if (!existsSync16(input.file_path))
31605
+ if (!existsSync17(input.file_path))
31265
31606
  throw new Error(`File not found: ${input.file_path}`);
31266
31607
  const raw = readFileSync14(input.file_path, "utf8");
31267
- const name = basename4(input.file_path).toLowerCase();
31608
+ const name = basename5(input.file_path).toLowerCase();
31268
31609
  const source_type2 = input.source_type ?? (name.includes("ci") || name.endsWith(".log") ? "ci_log" : "file");
31269
31610
  return {
31270
31611
  raw,
31271
31612
  source_type: source_type2,
31272
- metadata: { file_path: input.file_path, file_name: basename4(input.file_path) }
31613
+ metadata: { file_path: input.file_path, file_name: basename5(input.file_path) }
31273
31614
  };
31274
31615
  }
31275
31616
  const text = input.text?.trim();
@@ -31879,7 +32220,7 @@ function formatNlIntakePreviewText(preview) {
31879
32220
  }
31880
32221
  // src/lib/issue-importers.ts
31881
32222
  init_database();
31882
- import { existsSync as existsSync17, readFileSync as readFileSync15 } from "fs";
32223
+ import { existsSync as existsSync18, readFileSync as readFileSync15 } from "fs";
31883
32224
  var ISSUE_IMPORT_SCHEMA = "todos.issue_import.v1";
31884
32225
  var ISSUE_SOURCES = ["github", "linear", "jira", "auto"];
31885
32226
  var GITHUB_LABEL_PRIORITY = {
@@ -32098,7 +32439,7 @@ function parseIssueExport(data, source9 = "auto") {
32098
32439
  return normalized;
32099
32440
  }
32100
32441
  function loadIssueExportFromFile(path) {
32101
- if (!existsSync17(path))
32442
+ if (!existsSync18(path))
32102
32443
  throw new Error(`File not found: ${path}`);
32103
32444
  return JSON.parse(readFileSync15(path, "utf8"));
32104
32445
  }
@@ -32258,8 +32599,8 @@ todos import issues ./linear.json --source linear --dry-run
32258
32599
  // src/lib/run-records.ts
32259
32600
  init_database();
32260
32601
  init_secret_redaction();
32261
- import { existsSync as existsSync18, mkdirSync as mkdirSync12, writeFileSync as writeFileSync10 } from "fs";
32262
- import { join as join14, dirname as dirname10 } from "path";
32602
+ import { existsSync as existsSync19, mkdirSync as mkdirSync12, writeFileSync as writeFileSync10 } from "fs";
32603
+ import { join as join15, dirname as dirname11 } from "path";
32263
32604
  var RUN_RECORD_SCHEMA = "todos.run_record.v1";
32264
32605
  var RUN_RECORD_STATUSES = ["active", "completed", "failed", "archived"];
32265
32606
  function parseJsonArray3(raw, fallback = []) {
@@ -32452,8 +32793,8 @@ function buildRunReplayBundle(id, db) {
32452
32793
  }
32453
32794
  function exportRunReplay(id, outputPath, db) {
32454
32795
  const bundle = buildRunReplayBundle(id, db);
32455
- const path = outputPath ?? join14(process.cwd(), ".todos", "replays", `${id.slice(0, 8)}.json`);
32456
- mkdirSync12(dirname10(path), { recursive: true });
32796
+ const path = outputPath ?? join15(process.cwd(), ".todos", "replays", `${id.slice(0, 8)}.json`);
32797
+ mkdirSync12(dirname11(path), { recursive: true });
32457
32798
  writeFileSync10(path, JSON.stringify(bundle, null, 2));
32458
32799
  const d = db || getDatabase();
32459
32800
  d.run(`UPDATE run_records SET replay_bundle = ?, updated_at = ? WHERE id = ?`, [path, now(), id]);
@@ -32492,16 +32833,16 @@ function formatRunRecordMarkdown(record) {
32492
32833
  `;
32493
32834
  }
32494
32835
  function getDefaultReplayDir() {
32495
- const local = join14(process.cwd(), ".todos", "replays");
32496
- if (existsSync18(join14(process.cwd(), ".todos")))
32836
+ const local = join15(process.cwd(), ".todos", "replays");
32837
+ if (existsSync19(join15(process.cwd(), ".todos")))
32497
32838
  return local;
32498
32839
  const home = process.env["HOME"] || "~";
32499
- return join14(home, ".hasna", "todos", "replays");
32840
+ return join15(home, ".hasna", "todos", "replays");
32500
32841
  }
32501
32842
  // src/lib/release-checks.ts
32502
32843
  init_secret_redaction();
32503
- import { existsSync as existsSync19, readFileSync as readFileSync16, readdirSync as readdirSync3, statSync as statSync5 } from "fs";
32504
- import { join as join15, relative as relative5 } from "path";
32844
+ import { existsSync as existsSync20, readFileSync as readFileSync16, readdirSync as readdirSync4, statSync as statSync6 } from "fs";
32845
+ import { join as join16, relative as relative5 } from "path";
32505
32846
  var RELEASE_CHECK_SCHEMA = "todos.release_check.v1";
32506
32847
  var FORBIDDEN_DIST_PATTERNS = [
32507
32848
  {
@@ -32514,17 +32855,17 @@ var FORBIDDEN_DIST_PATTERNS = [
32514
32855
  ];
32515
32856
  var REQUIRED_BINS = ["todos", "todos-mcp", "todos-serve"];
32516
32857
  function readPackageJson3(root) {
32517
- const path = join15(root, "package.json");
32518
- if (!existsSync19(path))
32858
+ const path = join16(root, "package.json");
32859
+ if (!existsSync20(path))
32519
32860
  throw new Error(`package.json not found in ${root}`);
32520
32861
  return JSON.parse(readFileSync16(path, "utf8"));
32521
32862
  }
32522
32863
  function walkFiles(dir, acc = []) {
32523
- if (!existsSync19(dir))
32864
+ if (!existsSync20(dir))
32524
32865
  return acc;
32525
- for (const entry2 of readdirSync3(dir)) {
32526
- const full = join15(dir, entry2);
32527
- const st = statSync5(full);
32866
+ for (const entry2 of readdirSync4(dir)) {
32867
+ const full = join16(dir, entry2);
32868
+ const st = statSync6(full);
32528
32869
  if (st.isDirectory())
32529
32870
  walkFiles(full, acc);
32530
32871
  else if (/\.(js|mjs|cjs|json|d\.ts)$/.test(entry2))
@@ -32541,8 +32882,8 @@ function auditPackageContents(root) {
32541
32882
  checks.push({ id: "files_dist", severity: "error", message: "package.json files must include dist" });
32542
32883
  }
32543
32884
  for (const pattern of files) {
32544
- const target = join15(root, pattern);
32545
- if (!existsSync19(target)) {
32885
+ const target = join16(root, pattern);
32886
+ if (!existsSync20(target)) {
32546
32887
  checks.push({ id: `files_missing_${pattern}`, severity: "error", message: `Published file path missing: ${pattern}` });
32547
32888
  }
32548
32889
  }
@@ -32556,8 +32897,8 @@ function auditPackageContents(root) {
32556
32897
  checks.push({ id: `bin_${name}`, severity: "error", message: `Missing bin entry: ${name}` });
32557
32898
  continue;
32558
32899
  }
32559
- const binPath = join15(root, rel);
32560
- if (!existsSync19(binPath)) {
32900
+ const binPath = join16(root, rel);
32901
+ if (!existsSync20(binPath)) {
32561
32902
  checks.push({ id: `bin_path_${name}`, severity: "error", message: `Bin file missing: ${rel}` });
32562
32903
  } else {
32563
32904
  checks.push({ id: `bin_ok_${name}`, severity: "info", message: `Bin present: ${name} \u2192 ${rel}` });
@@ -32574,8 +32915,8 @@ function auditPackageContents(root) {
32574
32915
  }
32575
32916
  function scanDistArtifacts(root) {
32576
32917
  const checks = [];
32577
- const distDir = join15(root, "dist");
32578
- if (!existsSync19(distDir)) {
32918
+ const distDir = join16(root, "dist");
32919
+ if (!existsSync20(distDir)) {
32579
32920
  checks.push({ id: "dist_missing", severity: "error", message: "dist/ directory not found \u2014 run bun run build" });
32580
32921
  return checks;
32581
32922
  }
@@ -32881,15 +33222,15 @@ function renderReleaseNotesMarkdown(document) {
32881
33222
  // src/lib/db-backup.ts
32882
33223
  init_database();
32883
33224
  init_migrations();
32884
- import { existsSync as existsSync20, copyFileSync, mkdirSync as mkdirSync13, readFileSync as readFileSync17, statSync as statSync6, writeFileSync as writeFileSync11, unlinkSync } from "fs";
32885
- import { dirname as dirname11, join as join16, resolve as resolve15 } from "path";
32886
- import { Database as Database3 } from "bun:sqlite";
33225
+ import { existsSync as existsSync21, copyFileSync, mkdirSync as mkdirSync13, readFileSync as readFileSync17, statSync as statSync7, writeFileSync as writeFileSync11, unlinkSync } from "fs";
33226
+ import { dirname as dirname12, join as join17, resolve as resolve16 } from "path";
33227
+ import { Database as Database4 } from "bun:sqlite";
32887
33228
  var DB_BACKUP_SCHEMA = "todos.db_backup.v1";
32888
33229
  function resolveDbPath(dbPath) {
32889
33230
  if (dbPath)
32890
- return resolve15(dbPath);
33231
+ return resolve16(dbPath);
32891
33232
  if (process.env["TODOS_DB_PATH"] && process.env["TODOS_DB_PATH"] !== ":memory:") {
32892
- return resolve15(process.env["TODOS_DB_PATH"]);
33233
+ return resolve16(process.env["TODOS_DB_PATH"]);
32893
33234
  }
32894
33235
  const db = getDatabase();
32895
33236
  const filename = db.filename;
@@ -32899,11 +33240,11 @@ function resolveDbPath(dbPath) {
32899
33240
  }
32900
33241
  function backupDatabase(outputPath, sourcePath) {
32901
33242
  const source9 = resolveDbPath(sourcePath);
32902
- if (!existsSync20(source9))
33243
+ if (!existsSync21(source9))
32903
33244
  throw new Error(`Database not found: ${source9}`);
32904
- mkdirSync13(dirname11(outputPath), { recursive: true });
33245
+ mkdirSync13(dirname12(outputPath), { recursive: true });
32905
33246
  closeDatabase();
32906
- const src = new Database3(source9);
33247
+ const src = new Database4(source9);
32907
33248
  try {
32908
33249
  src.exec("PRAGMA wal_checkpoint(TRUNCATE)");
32909
33250
  } catch {}
@@ -32911,7 +33252,7 @@ function backupDatabase(outputPath, sourcePath) {
32911
33252
  src.close();
32912
33253
  writeFileSync11(outputPath, image);
32913
33254
  const method = "file_copy";
32914
- const bytes = statSync6(outputPath).size;
33255
+ const bytes = statSync7(outputPath).size;
32915
33256
  return {
32916
33257
  schema_version: DB_BACKUP_SCHEMA,
32917
33258
  source_path: source9,
@@ -32922,14 +33263,14 @@ function backupDatabase(outputPath, sourcePath) {
32922
33263
  };
32923
33264
  }
32924
33265
  function restoreDatabase(backupPath, targetPath) {
32925
- if (!existsSync20(backupPath))
33266
+ if (!existsSync21(backupPath))
32926
33267
  throw new Error(`Backup not found: ${backupPath}`);
32927
33268
  const integrity = checkDatabaseIntegrity(backupPath);
32928
33269
  if (!integrity.ok) {
32929
33270
  throw new Error(`Backup failed integrity check: ${integrity.errors.join("; ")}`);
32930
33271
  }
32931
- const target = targetPath ? resolve15(targetPath) : resolveDbPath();
32932
- mkdirSync13(dirname11(target), { recursive: true });
33272
+ const target = targetPath ? resolve16(targetPath) : resolveDbPath();
33273
+ mkdirSync13(dirname12(target), { recursive: true });
32933
33274
  const staging = `${target}.restore.tmp`;
32934
33275
  copyFileSync(backupPath, staging);
32935
33276
  copyFileSync(staging, target);
@@ -32941,15 +33282,15 @@ function restoreDatabase(backupPath, targetPath) {
32941
33282
  schema_version: DB_BACKUP_SCHEMA,
32942
33283
  source_path: backupPath,
32943
33284
  backup_path: target,
32944
- bytes: statSync6(target).size,
33285
+ bytes: statSync7(target).size,
32945
33286
  method: "file_copy",
32946
33287
  created_at: new Date().toISOString()
32947
33288
  };
32948
33289
  }
32949
33290
  function checkDatabaseIntegrity(dbPath) {
32950
- const path = dbPath ? resolve15(dbPath) : resolveDbPath();
33291
+ const path = dbPath ? resolve16(dbPath) : resolveDbPath();
32951
33292
  const errors = [];
32952
- if (!existsSync20(path)) {
33293
+ if (!existsSync21(path)) {
32953
33294
  return {
32954
33295
  schema_version: DB_BACKUP_SCHEMA,
32955
33296
  path,
@@ -32962,7 +33303,7 @@ function checkDatabaseIntegrity(dbPath) {
32962
33303
  }
32963
33304
  let db;
32964
33305
  try {
32965
- db = new Database3(path, { readonly: true });
33306
+ db = new Database4(path, { readonly: true });
32966
33307
  } catch (e) {
32967
33308
  return {
32968
33309
  schema_version: DB_BACKUP_SCHEMA,
@@ -33012,18 +33353,18 @@ function checkDatabaseIntegrity(dbPath) {
33012
33353
  };
33013
33354
  }
33014
33355
  function compactDatabase(dbPath) {
33015
- const path = dbPath ? resolve15(dbPath) : resolveDbPath();
33016
- const before = statSync6(path).size;
33017
- const db = new Database3(path);
33356
+ const path = dbPath ? resolve16(dbPath) : resolveDbPath();
33357
+ const before = statSync7(path).size;
33358
+ const db = new Database4(path);
33018
33359
  db.exec("VACUUM");
33019
33360
  db.close();
33020
- const after = statSync6(path).size;
33361
+ const after = statSync7(path).size;
33021
33362
  closeDatabase();
33022
33363
  return { path, bytes_before: before, bytes_after: after };
33023
33364
  }
33024
33365
  function migrationDryRun(dbPath) {
33025
- const path = dbPath ? resolve15(dbPath) : resolveDbPath();
33026
- const db = new Database3(path, { readonly: true });
33366
+ const path = dbPath ? resolve16(dbPath) : resolveDbPath();
33367
+ const db = new Database4(path, { readonly: true });
33027
33368
  let current = 0;
33028
33369
  try {
33029
33370
  const row = db.query("SELECT MAX(id) as id FROM _migrations").get();
@@ -33046,13 +33387,13 @@ function migrationDryRun(dbPath) {
33046
33387
  };
33047
33388
  }
33048
33389
  function defaultBackupPath(dbPath) {
33049
- const base = dbPath ? dirname11(resolve15(dbPath)) : dirname11(resolveDbPath());
33390
+ const base = dbPath ? dirname12(resolve16(dbPath)) : dirname12(resolveDbPath());
33050
33391
  const stamp = new Date().toISOString().replace(/[:.]/g, "-");
33051
- return join16(base, "backups", `todos-${stamp}.db`);
33392
+ return join17(base, "backups", `todos-${stamp}.db`);
33052
33393
  }
33053
33394
  function readBackupManifest(backupPath) {
33054
33395
  const manifestPath = `${backupPath}.json`;
33055
- if (!existsSync20(manifestPath))
33396
+ if (!existsSync21(manifestPath))
33056
33397
  return null;
33057
33398
  try {
33058
33399
  return JSON.parse(readFileSync17(manifestPath, "utf8"));
@@ -33065,7 +33406,7 @@ function writeBackupManifest(backupPath, result) {
33065
33406
  writeFileSyncSafe(manifestPath, JSON.stringify(result, null, 2));
33066
33407
  }
33067
33408
  function writeFileSyncSafe(path, content) {
33068
- mkdirSync13(dirname11(path), { recursive: true });
33409
+ mkdirSync13(dirname12(path), { recursive: true });
33069
33410
  writeFileSync11(path, content);
33070
33411
  }
33071
33412
  // src/lib/json-schemas.ts
@@ -33573,15 +33914,15 @@ ${SCHEMA_ENTITIES.map((e) => `- **${e}**: \`${JSON_SCHEMAS[e].schema_version}\``
33573
33914
  }
33574
33915
  function exportSchemasToDirectory(dir) {
33575
33916
  const { mkdirSync: mkdirSync14, writeFileSync: writeFileSync12 } = __require("fs");
33576
- const { join: join17 } = __require("path");
33917
+ const { join: join18 } = __require("path");
33577
33918
  mkdirSync14(dir, { recursive: true });
33578
33919
  const written = [];
33579
33920
  for (const entity of SCHEMA_ENTITIES) {
33580
- const path = join17(dir, `${entity}.${JSON_SCHEMAS[entity].schema_version.replace(/\./g, "-")}.json`);
33921
+ const path = join18(dir, `${entity}.${JSON_SCHEMAS[entity].schema_version.replace(/\./g, "-")}.json`);
33581
33922
  writeFileSync12(path, JSON.stringify(JSON_SCHEMAS[entity], null, 2));
33582
33923
  written.push(path);
33583
33924
  }
33584
- const catalogPath = join17(dir, "catalog.json");
33925
+ const catalogPath = join18(dir, "catalog.json");
33585
33926
  writeFileSync12(catalogPath, JSON.stringify({
33586
33927
  catalog_version: JSON_SCHEMA_CATALOG_VERSION,
33587
33928
  semver: SCHEMA_SEMVER,
@@ -34482,7 +34823,7 @@ function getReminderDocs() {
34482
34823
  // src/lib/import-export-bridge.ts
34483
34824
  init_database();
34484
34825
  import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, mkdirSync as mkdirSync14 } from "fs";
34485
- import { dirname as dirname12 } from "path";
34826
+ import { dirname as dirname13 } from "path";
34486
34827
  init_secret_redaction();
34487
34828
  var BUNDLE_SCHEMA = "todos.bundle.v1";
34488
34829
  var BUNDLE_TYPES = ["full_export", "tasks", "partial"];
@@ -34890,7 +35231,7 @@ function importBundle(bundle, options = {}, db) {
34890
35231
  return result;
34891
35232
  }
34892
35233
  function writeBundleFile(bundle, path) {
34893
- mkdirSync14(dirname12(path), { recursive: true });
35234
+ mkdirSync14(dirname13(path), { recursive: true });
34894
35235
  writeFileSync12(path, JSON.stringify(bundle, null, 2), "utf8");
34895
35236
  }
34896
35237
  function readBundleFile(path) {
@@ -35371,7 +35712,7 @@ function createPlanWithSteps(name, steps, opts = {}, db) {
35371
35712
  // src/lib/handoff-packets.ts
35372
35713
  init_database();
35373
35714
  import { writeFileSync as writeFileSync13, mkdirSync as mkdirSync15 } from "fs";
35374
- import { dirname as dirname13 } from "path";
35715
+ import { dirname as dirname14 } from "path";
35375
35716
  var HANDOFF_PACKET_SCHEMA = "todos.handoff_packet.v1";
35376
35717
  function summarizeTask2(t) {
35377
35718
  return {
@@ -35545,7 +35886,7 @@ function formatHandoffPacket(packet, format = "json") {
35545
35886
  function exportHandoffPacket(input = {}, path, db) {
35546
35887
  const packet = createHandoffPacket(input, db);
35547
35888
  if (path) {
35548
- mkdirSync15(dirname13(path), { recursive: true });
35889
+ mkdirSync15(dirname14(path), { recursive: true });
35549
35890
  writeFileSync13(path, formatHandoffPacket(packet, "json"), "utf8");
35550
35891
  }
35551
35892
  return packet;
@@ -36150,7 +36491,7 @@ function generateCliReferenceMarkdown() {
36150
36491
  // src/db/builtin-templates.ts
36151
36492
  init_database();
36152
36493
  import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync14 } from "fs";
36153
- import { join as join17 } from "path";
36494
+ import { join as join18 } from "path";
36154
36495
  var BUILTIN_TEMPLATE_LIBRARY_VERSION = "2026-05-21";
36155
36496
  var BUILTIN_TEMPLATE_LIBRARY_SOURCE = "bundled-local-template-library";
36156
36497
  var TEMPLATE_LIBRARY_SCHEMA = "todos.template_library.v1";
@@ -36426,7 +36767,7 @@ function writeBuiltinTemplateFiles(directory) {
36426
36767
  mkdirSync16(directory, { recursive: true });
36427
36768
  const files = [];
36428
36769
  for (const entry2 of exportBuiltinTemplateFiles()) {
36429
- const path = join17(directory, entry2.filename);
36770
+ const path = join18(directory, entry2.filename);
36430
36771
  writeFileSync14(path, `${JSON.stringify(entry2.template, null, 2)}
36431
36772
  `, "utf-8");
36432
36773
  files.push(path);
@@ -36471,7 +36812,7 @@ function initBuiltinTemplates(db) {
36471
36812
  // src/lib/template-library.ts
36472
36813
  init_database();
36473
36814
  import { writeFileSync as writeFileSync15, readFileSync as readFileSync19, mkdirSync as mkdirSync17 } from "fs";
36474
- import { dirname as dirname14 } from "path";
36815
+ import { dirname as dirname15 } from "path";
36475
36816
  function listTemplateLibrary(db) {
36476
36817
  const d = db || getDatabase();
36477
36818
  const installed = new Set(listTemplates(d).map((t) => t.name));
@@ -36513,7 +36854,7 @@ function exportTemplateLibraryCatalog(path, db) {
36513
36854
  templates: listTemplateLibrary(db)
36514
36855
  };
36515
36856
  if (path) {
36516
- mkdirSync17(dirname14(path), { recursive: true });
36857
+ mkdirSync17(dirname15(path), { recursive: true });
36517
36858
  writeFileSync15(path, JSON.stringify(catalog, null, 2), "utf8");
36518
36859
  }
36519
36860
  return catalog;
@@ -36573,11 +36914,11 @@ init_database();
36573
36914
  init_machines();
36574
36915
  import { hostname as hostname2 } from "os";
36575
36916
  var MACHINE_TOPOLOGY_SCHEMA = "todos.machine_topology.v1";
36576
- function normalizePath4(p) {
36917
+ function normalizePath5(p) {
36577
36918
  return p.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
36578
36919
  }
36579
36920
  function detectCasingMismatch(stored, canonical) {
36580
- return normalizePath4(stored) === normalizePath4(canonical) && stored !== canonical;
36921
+ return normalizePath5(stored) === normalizePath5(canonical) && stored !== canonical;
36581
36922
  }
36582
36923
  function registerLocalMachine(db) {
36583
36924
  resetMachineId();
@@ -36596,7 +36937,7 @@ function getPathOverrides(db) {
36596
36937
  project_name: project?.name ?? row.project_id.slice(0, 8),
36597
36938
  machine_id: row.machine_id,
36598
36939
  path: row.path,
36599
- path_normalized: normalizePath4(row.path),
36940
+ path_normalized: normalizePath5(row.path),
36600
36941
  casing_mismatch: detectCasingMismatch(row.path, canonical)
36601
36942
  };
36602
36943
  });
@@ -36708,10 +37049,10 @@ todos machines topology # full diagnostic report
36708
37049
  `;
36709
37050
  }
36710
37051
  // src/lib/environment-snapshots.ts
36711
- import { createHash as createHash12 } from "crypto";
36712
- import { existsSync as existsSync21, readFileSync as readFileSync20, statSync as statSync7 } from "fs";
37052
+ import { createHash as createHash13 } from "crypto";
37053
+ import { existsSync as existsSync22, readFileSync as readFileSync20, statSync as statSync8 } from "fs";
36713
37054
  import { hostname as hostname3, platform, arch } from "os";
36714
- import { dirname as dirname15, join as join18, resolve as resolve16 } from "path";
37055
+ import { dirname as dirname16, join as join19, resolve as resolve17 } from "path";
36715
37056
  import { tmpdir as tmpdir3 } from "os";
36716
37057
  init_database();
36717
37058
  init_redaction();
@@ -36733,13 +37074,13 @@ var CONFIG_FILES = [
36733
37074
  "dashboard/vite.config.ts"
36734
37075
  ];
36735
37076
  function sha2565(value) {
36736
- return createHash12("sha256").update(value).digest("hex");
37077
+ return createHash13("sha256").update(value).digest("hex");
36737
37078
  }
36738
37079
  function fileRecord(root, relativePath) {
36739
- const path = join18(root, relativePath);
36740
- if (!existsSync21(path))
37080
+ const path = join19(root, relativePath);
37081
+ if (!existsSync22(path))
36741
37082
  return null;
36742
- const stat = statSync7(path);
37083
+ const stat = statSync8(path);
36743
37084
  if (!stat.isFile())
36744
37085
  return null;
36745
37086
  const content = readFileSync20(path);
@@ -36749,7 +37090,7 @@ function manifestRecord(root, relativePath) {
36749
37090
  const base = fileRecord(root, relativePath);
36750
37091
  if (!base)
36751
37092
  return null;
36752
- const parsed = readJsonFile(join18(root, relativePath));
37093
+ const parsed = readJsonFile(join19(root, relativePath));
36753
37094
  if (!parsed)
36754
37095
  return { ...base, redacted: {} };
36755
37096
  const redacted = redactValue({
@@ -36844,15 +37185,15 @@ function commandEnv(env, includeValues) {
36844
37185
  function defaultSnapshotDir() {
36845
37186
  const dbPath = getDatabasePath();
36846
37187
  if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
36847
- return join18(tmpdir3(), "hasna-todos", "environment-snapshots");
36848
- return join18(dirname15(resolve16(dbPath)), "environment-snapshots");
37188
+ return join19(tmpdir3(), "hasna-todos", "environment-snapshots");
37189
+ return join19(dirname16(resolve17(dbPath)), "environment-snapshots");
36849
37190
  }
36850
37191
  function snapshotWithId(snapshot) {
36851
37192
  const digest = sha2565(JSON.stringify(snapshot)).slice(0, 24);
36852
37193
  return { id: `env_${digest}`, ...snapshot };
36853
37194
  }
36854
37195
  function captureEnvironmentSnapshot(input = {}) {
36855
- const root = resolve16(input.root || process.cwd());
37196
+ const root = resolve17(input.root || process.cwd());
36856
37197
  const env = input.env || process.env;
36857
37198
  const warnings = [];
36858
37199
  const manifests = MANIFEST_FILES.map((file) => manifestRecord(root, file)).filter((file) => Boolean(file));
@@ -36892,13 +37233,13 @@ function captureEnvironmentSnapshot(input = {}) {
36892
37233
  });
36893
37234
  }
36894
37235
  function writeEnvironmentSnapshot(snapshot, outputPath) {
36895
- const path = outputPath ? resolve16(outputPath) : join18(defaultSnapshotDir(), `${snapshot.id}.json`);
36896
- ensureDir2(dirname15(path));
37236
+ const path = outputPath ? resolve17(outputPath) : join19(defaultSnapshotDir(), `${snapshot.id}.json`);
37237
+ ensureDir2(dirname16(path));
36897
37238
  writeJsonFile(path, snapshot);
36898
37239
  return path;
36899
37240
  }
36900
37241
  function readEnvironmentSnapshot(path) {
36901
- const snapshot = readJsonFile(resolve16(path));
37242
+ const snapshot = readJsonFile(resolve17(path));
36902
37243
  if (!snapshot || snapshot.schema_version !== 1 || typeof snapshot.id !== "string") {
36903
37244
  throw new Error(`Invalid environment snapshot: ${path}`);
36904
37245
  }
@@ -36983,9 +37324,9 @@ function compareEnvironmentSnapshotFiles(leftPath, rightPath) {
36983
37324
  }
36984
37325
  // src/lib/decision-records.ts
36985
37326
  init_database();
36986
- import { createHash as createHash13 } from "crypto";
37327
+ import { createHash as createHash14 } from "crypto";
36987
37328
  import { mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
36988
- import { dirname as dirname16, join as join19 } from "path";
37329
+ import { dirname as dirname17, join as join20 } from "path";
36989
37330
  var DECISION_RECORD_SCHEMA = "todos.decision_record.v1";
36990
37331
  var KNOWLEDGE_SNAPSHOT_SCHEMA = "todos.knowledge_snapshot.v1";
36991
37332
  var DECISION_STATUSES = ["proposed", "accepted", "deprecated", "superseded", "rejected"];
@@ -37039,7 +37380,7 @@ function rowToDecisionRecord(row) {
37039
37380
  }
37040
37381
  function stableSnapshotHash(payload) {
37041
37382
  const { captured_at: _capturedAt, ...rest } = payload;
37042
- return createHash13("sha256").update(JSON.stringify(rest)).digest("hex");
37383
+ return createHash14("sha256").update(JSON.stringify(rest)).digest("hex");
37043
37384
  }
37044
37385
  function createDecisionRecord(input, db) {
37045
37386
  const d = db || getDatabase();
@@ -37215,8 +37556,8 @@ function exportDecisionRecord(id, outputPath, format = "markdown", db) {
37215
37556
  if (!record)
37216
37557
  throw new Error(`Decision record not found: ${id}`);
37217
37558
  const content = format === "markdown" ? formatDecisionRecordMarkdown(record) : JSON.stringify(record, null, 2);
37218
- const path = outputPath ?? join19(process.cwd(), ".todos", "decisions", `${record.short_ref}.${format === "markdown" ? "md" : "json"}`);
37219
- mkdirSync18(dirname16(path), { recursive: true });
37559
+ const path = outputPath ?? join20(process.cwd(), ".todos", "decisions", `${record.short_ref}.${format === "markdown" ? "md" : "json"}`);
37560
+ mkdirSync18(dirname17(path), { recursive: true });
37220
37561
  writeFileSync16(path, content, "utf8");
37221
37562
  return { path, content };
37222
37563
  }
@@ -37363,8 +37704,8 @@ function exportKnowledgeSnapshot(id, outputPath, format = "markdown", db) {
37363
37704
  throw new Error(`Knowledge snapshot not found: ${id}`);
37364
37705
  const content = format === "markdown" ? formatKnowledgeSnapshotMarkdown(record) : JSON.stringify(record, null, 2);
37365
37706
  const slug = record.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
37366
- const path = outputPath ?? join19(process.cwd(), ".todos", "knowledge", `${slug || record.id.slice(0, 8)}.${format === "markdown" ? "md" : "json"}`);
37367
- mkdirSync18(dirname16(path), { recursive: true });
37707
+ const path = outputPath ?? join20(process.cwd(), ".todos", "knowledge", `${slug || record.id.slice(0, 8)}.${format === "markdown" ? "md" : "json"}`);
37708
+ mkdirSync18(dirname17(path), { recursive: true });
37368
37709
  writeFileSync16(path, content, "utf8");
37369
37710
  return { path, content };
37370
37711
  }
@@ -37392,7 +37733,7 @@ Schema versions:
37392
37733
  // src/lib/report-exports.ts
37393
37734
  init_database();
37394
37735
  import { writeFileSync as writeFileSync17, mkdirSync as mkdirSync19 } from "fs";
37395
- import { dirname as dirname17 } from "path";
37736
+ import { dirname as dirname18 } from "path";
37396
37737
  init_secret_redaction();
37397
37738
  var REPORT_EXPORT_SCHEMA = "todos.report_export.v1";
37398
37739
  var REPORT_KINDS = ["project", "plan", "run", "evidence", "roadmap", "retrospective"];
@@ -37624,7 +37965,7 @@ function formatReportExport(data, format) {
37624
37965
  return format === "html" ? formatReportHtml(data) : formatReportMarkdown(data);
37625
37966
  }
37626
37967
  function writeReportExport(data, format, path) {
37627
- mkdirSync19(dirname17(path), { recursive: true });
37968
+ mkdirSync19(dirname18(path), { recursive: true });
37628
37969
  writeFileSync17(path, formatReportExport(data, format), "utf8");
37629
37970
  }
37630
37971
  function exportReport(input, db) {
@@ -37658,8 +37999,8 @@ todos report export --kind retrospective --days 14 --format markdown --out retro
37658
37999
  `;
37659
38000
  }
37660
38001
  // src/lib/command-aliases.ts
37661
- import { existsSync as existsSync22, readFileSync as readFileSync21, writeFileSync as writeFileSync18, mkdirSync as mkdirSync20 } from "fs";
37662
- import { join as join20 } from "path";
38002
+ import { existsSync as existsSync23, readFileSync as readFileSync21, writeFileSync as writeFileSync18, mkdirSync as mkdirSync20 } from "fs";
38003
+ import { join as join21 } from "path";
37663
38004
  var COMMAND_ALIASES_SCHEMA = "todos.command_aliases.v1";
37664
38005
  var RESERVED = new Set([...listTopLevelCommands(), "help", "version", "alias", "shortcuts"]);
37665
38006
  var BUILTIN_SHORTCUTS = [
@@ -37678,7 +38019,7 @@ var BUILTIN_SHORTCUTS = [
37678
38019
  { pattern: /^reports?$/, argv: ["report", "docs"], explain: "Report export documentation" }
37679
38020
  ];
37680
38021
  function aliasesPath(cwd = process.cwd()) {
37681
- return join20(cwd, ".todos", "aliases.json");
38022
+ return join21(cwd, ".todos", "aliases.json");
37682
38023
  }
37683
38024
  function emptyStore() {
37684
38025
  return { schema_version: COMMAND_ALIASES_SCHEMA, aliases: {}, updated_at: new Date(0).toISOString() };
@@ -37695,7 +38036,7 @@ function validateAliasName(name) {
37695
38036
  }
37696
38037
  function loadAliasStore(cwd) {
37697
38038
  const path = aliasesPath(cwd);
37698
- if (!existsSync22(path))
38039
+ if (!existsSync23(path))
37699
38040
  return emptyStore();
37700
38041
  const parsed = JSON.parse(readFileSync21(path, "utf8"));
37701
38042
  if (parsed.schema_version !== COMMAND_ALIASES_SCHEMA) {
@@ -37705,7 +38046,7 @@ function loadAliasStore(cwd) {
37705
38046
  }
37706
38047
  function saveAliasStore(store, cwd) {
37707
38048
  const path = aliasesPath(cwd);
37708
- mkdirSync20(join20(path, ".."), { recursive: true });
38049
+ mkdirSync20(join21(path, ".."), { recursive: true });
37709
38050
  store.updated_at = new Date().toISOString();
37710
38051
  writeFileSync18(path, JSON.stringify(store, null, 2), "utf8");
37711
38052
  }
@@ -38220,7 +38561,7 @@ function normalizeBranch(value) {
38220
38561
  }
38221
38562
  return branch;
38222
38563
  }
38223
- function normalizePath5(value) {
38564
+ function normalizePath6(value) {
38224
38565
  const path = value.trim().replace(/\\/g, "/");
38225
38566
  if (!path || path.startsWith("/") || path.includes("\x00"))
38226
38567
  return null;
@@ -38252,7 +38593,7 @@ function getGitStatus(root, branch, includeGitStatus) {
38252
38593
  const branchExists = runGit3(root, ["show-ref", "--verify", `refs/heads/${branch}`]) !== null;
38253
38594
  const status = runGit3(root, ["status", "--short"]) || "";
38254
38595
  const dirtyFiles = status.split(`
38255
- `).map((line) => line.trim()).filter(Boolean).map((line) => normalizePath5(line.replace(/^.. /, "").replace(/^.* -> /, ""))).filter((path) => Boolean(path));
38596
+ `).map((line) => line.trim()).filter(Boolean).map((line) => normalizePath6(line.replace(/^.. /, "").replace(/^.* -> /, ""))).filter((path) => Boolean(path));
38256
38597
  return { has_git: true, current_branch: currentBranch || null, branch_exists: branchExists, dirty_files: dirtyFiles };
38257
38598
  }
38258
38599
  function resolveScope2(input, db) {
@@ -38267,8 +38608,8 @@ function resolveScope2(input, db) {
38267
38608
  throw new Error("task_id or plan_id is required");
38268
38609
  }
38269
38610
  function collectPlannedFiles(tasks, explicitPaths, db) {
38270
- const fromTasks = tasks.flatMap((task2) => listTaskFiles(task2.id, db).map((file) => normalizePath5(file.path)));
38271
- const fromInput = (explicitPaths || []).map(normalizePath5);
38611
+ const fromTasks = tasks.flatMap((task2) => listTaskFiles(task2.id, db).map((file) => normalizePath6(file.path)));
38612
+ const fromInput = (explicitPaths || []).map(normalizePath6);
38272
38613
  return uniqueSorted2([...fromTasks, ...fromInput]);
38273
38614
  }
38274
38615
  function detectBranchPlanConflicts(taskIds, files, db) {
@@ -38353,18 +38694,18 @@ function createBranchWorkPlan(input, db) {
38353
38694
  }
38354
38695
  // src/lib/user-scaffolds.ts
38355
38696
  init_database();
38356
- import { existsSync as existsSync23, readFileSync as readFileSync22, writeFileSync as writeFileSync19, mkdirSync as mkdirSync21 } from "fs";
38357
- import { join as join21 } from "path";
38697
+ import { existsSync as existsSync24, readFileSync as readFileSync22, writeFileSync as writeFileSync19, mkdirSync as mkdirSync21 } from "fs";
38698
+ import { join as join22 } from "path";
38358
38699
  var USER_SCAFFOLD_SCHEMA = "todos.user_scaffold.v1";
38359
38700
  var SCAFFOLD_KINDS = ["task", "project", "plan", "checklist", "contract", "verification_policy"];
38360
38701
  function storeDir(cwd = process.cwd()) {
38361
- return join21(cwd, ".todos", "scaffolds");
38702
+ return join22(cwd, ".todos", "scaffolds");
38362
38703
  }
38363
38704
  function storePath(cwd) {
38364
- return join21(storeDir(cwd), "store.json");
38705
+ return join22(storeDir(cwd), "store.json");
38365
38706
  }
38366
38707
  function versionsDir(cwd) {
38367
- return join21(storeDir(cwd), "versions");
38708
+ return join22(storeDir(cwd), "versions");
38368
38709
  }
38369
38710
  function slugify5(name) {
38370
38711
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
@@ -38374,7 +38715,7 @@ function emptyStore2() {
38374
38715
  }
38375
38716
  function loadUserScaffoldStore(cwd) {
38376
38717
  const path = storePath(cwd);
38377
- if (!existsSync23(path))
38718
+ if (!existsSync24(path))
38378
38719
  return emptyStore2();
38379
38720
  const parsed = JSON.parse(readFileSync22(path, "utf8"));
38380
38721
  if (parsed.schema_version !== USER_SCAFFOLD_SCHEMA) {
@@ -38389,7 +38730,7 @@ function saveUserScaffoldStore(store, cwd) {
38389
38730
  }
38390
38731
  function snapshotVersion(scaffold, cwd) {
38391
38732
  mkdirSync21(versionsDir(cwd), { recursive: true });
38392
- const path = join21(versionsDir(cwd), `${scaffold.id}-v${scaffold.version}.json`);
38733
+ const path = join22(versionsDir(cwd), `${scaffold.id}-v${scaffold.version}.json`);
38393
38734
  writeFileSync19(path, JSON.stringify(scaffold, null, 2), "utf8");
38394
38735
  }
38395
38736
  function listUserScaffolds(kind, cwd) {
@@ -38636,7 +38977,7 @@ function listLinkedTemplates(db, cwd) {
38636
38977
  // src/lib/agent-workflow-demo.ts
38637
38978
  init_database();
38638
38979
  import { mkdtempSync } from "fs";
38639
- import { join as join22 } from "path";
38980
+ import { join as join23 } from "path";
38640
38981
  import { tmpdir as tmpdir4 } from "os";
38641
38982
  var AGENT_WORKFLOW_DEMO_SCHEMA = "todos.agent_workflow_demo.v1";
38642
38983
  var DEMO_DEFAULT_AGENT = "demoagent";
@@ -38652,7 +38993,7 @@ function setupEphemeralDemoDb(options = {}) {
38652
38993
  if (options.db_path) {
38653
38994
  db_path = options.db_path;
38654
38995
  } else if (options.persist) {
38655
- db_path = join22(mkdtempSync(join22(tmpdir4(), "todos-demo-")), "todos.db");
38996
+ db_path = join23(mkdtempSync(join23(tmpdir4(), "todos-demo-")), "todos.db");
38656
38997
  } else {
38657
38998
  db_path = ":memory:";
38658
38999
  }
@@ -40977,18 +41318,18 @@ function runSearchView(idOrName, db) {
40977
41318
  return { ...runSavedSearch(view.filters, view.scope, d), view };
40978
41319
  }
40979
41320
  // src/lib/claude-tasks.ts
40980
- import { existsSync as existsSync24, readFileSync as readFileSync23, readdirSync as readdirSync4, writeFileSync as writeFileSync20 } from "fs";
40981
- import { join as join23 } from "path";
41321
+ import { existsSync as existsSync25, readFileSync as readFileSync23, readdirSync as readdirSync5, writeFileSync as writeFileSync20 } from "fs";
41322
+ import { join as join24 } from "path";
40982
41323
  init_config();
40983
41324
  init_sync_utils();
40984
41325
  function getTaskListDir(taskListId) {
40985
- return join23(HOME, ".claude", "tasks", taskListId);
41326
+ return join24(HOME, ".claude", "tasks", taskListId);
40986
41327
  }
40987
41328
  function readClaudeTask(dir, filename) {
40988
- return readJsonFile(join23(dir, filename));
41329
+ return readJsonFile(join24(dir, filename));
40989
41330
  }
40990
41331
  function writeClaudeTask(dir, task2) {
40991
- writeJsonFile(join23(dir, `${task2.id}.json`), task2);
41332
+ writeJsonFile(join24(dir, `${task2.id}.json`), task2);
40992
41333
  }
40993
41334
  function toClaudeStatus(status) {
40994
41335
  if (status === "pending" || status === "in_progress" || status === "completed") {
@@ -41000,14 +41341,14 @@ function toSqliteStatus(status) {
41000
41341
  return status;
41001
41342
  }
41002
41343
  function readPrefixCounter(dir) {
41003
- const path = join23(dir, ".prefix-counter");
41004
- if (!existsSync24(path))
41344
+ const path = join24(dir, ".prefix-counter");
41345
+ if (!existsSync25(path))
41005
41346
  return 0;
41006
41347
  const val = parseInt(readFileSync23(path, "utf-8").trim(), 10);
41007
41348
  return isNaN(val) ? 0 : val;
41008
41349
  }
41009
41350
  function writePrefixCounter(dir, value) {
41010
- writeFileSync20(join23(dir, ".prefix-counter"), String(value));
41351
+ writeFileSync20(join24(dir, ".prefix-counter"), String(value));
41011
41352
  }
41012
41353
  function formatPrefixedSubject(title, prefix, counter) {
41013
41354
  const padded = String(counter).padStart(5, "0");
@@ -41034,7 +41375,7 @@ function taskToClaudeTask(task2, claudeTaskId, existingMeta) {
41034
41375
  }
41035
41376
  function pushToClaudeTaskList(taskListId, projectId, options = {}) {
41036
41377
  const dir = getTaskListDir(taskListId);
41037
- if (!existsSync24(dir))
41378
+ if (!existsSync25(dir))
41038
41379
  ensureDir2(dir);
41039
41380
  const filter = {};
41040
41381
  if (projectId)
@@ -41043,7 +41384,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
41043
41384
  const existingByTodosId = new Map;
41044
41385
  const files = listJsonFiles(dir);
41045
41386
  for (const f of files) {
41046
- const path = join23(dir, f);
41387
+ const path = join24(dir, f);
41047
41388
  const ct = readClaudeTask(dir, f);
41048
41389
  if (ct?.metadata?.["todos_id"]) {
41049
41390
  existingByTodosId.set(ct.metadata["todos_id"], { task: ct, mtimeMs: getFileMtimeMs(path) });
@@ -41130,10 +41471,10 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
41130
41471
  }
41131
41472
  function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
41132
41473
  const dir = getTaskListDir(taskListId);
41133
- if (!existsSync24(dir)) {
41474
+ if (!existsSync25(dir)) {
41134
41475
  return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
41135
41476
  }
41136
- const files = readdirSync4(dir).filter((f) => f.endsWith(".json"));
41477
+ const files = readdirSync5(dir).filter((f) => f.endsWith(".json"));
41137
41478
  let pulled = 0;
41138
41479
  const errors = [];
41139
41480
  const prefer = options.prefer || "remote";
@@ -41150,7 +41491,7 @@ function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
41150
41491
  }
41151
41492
  for (const f of files) {
41152
41493
  try {
41153
- const filePath = join23(dir, f);
41494
+ const filePath = join24(dir, f);
41154
41495
  const ct = readClaudeTask(dir, f);
41155
41496
  if (!ct)
41156
41497
  continue;
@@ -41218,22 +41559,22 @@ function syncClaudeTaskList(taskListId, projectId, options = {}) {
41218
41559
  }
41219
41560
 
41220
41561
  // src/lib/agent-tasks.ts
41221
- import { existsSync as existsSync25 } from "fs";
41222
- import { join as join24 } from "path";
41562
+ import { existsSync as existsSync26 } from "fs";
41563
+ import { join as join25 } from "path";
41223
41564
  init_sync_utils();
41224
41565
  init_config();
41225
41566
  function agentBaseDir(agent) {
41226
41567
  const key = `TODOS_${agent.toUpperCase()}_TASKS_DIR`;
41227
- return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join24(getTodosGlobalDir(), "agents");
41568
+ return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join25(getTodosGlobalDir(), "agents");
41228
41569
  }
41229
41570
  function getTaskListDir2(agent, taskListId) {
41230
- return join24(agentBaseDir(agent), agent, taskListId);
41571
+ return join25(agentBaseDir(agent), agent, taskListId);
41231
41572
  }
41232
41573
  function readAgentTask(dir, filename) {
41233
- return readJsonFile(join24(dir, filename));
41574
+ return readJsonFile(join25(dir, filename));
41234
41575
  }
41235
41576
  function writeAgentTask(dir, task2) {
41236
- writeJsonFile(join24(dir, `${task2.id}.json`), task2);
41577
+ writeJsonFile(join25(dir, `${task2.id}.json`), task2);
41237
41578
  }
41238
41579
  function taskToAgentTask(task2, externalId, existingMeta) {
41239
41580
  return {
@@ -41258,7 +41599,7 @@ function metadataKey(agent) {
41258
41599
  }
41259
41600
  function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
41260
41601
  const dir = getTaskListDir2(agent, taskListId);
41261
- if (!existsSync25(dir))
41602
+ if (!existsSync26(dir))
41262
41603
  ensureDir2(dir);
41263
41604
  const filter = {};
41264
41605
  if (projectId)
@@ -41267,7 +41608,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
41267
41608
  const existingByTodosId = new Map;
41268
41609
  const files = listJsonFiles(dir);
41269
41610
  for (const f of files) {
41270
- const path = join24(dir, f);
41611
+ const path = join25(dir, f);
41271
41612
  const at = readAgentTask(dir, f);
41272
41613
  if (at?.metadata?.["todos_id"]) {
41273
41614
  existingByTodosId.set(at.metadata["todos_id"], { task: at, mtimeMs: getFileMtimeMs(path) });
@@ -41341,7 +41682,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
41341
41682
  }
41342
41683
  function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
41343
41684
  const dir = getTaskListDir2(agent, taskListId);
41344
- if (!existsSync25(dir)) {
41685
+ if (!existsSync26(dir)) {
41345
41686
  return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
41346
41687
  }
41347
41688
  const files = listJsonFiles(dir);
@@ -41360,7 +41701,7 @@ function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
41360
41701
  }
41361
41702
  for (const f of files) {
41362
41703
  try {
41363
- const filePath = join24(dir, f);
41704
+ const filePath = join25(dir, f);
41364
41705
  const at = readAgentTask(dir, f);
41365
41706
  if (!at)
41366
41707
  continue;
@@ -41498,9 +41839,9 @@ function syncWithAgents(agents, taskListIdByAgent, projectId, direction = "both"
41498
41839
  return { pushed, pulled, errors };
41499
41840
  }
41500
41841
  // src/lib/extract.ts
41501
- import { existsSync as existsSync26, readFileSync as readFileSync24, statSync as statSync8 } from "fs";
41502
- import { createHash as createHash14 } from "crypto";
41503
- import { relative as relative6, resolve as resolve17, join as join25 } from "path";
41842
+ import { existsSync as existsSync27, readFileSync as readFileSync24, statSync as statSync9 } from "fs";
41843
+ import { createHash as createHash15 } from "crypto";
41844
+ import { relative as relative6, resolve as resolve18, join as join26 } from "path";
41504
41845
  var EXTRACT_TAGS = ["TODO", "FIXME", "HACK", "XXX", "BUG", "NOTE"];
41505
41846
  var DEFAULT_EXTENSIONS = new Set([
41506
41847
  ".ts",
@@ -41564,15 +41905,15 @@ var SKIP_DIRS2 = new Set([
41564
41905
  ".parcel-cache"
41565
41906
  ]);
41566
41907
  function stableHash(value) {
41567
- return createHash14("sha256").update(value).digest("hex");
41908
+ return createHash15("sha256").update(value).digest("hex");
41568
41909
  }
41569
41910
  function normalizePathForMatch(value) {
41570
41911
  return value.replace(/\\/g, "/").replace(/^\.\//, "");
41571
41912
  }
41572
41913
  function readGitignorePatterns(basePath) {
41573
- const root = statSync8(basePath).isFile() ? resolve17(basePath, "..") : basePath;
41574
- const gitignorePath = join25(root, ".gitignore");
41575
- if (!existsSync26(gitignorePath))
41914
+ const root = statSync9(basePath).isFile() ? resolve18(basePath, "..") : basePath;
41915
+ const gitignorePath = join26(root, ".gitignore");
41916
+ if (!existsSync27(gitignorePath))
41576
41917
  return [];
41577
41918
  try {
41578
41919
  return readFileSync24(gitignorePath, "utf-8").split(`
@@ -41681,7 +42022,7 @@ function extractFromSource(source9, filePath, tags = [...EXTRACT_TAGS]) {
41681
42022
  return results;
41682
42023
  }
41683
42024
  function collectFiles(basePath, extensions, excludes, respectGitignore) {
41684
- const stat = statSync8(basePath);
42025
+ const stat = statSync9(basePath);
41685
42026
  if (stat.isFile()) {
41686
42027
  return [basePath];
41687
42028
  }
@@ -41706,7 +42047,7 @@ function collectFiles(basePath, extensions, excludes, respectGitignore) {
41706
42047
  return files.sort();
41707
42048
  }
41708
42049
  function buildCodebaseIndex(options) {
41709
- const basePath = resolve17(options.path);
42050
+ const basePath = resolve18(options.path);
41710
42051
  const tags = options.patterns || [...EXTRACT_TAGS];
41711
42052
  const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
41712
42053
  const excludes = options.exclude || [];
@@ -41714,10 +42055,10 @@ function buildCodebaseIndex(options) {
41714
42055
  const files = collectFiles(basePath, extensions, excludes, respectGitignore);
41715
42056
  const indexed = [];
41716
42057
  for (const file of files) {
41717
- const fullPath = statSync8(basePath).isFile() ? basePath : join25(basePath, file);
42058
+ const fullPath = statSync9(basePath).isFile() ? basePath : join26(basePath, file);
41718
42059
  try {
41719
42060
  const source9 = readFileSync24(fullPath, "utf-8");
41720
- const relPath = statSync8(basePath).isFile() ? relative6(resolve17(basePath, ".."), fullPath) : file;
42061
+ const relPath = statSync9(basePath).isFile() ? relative6(resolve18(basePath, ".."), fullPath) : file;
41721
42062
  indexed.push({
41722
42063
  file: relPath,
41723
42064
  checksum: stableHash(source9).slice(0, 24),
@@ -41737,7 +42078,7 @@ function buildCodebaseIndex(options) {
41737
42078
  };
41738
42079
  }
41739
42080
  function extractTodos(options, db) {
41740
- const basePath = resolve17(options.path);
42081
+ const basePath = resolve18(options.path);
41741
42082
  const tags = options.patterns || [...EXTRACT_TAGS];
41742
42083
  const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
41743
42084
  const excludes = options.exclude || [];
@@ -41745,10 +42086,10 @@ function extractTodos(options, db) {
41745
42086
  const files = collectFiles(basePath, extensions, excludes, respectGitignore);
41746
42087
  const allComments = [];
41747
42088
  for (const file of files) {
41748
- const fullPath = statSync8(basePath).isFile() ? basePath : join25(basePath, file);
42089
+ const fullPath = statSync9(basePath).isFile() ? basePath : join26(basePath, file);
41749
42090
  try {
41750
42091
  const source9 = readFileSync24(fullPath, "utf-8");
41751
- const relPath = statSync8(basePath).isFile() ? relative6(resolve17(basePath, ".."), fullPath) : file;
42092
+ const relPath = statSync9(basePath).isFile() ? relative6(resolve18(basePath, ".."), fullPath) : file;
41752
42093
  const comments = extractFromSource(source9, relPath, tags);
41753
42094
  allComments.push(...comments);
41754
42095
  } catch {}
@@ -41842,7 +42183,7 @@ async function watchSourceTodos(options, onRun) {
41842
42183
  const interval = Math.max(100, options.interval_ms || 2000);
41843
42184
  const once = options.once !== false && (!options.max_runs || options.max_runs <= 1);
41844
42185
  const maxRuns = options.max_runs ?? (once ? 1 : Number.POSITIVE_INFINITY);
41845
- const root = resolve17(options.path);
42186
+ const root = resolve18(options.path);
41846
42187
  const runs = [];
41847
42188
  let previous = new Map;
41848
42189
  for (let runNumber = 1;runNumber <= maxRuns; runNumber++) {
@@ -42452,7 +42793,7 @@ function renderWorkflowStatesMarkdown(states = listWorkflowStates()) {
42452
42793
  }
42453
42794
  // src/lib/agent-replay-simulator.ts
42454
42795
  init_redaction();
42455
- import { createHash as createHash15 } from "crypto";
42796
+ import { createHash as createHash16 } from "crypto";
42456
42797
  import { readFileSync as readFileSync25 } from "fs";
42457
42798
  function isObject(value) {
42458
42799
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
@@ -42474,7 +42815,7 @@ function stable2(value) {
42474
42815
  return Object.fromEntries(Object.keys(value).sort().map((key) => [key, stable2(value[key])]));
42475
42816
  }
42476
42817
  function fingerprint3(value) {
42477
- return createHash15("sha256").update(JSON.stringify(stable2(value))).digest("hex");
42818
+ return createHash16("sha256").update(JSON.stringify(stable2(value))).digest("hex");
42478
42819
  }
42479
42820
  function unpackFixture(input) {
42480
42821
  if (!isObject(input))
@@ -42713,9 +43054,9 @@ function renderAgentReplaySimulationMarkdown(simulation) {
42713
43054
  }
42714
43055
  // src/lib/local-extensions.ts
42715
43056
  init_config();
42716
- import { createHash as createHash16, createVerify } from "crypto";
42717
- import { existsSync as existsSync27, readdirSync as readdirSync5, readFileSync as readFileSync26, statSync as statSync9 } from "fs";
42718
- import { basename as basename5, join as join26, resolve as resolve18 } from "path";
43057
+ import { createHash as createHash17, createVerify } from "crypto";
43058
+ import { existsSync as existsSync28, readdirSync as readdirSync6, readFileSync as readFileSync26, statSync as statSync10 } from "fs";
43059
+ import { basename as basename6, join as join27, resolve as resolve19 } from "path";
42719
43060
  init_redaction();
42720
43061
  function isObject2(value) {
42721
43062
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
@@ -42800,7 +43141,7 @@ function parseJson(path) {
42800
43141
  return JSON.parse(readFileSync26(path, "utf8"));
42801
43142
  }
42802
43143
  function sha2566(bytes) {
42803
- return `sha256:${createHash16("sha256").update(bytes).digest("hex")}`;
43144
+ return `sha256:${createHash17("sha256").update(bytes).digest("hex")}`;
42804
43145
  }
42805
43146
  function compareVersions(a, b) {
42806
43147
  const left = a.split(".").map((part) => Number.parseInt(part, 10) || 0);
@@ -42995,11 +43336,11 @@ function verifyExtensionSignature(input) {
42995
43336
  return verifier.verify(input.public_key, decodeSignature(input.signature));
42996
43337
  }
42997
43338
  function inspectExtensionSource(source9) {
42998
- const resolved = resolve18(source9);
42999
- if (!existsSync27(resolved))
43339
+ const resolved = resolve19(source9);
43340
+ if (!existsSync28(resolved))
43000
43341
  throw new Error(`extension source not found: ${source9}`);
43001
- const stat = statSync9(resolved);
43002
- const manifestPath = stat.isDirectory() ? [join26(resolved, "todos.extension.json"), join26(resolved, "extension.json")].find(existsSync27) : resolved;
43342
+ const stat = statSync10(resolved);
43343
+ const manifestPath = stat.isDirectory() ? [join27(resolved, "todos.extension.json"), join27(resolved, "extension.json")].find(existsSync28) : resolved;
43003
43344
  if (!manifestPath)
43004
43345
  throw new Error(`extension directory ${source9} is missing todos.extension.json`);
43005
43346
  const raw = readFileSync26(manifestPath);
@@ -43093,26 +43434,26 @@ function testExtensionCompatibility(sourceOrManifest) {
43093
43434
  function projectExtensionSources(projectPath) {
43094
43435
  if (!projectPath)
43095
43436
  return [];
43096
- const root = resolve18(projectPath);
43437
+ const root = resolve19(projectPath);
43097
43438
  const candidates = [
43098
- join26(root, "todos.extension.json"),
43099
- join26(root, ".todos", "todos.extension.json")
43439
+ join27(root, "todos.extension.json"),
43440
+ join27(root, ".todos", "todos.extension.json")
43100
43441
  ];
43101
- const extensionDir = join26(root, ".todos", "extensions");
43102
- if (existsSync27(extensionDir)) {
43103
- for (const entry2 of readdirSync5(extensionDir)) {
43442
+ const extensionDir = join27(root, ".todos", "extensions");
43443
+ if (existsSync28(extensionDir)) {
43444
+ for (const entry2 of readdirSync6(extensionDir)) {
43104
43445
  if (entry2.startsWith("."))
43105
43446
  continue;
43106
- const full = join26(extensionDir, entry2);
43107
- if (statSync9(full).isDirectory() || entry2.endsWith(".json"))
43447
+ const full = join27(extensionDir, entry2);
43448
+ if (statSync10(full).isDirectory() || entry2.endsWith(".json"))
43108
43449
  candidates.push(full);
43109
43450
  }
43110
43451
  }
43111
- return candidates.filter(existsSync27);
43452
+ return candidates.filter(existsSync28);
43112
43453
  }
43113
43454
  function discoverLocalExtensions(options = {}) {
43114
43455
  const config = loadConfig();
43115
- const projectPath = options.project_path ? resolve18(options.project_path) : null;
43456
+ const projectPath = options.project_path ? resolve19(options.project_path) : null;
43116
43457
  const configuredSources = [
43117
43458
  ...config.extension_sources || [],
43118
43459
  ...projectPath ? config.project_overrides?.[projectPath]?.extension_sources || [] : []
@@ -43120,7 +43461,7 @@ function discoverLocalExtensions(options = {}) {
43120
43461
  const sources = Array.from(new Set([
43121
43462
  ...configuredSources,
43122
43463
  ...projectExtensionSources(projectPath || undefined)
43123
- ])).map((source9) => projectPath && !source9.startsWith("/") ? resolve18(projectPath, source9) : resolve18(source9));
43464
+ ])).map((source9) => projectPath && !source9.startsWith("/") ? resolve19(projectPath, source9) : resolve19(source9));
43124
43465
  const warnings = [];
43125
43466
  const discovered = [];
43126
43467
  for (const source9 of sources) {
@@ -43202,7 +43543,7 @@ function removeLocalExtension(name) {
43202
43543
  return true;
43203
43544
  }
43204
43545
  function renderExtensionSummary(record) {
43205
- return `${record.name}@${record.version} ${record.status} ${basename5(record.source)} ${record.signature_verified ? "signed" : "unsigned"}`;
43546
+ return `${record.name}@${record.version} ${record.status} ${basename6(record.source)} ${record.signature_verified ? "signed" : "unsigned"}`;
43206
43547
  }
43207
43548
  // src/lib/workflow-prompts.ts
43208
43549
  var COMMON_ARGUMENTS = [
@@ -43969,7 +44310,7 @@ function resolveMissingTaskFindings(input, db) {
43969
44310
  init_redaction();
43970
44311
 
43971
44312
  // src/lib/retention-cleanup.ts
43972
- import { existsSync as existsSync28, unlinkSync as unlinkSync2 } from "fs";
44313
+ import { existsSync as existsSync29, unlinkSync as unlinkSync2 } from "fs";
43973
44314
  init_database();
43974
44315
  var RETENTION_CLEANUP_CONFIRMATION = "delete-local-retention-data";
43975
44316
  var ALL_SCOPES = ["comments", "runs", "verifications", "expired_artifacts"];
@@ -44181,7 +44522,7 @@ function applyRetentionCleanup(input, db) {
44181
44522
  for (const artifact of report.candidates.artifact_files) {
44182
44523
  try {
44183
44524
  const path = artifactStorePath(artifact.relative_path);
44184
- if (!existsSync28(path)) {
44525
+ if (!existsSync29(path)) {
44185
44526
  report.warnings.push(`stored artifact already missing: ${artifact.relative_path}`);
44186
44527
  continue;
44187
44528
  }
@@ -44419,8 +44760,8 @@ function renderScalePerformanceReportMarkdown(report) {
44419
44760
  init_database();
44420
44761
  init_migrations();
44421
44762
  init_schema();
44422
- import { chmodSync, copyFileSync as copyFileSync2, existsSync as existsSync29, mkdirSync as mkdirSync22, statSync as statSync10 } from "fs";
44423
- import { basename as basename6, dirname as dirname18, join as join27 } from "path";
44763
+ import { chmodSync, copyFileSync as copyFileSync2, existsSync as existsSync30, mkdirSync as mkdirSync22, statSync as statSync11 } from "fs";
44764
+ import { basename as basename7, dirname as dirname19, join as join28 } from "path";
44424
44765
  var REQUIRED_TABLES2 = [
44425
44766
  "_migrations",
44426
44767
  "projects",
@@ -44527,7 +44868,7 @@ function findMissingProjectRoots(db) {
44527
44868
  continue;
44528
44869
  if (!row.path.startsWith("/"))
44529
44870
  continue;
44530
- if (!existsSync29(row.path))
44871
+ if (!existsSync30(row.path))
44531
44872
  missing++;
44532
44873
  }
44533
44874
  return missing;
@@ -44579,7 +44920,7 @@ function databasePermissionsAreUnsafe(dbPath) {
44579
44920
  if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
44580
44921
  return false;
44581
44922
  try {
44582
- return (statSync10(dbPath).mode & 63) !== 0;
44923
+ return (statSync11(dbPath).mode & 63) !== 0;
44583
44924
  } catch {
44584
44925
  return false;
44585
44926
  }
@@ -44587,16 +44928,16 @@ function databasePermissionsAreUnsafe(dbPath) {
44587
44928
  function createBackup(dbPath) {
44588
44929
  if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
44589
44930
  return;
44590
- if (!existsSync29(dbPath))
44931
+ if (!existsSync30(dbPath))
44591
44932
  return;
44592
44933
  const stamp = now().replace(/[:.]/g, "-");
44593
- const backupDir = join27(dirname18(dbPath), `${basename6(dbPath)}.backup-${stamp}`);
44934
+ const backupDir = join28(dirname19(dbPath), `${basename7(dbPath)}.backup-${stamp}`);
44594
44935
  const files = [];
44595
44936
  mkdirSync22(backupDir, { recursive: true });
44596
44937
  for (const source9 of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
44597
- if (!existsSync29(source9))
44938
+ if (!existsSync30(source9))
44598
44939
  continue;
44599
- const target = join27(backupDir, basename6(source9));
44940
+ const target = join28(backupDir, basename7(source9));
44600
44941
  copyFileSync2(source9, target);
44601
44942
  files.push(target);
44602
44943
  }
@@ -46020,6 +46361,7 @@ export {
46020
46361
  dispatchToMultiple,
46021
46362
  dismissReminder,
46022
46363
  discoverVerificationProviderCapabilities,
46364
+ discoverTaskRouteSources,
46023
46365
  discoverProjectWorkspace,
46024
46366
  discoverLocalExtensions,
46025
46367
  detectSourceType,
@@ -46271,6 +46613,7 @@ export {
46271
46613
  TASK_WORKFLOW_POINTER_SCHEMA_VERSION,
46272
46614
  TASK_STATUSES,
46273
46615
  TASK_SCHEDULING_SCHEMA,
46616
+ TASK_ROUTE_SOURCE_DISCOVERY_SCHEMA_VERSION,
46274
46617
  TASK_PRIORITIES,
46275
46618
  TASK_FINDING_UPSERT_SCHEMA_VERSION,
46276
46619
  TASK_FINDING_SCHEMA_VERSION,