@hasna/todos 0.11.69 → 0.11.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -1011,7 +1011,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1011
1011
  this._exitCallback = (err) => {
1012
1012
  if (err.code !== "commander.executeSubCommandAsync") {
1013
1013
  throw err;
1014
- } else {}
1014
+ }
1015
1015
  };
1016
1016
  }
1017
1017
  return this;
@@ -13681,6 +13681,299 @@ var init_task_commands = __esm(() => {
13681
13681
  init_types();
13682
13682
  });
13683
13683
 
13684
+ // src/lib/plan-artifacts.ts
13685
+ import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
13686
+ import { join as join7, resolve as resolve10 } from "path";
13687
+ function assertSafePathSegment(value, label) {
13688
+ const trimmed = value.trim();
13689
+ if (!trimmed || trimmed === "." || trimmed === ".." || trimmed.includes("/") || trimmed.includes("\\")) {
13690
+ throw new Error(`Invalid ${label} for plan artifact path`);
13691
+ }
13692
+ if (!/^[A-Za-z0-9._-]+$/.test(trimmed)) {
13693
+ throw new Error(`Invalid ${label} for plan artifact path`);
13694
+ }
13695
+ return trimmed;
13696
+ }
13697
+ function frontmatterScalar(value) {
13698
+ return JSON.stringify(value);
13699
+ }
13700
+ function parseFrontmatterScalar(value) {
13701
+ const trimmed = value.trim();
13702
+ if (trimmed === "null")
13703
+ return null;
13704
+ try {
13705
+ const parsed = JSON.parse(trimmed);
13706
+ if (parsed === null || typeof parsed === "string")
13707
+ return parsed;
13708
+ } catch {}
13709
+ return trimmed.replace(/^["']|["']$/g, "") || null;
13710
+ }
13711
+ function markdownEscape(text) {
13712
+ return text.replace(/<!--[\s\S]*?-->/g, "").trim();
13713
+ }
13714
+ function markdownLine(text) {
13715
+ return markdownEscape(text).replace(/\s+/g, " ").trim();
13716
+ }
13717
+ function projectSlugMatches(project, ref) {
13718
+ const normalized = slugify(ref);
13719
+ return Boolean(normalized) && (project.task_list_id === normalized || slugify(project.name) === normalized);
13720
+ }
13721
+ function resolvePlanArtifactProject(input) {
13722
+ const db = input.db || getDatabase();
13723
+ const ref = input.project_id || input.project_ref;
13724
+ if (!ref)
13725
+ throw new Error("Plan artifacts require a project id or project reference");
13726
+ const byPath = getProjectByPath(resolve10(ref), db);
13727
+ if (byPath)
13728
+ return byPath;
13729
+ const resolvedId = resolvePartialId(db, "projects", ref);
13730
+ if (resolvedId) {
13731
+ const project2 = getProject(resolvedId, db);
13732
+ if (project2)
13733
+ return project2;
13734
+ }
13735
+ const project = listProjects(db).find((candidate) => projectSlugMatches(candidate, ref));
13736
+ if (project)
13737
+ return project;
13738
+ throw new Error(`Project not found for plan artifacts: ${ref}`);
13739
+ }
13740
+ function resolvePlanArtifactPaths(input) {
13741
+ const project = resolvePlanArtifactProject(input);
13742
+ const projectId = assertSafePathSegment(project.id, "project id");
13743
+ const projectRoot = resolve10(project.path);
13744
+ const directory = join7(projectRoot, ".hasna", "todos", "plans", projectId);
13745
+ const planId = input.plan_id ? assertSafePathSegment(input.plan_id, "plan id") : null;
13746
+ return {
13747
+ project_id: project.id,
13748
+ project_root: projectRoot,
13749
+ directory,
13750
+ file_path: planId ? join7(directory, `${planId}.md`) : directory
13751
+ };
13752
+ }
13753
+ function buildPlanArtifactSnapshot(plan, tasks = [], artifactUpdatedAt = new Date().toISOString()) {
13754
+ if (!plan.project_id)
13755
+ throw new Error("Plan artifacts require a project-scoped plan");
13756
+ const taskReferences = tasks.map((task) => ({
13757
+ task_id: task.id,
13758
+ title: task.title,
13759
+ status: task.status,
13760
+ priority: task.priority
13761
+ }));
13762
+ const body = renderPlanArtifactBody(plan, taskReferences);
13763
+ return {
13764
+ metadata: {
13765
+ schema: PLAN_MARKDOWN_SCHEMA,
13766
+ plan_id: plan.id,
13767
+ project_id: plan.project_id,
13768
+ task_list_id: plan.task_list_id ?? null,
13769
+ agent_id: plan.agent_id ?? null,
13770
+ stable_id: plan.id,
13771
+ name: plan.name,
13772
+ status: plan.status,
13773
+ created_at: plan.created_at,
13774
+ updated_at: plan.updated_at,
13775
+ artifact_updated_at: artifactUpdatedAt
13776
+ },
13777
+ task_references: taskReferences,
13778
+ body
13779
+ };
13780
+ }
13781
+ function renderPlanArtifactBody(plan, tasks) {
13782
+ const lines = [`# ${markdownLine(plan.name) || plan.id}`, ""];
13783
+ if (plan.description?.trim()) {
13784
+ lines.push(markdownEscape(plan.description), "");
13785
+ }
13786
+ lines.push("## Tasks", "");
13787
+ if (tasks.length === 0) {
13788
+ lines.push("_No tasks are currently attached to this plan._", "");
13789
+ } else {
13790
+ for (const task of tasks) {
13791
+ const check = task.status === "completed" ? "x" : " ";
13792
+ lines.push(`- [${check}] ${markdownLine(task.title) || task.task_id}`);
13793
+ lines.push(` <!-- todos: task_id=${task.task_id} status=${task.status} priority=${task.priority} -->`);
13794
+ }
13795
+ lines.push("");
13796
+ }
13797
+ return lines.join(`
13798
+ `);
13799
+ }
13800
+ function renderPlanArtifactMarkdown(snapshot) {
13801
+ const metadata = snapshot.metadata;
13802
+ const lines = [
13803
+ "---",
13804
+ `schema: ${frontmatterScalar(metadata.schema)}`,
13805
+ `plan_id: ${frontmatterScalar(metadata.plan_id)}`,
13806
+ `project_id: ${frontmatterScalar(metadata.project_id)}`,
13807
+ `task_list_id: ${frontmatterScalar(metadata.task_list_id)}`,
13808
+ `agent_id: ${frontmatterScalar(metadata.agent_id)}`,
13809
+ `stable_id: ${frontmatterScalar(metadata.stable_id)}`,
13810
+ `name: ${frontmatterScalar(metadata.name)}`,
13811
+ `status: ${frontmatterScalar(metadata.status)}`,
13812
+ `created_at: ${frontmatterScalar(metadata.created_at)}`,
13813
+ `updated_at: ${frontmatterScalar(metadata.updated_at)}`,
13814
+ `artifact_updated_at: ${frontmatterScalar(metadata.artifact_updated_at)}`,
13815
+ "---",
13816
+ "",
13817
+ snapshot.body
13818
+ ];
13819
+ return `${lines.join(`
13820
+ `).replace(/\n{3,}/g, `
13821
+
13822
+ `).trimEnd()}
13823
+ `;
13824
+ }
13825
+ function parsePlanArtifactMarkdown(markdown) {
13826
+ const match = markdown.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
13827
+ if (!match)
13828
+ throw new Error("Invalid plan artifact: missing frontmatter");
13829
+ const rawMetadata = {};
13830
+ for (const line of match[1].split(/\r?\n/)) {
13831
+ const separator = line.indexOf(":");
13832
+ if (separator === -1)
13833
+ continue;
13834
+ const key = line.slice(0, separator).trim();
13835
+ const value = line.slice(separator + 1);
13836
+ rawMetadata[key] = parseFrontmatterScalar(value);
13837
+ }
13838
+ if (rawMetadata.schema !== PLAN_MARKDOWN_SCHEMA) {
13839
+ throw new Error(`Unsupported plan artifact schema: ${rawMetadata.schema ?? "unknown"}`);
13840
+ }
13841
+ const required = ["plan_id", "project_id", "stable_id", "name", "status", "created_at", "updated_at", "artifact_updated_at"];
13842
+ for (const key of required) {
13843
+ if (!rawMetadata[key])
13844
+ throw new Error(`Invalid plan artifact: missing ${key}`);
13845
+ }
13846
+ const body = match[2] ?? "";
13847
+ return {
13848
+ metadata: {
13849
+ schema: PLAN_MARKDOWN_SCHEMA,
13850
+ plan_id: rawMetadata.plan_id,
13851
+ project_id: rawMetadata.project_id,
13852
+ task_list_id: rawMetadata.task_list_id ?? null,
13853
+ agent_id: rawMetadata.agent_id ?? null,
13854
+ stable_id: rawMetadata.stable_id,
13855
+ name: rawMetadata.name,
13856
+ status: rawMetadata.status,
13857
+ created_at: rawMetadata.created_at,
13858
+ updated_at: rawMetadata.updated_at,
13859
+ artifact_updated_at: rawMetadata.artifact_updated_at
13860
+ },
13861
+ task_references: parseTaskReferences(body),
13862
+ body
13863
+ };
13864
+ }
13865
+ function parseTaskReferences(body) {
13866
+ const references = [];
13867
+ const taskLine = /^\s*-\s+\[[ xX]\]\s+(.+)$/;
13868
+ const metadataLine = /<!--\s*todos:\s*task_id=([A-Za-z0-9._-]+)\s+status=([A-Za-z_]+)\s+priority=([A-Za-z_]+)\s*-->/;
13869
+ const lines = body.split(/\r?\n/);
13870
+ for (let index = 0;index < lines.length; index++) {
13871
+ const titleMatch = lines[index].match(taskLine);
13872
+ if (!titleMatch)
13873
+ continue;
13874
+ const metadataMatch = lines[index + 1]?.match(metadataLine);
13875
+ if (!metadataMatch)
13876
+ continue;
13877
+ references.push({
13878
+ task_id: metadataMatch[1],
13879
+ title: titleMatch[1].trim(),
13880
+ status: metadataMatch[2],
13881
+ priority: metadataMatch[3]
13882
+ });
13883
+ }
13884
+ return references;
13885
+ }
13886
+ function writePlanArtifact(plan, db) {
13887
+ if (!plan.project_id)
13888
+ return null;
13889
+ const d = db || getDatabase();
13890
+ const tasks = listTasks({ plan_id: plan.id, include_archived: true }, d);
13891
+ const paths = resolvePlanArtifactPaths({ project_id: plan.project_id, plan_id: plan.id, db: d });
13892
+ const snapshot = buildPlanArtifactSnapshot(plan, tasks);
13893
+ mkdirSync5(paths.directory, { recursive: true });
13894
+ writeFileSync3(paths.file_path, renderPlanArtifactMarkdown(snapshot), "utf8");
13895
+ return { path: paths.file_path, snapshot };
13896
+ }
13897
+ function readPlanArtifact(plan, db) {
13898
+ if (!plan.project_id)
13899
+ return null;
13900
+ const d = db || getDatabase();
13901
+ const paths = resolvePlanArtifactPaths({ project_id: plan.project_id, plan_id: plan.id, db: d });
13902
+ if (!existsSync8(paths.file_path))
13903
+ return null;
13904
+ const markdown = readFileSync4(paths.file_path, "utf8");
13905
+ return {
13906
+ path: paths.file_path,
13907
+ markdown,
13908
+ ...parsePlanArtifactMarkdown(markdown)
13909
+ };
13910
+ }
13911
+ function inspectPlanArtifact(plan, db) {
13912
+ if (!plan.project_id)
13913
+ return null;
13914
+ const d = db || getDatabase();
13915
+ const paths = resolvePlanArtifactPaths({ project_id: plan.project_id, plan_id: plan.id, db: d });
13916
+ if (!existsSync8(paths.file_path)) {
13917
+ return {
13918
+ path: paths.file_path,
13919
+ exists: false,
13920
+ parse_error: null,
13921
+ metadata: null,
13922
+ task_references: [],
13923
+ conflicts: []
13924
+ };
13925
+ }
13926
+ try {
13927
+ const artifact = parsePlanArtifactMarkdown(readFileSync4(paths.file_path, "utf8"));
13928
+ return {
13929
+ path: paths.file_path,
13930
+ exists: true,
13931
+ parse_error: null,
13932
+ metadata: artifact.metadata,
13933
+ task_references: artifact.task_references,
13934
+ conflicts: comparePlanArtifact(plan, artifact, listTasks({ plan_id: plan.id, include_archived: true }, d))
13935
+ };
13936
+ } catch (error) {
13937
+ return {
13938
+ path: paths.file_path,
13939
+ exists: true,
13940
+ parse_error: error instanceof Error ? error.message : String(error),
13941
+ metadata: null,
13942
+ task_references: [],
13943
+ conflicts: []
13944
+ };
13945
+ }
13946
+ }
13947
+ function comparePlanArtifact(plan, artifact, tasks) {
13948
+ const conflicts = [];
13949
+ compare("plan_id", plan.id, artifact.metadata.plan_id, conflicts);
13950
+ compare("project_id", plan.project_id ?? null, artifact.metadata.project_id, conflicts);
13951
+ compare("name", plan.name, artifact.metadata.name, conflicts);
13952
+ compare("status", plan.status, artifact.metadata.status, conflicts);
13953
+ compare("updated_at", plan.updated_at, artifact.metadata.updated_at, conflicts);
13954
+ const dbTaskIds = tasks.map((task) => task.id).sort();
13955
+ const artifactTaskIds = artifact.task_references.map((task) => task.task_id).sort();
13956
+ if (dbTaskIds.join(",") !== artifactTaskIds.join(",")) {
13957
+ conflicts.push({
13958
+ field: "task_references",
13959
+ database: dbTaskIds.join(",") || null,
13960
+ artifact: artifactTaskIds.join(",") || null
13961
+ });
13962
+ }
13963
+ return conflicts;
13964
+ }
13965
+ function compare(field, database, artifact, conflicts) {
13966
+ if ((database ?? null) !== (artifact ?? null)) {
13967
+ conflicts.push({ field, database: database ?? null, artifact: artifact ?? null });
13968
+ }
13969
+ }
13970
+ var PLAN_MARKDOWN_SCHEMA = "hasna.todos.plan/v1";
13971
+ var init_plan_artifacts = __esm(() => {
13972
+ init_database();
13973
+ init_projects();
13974
+ init_tasks();
13975
+ });
13976
+
13684
13977
  // src/db/builtin-templates.ts
13685
13978
  var exports_builtin_templates = {};
13686
13979
  __export(exports_builtin_templates, {
@@ -13695,8 +13988,8 @@ __export(exports_builtin_templates, {
13695
13988
  BUILTIN_TEMPLATE_LIBRARY_SOURCE: () => BUILTIN_TEMPLATE_LIBRARY_SOURCE,
13696
13989
  BUILTIN_TEMPLATES: () => BUILTIN_TEMPLATES
13697
13990
  });
13698
- import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync3 } from "fs";
13699
- import { join as join7 } from "path";
13991
+ import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync4 } from "fs";
13992
+ import { join as join8 } from "path";
13700
13993
  function templateMetadata(template) {
13701
13994
  return {
13702
13995
  source: BUILTIN_TEMPLATE_LIBRARY_SOURCE,
@@ -13752,11 +14045,11 @@ function exportBuiltinTemplateFiles() {
13752
14045
  }));
13753
14046
  }
13754
14047
  function writeBuiltinTemplateFiles(directory) {
13755
- mkdirSync5(directory, { recursive: true });
14048
+ mkdirSync6(directory, { recursive: true });
13756
14049
  const files = [];
13757
14050
  for (const entry of exportBuiltinTemplateFiles()) {
13758
- const path = join7(directory, entry.filename);
13759
- writeFileSync3(path, `${JSON.stringify(entry.template, null, 2)}
14051
+ const path = join8(directory, entry.filename);
14052
+ writeFileSync4(path, `${JSON.stringify(entry.template, null, 2)}
13760
14053
  `, "utf-8");
13761
14054
  files.push(path);
13762
14055
  }
@@ -14024,7 +14317,7 @@ __export(exports_plan_template_commands, {
14024
14317
  });
14025
14318
  import chalk3 from "chalk";
14026
14319
  function registerPlanTemplateCommands(program2) {
14027
- program2.command("plans").description("List and manage plans").option("--add <name>", "Create a plan").option("-d, --description <text>", "Plan description (with --add)").option("--show <id>", "Show plan details with its tasks").option("--delete <id>", "Delete a plan").option("--complete <id>", "Mark a plan as completed").action((opts) => {
14320
+ program2.command("plans").description("List and manage plans").option("--add <name>", "Create a plan").option("-d, --description <text>", "Plan description (with --add)").option("--show <id>", "Show plan details with its tasks").option("--artifact <id>", "Show local Markdown artifact diagnostics for a plan").option("--write-artifacts", "Write local Markdown artifacts for all project-scoped plans in scope").option("--delete <id>", "Delete a plan").option("--complete <id>", "Mark a plan as completed").action((opts) => {
14028
14321
  const globalOpts = program2.opts();
14029
14322
  const projectId = autoProject(globalOpts);
14030
14323
  if (opts.add) {
@@ -14033,11 +14326,71 @@ function registerPlanTemplateCommands(program2) {
14033
14326
  description: opts.description,
14034
14327
  project_id: projectId
14035
14328
  });
14329
+ const artifact = writePlanArtifact(plan);
14036
14330
  if (globalOpts.json) {
14037
14331
  output(plan, true);
14038
14332
  } else {
14039
14333
  console.log(chalk3.green("Plan created:"));
14040
14334
  console.log(`${chalk3.dim(plan.id.slice(0, 8))} ${chalk3.bold(plan.name)} ${chalk3.cyan(`[${plan.status}]`)}`);
14335
+ if (artifact)
14336
+ console.log(`${chalk3.dim("Artifact:")} ${artifact.path}`);
14337
+ }
14338
+ return;
14339
+ }
14340
+ if (opts.artifact) {
14341
+ const db = getDatabase();
14342
+ const resolvedId = resolvePartialId(db, "plans", opts.artifact);
14343
+ if (!resolvedId) {
14344
+ console.error(chalk3.red(`Could not resolve plan ID: ${opts.artifact}`));
14345
+ process.exit(1);
14346
+ }
14347
+ const plan = getPlan(resolvedId);
14348
+ if (!plan) {
14349
+ console.error(chalk3.red(`Plan not found: ${opts.artifact}`));
14350
+ process.exit(1);
14351
+ }
14352
+ const inspection = inspectPlanArtifact(plan, db);
14353
+ if (!inspection) {
14354
+ const result = { plan_id: plan.id, artifact: null, reason: "plan is not project-scoped" };
14355
+ if (globalOpts.json)
14356
+ output(result, true);
14357
+ else
14358
+ console.log(chalk3.dim("Plan is not project-scoped; no local Markdown artifact path is available."));
14359
+ return;
14360
+ }
14361
+ if (globalOpts.json) {
14362
+ output({ plan, artifact: inspection }, true);
14363
+ return;
14364
+ }
14365
+ console.log(chalk3.bold(`Plan Artifact:
14366
+ `));
14367
+ console.log(` ${chalk3.dim("Plan:")} ${plan.id}`);
14368
+ console.log(` ${chalk3.dim("Path:")} ${inspection.path}`);
14369
+ console.log(` ${chalk3.dim("Exists:")} ${inspection.exists ? "yes" : "no"}`);
14370
+ if (inspection.parse_error)
14371
+ console.log(` ${chalk3.dim("Parse:")} ${chalk3.red(inspection.parse_error)}`);
14372
+ console.log(` ${chalk3.dim("Conflicts:")} ${inspection.conflicts.length}`);
14373
+ for (const conflict of inspection.conflicts) {
14374
+ console.log(` ${conflict.field}: db=${conflict.database ?? "null"} artifact=${conflict.artifact ?? "null"}`);
14375
+ }
14376
+ return;
14377
+ }
14378
+ if (opts.writeArtifacts) {
14379
+ const plans2 = listPlans(projectId);
14380
+ const written = plans2.map((plan) => ({ plan, artifact: writePlanArtifact(plan) })).filter((entry) => entry.artifact);
14381
+ const result = {
14382
+ count: written.length,
14383
+ artifacts: written.map((entry) => ({
14384
+ plan_id: entry.plan.id,
14385
+ path: entry.artifact.path
14386
+ }))
14387
+ };
14388
+ if (globalOpts.json) {
14389
+ output(result, true);
14390
+ } else {
14391
+ console.log(chalk3.green(`Wrote ${written.length} plan artifact(s).`));
14392
+ for (const artifact of result.artifacts)
14393
+ console.log(`${chalk3.dim(artifact.plan_id.slice(0, 8))} ${artifact.path}`);
14041
14394
  }
14042
14395
  return;
14043
14396
  }
@@ -14055,8 +14408,18 @@ function registerPlanTemplateCommands(program2) {
14055
14408
  }
14056
14409
  const { listTasks: listTasks2 } = (init_tasks(), __toCommonJS(exports_tasks));
14057
14410
  const tasks = listTasks2({ plan_id: resolvedId });
14411
+ const artifact = readPlanArtifact(plan, db);
14058
14412
  if (globalOpts.json) {
14059
- output({ plan, tasks }, true);
14413
+ output({
14414
+ plan,
14415
+ tasks,
14416
+ artifact: artifact ? {
14417
+ path: artifact.path,
14418
+ metadata: artifact.metadata,
14419
+ task_references: artifact.task_references,
14420
+ body: artifact.body
14421
+ } : null
14422
+ }, true);
14060
14423
  return;
14061
14424
  }
14062
14425
  console.log(chalk3.bold(`Plan Details:
@@ -14068,6 +14431,8 @@ function registerPlanTemplateCommands(program2) {
14068
14431
  console.log(` ${chalk3.dim("Desc:")} ${plan.description}`);
14069
14432
  if (plan.project_id)
14070
14433
  console.log(` ${chalk3.dim("Project:")} ${plan.project_id}`);
14434
+ if (artifact)
14435
+ console.log(` ${chalk3.dim("Artifact:")} ${artifact.path}`);
14071
14436
  console.log(` ${chalk3.dim("Created:")} ${plan.created_at}`);
14072
14437
  if (tasks.length > 0) {
14073
14438
  console.log(chalk3.bold(`
@@ -14108,11 +14473,14 @@ function registerPlanTemplateCommands(program2) {
14108
14473
  }
14109
14474
  try {
14110
14475
  const plan = updatePlan(resolvedId, { status: "completed" });
14476
+ const artifact = writePlanArtifact(plan);
14111
14477
  if (globalOpts.json) {
14112
14478
  output(plan, true);
14113
14479
  } else {
14114
14480
  console.log(chalk3.green("Plan completed:"));
14115
14481
  console.log(`${chalk3.dim(plan.id.slice(0, 8))} ${chalk3.bold(plan.name)} ${chalk3.cyan(`[${plan.status}]`)}`);
14482
+ if (artifact)
14483
+ console.log(`${chalk3.dim("Artifact:")} ${artifact.path}`);
14116
14484
  }
14117
14485
  } catch (e) {
14118
14486
  handleError(e);
@@ -14390,14 +14758,14 @@ function registerPlanTemplateCommands(program2) {
14390
14758
  program2.command("template-import [file]").alias("templates-import").description("Import a template from a JSON file").option("--file <path>", "Path to template JSON file (alternative to positional arg)").action(async (file, opts) => {
14391
14759
  const globalOpts = program2.opts();
14392
14760
  const { importTemplate: importTemplate2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
14393
- const { readFileSync: readFileSync4 } = await import("fs");
14761
+ const { readFileSync: readFileSync5 } = await import("fs");
14394
14762
  try {
14395
14763
  const filePath = file || opts.file;
14396
14764
  if (!filePath) {
14397
14765
  console.error(chalk3.red("Provide a file path: todos template-import <file> or --file <path>"));
14398
14766
  process.exit(1);
14399
14767
  }
14400
- const content = readFileSync4(filePath, "utf-8");
14768
+ const content = readFileSync5(filePath, "utf-8");
14401
14769
  const json = JSON.parse(content);
14402
14770
  const template = importTemplate2(json);
14403
14771
  if (globalOpts.json) {
@@ -14441,6 +14809,7 @@ var init_plan_template_commands = __esm(() => {
14441
14809
  init_database();
14442
14810
  init_plans();
14443
14811
  init_tasks();
14812
+ init_plan_artifacts();
14444
14813
  init_helpers();
14445
14814
  });
14446
14815
 
@@ -15009,16 +15378,16 @@ var init_saved_search_views = __esm(() => {
15009
15378
  });
15010
15379
 
15011
15380
  // src/lib/claude-tasks.ts
15012
- import { existsSync as existsSync8, readFileSync as readFileSync4, readdirSync as readdirSync2, writeFileSync as writeFileSync4 } from "fs";
15013
- import { join as join8 } from "path";
15381
+ import { existsSync as existsSync9, readFileSync as readFileSync5, readdirSync as readdirSync2, writeFileSync as writeFileSync5 } from "fs";
15382
+ import { join as join9 } from "path";
15014
15383
  function getTaskListDir(taskListId) {
15015
- return join8(HOME, ".claude", "tasks", taskListId);
15384
+ return join9(HOME, ".claude", "tasks", taskListId);
15016
15385
  }
15017
15386
  function readClaudeTask(dir, filename) {
15018
- return readJsonFile(join8(dir, filename));
15387
+ return readJsonFile(join9(dir, filename));
15019
15388
  }
15020
15389
  function writeClaudeTask(dir, task) {
15021
- writeJsonFile(join8(dir, `${task.id}.json`), task);
15390
+ writeJsonFile(join9(dir, `${task.id}.json`), task);
15022
15391
  }
15023
15392
  function toClaudeStatus(status) {
15024
15393
  if (status === "pending" || status === "in_progress" || status === "completed") {
@@ -15030,14 +15399,14 @@ function toSqliteStatus(status) {
15030
15399
  return status;
15031
15400
  }
15032
15401
  function readPrefixCounter(dir) {
15033
- const path = join8(dir, ".prefix-counter");
15034
- if (!existsSync8(path))
15402
+ const path = join9(dir, ".prefix-counter");
15403
+ if (!existsSync9(path))
15035
15404
  return 0;
15036
- const val = parseInt(readFileSync4(path, "utf-8").trim(), 10);
15405
+ const val = parseInt(readFileSync5(path, "utf-8").trim(), 10);
15037
15406
  return isNaN(val) ? 0 : val;
15038
15407
  }
15039
15408
  function writePrefixCounter(dir, value) {
15040
- writeFileSync4(join8(dir, ".prefix-counter"), String(value));
15409
+ writeFileSync5(join9(dir, ".prefix-counter"), String(value));
15041
15410
  }
15042
15411
  function formatPrefixedSubject(title, prefix, counter) {
15043
15412
  const padded = String(counter).padStart(5, "0");
@@ -15064,7 +15433,7 @@ function taskToClaudeTask(task, claudeTaskId, existingMeta) {
15064
15433
  }
15065
15434
  function pushToClaudeTaskList(taskListId, projectId, options = {}) {
15066
15435
  const dir = getTaskListDir(taskListId);
15067
- if (!existsSync8(dir))
15436
+ if (!existsSync9(dir))
15068
15437
  ensureDir2(dir);
15069
15438
  const filter = {};
15070
15439
  if (projectId)
@@ -15073,7 +15442,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
15073
15442
  const existingByTodosId = new Map;
15074
15443
  const files = listJsonFiles(dir);
15075
15444
  for (const f of files) {
15076
- const path = join8(dir, f);
15445
+ const path = join9(dir, f);
15077
15446
  const ct = readClaudeTask(dir, f);
15078
15447
  if (ct?.metadata?.["todos_id"]) {
15079
15448
  existingByTodosId.set(ct.metadata["todos_id"], { task: ct, mtimeMs: getFileMtimeMs(path) });
@@ -15160,7 +15529,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
15160
15529
  }
15161
15530
  function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
15162
15531
  const dir = getTaskListDir(taskListId);
15163
- if (!existsSync8(dir)) {
15532
+ if (!existsSync9(dir)) {
15164
15533
  return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
15165
15534
  }
15166
15535
  const files = readdirSync2(dir).filter((f) => f.endsWith(".json"));
@@ -15180,7 +15549,7 @@ function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
15180
15549
  }
15181
15550
  for (const f of files) {
15182
15551
  try {
15183
- const filePath = join8(dir, f);
15552
+ const filePath = join9(dir, f);
15184
15553
  const ct = readClaudeTask(dir, f);
15185
15554
  if (!ct)
15186
15555
  continue;
@@ -15253,20 +15622,20 @@ var init_claude_tasks = __esm(() => {
15253
15622
  });
15254
15623
 
15255
15624
  // src/lib/agent-tasks.ts
15256
- import { existsSync as existsSync9 } from "fs";
15257
- import { join as join9 } from "path";
15625
+ import { existsSync as existsSync10 } from "fs";
15626
+ import { join as join10 } from "path";
15258
15627
  function agentBaseDir(agent) {
15259
15628
  const key = `TODOS_${agent.toUpperCase()}_TASKS_DIR`;
15260
- return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join9(getTodosGlobalDir(), "agents");
15629
+ return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join10(getTodosGlobalDir(), "agents");
15261
15630
  }
15262
15631
  function getTaskListDir2(agent, taskListId) {
15263
- return join9(agentBaseDir(agent), agent, taskListId);
15632
+ return join10(agentBaseDir(agent), agent, taskListId);
15264
15633
  }
15265
15634
  function readAgentTask(dir, filename) {
15266
- return readJsonFile(join9(dir, filename));
15635
+ return readJsonFile(join10(dir, filename));
15267
15636
  }
15268
15637
  function writeAgentTask(dir, task) {
15269
- writeJsonFile(join9(dir, `${task.id}.json`), task);
15638
+ writeJsonFile(join10(dir, `${task.id}.json`), task);
15270
15639
  }
15271
15640
  function taskToAgentTask(task, externalId, existingMeta) {
15272
15641
  return {
@@ -15291,7 +15660,7 @@ function metadataKey(agent) {
15291
15660
  }
15292
15661
  function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
15293
15662
  const dir = getTaskListDir2(agent, taskListId);
15294
- if (!existsSync9(dir))
15663
+ if (!existsSync10(dir))
15295
15664
  ensureDir2(dir);
15296
15665
  const filter = {};
15297
15666
  if (projectId)
@@ -15300,7 +15669,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
15300
15669
  const existingByTodosId = new Map;
15301
15670
  const files = listJsonFiles(dir);
15302
15671
  for (const f of files) {
15303
- const path = join9(dir, f);
15672
+ const path = join10(dir, f);
15304
15673
  const at = readAgentTask(dir, f);
15305
15674
  if (at?.metadata?.["todos_id"]) {
15306
15675
  existingByTodosId.set(at.metadata["todos_id"], { task: at, mtimeMs: getFileMtimeMs(path) });
@@ -15374,7 +15743,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
15374
15743
  }
15375
15744
  function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
15376
15745
  const dir = getTaskListDir2(agent, taskListId);
15377
- if (!existsSync9(dir)) {
15746
+ if (!existsSync10(dir)) {
15378
15747
  return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
15379
15748
  }
15380
15749
  const files = listJsonFiles(dir);
@@ -15393,7 +15762,7 @@ function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
15393
15762
  }
15394
15763
  for (const f of files) {
15395
15764
  try {
15396
- const filePath = join9(dir, f);
15765
+ const filePath = join10(dir, f);
15397
15766
  const at = readAgentTask(dir, f);
15398
15767
  if (!at)
15399
15768
  continue;
@@ -15546,8 +15915,8 @@ __export(exports_project_bootstrap, {
15546
15915
  discoverProjectWorkspace: () => discoverProjectWorkspace,
15547
15916
  bootstrapProject: () => bootstrapProject
15548
15917
  });
15549
- import { existsSync as existsSync10, readFileSync as readFileSync5, statSync as statSync3 } from "fs";
15550
- import { basename as basename4, dirname as dirname6, resolve as resolve10 } from "path";
15918
+ import { existsSync as existsSync11, readFileSync as readFileSync6, statSync as statSync3 } from "fs";
15919
+ import { basename as basename4, dirname as dirname6, resolve as resolve11 } from "path";
15551
15920
  function safeStat(path) {
15552
15921
  try {
15553
15922
  return statSync3(path);
@@ -15556,7 +15925,7 @@ function safeStat(path) {
15556
15925
  }
15557
15926
  }
15558
15927
  function canonicalPath(input) {
15559
- const resolved = resolve10(input);
15928
+ const resolved = resolve11(input);
15560
15929
  const stats = safeStat(resolved);
15561
15930
  if (stats?.isFile())
15562
15931
  return dirname6(resolved);
@@ -15565,7 +15934,7 @@ function canonicalPath(input) {
15565
15934
  function findUp(start, marker) {
15566
15935
  let current = canonicalPath(start);
15567
15936
  while (true) {
15568
- if (existsSync10(resolve10(current, marker)))
15937
+ if (existsSync11(resolve11(current, marker)))
15569
15938
  return current;
15570
15939
  const parent = dirname6(current);
15571
15940
  if (parent === current)
@@ -15576,11 +15945,11 @@ function findUp(start, marker) {
15576
15945
  function readPackageJson(path) {
15577
15946
  if (!path)
15578
15947
  return null;
15579
- const file = resolve10(path, "package.json");
15580
- if (!existsSync10(file))
15948
+ const file = resolve11(path, "package.json");
15949
+ if (!existsSync11(file))
15581
15950
  return null;
15582
15951
  try {
15583
- const parsed = JSON.parse(readFileSync5(file, "utf-8"));
15952
+ const parsed = JSON.parse(readFileSync6(file, "utf-8"));
15584
15953
  return parsed && typeof parsed === "object" ? parsed : null;
15585
15954
  } catch {
15586
15955
  return null;
@@ -15599,7 +15968,7 @@ function workspaceMarker(root, rootPackage) {
15599
15968
  if (rootPackage?.workspaces)
15600
15969
  markers.push("package.json#workspaces");
15601
15970
  for (const marker of ["pnpm-workspace.yaml", "turbo.json", "nx.json", "lerna.json", "rush.json", "bun.lock", "bun.lockb"]) {
15602
- if (existsSync10(resolve10(root, marker)))
15971
+ if (existsSync11(resolve11(root, marker)))
15603
15972
  markers.push(marker);
15604
15973
  }
15605
15974
  const kind = markers.find((marker) => marker !== "bun.lock" && marker !== "bun.lockb") ?? null;
@@ -21122,9 +21491,9 @@ __export(exports_extract, {
21122
21491
  buildCodebaseIndex: () => buildCodebaseIndex,
21123
21492
  EXTRACT_TAGS: () => EXTRACT_TAGS
21124
21493
  });
21125
- import { existsSync as existsSync11, readFileSync as readFileSync6, statSync as statSync4 } from "fs";
21494
+ import { existsSync as existsSync12, readFileSync as readFileSync7, statSync as statSync4 } from "fs";
21126
21495
  import { createHash as createHash3 } from "crypto";
21127
- import { relative as relative3, resolve as resolve11, join as join10 } from "path";
21496
+ import { relative as relative3, resolve as resolve12, join as join11 } from "path";
21128
21497
  function stableHash(value) {
21129
21498
  return createHash3("sha256").update(value).digest("hex");
21130
21499
  }
@@ -21132,12 +21501,12 @@ function normalizePathForMatch(value) {
21132
21501
  return value.replace(/\\/g, "/").replace(/^\.\//, "");
21133
21502
  }
21134
21503
  function readGitignorePatterns(basePath) {
21135
- const root = statSync4(basePath).isFile() ? resolve11(basePath, "..") : basePath;
21136
- const gitignorePath = join10(root, ".gitignore");
21137
- if (!existsSync11(gitignorePath))
21504
+ const root = statSync4(basePath).isFile() ? resolve12(basePath, "..") : basePath;
21505
+ const gitignorePath = join11(root, ".gitignore");
21506
+ if (!existsSync12(gitignorePath))
21138
21507
  return [];
21139
21508
  try {
21140
- return readFileSync6(gitignorePath, "utf-8").split(`
21509
+ return readFileSync7(gitignorePath, "utf-8").split(`
21141
21510
  `).map((line) => line.trim()).filter((line) => line && !line.startsWith("#") && !line.startsWith("!"));
21142
21511
  } catch {
21143
21512
  return [];
@@ -21268,7 +21637,7 @@ function collectFiles(basePath, extensions, excludes, respectGitignore) {
21268
21637
  return files.sort();
21269
21638
  }
21270
21639
  function buildCodebaseIndex(options) {
21271
- const basePath = resolve11(options.path);
21640
+ const basePath = resolve12(options.path);
21272
21641
  const tags = options.patterns || [...EXTRACT_TAGS];
21273
21642
  const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
21274
21643
  const excludes = options.exclude || [];
@@ -21276,10 +21645,10 @@ function buildCodebaseIndex(options) {
21276
21645
  const files = collectFiles(basePath, extensions, excludes, respectGitignore);
21277
21646
  const indexed = [];
21278
21647
  for (const file of files) {
21279
- const fullPath = statSync4(basePath).isFile() ? basePath : join10(basePath, file);
21648
+ const fullPath = statSync4(basePath).isFile() ? basePath : join11(basePath, file);
21280
21649
  try {
21281
- const source = readFileSync6(fullPath, "utf-8");
21282
- const relPath = statSync4(basePath).isFile() ? relative3(resolve11(basePath, ".."), fullPath) : file;
21650
+ const source = readFileSync7(fullPath, "utf-8");
21651
+ const relPath = statSync4(basePath).isFile() ? relative3(resolve12(basePath, ".."), fullPath) : file;
21283
21652
  indexed.push({
21284
21653
  file: relPath,
21285
21654
  checksum: stableHash(source).slice(0, 24),
@@ -21299,7 +21668,7 @@ function buildCodebaseIndex(options) {
21299
21668
  };
21300
21669
  }
21301
21670
  function extractTodos(options, db) {
21302
- const basePath = resolve11(options.path);
21671
+ const basePath = resolve12(options.path);
21303
21672
  const tags = options.patterns || [...EXTRACT_TAGS];
21304
21673
  const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
21305
21674
  const excludes = options.exclude || [];
@@ -21307,10 +21676,10 @@ function extractTodos(options, db) {
21307
21676
  const files = collectFiles(basePath, extensions, excludes, respectGitignore);
21308
21677
  const allComments = [];
21309
21678
  for (const file of files) {
21310
- const fullPath = statSync4(basePath).isFile() ? basePath : join10(basePath, file);
21679
+ const fullPath = statSync4(basePath).isFile() ? basePath : join11(basePath, file);
21311
21680
  try {
21312
- const source = readFileSync6(fullPath, "utf-8");
21313
- const relPath = statSync4(basePath).isFile() ? relative3(resolve11(basePath, ".."), fullPath) : file;
21681
+ const source = readFileSync7(fullPath, "utf-8");
21682
+ const relPath = statSync4(basePath).isFile() ? relative3(resolve12(basePath, ".."), fullPath) : file;
21314
21683
  const comments = extractFromSource(source, relPath, tags);
21315
21684
  allComments.push(...comments);
21316
21685
  } catch {}
@@ -21404,7 +21773,7 @@ async function watchSourceTodos(options, onRun) {
21404
21773
  const interval = Math.max(100, options.interval_ms || 2000);
21405
21774
  const once = options.once !== false && (!options.max_runs || options.max_runs <= 1);
21406
21775
  const maxRuns = options.max_runs ?? (once ? 1 : Number.POSITIVE_INFINITY);
21407
- const root = resolve11(options.path);
21776
+ const root = resolve12(options.path);
21408
21777
  const runs = [];
21409
21778
  let previous = new Map;
21410
21779
  for (let runNumber = 1;runNumber <= maxRuns; runNumber++) {
@@ -22575,7 +22944,7 @@ __export(exports_project_commands, {
22575
22944
  registerProjectCommands: () => registerProjectCommands
22576
22945
  });
22577
22946
  import chalk4 from "chalk";
22578
- import { basename as basename5, resolve as resolve12 } from "path";
22947
+ import { basename as basename5, resolve as resolve13 } from "path";
22579
22948
  function collectOption(value, previous = []) {
22580
22949
  return [...previous, value];
22581
22950
  }
@@ -22917,7 +23286,7 @@ function registerProjectCommands(program2) {
22917
23286
  program2.command("projects").description("List and manage projects").option("--add <path>", "Register a project by path").option("--name <name>", "Project name (with --add)").option("--task-list-id <id>", "Custom task list ID (with --add)").action(async (opts) => {
22918
23287
  const globalOpts = program2.opts();
22919
23288
  if (opts.add) {
22920
- const projectPath = resolve12(opts.add);
23289
+ const projectPath = resolve13(opts.add);
22921
23290
  const name = opts.name || basename5(projectPath);
22922
23291
  const existing = getProjectByPath(projectPath);
22923
23292
  let project;
@@ -23025,7 +23394,7 @@ function registerProjectCommands(program2) {
23025
23394
  console.error(chalk4.red(`Project not found: ${projectId}`));
23026
23395
  process.exit(1);
23027
23396
  }
23028
- const entry = setMachineLocalPath2(resolved, resolve12(projectPath));
23397
+ const entry = setMachineLocalPath2(resolved, resolve13(projectPath));
23029
23398
  if (useJson) {
23030
23399
  output(entry, true);
23031
23400
  } else {
@@ -23092,7 +23461,7 @@ function registerProjectCommands(program2) {
23092
23461
  const patterns = opts.pattern ? opts.pattern.split(",").map((t) => t.trim().toUpperCase()) : undefined;
23093
23462
  const taskListId = opts.list ? resolveTaskListId(opts.list) : undefined;
23094
23463
  const result = extractTodos2({
23095
- path: resolve12(scanPath),
23464
+ path: resolve13(scanPath),
23096
23465
  patterns,
23097
23466
  project_id: projectId,
23098
23467
  task_list_id: taskListId,
@@ -23153,7 +23522,7 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
23153
23522
  const taskListId = opts.list ? resolveTaskListId(opts.list) : undefined;
23154
23523
  const maxRuns = opts.maxRuns ? parseInt(opts.maxRuns, 10) : 1;
23155
23524
  const result = await watchSourceTodos2({
23156
- path: resolve12(scanPath),
23525
+ path: resolve13(scanPath),
23157
23526
  patterns,
23158
23527
  project_id: projectId,
23159
23528
  task_list_id: taskListId,
@@ -23189,8 +23558,8 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
23189
23558
  const projectId = autoProject(globalOpts);
23190
23559
  const writeOutput = async (content) => {
23191
23560
  if (opts.output) {
23192
- const { writeFileSync: writeFileSync5 } = await import("fs");
23193
- writeFileSync5(resolve12(opts.output), content.endsWith(`
23561
+ const { writeFileSync: writeFileSync6 } = await import("fs");
23562
+ writeFileSync6(resolve13(opts.output), content.endsWith(`
23194
23563
  `) ? content : `${content}
23195
23564
  `);
23196
23565
  } else {
@@ -23205,12 +23574,12 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
23205
23574
  const exported = opts.encrypt ? createEncryptedBridgeBundle2(bundle, { profile: opts.encryptionProfile }) : bundle;
23206
23575
  const json = JSON.stringify(exported, null, 2);
23207
23576
  await writeOutput(json);
23208
- emitLocalEventHooksQuiet3({ type: "export.finished", payload: { format: "bridge", encrypted: Boolean(opts.encrypt), project_id: projectId, output: opts.output ? resolve12(opts.output) : null, stats: bundle.stats } });
23577
+ emitLocalEventHooksQuiet3({ type: "export.finished", payload: { format: "bridge", encrypted: Boolean(opts.encrypt), project_id: projectId, output: opts.output ? resolve13(opts.output) : null, stats: bundle.stats } });
23209
23578
  if (!opts.encrypt && !opts.allowPlaintextSensitive) {
23210
23579
  console.error(chalk4.yellow("Warning: bridge exports are plaintext JSON. Use --encrypt for sensitive metadata, evidence, and artifact bundles."));
23211
23580
  }
23212
23581
  if (opts.output && !globalOpts.json) {
23213
- console.log(chalk4.green(`${opts.encrypt ? "Encrypted bridge export" : "Bridge export"} written to ${resolve12(opts.output)}`));
23582
+ console.log(chalk4.green(`${opts.encrypt ? "Encrypted bridge export" : "Bridge export"} written to ${resolve13(opts.output)}`));
23214
23583
  }
23215
23584
  return;
23216
23585
  }
@@ -23223,21 +23592,21 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
23223
23592
  await writeOutput(JSON.stringify(tasks, null, 2));
23224
23593
  }
23225
23594
  const { emitLocalEventHooksQuiet: emitLocalEventHooksQuiet2 } = await Promise.resolve().then(() => (init_event_hooks(), exports_event_hooks));
23226
- emitLocalEventHooksQuiet2({ type: "export.finished", payload: { format: opts.format, project_id: projectId, output: opts.output ? resolve12(opts.output) : null, count: exportedCount } });
23595
+ emitLocalEventHooksQuiet2({ type: "export.finished", payload: { format: opts.format, project_id: projectId, output: opts.output ? resolve13(opts.output) : null, count: exportedCount } });
23227
23596
  });
23228
23597
  program2.command("bridge-import <file>").description("Dry-run or apply a local hasna/todos bridge export bundle").option("--apply", "Apply the import. Defaults to dry-run.").option("--decrypt", "Decrypt an encrypted bridge export before importing").option("--resolve-conflicts", "Safely merge existing local tasks by filling blank fields, unioning tags, and recording unresolved divergences").action(async (file, opts) => {
23229
23598
  const globalOpts = program2.opts();
23230
23599
  try {
23231
- const { readFileSync: readFileSync7 } = await import("fs");
23600
+ const { readFileSync: readFileSync8 } = await import("fs");
23232
23601
  const { importLocalBridgeBundle: importLocalBridgeBundle2 } = await Promise.resolve().then(() => (init_local_bridge(), exports_local_bridge));
23233
23602
  const { decryptBridgeBundle: decryptBridgeBundle2, isEncryptedBridgeBundle: isEncryptedBridgeBundle2 } = await Promise.resolve().then(() => (init_local_encryption(), exports_local_encryption));
23234
- const parsed = JSON.parse(readFileSync7(resolve12(file), "utf-8"));
23603
+ const parsed = JSON.parse(readFileSync8(resolve13(file), "utf-8"));
23235
23604
  const bundle = isEncryptedBridgeBundle2(parsed) ? opts.decrypt ? decryptBridgeBundle2(parsed) : (() => {
23236
23605
  throw new Error("Bridge bundle is encrypted. Re-run with --decrypt and the configured key environment variable set.");
23237
23606
  })() : parsed;
23238
23607
  const result = importLocalBridgeBundle2(bundle, { dryRun: !opts.apply, conflictStrategy: opts.resolveConflicts ? "safe_merge" : "skip" });
23239
23608
  const { emitLocalEventHooksQuiet: emitLocalEventHooksQuiet2 } = await Promise.resolve().then(() => (init_event_hooks(), exports_event_hooks));
23240
- emitLocalEventHooksQuiet2({ type: "import.finished", payload: { file: resolve12(file), dry_run: result.dry_run, ok: result.ok, inserted: result.inserted, skipped: result.skipped, conflicts: result.conflicts.length, issues: result.issues.length } });
23609
+ emitLocalEventHooksQuiet2({ type: "import.finished", payload: { file: resolve13(file), dry_run: result.dry_run, ok: result.ok, inserted: result.inserted, skipped: result.skipped, conflicts: result.conflicts.length, issues: result.issues.length } });
23241
23610
  if (globalOpts.json) {
23242
23611
  output(result, true);
23243
23612
  return;
@@ -23265,11 +23634,11 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
23265
23634
  program2.command("todos-md-import <file>").alias("markdown-import").alias("import-md").description("Dry-run or apply a local todos.md Markdown import").option("--apply", "Apply the import. Defaults to dry-run.").option("--resolve-conflicts", "Safely merge embedded bridge task conflicts while preserving local divergent fields").action(async (file, opts) => {
23266
23635
  const globalOpts = program2.opts();
23267
23636
  try {
23268
- const { readFileSync: readFileSync7 } = await import("fs");
23637
+ const { readFileSync: readFileSync8 } = await import("fs");
23269
23638
  const { importTodosMarkdown: importTodosMarkdown2 } = await Promise.resolve().then(() => (init_todos_md(), exports_todos_md));
23270
- const result = importTodosMarkdown2(readFileSync7(resolve12(file), "utf-8"), { dryRun: !opts.apply, conflictStrategy: opts.resolveConflicts ? "safe_merge" : "skip" });
23639
+ const result = importTodosMarkdown2(readFileSync8(resolve13(file), "utf-8"), { dryRun: !opts.apply, conflictStrategy: opts.resolveConflicts ? "safe_merge" : "skip" });
23271
23640
  const { emitLocalEventHooksQuiet: emitLocalEventHooksQuiet2 } = await Promise.resolve().then(() => (init_event_hooks(), exports_event_hooks));
23272
- emitLocalEventHooksQuiet2({ type: "import.finished", payload: { file: resolve12(file), format: "todos.md", dry_run: result.dry_run, ok: result.ok, inserted: result.inserted, skipped: result.skipped, issues: result.issues.length } });
23641
+ emitLocalEventHooksQuiet2({ type: "import.finished", payload: { file: resolve13(file), format: "todos.md", dry_run: result.dry_run, ok: result.ok, inserted: result.inserted, skipped: result.skipped, issues: result.issues.length } });
23273
23642
  if (globalOpts.json) {
23274
23643
  output(result, true);
23275
23644
  return;
@@ -24397,7 +24766,7 @@ __export(exports_retention_cleanup, {
24397
24766
  applyRetentionCleanup: () => applyRetentionCleanup,
24398
24767
  RETENTION_CLEANUP_CONFIRMATION: () => RETENTION_CLEANUP_CONFIRMATION
24399
24768
  });
24400
- import { existsSync as existsSync12, unlinkSync } from "fs";
24769
+ import { existsSync as existsSync13, unlinkSync } from "fs";
24401
24770
  function normalizeScopes(scopes) {
24402
24771
  if (!scopes || scopes.length === 0)
24403
24772
  return [...ALL_SCOPES];
@@ -24600,7 +24969,7 @@ function applyRetentionCleanup(input, db) {
24600
24969
  for (const artifact of report.candidates.artifact_files) {
24601
24970
  try {
24602
24971
  const path = artifactStorePath(artifact.relative_path);
24603
- if (!existsSync12(path)) {
24972
+ if (!existsSync13(path)) {
24604
24973
  report.warnings.push(`stored artifact already missing: ${artifact.relative_path}`);
24605
24974
  continue;
24606
24975
  }
@@ -25278,8 +25647,8 @@ __export(exports_local_extensions, {
25278
25647
  discoverLocalExtensions: () => discoverLocalExtensions
25279
25648
  });
25280
25649
  import { createHash as createHash5, createVerify } from "crypto";
25281
- import { existsSync as existsSync13, readdirSync as readdirSync3, readFileSync as readFileSync7, statSync as statSync5 } from "fs";
25282
- import { basename as basename6, join as join11, resolve as resolve13 } from "path";
25650
+ import { existsSync as existsSync14, readdirSync as readdirSync3, readFileSync as readFileSync8, statSync as statSync5 } from "fs";
25651
+ import { basename as basename6, join as join12, resolve as resolve14 } from "path";
25283
25652
  function isObject(value) {
25284
25653
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
25285
25654
  }
@@ -25360,7 +25729,7 @@ function normalizeManifest(input) {
25360
25729
  };
25361
25730
  }
25362
25731
  function parseJson(path) {
25363
- return JSON.parse(readFileSync7(path, "utf8"));
25732
+ return JSON.parse(readFileSync8(path, "utf8"));
25364
25733
  }
25365
25734
  function sha2563(bytes) {
25366
25735
  return `sha256:${createHash5("sha256").update(bytes).digest("hex")}`;
@@ -25537,14 +25906,14 @@ function verifyExtensionSignature(input) {
25537
25906
  return verifier.verify(input.public_key, decodeSignature(input.signature));
25538
25907
  }
25539
25908
  function inspectExtensionSource(source2) {
25540
- const resolved = resolve13(source2);
25541
- if (!existsSync13(resolved))
25909
+ const resolved = resolve14(source2);
25910
+ if (!existsSync14(resolved))
25542
25911
  throw new Error(`extension source not found: ${source2}`);
25543
25912
  const stat = statSync5(resolved);
25544
- const manifestPath = stat.isDirectory() ? [join11(resolved, "todos.extension.json"), join11(resolved, "extension.json")].find(existsSync13) : resolved;
25913
+ const manifestPath = stat.isDirectory() ? [join12(resolved, "todos.extension.json"), join12(resolved, "extension.json")].find(existsSync14) : resolved;
25545
25914
  if (!manifestPath)
25546
25915
  throw new Error(`extension directory ${source2} is missing todos.extension.json`);
25547
- const raw = readFileSync7(manifestPath);
25916
+ const raw = readFileSync8(manifestPath);
25548
25917
  const parsed = parseJson(manifestPath);
25549
25918
  const bundle = isObject(parsed) && isObject(parsed["manifest"]);
25550
25919
  const manifest = normalizeManifest(bundle ? parsed["manifest"] : parsed);
@@ -25635,26 +26004,26 @@ function testExtensionCompatibility(sourceOrManifest) {
25635
26004
  function projectExtensionSources(projectPath) {
25636
26005
  if (!projectPath)
25637
26006
  return [];
25638
- const root = resolve13(projectPath);
26007
+ const root = resolve14(projectPath);
25639
26008
  const candidates = [
25640
- join11(root, "todos.extension.json"),
25641
- join11(root, ".todos", "todos.extension.json")
26009
+ join12(root, "todos.extension.json"),
26010
+ join12(root, ".todos", "todos.extension.json")
25642
26011
  ];
25643
- const extensionDir = join11(root, ".todos", "extensions");
25644
- if (existsSync13(extensionDir)) {
26012
+ const extensionDir = join12(root, ".todos", "extensions");
26013
+ if (existsSync14(extensionDir)) {
25645
26014
  for (const entry of readdirSync3(extensionDir)) {
25646
26015
  if (entry.startsWith("."))
25647
26016
  continue;
25648
- const full = join11(extensionDir, entry);
26017
+ const full = join12(extensionDir, entry);
25649
26018
  if (statSync5(full).isDirectory() || entry.endsWith(".json"))
25650
26019
  candidates.push(full);
25651
26020
  }
25652
26021
  }
25653
- return candidates.filter(existsSync13);
26022
+ return candidates.filter(existsSync14);
25654
26023
  }
25655
26024
  function discoverLocalExtensions(options = {}) {
25656
26025
  const config = loadConfig();
25657
- const projectPath = options.project_path ? resolve13(options.project_path) : null;
26026
+ const projectPath = options.project_path ? resolve14(options.project_path) : null;
25658
26027
  const configuredSources = [
25659
26028
  ...config.extension_sources || [],
25660
26029
  ...projectPath ? config.project_overrides?.[projectPath]?.extension_sources || [] : []
@@ -25662,7 +26031,7 @@ function discoverLocalExtensions(options = {}) {
25662
26031
  const sources = Array.from(new Set([
25663
26032
  ...configuredSources,
25664
26033
  ...projectExtensionSources(projectPath || undefined)
25665
- ])).map((source2) => projectPath && !source2.startsWith("/") ? resolve13(projectPath, source2) : resolve13(source2));
26034
+ ])).map((source2) => projectPath && !source2.startsWith("/") ? resolve14(projectPath, source2) : resolve14(source2));
25666
26035
  const warnings = [];
25667
26036
  const discovered = [];
25668
26037
  for (const source2 of sources) {
@@ -25922,9 +26291,9 @@ __export(exports_policy_packs, {
25922
26291
  getPolicyPack: () => getPolicyPack,
25923
26292
  explainPolicyPack: () => explainPolicyPack
25924
26293
  });
25925
- import { relative as relative4, resolve as resolve14 } from "path";
26294
+ import { relative as relative4, resolve as resolve15 } from "path";
25926
26295
  function normalizePath3(path) {
25927
- return resolve14(path);
26296
+ return resolve15(path);
25928
26297
  }
25929
26298
  function unique5(values) {
25930
26299
  return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
@@ -25979,7 +26348,7 @@ function commandMatches(commands, pattern) {
25979
26348
  }
25980
26349
  function pathMatches(paths, pattern, root) {
25981
26350
  return paths.filter((path) => {
25982
- const candidate = path.startsWith("/") ? path : resolve14(root, path);
26351
+ const candidate = path.startsWith("/") ? path : resolve15(root, path);
25983
26352
  if (!isPathInside3(root, candidate))
25984
26353
  return matchesPattern3(path, pattern);
25985
26354
  return matchesPattern3(path, pattern) || matchesPattern3(relative4(root, candidate), pattern);
@@ -26945,8 +27314,8 @@ var exports_doctor = {};
26945
27314
  __export(exports_doctor, {
26946
27315
  runTodosDoctor: () => runTodosDoctor
26947
27316
  });
26948
- import { chmodSync, copyFileSync, existsSync as existsSync14, mkdirSync as mkdirSync6, statSync as statSync6 } from "fs";
26949
- import { basename as basename7, dirname as dirname7, join as join12 } from "path";
27317
+ import { chmodSync, copyFileSync, existsSync as existsSync15, mkdirSync as mkdirSync7, statSync as statSync6 } from "fs";
27318
+ import { basename as basename7, dirname as dirname7, join as join13 } from "path";
26950
27319
  function tableExists(db, table) {
26951
27320
  return Boolean(db.query("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(table));
26952
27321
  }
@@ -27040,7 +27409,7 @@ function findMissingProjectRoots(db) {
27040
27409
  continue;
27041
27410
  if (!row.path.startsWith("/"))
27042
27411
  continue;
27043
- if (!existsSync14(row.path))
27412
+ if (!existsSync15(row.path))
27044
27413
  missing++;
27045
27414
  }
27046
27415
  return missing;
@@ -27100,16 +27469,16 @@ function databasePermissionsAreUnsafe(dbPath) {
27100
27469
  function createBackup(dbPath) {
27101
27470
  if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
27102
27471
  return;
27103
- if (!existsSync14(dbPath))
27472
+ if (!existsSync15(dbPath))
27104
27473
  return;
27105
27474
  const stamp = now().replace(/[:.]/g, "-");
27106
- const backupDir = join12(dirname7(dbPath), `${basename7(dbPath)}.backup-${stamp}`);
27475
+ const backupDir = join13(dirname7(dbPath), `${basename7(dbPath)}.backup-${stamp}`);
27107
27476
  const files = [];
27108
- mkdirSync6(backupDir, { recursive: true });
27477
+ mkdirSync7(backupDir, { recursive: true });
27109
27478
  for (const source2 of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
27110
- if (!existsSync14(source2))
27479
+ if (!existsSync15(source2))
27111
27480
  continue;
27112
- const target = join12(backupDir, basename7(source2));
27481
+ const target = join13(backupDir, basename7(source2));
27113
27482
  copyFileSync(source2, target);
27114
27483
  files.push(target);
27115
27484
  }
@@ -27335,7 +27704,7 @@ var init_doctor = __esm(() => {
27335
27704
  });
27336
27705
 
27337
27706
  // src/server/routes.ts
27338
- import { join as join13, resolve as resolve15, sep as sep2 } from "path";
27707
+ import { join as join14, resolve as resolve16, sep as sep2 } from "path";
27339
27708
  function parseFieldsParam(url) {
27340
27709
  const fieldsParam = url.searchParams.get("fields");
27341
27710
  return fieldsParam ? fieldsParam.split(",").map((f) => f.trim()).filter(Boolean) : undefined;
@@ -28072,9 +28441,9 @@ function handleStaticFiles(path, method, ctx, json2, serveStaticFile2) {
28072
28441
  if (!ctx.dashboardExists || method !== "GET" && method !== "HEAD")
28073
28442
  return null;
28074
28443
  if (path !== "/") {
28075
- const filePath = join13(ctx.dashboardDir, path);
28076
- const resolvedFile = resolve15(filePath);
28077
- const resolvedBase = resolve15(ctx.dashboardDir);
28444
+ const filePath = join14(ctx.dashboardDir, path);
28445
+ const resolvedFile = resolve16(filePath);
28446
+ const resolvedBase = resolve16(ctx.dashboardDir);
28078
28447
  if (!resolvedFile.startsWith(resolvedBase + sep2) && resolvedFile !== resolvedBase) {
28079
28448
  return json2({ error: "Forbidden" }, 403);
28080
28449
  }
@@ -28082,7 +28451,7 @@ function handleStaticFiles(path, method, ctx, json2, serveStaticFile2) {
28082
28451
  if (res2)
28083
28452
  return res2;
28084
28453
  }
28085
- const indexPath = join13(ctx.dashboardDir, "index.html");
28454
+ const indexPath = join14(ctx.dashboardDir, "index.html");
28086
28455
  const res = serveStaticFile2(indexPath);
28087
28456
  if (res)
28088
28457
  return res;
@@ -33077,8 +33446,8 @@ var exports_mention_resolver = {};
33077
33446
  __export(exports_mention_resolver, {
33078
33447
  resolveMentions: () => resolveMentions
33079
33448
  });
33080
- import { existsSync as existsSync15, readdirSync as readdirSync4, readFileSync as readFileSync8, statSync as statSync7 } from "fs";
33081
- import { basename as basename8, isAbsolute, join as join14, relative as relative5, resolve as resolve16, sep as sep3 } from "path";
33449
+ import { existsSync as existsSync16, readdirSync as readdirSync4, readFileSync as readFileSync9, statSync as statSync7 } from "fs";
33450
+ import { basename as basename8, isAbsolute, join as join15, relative as relative5, resolve as resolve17, sep as sep3 } from "path";
33082
33451
  function blankResolution(parsed) {
33083
33452
  return {
33084
33453
  input: parsed.input,
@@ -33101,7 +33470,7 @@ function backlink(kind, key, label, target = key) {
33101
33470
  return { kind, key, label, target };
33102
33471
  }
33103
33472
  function normalizeWorkspace(workspace) {
33104
- return resolve16(workspace || process.cwd());
33473
+ return resolve17(workspace || process.cwd());
33105
33474
  }
33106
33475
  function isInside(root, absolutePath) {
33107
33476
  const rel = relative5(root, absolutePath);
@@ -33169,14 +33538,14 @@ function resolveFile(parsed, workspace) {
33169
33538
  resolution.warnings.push("path is empty or escapes the workspace");
33170
33539
  return resolution;
33171
33540
  }
33172
- const absolutePath = resolve16(workspace, relPath);
33541
+ const absolutePath = resolve17(workspace, relPath);
33173
33542
  if (!isInside(workspace, absolutePath)) {
33174
33543
  resolution.path = relPath;
33175
33544
  resolution.warnings.push("path escapes the workspace");
33176
33545
  return resolution;
33177
33546
  }
33178
33547
  resolution.path = relPath;
33179
- if (!existsSync15(absolutePath)) {
33548
+ if (!existsSync16(absolutePath)) {
33180
33549
  resolution.warnings.push("file does not exist in the local workspace");
33181
33550
  return resolution;
33182
33551
  }
@@ -33186,7 +33555,7 @@ function resolveFile(parsed, workspace) {
33186
33555
  return resolution;
33187
33556
  }
33188
33557
  if (parsed.line !== undefined) {
33189
- const lineCount = readFileSync8(absolutePath, "utf-8").split(/\r?\n/).length;
33558
+ const lineCount = readFileSync9(absolutePath, "utf-8").split(/\r?\n/).length;
33190
33559
  if (parsed.line < 1 || parsed.line > lineCount) {
33191
33560
  resolution.warnings.push(`line ${parsed.line} is outside the file range 1-${lineCount}`);
33192
33561
  return resolution;
@@ -33209,7 +33578,7 @@ function walkSourceFiles(root, current = root, files = []) {
33209
33578
  if (SKIP_DIRS3.has(entry.name))
33210
33579
  continue;
33211
33580
  }
33212
- const absolutePath = join14(current, entry.name);
33581
+ const absolutePath = join15(current, entry.name);
33213
33582
  if (entry.isDirectory()) {
33214
33583
  if (!SKIP_DIRS3.has(entry.name))
33215
33584
  walkSourceFiles(root, absolutePath, files);
@@ -33239,7 +33608,7 @@ function resolveSymbol(parsed, workspace, maxMatches) {
33239
33608
  const pattern = symbolPattern(name);
33240
33609
  const matches = [];
33241
33610
  for (const file of walkSourceFiles(workspace)) {
33242
- const lines = readFileSync8(file, "utf-8").split(/\r?\n/);
33611
+ const lines = readFileSync9(file, "utf-8").split(/\r?\n/);
33243
33612
  for (let index = 0;index < lines.length; index += 1) {
33244
33613
  const line = lines[index];
33245
33614
  const found = pattern.exec(line);
@@ -35973,8 +36342,8 @@ __export(exports_release_compatibility, {
35973
36342
  createReleaseCompatibilityReport: () => createReleaseCompatibilityReport,
35974
36343
  LOCAL_RELEASE_COMPATIBILITY_SCHEMA_VERSION: () => LOCAL_RELEASE_COMPATIBILITY_SCHEMA_VERSION
35975
36344
  });
35976
- import { readFileSync as readFileSync9 } from "fs";
35977
- import { join as join15, resolve as resolve17 } from "path";
36345
+ import { readFileSync as readFileSync10 } from "fs";
36346
+ import { join as join16, resolve as resolve18 } from "path";
35978
36347
  import { Database as Database2 } from "bun:sqlite";
35979
36348
  function pass(id, message, details) {
35980
36349
  return { id, status: "passed", message, details };
@@ -35986,7 +36355,7 @@ function warn(id, message, details) {
35986
36355
  return { id, status: "warning", message, details };
35987
36356
  }
35988
36357
  function readPackageJson2(root) {
35989
- return JSON.parse(readFileSync9(join15(root, "package.json"), "utf8"));
36358
+ return JSON.parse(readFileSync10(join16(root, "package.json"), "utf8"));
35990
36359
  }
35991
36360
  function sortedKeys(value) {
35992
36361
  return Object.keys(value ?? {}).sort((left, right) => left.localeCompare(right));
@@ -36082,7 +36451,7 @@ function checkChangelog() {
36082
36451
  ];
36083
36452
  }
36084
36453
  function createReleaseCompatibilityReport(options = {}) {
36085
- const root = resolve17(options.root ?? process.cwd());
36454
+ const root = resolve18(options.root ?? process.cwd());
36086
36455
  const packageJson = readPackageJson2(root);
36087
36456
  const simulatedLevels = options.simulated_levels ?? defaultSimulationLevels();
36088
36457
  const checks = [
@@ -41665,7 +42034,7 @@ __export(exports_verification_providers, {
41665
42034
  getVerificationRecord: () => getVerificationRecord,
41666
42035
  discoverVerificationProviderCapabilities: () => discoverVerificationProviderCapabilities
41667
42036
  });
41668
- import { existsSync as existsSync16, readFileSync as readFileSync10 } from "fs";
42037
+ import { existsSync as existsSync17, readFileSync as readFileSync11 } from "fs";
41669
42038
  function normalizeName6(name) {
41670
42039
  const normalized = name.trim().toLowerCase();
41671
42040
  if (!/^[a-z0-9][a-z0-9_-]{0,63}$/.test(normalized)) {
@@ -41762,7 +42131,7 @@ function classifyLog(text) {
41762
42131
  async function sleep3(ms) {
41763
42132
  if (ms <= 0)
41764
42133
  return;
41765
- await new Promise((resolve18) => setTimeout(resolve18, ms));
42134
+ await new Promise((resolve19) => setTimeout(resolve19, ms));
41766
42135
  }
41767
42136
  async function runCommandProvider(provider, input) {
41768
42137
  const commandTemplate = input.command || provider.command;
@@ -41817,7 +42186,7 @@ Timed out after ${provider.timeout_ms}ms`);
41817
42186
  };
41818
42187
  }
41819
42188
  function runCiLogProvider(input) {
41820
- const text = input.log_text ?? (input.log_path && existsSync16(input.log_path) ? readFileSync10(input.log_path, "utf-8") : "");
42189
+ const text = input.log_text ?? (input.log_path && existsSync17(input.log_path) ? readFileSync11(input.log_path, "utf-8") : "");
41821
42190
  return {
41822
42191
  status: classifyLog(text),
41823
42192
  attempts: 1,
@@ -41829,7 +42198,7 @@ function runBrowserProvider(input) {
41829
42198
  if (!input.artifact_path) {
41830
42199
  return { status: "unknown", attempts: 1, exit_code: null, output_summary: "browser provider needs a screenshot or artifact path" };
41831
42200
  }
41832
- if (!existsSync16(input.artifact_path)) {
42201
+ if (!existsSync17(input.artifact_path)) {
41833
42202
  return { status: "failed", attempts: 1, exit_code: null, output_summary: `artifact not found: ${input.artifact_path}` };
41834
42203
  }
41835
42204
  return {
@@ -44111,9 +44480,9 @@ __export(exports_local_backups, {
44111
44480
  LOCAL_BACKUP_CHECKSUM_ALGORITHM: () => LOCAL_BACKUP_CHECKSUM_ALGORITHM
44112
44481
  });
44113
44482
  import { createHash as createHash8 } from "crypto";
44114
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync5 } from "fs";
44115
- import { dirname as dirname8, resolve as resolve18 } from "path";
44116
- import { mkdirSync as mkdirSync7 } from "fs";
44483
+ import { readFileSync as readFileSync12, writeFileSync as writeFileSync6 } from "fs";
44484
+ import { dirname as dirname8, resolve as resolve19 } from "path";
44485
+ import { mkdirSync as mkdirSync8 } from "fs";
44117
44486
  function stableJson(value) {
44118
44487
  if (value === null || typeof value !== "object")
44119
44488
  return JSON.stringify(value);
@@ -44214,14 +44583,14 @@ function createLocalBackup(options = {}, db) {
44214
44583
  return backup;
44215
44584
  }
44216
44585
  function writeLocalBackupFile(backup, outputPath) {
44217
- const path = resolve18(outputPath);
44218
- mkdirSync7(dirname8(path), { recursive: true });
44219
- writeFileSync5(path, `${JSON.stringify(backup, null, 2)}
44586
+ const path = resolve19(outputPath);
44587
+ mkdirSync8(dirname8(path), { recursive: true });
44588
+ writeFileSync6(path, `${JSON.stringify(backup, null, 2)}
44220
44589
  `);
44221
44590
  return path;
44222
44591
  }
44223
44592
  function readLocalBackupFile(path) {
44224
- return JSON.parse(readFileSync11(resolve18(path), "utf-8"));
44593
+ return JSON.parse(readFileSync12(resolve19(path), "utf-8"));
44225
44594
  }
44226
44595
  function verifyLocalBackup(value, options = {}, db) {
44227
44596
  const verifiedAt = options.verified_at ?? now();
@@ -44417,8 +44786,8 @@ __export(exports_onboarding_fixtures, {
44417
44786
  TODOS_ONBOARDING_FIXTURE_SOURCE: () => TODOS_ONBOARDING_FIXTURE_SOURCE,
44418
44787
  TODOS_ONBOARDING_FIXTURE_LIBRARY_VERSION: () => TODOS_ONBOARDING_FIXTURE_LIBRARY_VERSION
44419
44788
  });
44420
- import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync6 } from "fs";
44421
- import { join as join16 } from "path";
44789
+ import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync7 } from "fs";
44790
+ import { join as join17 } from "path";
44422
44791
  function emptyData() {
44423
44792
  return {
44424
44793
  projects: [],
@@ -44748,11 +45117,11 @@ function getOnboardingFixtureBundle(name = "agent-project-demo") {
44748
45117
  return getOnboardingFixture(name).bundle;
44749
45118
  }
44750
45119
  function writeOnboardingFixtureFiles(directory) {
44751
- mkdirSync8(directory, { recursive: true });
45120
+ mkdirSync9(directory, { recursive: true });
44752
45121
  const files = [];
44753
45122
  for (const fixture of allFixtures()) {
44754
- const path = join16(directory, `${fixture.summary.name}.bridge.json`);
44755
- writeFileSync6(path, `${JSON.stringify(fixture.bundle, null, 2)}
45123
+ const path = join17(directory, `${fixture.summary.name}.bridge.json`);
45124
+ writeFileSync7(path, `${JSON.stringify(fixture.bundle, null, 2)}
44756
45125
  `, "utf-8");
44757
45126
  files.push(path);
44758
45127
  }
@@ -45399,7 +45768,7 @@ __export(exports_agent_replay_simulator, {
45399
45768
  renderAgentReplaySimulationMarkdown: () => renderAgentReplaySimulationMarkdown
45400
45769
  });
45401
45770
  import { createHash as createHash10 } from "crypto";
45402
- import { readFileSync as readFileSync12 } from "fs";
45771
+ import { readFileSync as readFileSync13 } from "fs";
45403
45772
  function isObject2(value) {
45404
45773
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
45405
45774
  }
@@ -45632,7 +46001,7 @@ function simulateAgentReplay(input, options = {}) {
45632
46001
  };
45633
46002
  }
45634
46003
  function simulateAgentReplayFile(path, options = {}) {
45635
- const parsed = JSON.parse(readFileSync12(path, "utf8"));
46004
+ const parsed = JSON.parse(readFileSync13(path, "utf8"));
45636
46005
  return simulateAgentReplay(parsed, options);
45637
46006
  }
45638
46007
  function renderAgentReplaySimulationMarkdown(simulation) {
@@ -50919,28 +51288,28 @@ __export(exports_environment_snapshots, {
50919
51288
  captureEnvironmentSnapshot: () => captureEnvironmentSnapshot
50920
51289
  });
50921
51290
  import { createHash as createHash12 } from "crypto";
50922
- import { existsSync as existsSync17, readFileSync as readFileSync13, statSync as statSync8 } from "fs";
51291
+ import { existsSync as existsSync18, readFileSync as readFileSync14, statSync as statSync8 } from "fs";
50923
51292
  import { hostname as hostname2, platform, arch } from "os";
50924
- import { dirname as dirname9, join as join17, resolve as resolve19 } from "path";
51293
+ import { dirname as dirname9, join as join18, resolve as resolve20 } from "path";
50925
51294
  import { tmpdir as tmpdir3 } from "os";
50926
51295
  function sha2566(value) {
50927
51296
  return createHash12("sha256").update(value).digest("hex");
50928
51297
  }
50929
51298
  function fileRecord(root, relativePath) {
50930
- const path = join17(root, relativePath);
50931
- if (!existsSync17(path))
51299
+ const path = join18(root, relativePath);
51300
+ if (!existsSync18(path))
50932
51301
  return null;
50933
51302
  const stat = statSync8(path);
50934
51303
  if (!stat.isFile())
50935
51304
  return null;
50936
- const content = readFileSync13(path);
51305
+ const content = readFileSync14(path);
50937
51306
  return { path: relativePath, sha256: sha2566(content), size_bytes: content.length };
50938
51307
  }
50939
51308
  function manifestRecord(root, relativePath) {
50940
51309
  const base = fileRecord(root, relativePath);
50941
51310
  if (!base)
50942
51311
  return null;
50943
- const parsed = readJsonFile(join17(root, relativePath));
51312
+ const parsed = readJsonFile(join18(root, relativePath));
50944
51313
  if (!parsed)
50945
51314
  return { ...base, redacted: {} };
50946
51315
  const redacted = redactValue({
@@ -51035,15 +51404,15 @@ function commandEnv(env, includeValues) {
51035
51404
  function defaultSnapshotDir() {
51036
51405
  const dbPath = getDatabasePath();
51037
51406
  if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
51038
- return join17(tmpdir3(), "hasna-todos", "environment-snapshots");
51039
- return join17(dirname9(resolve19(dbPath)), "environment-snapshots");
51407
+ return join18(tmpdir3(), "hasna-todos", "environment-snapshots");
51408
+ return join18(dirname9(resolve20(dbPath)), "environment-snapshots");
51040
51409
  }
51041
51410
  function snapshotWithId(snapshot) {
51042
51411
  const digest = sha2566(JSON.stringify(snapshot)).slice(0, 24);
51043
51412
  return { id: `env_${digest}`, ...snapshot };
51044
51413
  }
51045
51414
  function captureEnvironmentSnapshot(input = {}) {
51046
- const root = resolve19(input.root || process.cwd());
51415
+ const root = resolve20(input.root || process.cwd());
51047
51416
  const env = input.env || process.env;
51048
51417
  const warnings = [];
51049
51418
  const manifests = MANIFEST_FILES.map((file) => manifestRecord(root, file)).filter((file) => Boolean(file));
@@ -51083,13 +51452,13 @@ function captureEnvironmentSnapshot(input = {}) {
51083
51452
  });
51084
51453
  }
51085
51454
  function writeEnvironmentSnapshot(snapshot, outputPath) {
51086
- const path = outputPath ? resolve19(outputPath) : join17(defaultSnapshotDir(), `${snapshot.id}.json`);
51455
+ const path = outputPath ? resolve20(outputPath) : join18(defaultSnapshotDir(), `${snapshot.id}.json`);
51087
51456
  ensureDir2(dirname9(path));
51088
51457
  writeJsonFile(path, snapshot);
51089
51458
  return path;
51090
51459
  }
51091
51460
  function readEnvironmentSnapshot(path) {
51092
- const snapshot = readJsonFile(resolve19(path));
51461
+ const snapshot = readJsonFile(resolve20(path));
51093
51462
  if (!snapshot || snapshot.schema_version !== 1 || typeof snapshot.id !== "string") {
51094
51463
  throw new Error(`Invalid environment snapshot: ${path}`);
51095
51464
  }
@@ -51614,27 +51983,27 @@ __export(exports_serve, {
51614
51983
  SECURITY_HEADERS: () => SECURITY_HEADERS,
51615
51984
  MIME_TYPES: () => MIME_TYPES
51616
51985
  });
51617
- import { existsSync as existsSync18 } from "fs";
51618
- import { join as join18, dirname as dirname10, extname } from "path";
51986
+ import { existsSync as existsSync19 } from "fs";
51987
+ import { join as join19, dirname as dirname10, extname } from "path";
51619
51988
  import { fileURLToPath as fileURLToPath2 } from "url";
51620
51989
  function resolveDashboardDir() {
51621
51990
  const candidates = [];
51622
51991
  try {
51623
51992
  const scriptDir = dirname10(fileURLToPath2(import.meta.url));
51624
- candidates.push(join18(scriptDir, "..", "dashboard", "dist"));
51625
- candidates.push(join18(scriptDir, "..", "..", "dashboard", "dist"));
51993
+ candidates.push(join19(scriptDir, "..", "dashboard", "dist"));
51994
+ candidates.push(join19(scriptDir, "..", "..", "dashboard", "dist"));
51626
51995
  } catch {}
51627
51996
  if (process.argv[1]) {
51628
51997
  const mainDir = dirname10(process.argv[1]);
51629
- candidates.push(join18(mainDir, "..", "dashboard", "dist"));
51630
- candidates.push(join18(mainDir, "..", "..", "dashboard", "dist"));
51998
+ candidates.push(join19(mainDir, "..", "dashboard", "dist"));
51999
+ candidates.push(join19(mainDir, "..", "..", "dashboard", "dist"));
51631
52000
  }
51632
- candidates.push(join18(process.cwd(), "dashboard", "dist"));
52001
+ candidates.push(join19(process.cwd(), "dashboard", "dist"));
51633
52002
  for (const candidate of candidates) {
51634
- if (existsSync18(candidate))
52003
+ if (existsSync19(candidate))
51635
52004
  return candidate;
51636
52005
  }
51637
- return join18(process.cwd(), "dashboard", "dist");
52006
+ return join19(process.cwd(), "dashboard", "dist");
51638
52007
  }
51639
52008
  function getProvidedApiKey(req) {
51640
52009
  const headerKey = req.headers.get("x-api-key");
@@ -51684,7 +52053,7 @@ function json(data, status = 200, headers) {
51684
52053
  });
51685
52054
  }
51686
52055
  function serveStaticFile(filePath) {
51687
- if (!existsSync18(filePath))
52056
+ if (!existsSync19(filePath))
51688
52057
  return null;
51689
52058
  const ext = extname(filePath);
51690
52059
  const contentType = MIME_TYPES[ext] || "application/octet-stream";
@@ -51765,7 +52134,7 @@ data: ${data}
51765
52134
  filteredSseClients.delete(client);
51766
52135
  }
51767
52136
  const dashboardDir = resolveDashboardDir();
51768
- const dashboardExists = existsSync18(dashboardDir);
52137
+ const dashboardExists = existsSync19(dashboardDir);
51769
52138
  if (!dashboardExists) {
51770
52139
  console.error(`
51771
52140
  Dashboard not found at: ${dashboardDir}`);
@@ -53595,12 +53964,12 @@ __export(exports_config_serve_commands, {
53595
53964
  registerConfigServeCommands: () => registerConfigServeCommands
53596
53965
  });
53597
53966
  import chalk6 from "chalk";
53598
- import { existsSync as existsSync19, mkdirSync as mkdirSync9, readFileSync as readFileSync14, writeFileSync as writeFileSync7 } from "fs";
53599
- import { dirname as dirname11, join as join19 } from "path";
53967
+ import { existsSync as existsSync20, mkdirSync as mkdirSync10, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "fs";
53968
+ import { dirname as dirname11, join as join20 } from "path";
53600
53969
  function registerConfigServeCommands(program2) {
53601
53970
  program2.command("config").description("View or update configuration").option("--get <key>", "Get a config value").option("--set <key=value>", "Set a config value (e.g. completion_guard.enabled=true)").action((opts) => {
53602
53971
  const globalOpts = program2.opts();
53603
- const configPath = join19(getTodosGlobalDir(), "config.json");
53972
+ const configPath = join20(getTodosGlobalDir(), "config.json");
53604
53973
  if (opts.get) {
53605
53974
  const config2 = loadConfig();
53606
53975
  const keys = opts.get.split(".");
@@ -53626,7 +53995,7 @@ function registerConfigServeCommands(program2) {
53626
53995
  }
53627
53996
  let config2 = {};
53628
53997
  try {
53629
- config2 = JSON.parse(readFileSync14(configPath, "utf-8"));
53998
+ config2 = JSON.parse(readFileSync15(configPath, "utf-8"));
53630
53999
  } catch {}
53631
54000
  const keys = key.split(".");
53632
54001
  let obj = config2;
@@ -53637,9 +54006,9 @@ function registerConfigServeCommands(program2) {
53637
54006
  }
53638
54007
  obj[keys[keys.length - 1]] = parsedValue;
53639
54008
  const dir = dirname11(configPath);
53640
- if (!existsSync19(dir))
53641
- mkdirSync9(dir, { recursive: true });
53642
- writeFileSync7(configPath, JSON.stringify(config2, null, 2));
54009
+ if (!existsSync20(dir))
54010
+ mkdirSync10(dir, { recursive: true });
54011
+ writeFileSync8(configPath, JSON.stringify(config2, null, 2));
53643
54012
  if (globalOpts.json) {
53644
54013
  output({ key, value: parsedValue }, true);
53645
54014
  } else {
@@ -53766,7 +54135,7 @@ function registerConfigServeCommands(program2) {
53766
54135
  redaction.command("scan [text]").description("Scan text or a file for secret-like values without printing values").option("--file <path>", "File to scan").action(async (text2, opts) => {
53767
54136
  const globalOpts = program2.opts();
53768
54137
  const { listSecretFindings: listSecretFindings2 } = await Promise.resolve().then(() => (init_redaction(), exports_redaction));
53769
- const value = opts.file ? readFileSync14(opts.file, "utf-8") : text2 || "";
54138
+ const value = opts.file ? readFileSync15(opts.file, "utf-8") : text2 || "";
53770
54139
  const findings = listSecretFindings2(value);
53771
54140
  if (globalOpts.json) {
53772
54141
  output({ ok: findings.length === 0, findings }, true);
@@ -55152,7 +55521,7 @@ __export(exports_query_commands, {
55152
55521
  registerQueryCommands: () => registerQueryCommands
55153
55522
  });
55154
55523
  import chalk7 from "chalk";
55155
- import { readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "fs";
55524
+ import { readFileSync as readFileSync16, writeFileSync as writeFileSync9 } from "fs";
55156
55525
  function parseJsonObjectOption2(value, label) {
55157
55526
  if (!value)
55158
55527
  return;
@@ -55811,9 +56180,9 @@ Repairs`));
55811
56180
  const db = getDatabase();
55812
56181
  const row = db.query("SELECT COUNT(*) as count FROM tasks").get();
55813
56182
  const { statSync: statSync9 } = await import("fs");
55814
- const { join: join20 } = await import("path");
56183
+ const { join: join21 } = await import("path");
55815
56184
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
55816
- const dbPath = process.env["HASNA_TODOS_DB_PATH"] || process.env["TODOS_DB_PATH"] || join20(home, ".hasna", "todos", "todos.db");
56185
+ const dbPath = process.env["HASNA_TODOS_DB_PATH"] || process.env["TODOS_DB_PATH"] || join21(home, ".hasna", "todos", "todos.db");
55817
56186
  let size = "unknown";
55818
56187
  try {
55819
56188
  size = `${(statSync9(dbPath).size / 1024 / 1024).toFixed(1)} MB`;
@@ -56430,7 +56799,7 @@ Repairs`));
56430
56799
  const sessionId = opts.session || globalOpts.session || undefined;
56431
56800
  try {
56432
56801
  if (opts.import) {
56433
- const bundle = JSON.parse(readFileSync15(opts.import, "utf-8"));
56802
+ const bundle = JSON.parse(readFileSync16(opts.import, "utf-8"));
56434
56803
  const result = importHandoffBundle(bundle, { apply: opts.apply }, db);
56435
56804
  if (opts.json || globalOpts.json) {
56436
56805
  console.log(JSON.stringify(result));
@@ -56446,7 +56815,7 @@ Repairs`));
56446
56815
  const bundle = exportHandoffBundle(opts.export, db);
56447
56816
  const json2 = JSON.stringify(bundle, null, 2);
56448
56817
  if (opts.output) {
56449
- writeFileSync8(opts.output, `${json2}
56818
+ writeFileSync9(opts.output, `${json2}
56450
56819
  `);
56451
56820
  if (opts.json || globalOpts.json) {
56452
56821
  console.log(JSON.stringify({ path: opts.output, handoff_id: bundle.handoff.id }));
@@ -56677,7 +57046,7 @@ Repairs`));
56677
57046
  });
56678
57047
  const content = format === "json" ? JSON.stringify(document, null, 2) : renderReleaseNotesMarkdown2(document);
56679
57048
  if (opts.out) {
56680
- writeFileSync8(opts.out, content);
57049
+ writeFileSync9(opts.out, content);
56681
57050
  if (format !== "json")
56682
57051
  console.log(chalk7.green(`Wrote release notes to ${opts.out}`));
56683
57052
  return;
@@ -56792,7 +57161,7 @@ Repairs`));
56792
57161
  redact: Boolean(opts.redact)
56793
57162
  });
56794
57163
  if (opts.out) {
56795
- writeFileSync8(opts.out, exported.content);
57164
+ writeFileSync9(opts.out, exported.content);
56796
57165
  if (!(opts.json || globalOpts.json))
56797
57166
  console.log(chalk7.green(`Wrote ${exported.events.length} events to ${opts.out}`));
56798
57167
  }
@@ -56808,7 +57177,7 @@ Repairs`));
56808
57177
  });
56809
57178
  calendar.command("import <path>").description("Import VEVENT entries from an ICS file as local imported calendar items").option("-j, --json", "Output JSON").action((path, opts) => {
56810
57179
  try {
56811
- const result = importCalendarIcs(readFileSync15(path, "utf-8"));
57180
+ const result = importCalendarIcs(readFileSync16(path, "utf-8"));
56812
57181
  if (opts.json || program2.opts().json) {
56813
57182
  output(result, true);
56814
57183
  return;
@@ -56947,7 +57316,7 @@ Repairs`));
56947
57316
  const bundle = exportTaskBoardBundle(boardId);
56948
57317
  const json2 = JSON.stringify(bundle, null, 2);
56949
57318
  if (opts.out) {
56950
- writeFileSync8(opts.out, json2);
57319
+ writeFileSync9(opts.out, json2);
56951
57320
  if (!(opts.json || program2.opts().json))
56952
57321
  console.log(chalk7.green(`Wrote ${bundle.boards.length} board(s) to ${opts.out}`));
56953
57322
  }
@@ -56959,7 +57328,7 @@ Repairs`));
56959
57328
  });
56960
57329
  board.command("import <path>").description("Import local board definitions from a JSON bundle").option("-j, --json", "Output JSON").action((path, opts) => {
56961
57330
  try {
56962
- const bundle = JSON.parse(readFileSync15(path, "utf-8"));
57331
+ const bundle = JSON.parse(readFileSync16(path, "utf-8"));
56963
57332
  const result = importTaskBoardBundle(bundle);
56964
57333
  if (opts.json || program2.opts().json) {
56965
57334
  output(result, true);
@@ -57335,7 +57704,7 @@ Repairs`));
57335
57704
  const { importExternalIssues: importExternalIssues2 } = await Promise.resolve().then(() => (init_external_issue_importers(), exports_external_issue_importers));
57336
57705
  let body = text2 || "";
57337
57706
  if (opts.file)
57338
- body = readFileSync15(opts.file, "utf-8");
57707
+ body = readFileSync16(opts.file, "utf-8");
57339
57708
  if (!body && !opts.url && !process.stdin.isTTY)
57340
57709
  body = await Bun.stdin.text();
57341
57710
  if (!body.trim() && !opts.url) {
@@ -57393,7 +57762,7 @@ Repairs`));
57393
57762
  } = await Promise.resolve().then(() => (init_tester_issue_reports(), exports_tester_issue_reports));
57394
57763
  let body = jsonText || "";
57395
57764
  if (opts.file)
57396
- body = readFileSync15(opts.file, "utf-8");
57765
+ body = readFileSync16(opts.file, "utf-8");
57397
57766
  if (!body && !process.stdin.isTTY)
57398
57767
  body = await Bun.stdin.text();
57399
57768
  if (!body.trim()) {
@@ -57436,11 +57805,11 @@ Repairs`));
57436
57805
  const inbox = program2.command("inbox").description("Capture local inbox items from pasted errors, CI logs, git context, files, or GitHub issue URLs");
57437
57806
  inbox.command("add [text]").description("Create a local inbox item and linked task from text, stdin, or a file").option("--file <path>", "Read captured context from a file").option("--source-type <type>", "pasted_error, ci_log, git_context, github_issue, file, or other").option("--source-name <name>", "Human-readable source name").option("--source-url <url>", "Source URL, including GitHub issue URLs").option("--title <title>", "Task/inbox title").option("--priority <priority>", "Task priority").option("--tags <tags>", "Comma-separated extra tags").option("--metadata <json>", "Additional JSON metadata").option("--no-task", "Only store inbox item; do not create a linked task").option("-j, --json", "Output as JSON").action(async (text2, opts) => {
57438
57807
  const globalOpts = program2.opts();
57439
- const { readFileSync: readFileSync16 } = await import("fs");
57808
+ const { readFileSync: readFileSync17 } = await import("fs");
57440
57809
  const { createInboxItem: createInboxItem2 } = await Promise.resolve().then(() => (init_inbox(), exports_inbox));
57441
57810
  let body = text2 || "";
57442
57811
  if (opts.file)
57443
- body = readFileSync16(opts.file, "utf-8");
57812
+ body = readFileSync17(opts.file, "utf-8");
57444
57813
  if (!body && !process.stdin.isTTY)
57445
57814
  body = await Bun.stdin.text();
57446
57815
  if (!body.trim()) {
@@ -57501,11 +57870,11 @@ ${diff}` : null].filter(Boolean).join(`
57501
57870
  });
57502
57871
  inbox.command("parse [text]").description("Preview or apply deterministic local natural-language task intake").option("--file <path>", "Read natural-language input from a file").option("--priority <priority>", "Default priority for parsed tasks", "medium").option("--project <id>", "Project ID for applied tasks").option("--list <id>", "Task list ID for applied tasks").option("--reference-date <iso>", "Reference date for due today/tomorrow/next week").option("--apply", "Create parsed tasks; default is dry-run preview").option("-j, --json", "Output as JSON").action(async (text2, opts) => {
57503
57872
  const globalOpts = program2.opts();
57504
- const { readFileSync: readFileSync16 } = await import("fs");
57873
+ const { readFileSync: readFileSync17 } = await import("fs");
57505
57874
  const { previewNaturalLanguageIntake: previewNaturalLanguageIntake2 } = await Promise.resolve().then(() => (init_natural_language_intake(), exports_natural_language_intake));
57506
57875
  let body = text2 || "";
57507
57876
  if (opts.file)
57508
- body = readFileSync16(opts.file, "utf-8");
57877
+ body = readFileSync17(opts.file, "utf-8");
57509
57878
  if (!body && !process.stdin.isTTY)
57510
57879
  body = await Bun.stdin.text();
57511
57880
  if (!body.trim()) {
@@ -57629,45 +57998,45 @@ __export(exports_mcp_hooks_commands, {
57629
57998
  });
57630
57999
  import chalk8 from "chalk";
57631
58000
  import { execSync as execSync3 } from "child_process";
57632
- import { existsSync as existsSync20, readFileSync as readFileSync16, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10, chmodSync as chmodSync2 } from "fs";
57633
- import { dirname as dirname12, join as join20 } from "path";
58001
+ import { existsSync as existsSync21, readFileSync as readFileSync17, writeFileSync as writeFileSync10, mkdirSync as mkdirSync11, chmodSync as chmodSync2 } from "fs";
58002
+ import { dirname as dirname12, join as join21 } from "path";
57634
58003
  function getMcpBinaryPath() {
57635
58004
  try {
57636
58005
  const p = execSync3("which todos-mcp", { encoding: "utf-8" }).trim();
57637
58006
  if (p)
57638
58007
  return p;
57639
58008
  } catch {}
57640
- const bunBin = join20(HOME2, ".bun", "bin", "todos-mcp");
57641
- if (existsSync20(bunBin))
58009
+ const bunBin = join21(HOME2, ".bun", "bin", "todos-mcp");
58010
+ if (existsSync21(bunBin))
57642
58011
  return bunBin;
57643
58012
  return "todos-mcp";
57644
58013
  }
57645
58014
  function readJsonFile2(path) {
57646
- if (!existsSync20(path))
58015
+ if (!existsSync21(path))
57647
58016
  return {};
57648
58017
  try {
57649
- return JSON.parse(readFileSync16(path, "utf-8"));
58018
+ return JSON.parse(readFileSync17(path, "utf-8"));
57650
58019
  } catch {
57651
58020
  return {};
57652
58021
  }
57653
58022
  }
57654
58023
  function writeJsonFile2(path, data) {
57655
58024
  const dir = dirname12(path);
57656
- if (!existsSync20(dir))
57657
- mkdirSync10(dir, { recursive: true });
57658
- writeFileSync9(path, JSON.stringify(data, null, 2) + `
58025
+ if (!existsSync21(dir))
58026
+ mkdirSync11(dir, { recursive: true });
58027
+ writeFileSync10(path, JSON.stringify(data, null, 2) + `
57659
58028
  `);
57660
58029
  }
57661
58030
  function readTomlFile(path) {
57662
- if (!existsSync20(path))
58031
+ if (!existsSync21(path))
57663
58032
  return "";
57664
- return readFileSync16(path, "utf-8");
58033
+ return readFileSync17(path, "utf-8");
57665
58034
  }
57666
58035
  function writeTomlFile(path, content) {
57667
58036
  const dir = dirname12(path);
57668
- if (!existsSync20(dir))
57669
- mkdirSync10(dir, { recursive: true });
57670
- writeFileSync9(path, content);
58037
+ if (!existsSync21(dir))
58038
+ mkdirSync11(dir, { recursive: true });
58039
+ writeFileSync10(path, content);
57671
58040
  }
57672
58041
  function removeTomlBlock(content, blockName) {
57673
58042
  const lines = content.split(`
@@ -57731,7 +58100,7 @@ function unregisterClaude(_global) {
57731
58100
  }
57732
58101
  }
57733
58102
  function registerCodex(binPath) {
57734
- const configPath = join20(HOME2, ".codex", "config.toml");
58103
+ const configPath = join21(HOME2, ".codex", "config.toml");
57735
58104
  let content = readTomlFile(configPath);
57736
58105
  content = removeTomlBlock(content, "mcp_servers.todos");
57737
58106
  const block = `
@@ -57745,7 +58114,7 @@ args = []
57745
58114
  console.log(chalk8.green(`Codex CLI: registered in ${configPath}`));
57746
58115
  }
57747
58116
  function unregisterCodex() {
57748
- const configPath = join20(HOME2, ".codex", "config.toml");
58117
+ const configPath = join21(HOME2, ".codex", "config.toml");
57749
58118
  let content = readTomlFile(configPath);
57750
58119
  if (!content.includes("[mcp_servers.todos]")) {
57751
58120
  console.log(chalk8.dim(`Codex CLI: todos not found in ${configPath}`));
@@ -57757,7 +58126,7 @@ function unregisterCodex() {
57757
58126
  console.log(chalk8.green(`Codex CLI: unregistered from ${configPath}`));
57758
58127
  }
57759
58128
  function registerGemini(binPath) {
57760
- const configPath = join20(HOME2, ".gemini", "settings.json");
58129
+ const configPath = join21(HOME2, ".gemini", "settings.json");
57761
58130
  const config = readJsonFile2(configPath);
57762
58131
  if (!config["mcpServers"]) {
57763
58132
  config["mcpServers"] = {};
@@ -57771,7 +58140,7 @@ function registerGemini(binPath) {
57771
58140
  console.log(chalk8.green(`Gemini CLI: registered in ${configPath}`));
57772
58141
  }
57773
58142
  function unregisterGemini() {
57774
- const configPath = join20(HOME2, ".gemini", "settings.json");
58143
+ const configPath = join21(HOME2, ".gemini", "settings.json");
57775
58144
  const config = readJsonFile2(configPath);
57776
58145
  const servers = config["mcpServers"];
57777
58146
  if (!servers || !("todos" in servers)) {
@@ -57828,9 +58197,9 @@ function registerMcpHooksCommands(program2) {
57828
58197
  if (p)
57829
58198
  todosBin = p;
57830
58199
  } catch {}
57831
- const hooksDir = join20(process.cwd(), ".claude", "hooks");
57832
- if (!existsSync20(hooksDir))
57833
- mkdirSync10(hooksDir, { recursive: true });
58200
+ const hooksDir = join21(process.cwd(), ".claude", "hooks");
58201
+ if (!existsSync21(hooksDir))
58202
+ mkdirSync11(hooksDir, { recursive: true });
57834
58203
  const hookScript = `#!/usr/bin/env bash
57835
58204
  # Auto-generated by: todos hooks install
57836
58205
  # Syncs todos with Claude Code task list on tool use events.
@@ -57854,11 +58223,11 @@ esac
57854
58223
 
57855
58224
  exit 0
57856
58225
  `;
57857
- const hookPath = join20(hooksDir, "todos-sync.sh");
57858
- writeFileSync9(hookPath, hookScript);
58226
+ const hookPath = join21(hooksDir, "todos-sync.sh");
58227
+ writeFileSync10(hookPath, hookScript);
57859
58228
  execSync3(`chmod +x "${hookPath}"`);
57860
58229
  console.log(chalk8.green(`Hook script created: ${hookPath}`));
57861
- const settingsPath = join20(process.cwd(), ".claude", "settings.json");
58230
+ const settingsPath = join21(process.cwd(), ".claude", "settings.json");
57862
58231
  const settings = readJsonFile2(settingsPath);
57863
58232
  if (!settings["hooks"]) {
57864
58233
  settings["hooks"] = {};
@@ -58727,18 +59096,18 @@ Artifacts:`));
58727
59096
  const gitDir = execSync3("git rev-parse --git-dir", { encoding: "utf-8" }).trim();
58728
59097
  const hookPath = `${gitDir}/hooks/post-commit`;
58729
59098
  const marker = "# todos-auto-link";
58730
- if (existsSync20(hookPath)) {
58731
- const existing = readFileSync16(hookPath, "utf-8");
59099
+ if (existsSync21(hookPath)) {
59100
+ const existing = readFileSync17(hookPath, "utf-8");
58732
59101
  if (existing.includes(marker)) {
58733
59102
  console.log(chalk8.yellow("Hook already installed."));
58734
59103
  return;
58735
59104
  }
58736
- writeFileSync9(hookPath, existing + `
59105
+ writeFileSync10(hookPath, existing + `
58737
59106
  ${marker}
58738
59107
  $(dirname "$0")/../../scripts/post-commit-hook.sh
58739
59108
  `);
58740
59109
  } else {
58741
- writeFileSync9(hookPath, `#!/usr/bin/env bash
59110
+ writeFileSync10(hookPath, `#!/usr/bin/env bash
58742
59111
  ${marker}
58743
59112
  $(dirname "$0")/../../scripts/post-commit-hook.sh
58744
59113
  `);
@@ -58755,11 +59124,11 @@ $(dirname "$0")/../../scripts/post-commit-hook.sh
58755
59124
  const gitDir = execSync3("git rev-parse --git-dir", { encoding: "utf-8" }).trim();
58756
59125
  const hookPath = `${gitDir}/hooks/post-commit`;
58757
59126
  const marker = "# todos-auto-link";
58758
- if (!existsSync20(hookPath)) {
59127
+ if (!existsSync21(hookPath)) {
58759
59128
  console.log(chalk8.dim("No post-commit hook found."));
58760
59129
  return;
58761
59130
  }
58762
- const content = readFileSync16(hookPath, "utf-8");
59131
+ const content = readFileSync17(hookPath, "utf-8");
58763
59132
  if (!content.includes(marker)) {
58764
59133
  console.log(chalk8.dim("Hook not managed by todos."));
58765
59134
  return;
@@ -58770,7 +59139,7 @@ $(dirname "$0")/../../scripts/post-commit-hook.sh
58770
59139
  if (cleaned === "#!/usr/bin/env bash" || cleaned === "") {
58771
59140
  (await import("fs")).unlinkSync(hookPath);
58772
59141
  } else {
58773
- writeFileSync9(hookPath, cleaned + `
59142
+ writeFileSync10(hookPath, cleaned + `
58774
59143
  `);
58775
59144
  }
58776
59145
  console.log(chalk8.green("Post-commit hook removed."));
@@ -58939,9 +59308,9 @@ __export(exports_machines, {
58939
59308
  });
58940
59309
  import chalk10 from "chalk";
58941
59310
  import { execSync as execSync4 } from "child_process";
58942
- import { readFileSync as readFileSync17, unlinkSync as unlinkSync2, writeFileSync as writeFileSync10 } from "fs";
59311
+ import { readFileSync as readFileSync18, unlinkSync as unlinkSync2, writeFileSync as writeFileSync11 } from "fs";
58943
59312
  import { tmpdir as tmpdir4 } from "os";
58944
- import { join as join21 } from "path";
59313
+ import { join as join22 } from "path";
58945
59314
  function getOrCreateLocalMachineName() {
58946
59315
  return process.env["TODOS_MACHINE_NAME"] || __require("os").hostname() || "unknown";
58947
59316
  }
@@ -58979,11 +59348,11 @@ function remoteTempPath(sshAddress) {
58979
59348
  }
58980
59349
  function readRemoteBridgeBundle(sshAddress) {
58981
59350
  const remotePath = remoteTempPath(sshAddress);
58982
- const localPath = join21(tmpdir4(), `todos-bridge-pull-${uuid()}.json`);
59351
+ const localPath = join22(tmpdir4(), `todos-bridge-pull-${uuid()}.json`);
58983
59352
  try {
58984
59353
  runSsh(sshAddress, `todos export --format bridge --allow-plaintext-sensitive --output ${shellQuote(remotePath)}`, 120000);
58985
59354
  scpFromRemote(sshAddress, remotePath, localPath);
58986
- return JSON.parse(readFileSync17(localPath, "utf-8"));
59355
+ return JSON.parse(readFileSync18(localPath, "utf-8"));
58987
59356
  } finally {
58988
59357
  try {
58989
59358
  runSsh(sshAddress, `rm -f ${shellQuote(remotePath)}`, 1e4);
@@ -58994,8 +59363,8 @@ function readRemoteBridgeBundle(sshAddress) {
58994
59363
  }
58995
59364
  }
58996
59365
  function writeLocalBridgeBundle() {
58997
- const localPath = join21(tmpdir4(), `todos-bridge-push-${uuid()}.json`);
58998
- writeFileSync10(localPath, JSON.stringify(createLocalBridgeBundle(), null, 2));
59366
+ const localPath = join22(tmpdir4(), `todos-bridge-push-${uuid()}.json`);
59367
+ writeFileSync11(localPath, JSON.stringify(createLocalBridgeBundle(), null, 2));
58999
59368
  return localPath;
59000
59369
  }
59001
59370
  function pushLocalBridgeBundle(sshAddress, dryRun) {
@@ -60058,7 +60427,7 @@ __export(exports_onboarding_commands, {
60058
60427
  registerOnboardingCommands: () => registerOnboardingCommands
60059
60428
  });
60060
60429
  import chalk17 from "chalk";
60061
- import { resolve as resolve20 } from "path";
60430
+ import { resolve as resolve21 } from "path";
60062
60431
  function registerOnboardingCommands(program2) {
60063
60432
  program2.command("onboarding").alias("demo-fixtures").description("List, show, write, or import bundled local onboarding fixtures").option("--show <name>", "Show one fixture bridge bundle as JSON").option("--write <dir>", "Write all bundled fixture bridge bundles to a directory").option("--import <name>", "Dry-run or apply an onboarding fixture import").option("--apply", "Apply an onboarding fixture import. Defaults to dry-run.").option("--resolve-conflicts", "Safely merge existing local tasks while preserving divergent fields").action(async (opts) => {
60064
60433
  const globalOpts = program2.opts();
@@ -60074,7 +60443,7 @@ function registerOnboardingCommands(program2) {
60074
60443
  return;
60075
60444
  }
60076
60445
  if (opts.write) {
60077
- const result = writeOnboardingFixtureFiles2(resolve20(opts.write));
60446
+ const result = writeOnboardingFixtureFiles2(resolve21(opts.write));
60078
60447
  if (globalOpts.json) {
60079
60448
  output(result, true);
60080
60449
  return;
@@ -63522,8 +63891,8 @@ __export(exports_sdk_integration_fixtures, {
63522
63891
  TODOS_SDK_INTEGRATION_FIXTURE_SCHEMA_VERSION: () => TODOS_SDK_INTEGRATION_FIXTURE_SCHEMA_VERSION,
63523
63892
  TODOS_SDK_INTEGRATION_FIXTURE_GENERATED_AT: () => TODOS_SDK_INTEGRATION_FIXTURE_GENERATED_AT
63524
63893
  });
63525
- import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
63526
- import { join as join22 } from "path";
63894
+ import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync12 } from "fs";
63895
+ import { join as join23 } from "path";
63527
63896
  function source5(version) {
63528
63897
  return {
63529
63898
  packageName: "@hasna/todos",
@@ -63619,7 +63988,7 @@ function createSdkIntegrationFixturePack(options = {}) {
63619
63988
  };
63620
63989
  }
63621
63990
  function writeSdkIntegrationFixtures(directory, options = {}) {
63622
- mkdirSync11(directory, { recursive: true });
63991
+ mkdirSync12(directory, { recursive: true });
63623
63992
  const pack = createSdkIntegrationFixturePack(options);
63624
63993
  const bundle = getOnboardingFixtureBundle("agent-project-demo");
63625
63994
  const files = [
@@ -63630,8 +63999,8 @@ function writeSdkIntegrationFixtures(directory, options = {}) {
63630
63999
  ];
63631
64000
  const written = [];
63632
64001
  for (const [name, payload] of files) {
63633
- const file = join22(directory, name);
63634
- writeFileSync11(file, `${JSON.stringify(payload, null, 2)}
64002
+ const file = join23(directory, name);
64003
+ writeFileSync12(file, `${JSON.stringify(payload, null, 2)}
63635
64004
  `, "utf-8");
63636
64005
  written.push(file);
63637
64006
  }
@@ -63654,7 +64023,7 @@ __export(exports_sdk_fixture_commands, {
63654
64023
  registerSdkFixtureCommands: () => registerSdkFixtureCommands
63655
64024
  });
63656
64025
  import chalk19 from "chalk";
63657
- import { resolve as resolve21 } from "path";
64026
+ import { resolve as resolve22 } from "path";
63658
64027
  function registerSdkFixtureCommands(program2) {
63659
64028
  program2.command("sdk-fixtures").description("List, show, or write local SDK integration fixtures").option("--show", "Print the full fixture pack JSON").option("--write <dir>", "Write fixture pack, bridge fixture, contract snapshots, and example index to a directory").action(async (opts) => {
63660
64029
  const globalOpts = program2.opts();
@@ -63665,7 +64034,7 @@ function registerSdkFixtureCommands(program2) {
63665
64034
  writeSdkIntegrationFixtures: writeSdkIntegrationFixtures2
63666
64035
  } = await Promise.resolve().then(() => (init_sdk_integration_fixtures(), exports_sdk_integration_fixtures));
63667
64036
  if (opts.write) {
63668
- const result = writeSdkIntegrationFixtures2(resolve21(opts.write));
64037
+ const result = writeSdkIntegrationFixtures2(resolve22(opts.write));
63669
64038
  if (globalOpts.json) {
63670
64039
  console.log(JSON.stringify(result));
63671
64040
  return;
@@ -63895,7 +64264,7 @@ var exports_roadmap_commands = {};
63895
64264
  __export(exports_roadmap_commands, {
63896
64265
  registerRoadmapCommands: () => registerRoadmapCommands
63897
64266
  });
63898
- import { readFileSync as readFileSync18, writeFileSync as writeFileSync12 } from "fs";
64267
+ import { readFileSync as readFileSync19, writeFileSync as writeFileSync13 } from "fs";
63899
64268
  import chalk21 from "chalk";
63900
64269
  function splitList3(value) {
63901
64270
  return value?.split(";").flatMap((part) => part.split(",")).map((item) => item.trim()).filter(Boolean);
@@ -64106,7 +64475,7 @@ function registerRoadmapCommands(program2) {
64106
64475
  const { exportRoadmapBundle: exportRoadmapBundle2, renderRoadmapMarkdown: renderRoadmapMarkdown2 } = await Promise.resolve().then(() => (init_roadmaps(), exports_roadmaps));
64107
64476
  const content = opts.format === "markdown" ? renderRoadmapMarkdown2(roadmap) : JSON.stringify(exportRoadmapBundle2(roadmap), null, 2);
64108
64477
  if (opts.out) {
64109
- writeFileSync12(opts.out, content);
64478
+ writeFileSync13(opts.out, content);
64110
64479
  if (!globalOpts.json)
64111
64480
  console.log(chalk21.green(`Wrote roadmap export to ${opts.out}`));
64112
64481
  }
@@ -64124,7 +64493,7 @@ function registerRoadmapCommands(program2) {
64124
64493
  const globalOpts = globalOptions(program2);
64125
64494
  try {
64126
64495
  const { importRoadmapBundle: importRoadmapBundle2 } = await Promise.resolve().then(() => (init_roadmaps(), exports_roadmaps));
64127
- const bundle = JSON.parse(readFileSync18(path, "utf8"));
64496
+ const bundle = JSON.parse(readFileSync19(path, "utf8"));
64128
64497
  const result = importRoadmapBundle2(bundle, { apply: Boolean(opts.apply) });
64129
64498
  if (globalOpts.json) {
64130
64499
  output(result, true);
@@ -64487,7 +64856,7 @@ __export(exports_local_backup_commands, {
64487
64856
  registerLocalBackupCommands: () => registerLocalBackupCommands
64488
64857
  });
64489
64858
  import chalk26 from "chalk";
64490
- import { resolve as resolve22 } from "path";
64859
+ import { resolve as resolve23 } from "path";
64491
64860
  function globalOptions6(program2) {
64492
64861
  const command = program2;
64493
64862
  return command.optsWithGlobals?.() ?? program2.opts();
@@ -64509,10 +64878,10 @@ function registerLocalBackupCommands(program2) {
64509
64878
  const projectId = opts.projectId ?? autoProject(globalOpts);
64510
64879
  const backupBundle = createLocalBackup2({
64511
64880
  project_id: projectId,
64512
- output_path: opts.output ? resolve22(opts.output) : undefined
64881
+ output_path: opts.output ? resolve23(opts.output) : undefined
64513
64882
  });
64514
64883
  const result = {
64515
- output_path: opts.output ? resolve22(opts.output) : null,
64884
+ output_path: opts.output ? resolve23(opts.output) : null,
64516
64885
  backup: backupBundle
64517
64886
  };
64518
64887
  if (opts.json || globalOpts.json) {