@hasna/todos 0.11.42 → 0.11.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2538,6 +2538,50 @@ var TODOS_JSON_CONTRACTS = [
2538
2538
  },
2539
2539
  optional: {}
2540
2540
  }),
2541
+ contract({
2542
+ id: "environment_snapshot",
2543
+ name: "Environment Snapshot",
2544
+ description: "Local reproducibility snapshot for task and run verification context.",
2545
+ surfaces: ["cli", "mcp", "sdk"],
2546
+ stability: "stable",
2547
+ required: {
2548
+ schema_version: field("integer", "Snapshot schema version."),
2549
+ id: field("string", "Content-derived snapshot identifier."),
2550
+ captured_at: isoDateField,
2551
+ root: field("string", "Canonical local project root inspected."),
2552
+ machine: field("object", "Local hostname, platform, and architecture metadata."),
2553
+ target: field("object", "Optional task, run, and agent attachment IDs."),
2554
+ runtime: field("object", "Bun, Node, and executable metadata."),
2555
+ package_manager: field("object", "Detected package manager, lockfile hashes, and redacted manifests."),
2556
+ git: field("object", "Local git branch, commit, dirty state, and porcelain status."),
2557
+ config_hashes: field("array", "SHA-256 hashes of relevant local config files."),
2558
+ command_env: field("object", "Redacted command and environment metadata."),
2559
+ warnings: field("array", "Warnings about missing or unavailable local data.")
2560
+ },
2561
+ optional: {}
2562
+ }),
2563
+ contract({
2564
+ id: "environment_snapshot_comparison",
2565
+ name: "Environment Snapshot Comparison",
2566
+ description: "Drift summary returned when comparing two local environment snapshots.",
2567
+ surfaces: ["cli", "mcp", "sdk"],
2568
+ stability: "stable",
2569
+ required: {
2570
+ schema_version: field("integer", "Comparison schema version."),
2571
+ left_id: field("string", "Left snapshot ID."),
2572
+ right_id: field("string", "Right snapshot ID."),
2573
+ same_root: field("boolean", "Whether both snapshots were captured for the same root."),
2574
+ same_machine: field("boolean", "Whether hostname, platform, and architecture match."),
2575
+ same_runtime: field("boolean", "Whether Bun and Node versions match."),
2576
+ same_git_commit: field("boolean", "Whether git commit IDs match."),
2577
+ dirty_state_changed: field("boolean", "Whether the git dirty flag changed."),
2578
+ changed_config_hashes: field("array", "Changed config hash records."),
2579
+ changed_lockfiles: field("array", "Changed lockfile hash records."),
2580
+ changed_manifests: field("array", "Changed manifest hash records."),
2581
+ warnings: field("array", "Comparison warnings.")
2582
+ },
2583
+ optional: {}
2584
+ }),
2541
2585
  contract({
2542
2586
  id: "local_event_hook",
2543
2587
  name: "Local Event Hook",
@@ -7393,6 +7437,8 @@ var MCP_TOOL_GROUPS = {
7393
7437
  "check_file_lock",
7394
7438
  "create_comment",
7395
7439
  "create_handoff",
7440
+ "capture_environment_snapshot",
7441
+ "compare_environment_snapshots",
7396
7442
  "create_inbox_item",
7397
7443
  "delete_comment",
7398
7444
  "detect_file_relationships",
@@ -7515,10 +7561,12 @@ var MCP_TOOL_GROUPS = {
7515
7561
  "export_template",
7516
7562
  "import_template",
7517
7563
  "init_templates",
7564
+ "list_template_library",
7518
7565
  "list_templates",
7519
7566
  "preview_template",
7520
7567
  "template_history",
7521
- "update_template"
7568
+ "update_template",
7569
+ "write_template_library"
7522
7570
  ],
7523
7571
  webhooks: ["create_webhook", "delete_webhook", "list_webhooks"],
7524
7572
  machines: [
@@ -8033,6 +8081,39 @@ var TODOS_CLI_MCP_PARITY = [
8033
8081
  mcpTool: "create_plan"
8034
8082
  }
8035
8083
  },
8084
+ {
8085
+ domain: "templates",
8086
+ cliCommands: [
8087
+ "todos template-library",
8088
+ "todos template-init",
8089
+ "todos template-preview",
8090
+ "todos templates --use",
8091
+ "todos template-export",
8092
+ "todos template-import",
8093
+ "todos template-history"
8094
+ ],
8095
+ mcpTools: [
8096
+ "list_template_library",
8097
+ "write_template_library",
8098
+ "init_templates",
8099
+ "preview_template",
8100
+ "create_task_from_template",
8101
+ "create_template",
8102
+ "list_templates",
8103
+ "update_template",
8104
+ "delete_template",
8105
+ "export_template",
8106
+ "import_template",
8107
+ "template_history"
8108
+ ],
8109
+ jsonContracts: ["template", "task", "structured_error", "api_error"],
8110
+ errorContracts: ["structured_error", "api_error"],
8111
+ status: "matched",
8112
+ example: {
8113
+ cli: "todos template-library --json",
8114
+ mcpTool: "list_template_library"
8115
+ }
8116
+ },
8036
8117
  {
8037
8118
  domain: "workspace-trust",
8038
8119
  cliCommands: [
@@ -8332,6 +8413,18 @@ var TODOS_CLI_MCP_PARITY = [
8332
8413
  mcpTool: "build_agent_context_pack"
8333
8414
  }
8334
8415
  },
8416
+ {
8417
+ domain: "environment-snapshots",
8418
+ cliCommands: ["todos env-snapshot"],
8419
+ mcpTools: ["capture_environment_snapshot", "compare_environment_snapshots"],
8420
+ jsonContracts: ["environment_snapshot", "environment_snapshot_comparison", "structured_error", "api_error"],
8421
+ errorContracts: ["structured_error", "api_error"],
8422
+ status: "matched",
8423
+ example: {
8424
+ cli: "todos env-snapshot capture --task 1234abcd --json",
8425
+ mcpTool: "capture_environment_snapshot"
8426
+ }
8427
+ },
8335
8428
  {
8336
8429
  domain: "imports",
8337
8430
  cliCommands: [
@@ -10381,10 +10474,141 @@ function clearActiveModel() {
10381
10474
  }
10382
10475
  // src/db/builtin-templates.ts
10383
10476
  init_database();
10477
+ import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync4 } from "fs";
10478
+ import { join as join7 } from "path";
10479
+ var BUILTIN_TEMPLATE_LIBRARY_VERSION = "2026-05-21";
10480
+ var BUILTIN_TEMPLATE_LIBRARY_SOURCE = "bundled-local-template-library";
10384
10481
  var BUILTIN_TEMPLATES = [
10482
+ {
10483
+ name: "bug-fix",
10484
+ description: "Reproduce, diagnose, fix, test, and release a defect.",
10485
+ category: "bug-fix",
10486
+ version: BUILTIN_TEMPLATE_LIBRARY_VERSION,
10487
+ variables: [{ name: "bug", required: true, description: "Bug description" }],
10488
+ tasks: [
10489
+ { position: 0, title_pattern: "Reproduce: {bug}", priority: "critical", tags: ["bug", "repro"] },
10490
+ { position: 1, title_pattern: "Diagnose root cause of {bug}", priority: "critical", tags: ["bug", "diagnosis"], depends_on_positions: [0] },
10491
+ { position: 2, title_pattern: "Write regression test for {bug}", priority: "high", tags: ["bug", "test"], depends_on_positions: [1] },
10492
+ { position: 3, title_pattern: "Implement fix for {bug}", priority: "critical", tags: ["bug", "implementation"], depends_on_positions: [2] },
10493
+ { position: 4, title_pattern: "Run full verification for {bug}", priority: "high", tags: ["bug", "verification"], depends_on_positions: [3] },
10494
+ { position: 5, title_pattern: "Publish and smoke test fix for {bug}", priority: "high", tags: ["bug", "release"], depends_on_positions: [4] }
10495
+ ]
10496
+ },
10497
+ {
10498
+ name: "feature-implementation",
10499
+ description: "Plan, build, test, document, and release a product feature.",
10500
+ category: "feature",
10501
+ version: BUILTIN_TEMPLATE_LIBRARY_VERSION,
10502
+ variables: [
10503
+ { name: "feature", required: true, description: "Feature name" },
10504
+ { name: "scope", required: false, default: "medium", description: "Implementation size or risk" }
10505
+ ],
10506
+ tasks: [
10507
+ { position: 0, title_pattern: "Define acceptance criteria for {feature}", priority: "high", tags: ["feature", "spec"] },
10508
+ { position: 1, title_pattern: "Design {scope} implementation plan for {feature}", priority: "high", tags: ["feature", "design"], depends_on_positions: [0] },
10509
+ { position: 2, title_pattern: "Implement {feature}", priority: "critical", tags: ["feature", "implementation"], depends_on_positions: [1] },
10510
+ { position: 3, title_pattern: "Add tests for {feature}", priority: "high", tags: ["feature", "test"], depends_on_positions: [2] },
10511
+ { position: 4, title_pattern: "Update docs for {feature}", priority: "medium", tags: ["feature", "docs"], depends_on_positions: [2] },
10512
+ { position: 5, title_pattern: "Run release checks for {feature}", priority: "high", tags: ["feature", "verification"], depends_on_positions: [3, 4] }
10513
+ ]
10514
+ },
10515
+ {
10516
+ name: "security-review",
10517
+ description: "Threat model, test, remediate, and report on security posture.",
10518
+ category: "security",
10519
+ version: BUILTIN_TEMPLATE_LIBRARY_VERSION,
10520
+ variables: [{ name: "target", required: true, description: "System, package, or change under review" }],
10521
+ tasks: [
10522
+ { position: 0, title_pattern: "Map trust boundaries for {target}", priority: "critical", tags: ["security", "threat-model"] },
10523
+ { position: 1, title_pattern: "Scan {target} for vulnerabilities and secret exposure", priority: "critical", tags: ["security", "scan"], depends_on_positions: [0] },
10524
+ { position: 2, title_pattern: "Review authz, data access, and dependency risks in {target}", priority: "critical", tags: ["security", "review"], depends_on_positions: [0] },
10525
+ { position: 3, title_pattern: "Fix critical security findings in {target}", priority: "critical", tags: ["security", "fix"], depends_on_positions: [1, 2] },
10526
+ { position: 4, title_pattern: "Retest {target} security fixes", priority: "high", tags: ["security", "verification"], depends_on_positions: [3] },
10527
+ { position: 5, title_pattern: "Write local security review report for {target}", priority: "medium", tags: ["security", "report"], depends_on_positions: [4] }
10528
+ ]
10529
+ },
10530
+ {
10531
+ name: "release",
10532
+ description: "Prepare, verify, publish, install, and smoke test a package release.",
10533
+ category: "release",
10534
+ version: BUILTIN_TEMPLATE_LIBRARY_VERSION,
10535
+ variables: [
10536
+ { name: "package", required: true, description: "Package name" },
10537
+ { name: "version", required: false, default: "patch", description: "Release version or bump type" }
10538
+ ],
10539
+ tasks: [
10540
+ { position: 0, title_pattern: "Prepare {package} {version} release notes", priority: "medium", tags: ["release", "docs"] },
10541
+ { position: 1, title_pattern: "Run full tests for {package}", priority: "critical", tags: ["release", "test"] },
10542
+ { position: 2, title_pattern: "Run build and release verification for {package}", priority: "critical", tags: ["release", "verification"], depends_on_positions: [1] },
10543
+ { position: 3, title_pattern: "Scan {package} release diff for secrets", priority: "critical", tags: ["release", "security"], depends_on_positions: [2] },
10544
+ { position: 4, title_pattern: "Publish {package} {version}", priority: "high", tags: ["release", "publish"], depends_on_positions: [3] },
10545
+ { position: 5, title_pattern: "Install and smoke test published {package}", priority: "high", tags: ["release", "smoke"], depends_on_positions: [4] }
10546
+ ]
10547
+ },
10548
+ {
10549
+ name: "migration",
10550
+ description: "Plan, test, apply, and verify a schema or data migration.",
10551
+ category: "migration",
10552
+ version: BUILTIN_TEMPLATE_LIBRARY_VERSION,
10553
+ variables: [{ name: "migration", required: true, description: "Migration name or objective" }],
10554
+ tasks: [
10555
+ { position: 0, title_pattern: "Design migration plan for {migration}", priority: "critical", tags: ["migration", "plan"] },
10556
+ { position: 1, title_pattern: "Write rollback plan for {migration}", priority: "critical", tags: ["migration", "rollback"], depends_on_positions: [0] },
10557
+ { position: 2, title_pattern: "Implement migration {migration}", priority: "critical", tags: ["migration", "implementation"], depends_on_positions: [0] },
10558
+ { position: 3, title_pattern: "Test migration {migration} on fixture data", priority: "high", tags: ["migration", "test"], depends_on_positions: [2] },
10559
+ { position: 4, title_pattern: "Run migration {migration} verification and drift checks", priority: "high", tags: ["migration", "verification"], depends_on_positions: [1, 3] },
10560
+ { position: 5, title_pattern: "Document migration {migration} evidence", priority: "medium", tags: ["migration", "docs"], depends_on_positions: [4] }
10561
+ ]
10562
+ },
10563
+ {
10564
+ name: "incident",
10565
+ description: "Triage, mitigate, repair, verify, and retrospect an incident.",
10566
+ category: "incident",
10567
+ version: BUILTIN_TEMPLATE_LIBRARY_VERSION,
10568
+ variables: [{ name: "incident", required: true, description: "Incident summary" }],
10569
+ tasks: [
10570
+ { position: 0, title_pattern: "Triage incident: {incident}", priority: "critical", tags: ["incident", "triage"] },
10571
+ { position: 1, title_pattern: "Mitigate customer impact for {incident}", priority: "critical", tags: ["incident", "mitigation"], depends_on_positions: [0] },
10572
+ { position: 2, title_pattern: "Diagnose root cause for {incident}", priority: "critical", tags: ["incident", "diagnosis"], depends_on_positions: [0] },
10573
+ { position: 3, title_pattern: "Implement durable repair for {incident}", priority: "critical", tags: ["incident", "repair"], depends_on_positions: [2] },
10574
+ { position: 4, title_pattern: "Verify recovery from {incident}", priority: "high", tags: ["incident", "verification"], depends_on_positions: [1, 3] },
10575
+ { position: 5, title_pattern: "Write retrospective for {incident}", priority: "medium", tags: ["incident", "retro"], depends_on_positions: [4] }
10576
+ ]
10577
+ },
10578
+ {
10579
+ name: "docs-refresh",
10580
+ description: "Audit, update, validate, and publish documentation changes.",
10581
+ category: "docs",
10582
+ version: BUILTIN_TEMPLATE_LIBRARY_VERSION,
10583
+ variables: [{ name: "area", required: true, description: "Documentation area or product surface" }],
10584
+ tasks: [
10585
+ { position: 0, title_pattern: "Audit current docs for {area}", priority: "medium", tags: ["docs", "audit"] },
10586
+ { position: 1, title_pattern: "Update examples and commands for {area}", priority: "medium", tags: ["docs", "examples"], depends_on_positions: [0] },
10587
+ { position: 2, title_pattern: "Validate docs snippets for {area}", priority: "high", tags: ["docs", "verification"], depends_on_positions: [1] },
10588
+ { position: 3, title_pattern: "Refresh screenshots or generated artifacts for {area}", priority: "medium", tags: ["docs", "assets"], depends_on_positions: [1] },
10589
+ { position: 4, title_pattern: "Publish docs refresh for {area}", priority: "medium", tags: ["docs", "release"], depends_on_positions: [2, 3] }
10590
+ ]
10591
+ },
10592
+ {
10593
+ name: "qa",
10594
+ description: "Build a focused QA plan, execute checks, file defects, and sign off.",
10595
+ category: "qa",
10596
+ version: BUILTIN_TEMPLATE_LIBRARY_VERSION,
10597
+ variables: [{ name: "target", required: true, description: "Feature, release, or workflow under QA" }],
10598
+ tasks: [
10599
+ { position: 0, title_pattern: "Create QA matrix for {target}", priority: "high", tags: ["qa", "plan"] },
10600
+ { position: 1, title_pattern: "Run happy-path QA for {target}", priority: "high", tags: ["qa", "manual"], depends_on_positions: [0] },
10601
+ { position: 2, title_pattern: "Run edge-case QA for {target}", priority: "high", tags: ["qa", "edge-cases"], depends_on_positions: [0] },
10602
+ { position: 3, title_pattern: "File and dedupe QA defects for {target}", priority: "medium", tags: ["qa", "bugs"], depends_on_positions: [1, 2] },
10603
+ { position: 4, title_pattern: "Verify QA fixes for {target}", priority: "high", tags: ["qa", "verification"], depends_on_positions: [3] },
10604
+ { position: 5, title_pattern: "Record QA signoff for {target}", priority: "medium", tags: ["qa", "signoff"], depends_on_positions: [4] }
10605
+ ]
10606
+ },
10385
10607
  {
10386
10608
  name: "open-source-project",
10387
10609
  description: "Full open-source project bootstrap \u2014 scaffold to publish",
10610
+ category: "open-source",
10611
+ version: BUILTIN_TEMPLATE_LIBRARY_VERSION,
10388
10612
  variables: [
10389
10613
  { name: "name", required: true, description: "Service name" },
10390
10614
  { name: "org", required: false, default: "hasna", description: "GitHub org" }
@@ -10404,47 +10628,73 @@ var BUILTIN_TEMPLATES = [
10404
10628
  { position: 11, title_pattern: "Publish @hasna/{name} to npm", priority: "high", depends_on_positions: [6, 7, 8] },
10405
10629
  { position: 12, title_pattern: "Install @hasna/{name} globally and verify", priority: "medium", depends_on_positions: [11] }
10406
10630
  ]
10407
- },
10408
- {
10409
- name: "bug-fix",
10410
- description: "Standard bug fix workflow",
10411
- variables: [{ name: "bug", required: true, description: "Bug description" }],
10412
- tasks: [
10413
- { position: 0, title_pattern: "Reproduce: {bug}", priority: "critical" },
10414
- { position: 1, title_pattern: "Diagnose root cause of {bug}", priority: "critical", depends_on_positions: [0] },
10415
- { position: 2, title_pattern: "Implement fix for {bug}", priority: "critical", depends_on_positions: [1] },
10416
- { position: 3, title_pattern: "Write regression test for {bug}", priority: "high", depends_on_positions: [2] },
10417
- { position: 4, title_pattern: "Publish fix and verify in production", priority: "high", depends_on_positions: [3] }
10418
- ]
10419
- },
10420
- {
10421
- name: "feature",
10422
- description: "Standard feature development workflow",
10423
- variables: [{ name: "feature", required: true }, { name: "scope", required: false, default: "medium" }],
10424
- tasks: [
10425
- { position: 0, title_pattern: "Write spec for {feature}", priority: "high" },
10426
- { position: 1, title_pattern: "Design implementation approach for {feature}", priority: "high", depends_on_positions: [0] },
10427
- { position: 2, title_pattern: "Implement {feature}", priority: "critical", depends_on_positions: [1] },
10428
- { position: 3, title_pattern: "Write tests for {feature}", priority: "high", depends_on_positions: [2] },
10429
- { position: 4, title_pattern: "Code review for {feature}", priority: "medium", depends_on_positions: [3] },
10430
- { position: 5, title_pattern: "Update docs for {feature}", priority: "medium", depends_on_positions: [2] },
10431
- { position: 6, title_pattern: "Deploy {feature}", priority: "high", depends_on_positions: [4] }
10432
- ]
10433
- },
10434
- {
10435
- name: "security-audit",
10436
- description: "Security audit workflow",
10437
- variables: [{ name: "target", required: true }],
10438
- tasks: [
10439
- { position: 0, title_pattern: "Scan {target} for vulnerabilities", priority: "critical" },
10440
- { position: 1, title_pattern: "Review {target} security findings", priority: "critical", depends_on_positions: [0] },
10441
- { position: 2, title_pattern: "Fix critical issues in {target}", priority: "critical", depends_on_positions: [1] },
10442
- { position: 3, title_pattern: "Retest {target} after fixes", priority: "high", depends_on_positions: [2] },
10443
- { position: 4, title_pattern: "Write security report for {target}", priority: "medium", depends_on_positions: [3] },
10444
- { position: 5, title_pattern: "Close audit for {target}", priority: "low", depends_on_positions: [4] }
10445
- ]
10446
10631
  }
10447
10632
  ];
10633
+ function templateMetadata(template) {
10634
+ return {
10635
+ source: BUILTIN_TEMPLATE_LIBRARY_SOURCE,
10636
+ library_version: template.version,
10637
+ category: template.category,
10638
+ template_file: `${template.name}.json`,
10639
+ local_only: true,
10640
+ marketplace_free: true
10641
+ };
10642
+ }
10643
+ function listBuiltinTemplates() {
10644
+ return BUILTIN_TEMPLATES.map((template) => ({
10645
+ ...template,
10646
+ variables: template.variables.map((variable) => ({ ...variable })),
10647
+ tasks: template.tasks.map((task) => ({ ...task, tags: task.tags ? [...task.tags] : undefined }))
10648
+ }));
10649
+ }
10650
+ function getBuiltinTemplate(name) {
10651
+ return listBuiltinTemplates().find((template) => template.name === name) ?? null;
10652
+ }
10653
+ function exportBuiltinTemplate(name) {
10654
+ const template = getBuiltinTemplate(name);
10655
+ if (!template)
10656
+ throw new Error(`Built-in template not found: ${name}`);
10657
+ return {
10658
+ name: template.name,
10659
+ title_pattern: `${template.name}: {${template.variables[0]?.name ?? "name"}}`,
10660
+ description: template.description,
10661
+ priority: "medium",
10662
+ tags: [template.category, "local-template"],
10663
+ variables: template.variables,
10664
+ project_id: null,
10665
+ plan_id: null,
10666
+ metadata: templateMetadata(template),
10667
+ tasks: template.tasks.map((task) => ({
10668
+ position: task.position,
10669
+ title_pattern: task.title_pattern,
10670
+ description: task.description ?? null,
10671
+ priority: task.priority ?? "medium",
10672
+ tags: task.tags ?? [template.category],
10673
+ task_type: task.task_type ?? null,
10674
+ condition: task.condition ?? null,
10675
+ include_template_id: task.include_template_id ?? null,
10676
+ depends_on_positions: task.depends_on_positions ?? task.depends_on ?? [],
10677
+ metadata: task.metadata ?? { category: template.category }
10678
+ }))
10679
+ };
10680
+ }
10681
+ function exportBuiltinTemplateFiles() {
10682
+ return BUILTIN_TEMPLATES.map((template) => ({
10683
+ filename: `${template.name}.json`,
10684
+ template: exportBuiltinTemplate(template.name)
10685
+ }));
10686
+ }
10687
+ function writeBuiltinTemplateFiles(directory) {
10688
+ mkdirSync6(directory, { recursive: true });
10689
+ const files = [];
10690
+ for (const entry of exportBuiltinTemplateFiles()) {
10691
+ const path = join7(directory, entry.filename);
10692
+ writeFileSync4(path, `${JSON.stringify(entry.template, null, 2)}
10693
+ `, "utf-8");
10694
+ files.push(path);
10695
+ }
10696
+ return { directory, written: files.length, files };
10697
+ }
10448
10698
  function initBuiltinTemplates(db) {
10449
10699
  const d = db || getDatabase();
10450
10700
  const existing = listTemplates(d);
@@ -10470,7 +10720,9 @@ function initBuiltinTemplates(db) {
10470
10720
  name: bt.name,
10471
10721
  title_pattern: `${bt.name}: {${bt.variables[0]?.name || "name"}}`,
10472
10722
  description: bt.description,
10723
+ tags: [bt.category, "local-template"],
10473
10724
  variables: bt.variables,
10725
+ metadata: templateMetadata(bt),
10474
10726
  tasks
10475
10727
  }, d);
10476
10728
  created++;
@@ -11859,16 +12111,16 @@ function runSearchView(idOrName, db) {
11859
12111
  return { ...runSavedSearch(view.filters, view.scope, d), view };
11860
12112
  }
11861
12113
  // src/lib/claude-tasks.ts
11862
- import { existsSync as existsSync8, readFileSync as readFileSync6, readdirSync as readdirSync2, writeFileSync as writeFileSync4 } from "fs";
11863
- import { join as join7 } from "path";
12114
+ import { existsSync as existsSync8, readFileSync as readFileSync6, readdirSync as readdirSync2, writeFileSync as writeFileSync5 } from "fs";
12115
+ import { join as join8 } from "path";
11864
12116
  function getTaskListDir(taskListId) {
11865
- return join7(HOME, ".claude", "tasks", taskListId);
12117
+ return join8(HOME, ".claude", "tasks", taskListId);
11866
12118
  }
11867
12119
  function readClaudeTask(dir, filename) {
11868
- return readJsonFile(join7(dir, filename));
12120
+ return readJsonFile(join8(dir, filename));
11869
12121
  }
11870
12122
  function writeClaudeTask(dir, task) {
11871
- writeJsonFile(join7(dir, `${task.id}.json`), task);
12123
+ writeJsonFile(join8(dir, `${task.id}.json`), task);
11872
12124
  }
11873
12125
  function toClaudeStatus(status) {
11874
12126
  if (status === "pending" || status === "in_progress" || status === "completed") {
@@ -11880,14 +12132,14 @@ function toSqliteStatus(status) {
11880
12132
  return status;
11881
12133
  }
11882
12134
  function readPrefixCounter(dir) {
11883
- const path = join7(dir, ".prefix-counter");
12135
+ const path = join8(dir, ".prefix-counter");
11884
12136
  if (!existsSync8(path))
11885
12137
  return 0;
11886
12138
  const val = parseInt(readFileSync6(path, "utf-8").trim(), 10);
11887
12139
  return isNaN(val) ? 0 : val;
11888
12140
  }
11889
12141
  function writePrefixCounter(dir, value) {
11890
- writeFileSync4(join7(dir, ".prefix-counter"), String(value));
12142
+ writeFileSync5(join8(dir, ".prefix-counter"), String(value));
11891
12143
  }
11892
12144
  function formatPrefixedSubject(title, prefix, counter) {
11893
12145
  const padded = String(counter).padStart(5, "0");
@@ -11923,7 +12175,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
11923
12175
  const existingByTodosId = new Map;
11924
12176
  const files = listJsonFiles(dir);
11925
12177
  for (const f of files) {
11926
- const path = join7(dir, f);
12178
+ const path = join8(dir, f);
11927
12179
  const ct = readClaudeTask(dir, f);
11928
12180
  if (ct?.metadata?.["todos_id"]) {
11929
12181
  existingByTodosId.set(ct.metadata["todos_id"], { task: ct, mtimeMs: getFileMtimeMs(path) });
@@ -12030,7 +12282,7 @@ function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
12030
12282
  }
12031
12283
  for (const f of files) {
12032
12284
  try {
12033
- const filePath = join7(dir, f);
12285
+ const filePath = join8(dir, f);
12034
12286
  const ct = readClaudeTask(dir, f);
12035
12287
  if (!ct)
12036
12288
  continue;
@@ -12099,26 +12351,26 @@ function syncClaudeTaskList(taskListId, projectId, options = {}) {
12099
12351
 
12100
12352
  // src/lib/agent-tasks.ts
12101
12353
  import { existsSync as existsSync9 } from "fs";
12102
- import { join as join8 } from "path";
12354
+ import { join as join9 } from "path";
12103
12355
  function getTodosGlobalDir3() {
12104
- const newDir = join8(HOME, ".hasna", "todos");
12105
- const legacyDir = join8(HOME, ".todos");
12356
+ const newDir = join9(HOME, ".hasna", "todos");
12357
+ const legacyDir = join9(HOME, ".todos");
12106
12358
  if (!existsSync9(newDir) && existsSync9(legacyDir))
12107
12359
  return legacyDir;
12108
12360
  return newDir;
12109
12361
  }
12110
12362
  function agentBaseDir(agent) {
12111
12363
  const key = `TODOS_${agent.toUpperCase()}_TASKS_DIR`;
12112
- return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join8(getTodosGlobalDir3(), "agents");
12364
+ return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join9(getTodosGlobalDir3(), "agents");
12113
12365
  }
12114
12366
  function getTaskListDir2(agent, taskListId) {
12115
- return join8(agentBaseDir(agent), agent, taskListId);
12367
+ return join9(agentBaseDir(agent), agent, taskListId);
12116
12368
  }
12117
12369
  function readAgentTask(dir, filename) {
12118
- return readJsonFile(join8(dir, filename));
12370
+ return readJsonFile(join9(dir, filename));
12119
12371
  }
12120
12372
  function writeAgentTask(dir, task) {
12121
- writeJsonFile(join8(dir, `${task.id}.json`), task);
12373
+ writeJsonFile(join9(dir, `${task.id}.json`), task);
12122
12374
  }
12123
12375
  function taskToAgentTask(task, externalId, existingMeta) {
12124
12376
  return {
@@ -12152,7 +12404,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
12152
12404
  const existingByTodosId = new Map;
12153
12405
  const files = listJsonFiles(dir);
12154
12406
  for (const f of files) {
12155
- const path = join8(dir, f);
12407
+ const path = join9(dir, f);
12156
12408
  const at = readAgentTask(dir, f);
12157
12409
  if (at?.metadata?.["todos_id"]) {
12158
12410
  existingByTodosId.set(at.metadata["todos_id"], { task: at, mtimeMs: getFileMtimeMs(path) });
@@ -12245,7 +12497,7 @@ function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
12245
12497
  }
12246
12498
  for (const f of files) {
12247
12499
  try {
12248
- const filePath = join8(dir, f);
12500
+ const filePath = join9(dir, f);
12249
12501
  const at = readAgentTask(dir, f);
12250
12502
  if (!at)
12251
12503
  continue;
@@ -12383,7 +12635,7 @@ function syncWithAgents(agents, taskListIdByAgent, projectId, direction = "both"
12383
12635
  }
12384
12636
  // src/lib/extract.ts
12385
12637
  import { readFileSync as readFileSync7, statSync as statSync4 } from "fs";
12386
- import { relative as relative3, resolve as resolve7, join as join9 } from "path";
12638
+ import { relative as relative3, resolve as resolve7, join as join10 } from "path";
12387
12639
  var EXTRACT_TAGS = ["TODO", "FIXME", "HACK", "XXX", "BUG", "NOTE"];
12388
12640
  var DEFAULT_EXTENSIONS = new Set([
12389
12641
  ".ts",
@@ -12517,7 +12769,7 @@ function extractTodos(options, db) {
12517
12769
  const files = collectFiles(basePath, extensions);
12518
12770
  const allComments = [];
12519
12771
  for (const file of files) {
12520
- const fullPath = statSync4(basePath).isFile() ? basePath : join9(basePath, file);
12772
+ const fullPath = statSync4(basePath).isFile() ? basePath : join10(basePath, file);
12521
12773
  try {
12522
12774
  const source7 = readFileSync7(fullPath, "utf-8");
12523
12775
  const relPath = statSync4(basePath).isFile() ? relative3(resolve7(basePath, ".."), fullPath) : file;
@@ -15720,8 +15972,8 @@ function getLocalActivityTimeline(options = {}, db) {
15720
15972
  init_database();
15721
15973
  init_migrations();
15722
15974
  init_schema();
15723
- import { chmodSync, copyFileSync, existsSync as existsSync11, mkdirSync as mkdirSync6, statSync as statSync5 } from "fs";
15724
- import { basename as basename2, dirname as dirname7, join as join10 } from "path";
15975
+ import { chmodSync, copyFileSync, existsSync as existsSync11, mkdirSync as mkdirSync7, statSync as statSync5 } from "fs";
15976
+ import { basename as basename2, dirname as dirname7, join as join11 } from "path";
15725
15977
  var REQUIRED_TABLES = [
15726
15978
  "_migrations",
15727
15979
  "projects",
@@ -15891,13 +16143,13 @@ function createBackup(dbPath) {
15891
16143
  if (!existsSync11(dbPath))
15892
16144
  return;
15893
16145
  const stamp = now().replace(/[:.]/g, "-");
15894
- const backupDir = join10(dirname7(dbPath), `${basename2(dbPath)}.backup-${stamp}`);
16146
+ const backupDir = join11(dirname7(dbPath), `${basename2(dbPath)}.backup-${stamp}`);
15895
16147
  const files = [];
15896
- mkdirSync6(backupDir, { recursive: true });
16148
+ mkdirSync7(backupDir, { recursive: true });
15897
16149
  for (const source7 of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
15898
16150
  if (!existsSync11(source7))
15899
16151
  continue;
15900
- const target = join10(backupDir, basename2(source7));
16152
+ const target = join11(backupDir, basename2(source7));
15901
16153
  copyFileSync(source7, target);
15902
16154
  files.push(target);
15903
16155
  }
@@ -16101,6 +16353,278 @@ function runTodosDoctor(options = {}) {
16101
16353
  summary
16102
16354
  };
16103
16355
  }
16356
+ // src/lib/environment-snapshots.ts
16357
+ import { createHash as createHash6 } from "crypto";
16358
+ import { existsSync as existsSync12, readFileSync as readFileSync9, statSync as statSync6 } from "fs";
16359
+ import { hostname, platform, arch } from "os";
16360
+ import { dirname as dirname8, join as join12, resolve as resolve9 } from "path";
16361
+ import { tmpdir as tmpdir2 } from "os";
16362
+ init_database();
16363
+ var MANIFEST_FILES = ["package.json", "dashboard/package.json", "sdk/package.json"];
16364
+ var LOCKFILES = ["bun.lock", "bun.lockb", "package-lock.json", "npm-shrinkwrap.json"];
16365
+ var CONFIG_FILES = [
16366
+ "AGENTS.md",
16367
+ "CLAUDE.md",
16368
+ "README.md",
16369
+ "SECURITY.md",
16370
+ "bunfig.toml",
16371
+ "tsconfig.json",
16372
+ "components.json",
16373
+ "next.config.js",
16374
+ "next.config.mjs",
16375
+ "next.config.ts",
16376
+ "vite.config.ts",
16377
+ "dashboard/vite.config.ts"
16378
+ ];
16379
+ function sha2563(value) {
16380
+ return createHash6("sha256").update(value).digest("hex");
16381
+ }
16382
+ function fileRecord(root, relativePath) {
16383
+ const path = join12(root, relativePath);
16384
+ if (!existsSync12(path))
16385
+ return null;
16386
+ const stat = statSync6(path);
16387
+ if (!stat.isFile())
16388
+ return null;
16389
+ const content = readFileSync9(path);
16390
+ return { path: relativePath, sha256: sha2563(content), size_bytes: content.length };
16391
+ }
16392
+ function manifestRecord(root, relativePath) {
16393
+ const base = fileRecord(root, relativePath);
16394
+ if (!base)
16395
+ return null;
16396
+ const parsed = readJsonFile(join12(root, relativePath));
16397
+ if (!parsed)
16398
+ return { ...base, redacted: {} };
16399
+ const redacted = redactValue({
16400
+ name: parsed["name"] ?? null,
16401
+ version: parsed["version"] ?? null,
16402
+ packageManager: parsed["packageManager"] ?? null,
16403
+ scripts: parsed["scripts"] ?? {},
16404
+ dependencies: parsed["dependencies"] ?? {},
16405
+ devDependencies: parsed["devDependencies"] ?? {},
16406
+ peerDependencies: parsed["peerDependencies"] ?? {},
16407
+ optionalDependencies: parsed["optionalDependencies"] ?? {}
16408
+ });
16409
+ return { ...base, redacted };
16410
+ }
16411
+ function runLocalCommand(root, args) {
16412
+ const result = Bun.spawnSync({
16413
+ cmd: args,
16414
+ cwd: root,
16415
+ stdout: "pipe",
16416
+ stderr: "pipe",
16417
+ env: { PATH: process.env["PATH"] || "" }
16418
+ });
16419
+ return {
16420
+ exitCode: result.exitCode,
16421
+ stdout: redactEvidenceText(result.stdout.toString("utf8").trim()),
16422
+ stderr: redactEvidenceText(result.stderr.toString("utf8").trim())
16423
+ };
16424
+ }
16425
+ function summarizeGitStatus(lines) {
16426
+ const summary = { added: 0, modified: 0, deleted: 0, renamed: 0, untracked: 0 };
16427
+ for (const line of lines) {
16428
+ if (line.startsWith("??"))
16429
+ summary.untracked += 1;
16430
+ else if (line.includes("R"))
16431
+ summary.renamed += 1;
16432
+ else if (line.includes("D"))
16433
+ summary.deleted += 1;
16434
+ else if (line.includes("A"))
16435
+ summary.added += 1;
16436
+ else if (line.includes("M"))
16437
+ summary.modified += 1;
16438
+ }
16439
+ return summary;
16440
+ }
16441
+ function captureGit(root, warnings) {
16442
+ const inside = runLocalCommand(root, ["git", "rev-parse", "--is-inside-work-tree"]);
16443
+ if (inside.exitCode !== 0 || inside.stdout !== "true") {
16444
+ return { present: false, branch: null, commit: null, is_dirty: false, status_porcelain: [], status_summary: summarizeGitStatus([]) };
16445
+ }
16446
+ const branch = runLocalCommand(root, ["git", "branch", "--show-current"]);
16447
+ const commit = runLocalCommand(root, ["git", "rev-parse", "HEAD"]);
16448
+ const status = runLocalCommand(root, ["git", "status", "--porcelain=v1"]);
16449
+ if (commit.exitCode !== 0)
16450
+ warnings.push(`git commit unavailable: ${commit.stderr || commit.stdout || "unknown error"}`);
16451
+ if (status.exitCode !== 0)
16452
+ warnings.push(`git status unavailable: ${status.stderr || status.stdout || "unknown error"}`);
16453
+ const lines = status.stdout ? status.stdout.split(/\r?\n/).filter(Boolean) : [];
16454
+ return {
16455
+ present: true,
16456
+ branch: branch.stdout || null,
16457
+ commit: commit.stdout || null,
16458
+ is_dirty: lines.length > 0,
16459
+ status_porcelain: lines,
16460
+ status_summary: summarizeGitStatus(lines)
16461
+ };
16462
+ }
16463
+ function packageManager(env, lockfiles) {
16464
+ const userAgent = (env["npm_config_user_agent"] || "").toLowerCase();
16465
+ if (userAgent.includes("bun"))
16466
+ return "bun";
16467
+ if (lockfiles.some((file) => file.path.startsWith("bun.lock")))
16468
+ return "bun";
16469
+ if (userAgent.includes("npm") || lockfiles.some((file) => file.path.includes("package-lock")))
16470
+ return "npm";
16471
+ return "unknown";
16472
+ }
16473
+ function isSecretEnvKey(key) {
16474
+ return /api[_-]?key|token|secret|password|credential|private|session|cookie/i.test(key);
16475
+ }
16476
+ function commandEnv(env, includeValues) {
16477
+ const keys = Object.keys(env).sort();
16478
+ const interesting = keys.filter((key) => isSecretEnvKey(key) || ["CI", "NODE_ENV", "BUN_ENV", "SHELL", "TERM", "PATH", "PWD", "USER", "npm_config_user_agent"].includes(key) || key.startsWith("TODOS_") || key.startsWith("BUN_"));
16479
+ const redactedKeys = interesting.filter(isSecretEnvKey);
16480
+ const values = includeValues ? Object.fromEntries(interesting.map((key) => [key, isSecretEnvKey(key) ? "[REDACTED]" : redactEvidenceText(String(env[key] ?? ""))])) : null;
16481
+ return {
16482
+ command: null,
16483
+ env_keys: interesting,
16484
+ env: values,
16485
+ redacted_keys: redactedKeys
16486
+ };
16487
+ }
16488
+ function defaultSnapshotDir() {
16489
+ const dbPath = getDatabasePath();
16490
+ if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
16491
+ return join12(tmpdir2(), "hasna-todos", "environment-snapshots");
16492
+ return join12(dirname8(resolve9(dbPath)), "environment-snapshots");
16493
+ }
16494
+ function snapshotWithId(snapshot) {
16495
+ const digest = sha2563(JSON.stringify(snapshot)).slice(0, 24);
16496
+ return { id: `env_${digest}`, ...snapshot };
16497
+ }
16498
+ function captureEnvironmentSnapshot(input = {}) {
16499
+ const root = resolve9(input.root || process.cwd());
16500
+ const env = input.env || process.env;
16501
+ const warnings = [];
16502
+ const manifests = MANIFEST_FILES.map((file) => manifestRecord(root, file)).filter((file) => Boolean(file));
16503
+ const lockfiles = LOCKFILES.map((file) => fileRecord(root, file)).filter((file) => Boolean(file));
16504
+ const configHashes = CONFIG_FILES.map((file) => fileRecord(root, file)).filter((file) => Boolean(file));
16505
+ const commandMetadata = commandEnv(env, Boolean(input.include_env_values));
16506
+ commandMetadata.command = input.command ? redactEvidenceText(input.command) : null;
16507
+ if (manifests.length === 0)
16508
+ warnings.push("no package manifest found");
16509
+ if (lockfiles.length === 0)
16510
+ warnings.push("no package lockfile found");
16511
+ return snapshotWithId({
16512
+ schema_version: 1,
16513
+ captured_at: input.now ? new Date(input.now).toISOString() : new Date().toISOString(),
16514
+ root,
16515
+ machine: { hostname: hostname(), platform: platform(), arch: arch() },
16516
+ target: {
16517
+ task_id: input.task_id ?? null,
16518
+ run_id: input.run_id ?? null,
16519
+ agent_id: input.agent_id ?? null
16520
+ },
16521
+ runtime: {
16522
+ bun: Bun.version || null,
16523
+ node: process.version,
16524
+ executable: process.execPath
16525
+ },
16526
+ package_manager: {
16527
+ manager: packageManager(env, lockfiles),
16528
+ user_agent: env["npm_config_user_agent"] ? redactEvidenceText(env["npm_config_user_agent"]) : null,
16529
+ manifests,
16530
+ lockfiles
16531
+ },
16532
+ git: captureGit(root, warnings),
16533
+ config_hashes: configHashes,
16534
+ command_env: commandMetadata,
16535
+ warnings
16536
+ });
16537
+ }
16538
+ function writeEnvironmentSnapshot(snapshot, outputPath) {
16539
+ const path = outputPath ? resolve9(outputPath) : join12(defaultSnapshotDir(), `${snapshot.id}.json`);
16540
+ ensureDir2(dirname8(path));
16541
+ writeJsonFile(path, snapshot);
16542
+ return path;
16543
+ }
16544
+ function readEnvironmentSnapshot(path) {
16545
+ const snapshot = readJsonFile(resolve9(path));
16546
+ if (!snapshot || snapshot.schema_version !== 1 || typeof snapshot.id !== "string") {
16547
+ throw new Error(`Invalid environment snapshot: ${path}`);
16548
+ }
16549
+ return snapshot;
16550
+ }
16551
+ function recordEnvironmentSnapshot(input = {}, db) {
16552
+ let taskId = input.task_id;
16553
+ let runId = input.run_id;
16554
+ const needsDatabase = Boolean(taskId || runId);
16555
+ const d = needsDatabase ? db || getDatabase() : null;
16556
+ if (runId) {
16557
+ runId = resolveTaskRunId(runId, d);
16558
+ const run = getTaskRun(runId, d);
16559
+ if (!run)
16560
+ throw new Error(`Run not found: ${input.run_id}`);
16561
+ taskId = taskId || run.task_id;
16562
+ }
16563
+ if (taskId && d) {
16564
+ taskId = resolvePartialId(d, "tasks", taskId) || taskId;
16565
+ if (!getTask(taskId, d))
16566
+ throw new Error(`Task not found: ${taskId}`);
16567
+ }
16568
+ const snapshot = captureEnvironmentSnapshot({ ...input, task_id: taskId, run_id: runId });
16569
+ const outputPath = writeEnvironmentSnapshot(snapshot, input.output_path);
16570
+ let taskVerificationId = null;
16571
+ let runArtifactId = null;
16572
+ if (runId) {
16573
+ const artifact = addTaskRunArtifact({
16574
+ run_id: runId,
16575
+ path: outputPath,
16576
+ artifact_type: "environment_snapshot",
16577
+ description: "Reproducible local environment snapshot",
16578
+ metadata: { environment_snapshot_id: snapshot.id, schema_version: snapshot.schema_version },
16579
+ store_content: input.store_content ?? true,
16580
+ agent_id: input.agent_id
16581
+ }, d);
16582
+ runArtifactId = artifact.id;
16583
+ } else if (taskId) {
16584
+ const verification = addTaskVerification({
16585
+ task_id: taskId,
16586
+ command: input.command || "capture environment snapshot",
16587
+ status: "unknown",
16588
+ output_summary: `environment snapshot ${snapshot.id}`,
16589
+ artifact_path: outputPath,
16590
+ agent_id: input.agent_id,
16591
+ run_at: snapshot.captured_at
16592
+ }, d);
16593
+ taskVerificationId = verification.id;
16594
+ }
16595
+ return { snapshot, output_path: outputPath, task_verification_id: taskVerificationId, run_artifact_id: runArtifactId };
16596
+ }
16597
+ function keyed(files) {
16598
+ return new Map(files.map((file) => [file.path, file]));
16599
+ }
16600
+ function diffFiles(left, right) {
16601
+ const leftMap = keyed(left);
16602
+ const rightMap = keyed(right);
16603
+ const paths = [...new Set([...leftMap.keys(), ...rightMap.keys()])].sort((a, b) => a.localeCompare(b));
16604
+ return paths.map((path) => ({ path, left_sha256: leftMap.get(path)?.sha256 ?? null, right_sha256: rightMap.get(path)?.sha256 ?? null })).filter((entry) => entry.left_sha256 !== entry.right_sha256);
16605
+ }
16606
+ function compareEnvironmentSnapshots(left, right) {
16607
+ const warnings = [];
16608
+ if (left.schema_version !== right.schema_version)
16609
+ warnings.push("snapshot schema versions differ");
16610
+ return {
16611
+ schema_version: 1,
16612
+ left_id: left.id,
16613
+ right_id: right.id,
16614
+ same_root: left.root === right.root,
16615
+ same_machine: left.machine.hostname === right.machine.hostname && left.machine.platform === right.machine.platform && left.machine.arch === right.machine.arch,
16616
+ same_runtime: left.runtime.bun === right.runtime.bun && left.runtime.node === right.runtime.node,
16617
+ same_git_commit: left.git.commit === right.git.commit,
16618
+ dirty_state_changed: left.git.is_dirty !== right.git.is_dirty,
16619
+ changed_config_hashes: diffFiles(left.config_hashes, right.config_hashes),
16620
+ changed_lockfiles: diffFiles(left.package_manager.lockfiles, right.package_manager.lockfiles),
16621
+ changed_manifests: diffFiles(left.package_manager.manifests, right.package_manager.manifests),
16622
+ warnings
16623
+ };
16624
+ }
16625
+ function compareEnvironmentSnapshotFiles(leftPath, rightPath) {
16626
+ return compareEnvironmentSnapshots(readEnvironmentSnapshot(leftPath), readEnvironmentSnapshot(rightPath));
16627
+ }
16104
16628
  // src/lib/task-contracts.ts
16105
16629
  init_database();
16106
16630
  var CONTRACT_KEY = "_contract";
@@ -16315,6 +16839,8 @@ function checkTaskDoneContract(taskId, db) {
16315
16839
  };
16316
16840
  }
16317
16841
  export {
16842
+ writeEnvironmentSnapshot,
16843
+ writeBuiltinTemplateFiles,
16318
16844
  verifyTaskRunArtifacts,
16319
16845
  verifyStoredArtifact,
16320
16846
  verifyApiKey,
@@ -16413,6 +16939,8 @@ export {
16413
16939
  redistributeStaleTasks,
16414
16940
  redactEvidenceText,
16415
16941
  recordTaskReview,
16942
+ recordEnvironmentSnapshot,
16943
+ readEnvironmentSnapshot,
16416
16944
  queueAgentRun,
16417
16945
  queryTasksByLocalFields,
16418
16946
  previewTemplate,
@@ -16465,6 +16993,7 @@ export {
16465
16993
  listCyclesWithStats,
16466
16994
  listCycles,
16467
16995
  listComments,
16996
+ listBuiltinTemplates,
16468
16997
  listApprovalGates,
16469
16998
  listApiKeys,
16470
16999
  listAgents,
@@ -16559,6 +17088,7 @@ export {
16559
17088
  getChecklist,
16560
17089
  getCapableAgents,
16561
17090
  getBurndown,
17091
+ getBuiltinTemplate,
16562
17092
  getBudget,
16563
17093
  getBlockingDeps,
16564
17094
  getAgentMetrics,
@@ -16584,6 +17114,8 @@ export {
16584
17114
  exportTodosMarkdown,
16585
17115
  exportTemplate,
16586
17116
  exportStoredArtifactContent,
17117
+ exportBuiltinTemplateFiles,
17118
+ exportBuiltinTemplate,
16587
17119
  explainRunnerSandbox,
16588
17120
  explainPolicyPack,
16589
17121
  expireApprovalGate,
@@ -16649,6 +17181,8 @@ export {
16649
17181
  createAgentContextPack,
16650
17182
  countTasks,
16651
17183
  completeTask,
17184
+ compareEnvironmentSnapshots,
17185
+ compareEnvironmentSnapshotFiles,
16652
17186
  closeDatabase,
16653
17187
  cloneTask,
16654
17188
  clearChecklist,
@@ -16664,6 +17198,7 @@ export {
16664
17198
  checkChecklistItem,
16665
17199
  checkBudget,
16666
17200
  checkApprovalGate,
17201
+ captureEnvironmentSnapshot,
16667
17202
  cancelDispatch,
16668
17203
  cancelAgentRunDispatch,
16669
17204
  calculateDelay,
@@ -16736,6 +17271,8 @@ export {
16736
17271
  DEFAULT_ENCRYPTION_KEY_ENV,
16737
17272
  CompletionGuardError,
16738
17273
  CORE_MCP_TOOLS,
17274
+ BUILTIN_TEMPLATE_LIBRARY_VERSION,
17275
+ BUILTIN_TEMPLATE_LIBRARY_SOURCE,
16739
17276
  BUILTIN_TEMPLATES,
16740
17277
  AgentNotFoundError
16741
17278
  };