@hasna/todos 0.15.35 → 0.15.41

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.
Files changed (85) hide show
  1. package/dist/cli/cloud-router.d.ts +52 -18
  2. package/dist/cli/cloud-router.d.ts.map +1 -1
  3. package/dist/cli/commands/agent-commands.d.ts.map +1 -1
  4. package/dist/cli/commands/plan-template-commands.d.ts.map +1 -1
  5. package/dist/cli/commands/project-commands.d.ts.map +1 -1
  6. package/dist/cli/commands/task-commands.d.ts.map +1 -1
  7. package/dist/cli/commands/task-subtree-transfer-commands.d.ts +3 -0
  8. package/dist/cli/commands/task-subtree-transfer-commands.d.ts.map +1 -0
  9. package/dist/cli/index.js +3299 -796
  10. package/dist/cli/stage-a.d.ts.map +1 -1
  11. package/dist/contracts.js +62 -54
  12. package/dist/db/plan-comments.d.ts +14 -0
  13. package/dist/db/plan-comments.d.ts.map +1 -0
  14. package/dist/db/schema.d.ts.map +1 -1
  15. package/dist/db/task-crud.d.ts.map +1 -1
  16. package/dist/db/task-lifecycle.d.ts.map +1 -1
  17. package/dist/db/task-lists.d.ts.map +1 -1
  18. package/dist/db/task-relations.d.ts.map +1 -1
  19. package/dist/index.d.ts +3 -2
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +1787 -309
  22. package/dist/lib/comment-cursor.d.ts +19 -0
  23. package/dist/lib/comment-cursor.d.ts.map +1 -1
  24. package/dist/lib/import-export-bridge.d.ts.map +1 -1
  25. package/dist/mcp/index.js +2273 -471
  26. package/dist/mcp.js +8 -4
  27. package/dist/project-registration.js +207 -63
  28. package/dist/registry.d.ts +1 -1
  29. package/dist/registry.d.ts.map +1 -1
  30. package/dist/registry.js +69 -54
  31. package/dist/release-provenance.json +5 -5
  32. package/dist/sdk/index.d.ts +1 -1
  33. package/dist/sdk/index.d.ts.map +1 -1
  34. package/dist/sdk/index.js +35 -0
  35. package/dist/sdk/v1.generated.d.ts +141 -0
  36. package/dist/sdk/v1.generated.d.ts.map +1 -1
  37. package/dist/server/cloud.d.ts +12 -2
  38. package/dist/server/cloud.d.ts.map +1 -1
  39. package/dist/server/index.js +5171 -8535
  40. package/dist/server/openapi.d.ts +2714 -1937
  41. package/dist/server/openapi.d.ts.map +1 -1
  42. package/dist/server/v1.d.ts +2 -1
  43. package/dist/server/v1.d.ts.map +1 -1
  44. package/dist/storage/config.d.ts +12 -30
  45. package/dist/storage/config.d.ts.map +1 -1
  46. package/dist/storage/index.d.ts +2 -2
  47. package/dist/storage/index.d.ts.map +1 -1
  48. package/dist/storage/interfaces.d.ts +13 -2
  49. package/dist/storage/interfaces.d.ts.map +1 -1
  50. package/dist/storage/local-sqlite.d.ts.map +1 -1
  51. package/dist/storage/postgres-adapter.d.ts.map +1 -1
  52. package/dist/storage/timestamp-backfill.d.ts +62 -0
  53. package/dist/storage/timestamp-backfill.d.ts.map +1 -0
  54. package/dist/storage.d.ts +2 -2
  55. package/dist/storage.d.ts.map +1 -1
  56. package/dist/storage.js +199 -63
  57. package/dist/task-subtree-transfer/authority.d.ts +27 -0
  58. package/dist/task-subtree-transfer/authority.d.ts.map +1 -0
  59. package/dist/task-subtree-transfer/backend.d.ts +9 -0
  60. package/dist/task-subtree-transfer/backend.d.ts.map +1 -0
  61. package/dist/task-subtree-transfer/canonical.d.ts +14 -0
  62. package/dist/task-subtree-transfer/canonical.d.ts.map +1 -0
  63. package/dist/task-subtree-transfer/http.d.ts +16 -0
  64. package/dist/task-subtree-transfer/http.d.ts.map +1 -0
  65. package/dist/task-subtree-transfer/index.d.ts +6 -0
  66. package/dist/task-subtree-transfer/index.d.ts.map +1 -0
  67. package/dist/task-subtree-transfer/planner.d.ts +24 -0
  68. package/dist/task-subtree-transfer/planner.d.ts.map +1 -0
  69. package/dist/task-subtree-transfer/postgres.d.ts +19 -0
  70. package/dist/task-subtree-transfer/postgres.d.ts.map +1 -0
  71. package/dist/task-subtree-transfer/schema-sql.d.ts +5 -0
  72. package/dist/task-subtree-transfer/schema-sql.d.ts.map +1 -0
  73. package/dist/task-subtree-transfer/sqlite.d.ts +16 -0
  74. package/dist/task-subtree-transfer/sqlite.d.ts.map +1 -0
  75. package/dist/task-subtree-transfer/types.d.ts +148 -0
  76. package/dist/task-subtree-transfer/types.d.ts.map +1 -0
  77. package/dist/task-subtree-transfer.d.ts +2 -0
  78. package/dist/task-subtree-transfer.d.ts.map +1 -0
  79. package/dist/task-subtree-transfer.js +1869 -0
  80. package/dist/testing.d.ts +41 -7
  81. package/dist/testing.d.ts.map +1 -1
  82. package/dist/testing.js +44 -1
  83. package/dist/types/index.d.ts +24 -0
  84. package/dist/types/index.d.ts.map +1 -1
  85. package/package.json +8 -4
package/dist/mcp.js CHANGED
@@ -41,7 +41,7 @@ var __require = import.meta.require;
41
41
  // package.json
42
42
  var package_default = {
43
43
  name: "@hasna/todos",
44
- version: "0.15.35",
44
+ version: "0.15.41",
45
45
  description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
46
46
  type: "module",
47
47
  main: "dist/index.js",
@@ -87,6 +87,10 @@ var package_default = {
87
87
  "./task-manifest": {
88
88
  types: "./dist/task-manifest.d.ts",
89
89
  import: "./dist/task-manifest.js"
90
+ },
91
+ "./task-subtree-transfer": {
92
+ types: "./dist/task-subtree-transfer.d.ts",
93
+ import: "./dist/task-subtree-transfer.js"
90
94
  }
91
95
  },
92
96
  workspaces: [
@@ -100,8 +104,8 @@ var package_default = {
100
104
  "README.md"
101
105
  ],
102
106
  scripts: {
103
- build: "rm -rf dist dashboard/dist && cd dashboard && bun install --frozen-lockfile && bun run build && cd .. && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun && bun build src/sdk/index.ts --outdir dist/sdk --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/index.ts src/mcp.ts src/registry.ts src/contracts.ts src/storage.ts src/testing.ts src/project-registration.ts src/task-manifest.ts --outdir dist --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && tsc --emitDeclarationOnly --outDir dist",
104
- "build:server": "rm -rf dist && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun && bun build src/sdk/index.ts --outdir dist/sdk --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/index.ts src/mcp.ts src/registry.ts src/contracts.ts src/storage.ts src/testing.ts src/project-registration.ts src/task-manifest.ts --outdir dist --target bun --external '@hasna/contracts' --external '@hasna/contracts/*'",
107
+ build: "rm -rf dist dashboard/dist && cd dashboard && bun install --frozen-lockfile && bun run build && cd .. && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun && bun build src/sdk/index.ts --outdir dist/sdk --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/index.ts src/mcp.ts src/registry.ts src/contracts.ts src/storage.ts src/testing.ts src/project-registration.ts src/task-manifest.ts src/task-subtree-transfer.ts --outdir dist --root src --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && tsc --emitDeclarationOnly --outDir dist",
108
+ "build:server": "rm -rf dist && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun && bun build src/sdk/index.ts --outdir dist/sdk --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/index.ts src/mcp.ts src/registry.ts src/contracts.ts src/storage.ts src/testing.ts src/project-registration.ts src/task-manifest.ts src/task-subtree-transfer.ts --outdir dist --target bun --external '@hasna/contracts' --external '@hasna/contracts/*'",
105
109
  migrate: "bun run src/server/index.ts migrate",
106
110
  "backfill:comment-redaction": "bun run src/server/index.ts redact-comments",
107
111
  "generate:sdk": "bun run scripts/generate-sdk.ts",
@@ -155,7 +159,7 @@ var package_default = {
155
159
  author: "Andrei Hasna <andrei@hasna.com>",
156
160
  license: "Apache-2.0",
157
161
  dependencies: {
158
- "@hasna/contracts": "0.5.2",
162
+ "@hasna/contracts": "0.13.3",
159
163
  "@hasna/events": "^0.1.11",
160
164
  "@modelcontextprotocol/sdk": "^1.12.1",
161
165
  chalk: "^5.4.1",
@@ -3692,6 +3692,20 @@ function ensureSchema(db) {
3692
3692
  ensureIndex("CREATE INDEX IF NOT EXISTS idx_webhook_deliveries_event ON webhook_deliveries(event)");
3693
3693
  ensureColumn("task_comments", "type", "TEXT DEFAULT 'comment'");
3694
3694
  ensureColumn("task_comments", "progress_pct", "INTEGER");
3695
+ ensureTable("plan_comments", `
3696
+ CREATE TABLE plan_comments (
3697
+ id TEXT PRIMARY KEY,
3698
+ plan_id TEXT NOT NULL REFERENCES plans(id) ON DELETE CASCADE,
3699
+ agent_id TEXT,
3700
+ session_id TEXT,
3701
+ content TEXT NOT NULL,
3702
+ type TEXT DEFAULT 'comment' CHECK(type IN ('comment', 'progress', 'note')),
3703
+ progress_pct INTEGER CHECK(progress_pct IS NULL OR (progress_pct >= 0 AND progress_pct <= 100)),
3704
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
3705
+ machine_id TEXT,
3706
+ synced_at TEXT
3707
+ )`);
3708
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_plan_comments_plan ON plan_comments(plan_id)");
3695
3709
  ensureColumn("projects", "machine_id", "TEXT");
3696
3710
  ensureColumn("projects", "synced_at", "TEXT");
3697
3711
  ensureColumn("tasks", "machine_id", "TEXT");
@@ -4673,6 +4687,7 @@ var init_machines = __esm(() => {
4673
4687
  "task_lists",
4674
4688
  "plans",
4675
4689
  "task_comments",
4690
+ "plan_comments",
4676
4691
  "sessions",
4677
4692
  "task_history",
4678
4693
  "webhooks",
@@ -4866,20 +4881,16 @@ var init_identity_mapping = __esm(() => {
4866
4881
  // src/storage/config.ts
4867
4882
  var exports_config = {};
4868
4883
  __export(exports_config, {
4869
- parseStorageMode: () => parseStorageMode,
4870
4884
  parseStorageBackend: () => parseStorageBackend,
4871
4885
  loadTodosStorageConfig: () => loadTodosStorageConfig,
4872
4886
  loadStorageConfig: () => loadStorageConfig,
4873
4887
  isTodosShadowEnabled: () => isTodosShadowEnabled,
4874
- isTodosRemoteStorageEnabled: () => isTodosRemoteStorageEnabled,
4875
4888
  isTodosPostgresBackend: () => isTodosPostgresBackend,
4876
4889
  getTodosStorageShadowEnvName: () => getTodosStorageShadowEnvName,
4877
- getTodosStorageMode: () => getTodosStorageMode,
4878
4890
  getTodosStorageEnvName: () => getTodosStorageEnvName,
4879
4891
  getTodosStorageDatabaseUrl: () => getTodosStorageDatabaseUrl,
4880
4892
  getTodosStorageDatabaseEnv: () => getTodosStorageDatabaseEnv,
4881
4893
  getTodosStorageBackend: () => getTodosStorageBackend,
4882
- getStorageMode: () => getStorageMode,
4883
4894
  getStorageDatabaseUrl: () => getStorageDatabaseUrl,
4884
4895
  getStorageDatabaseEnv: () => getStorageDatabaseEnv,
4885
4896
  getCanonicalTodosRdsConfig: () => getCanonicalTodosRdsConfig,
@@ -4889,7 +4900,6 @@ __export(exports_config, {
4889
4900
  TODOS_STORAGE_FALLBACK_ENV: () => TODOS_STORAGE_FALLBACK_ENV,
4890
4901
  TODOS_STORAGE_ENV: () => TODOS_STORAGE_ENV,
4891
4902
  STORAGE_TABLES: () => STORAGE_TABLES,
4892
- REMOVED_STORAGE_MODE_ENV_KEYS: () => REMOVED_STORAGE_MODE_ENV_KEYS,
4893
4903
  CANONICAL_TODOS_RDS_RUNTIME_PATH_ENV: () => CANONICAL_TODOS_RDS_RUNTIME_PATH_ENV,
4894
4904
  CANONICAL_TODOS_RDS_DATABASE: () => CANONICAL_TODOS_RDS_DATABASE,
4895
4905
  CANONICAL_TODOS_RDS_CLUSTER_ENV: () => CANONICAL_TODOS_RDS_CLUSTER_ENV
@@ -4944,9 +4954,6 @@ function loadStorageConfig(env = process.env) {
4944
4954
  function isTodosPostgresBackend(config) {
4945
4955
  return config.mode === "postgres";
4946
4956
  }
4947
- function isTodosRemoteStorageEnabled(config) {
4948
- return isTodosPostgresBackend(config);
4949
- }
4950
4957
  function assertTodosRemoteStorageConfig(config) {
4951
4958
  if (!isTodosPostgresBackend(config))
4952
4959
  return;
@@ -4962,32 +4969,15 @@ function parseStorageBackend(value) {
4962
4969
  return "sqlite";
4963
4970
  if (normalized === "postgres" || normalized === "postgresql")
4964
4971
  return "postgres";
4965
- if (["local", "remote", "cloud", "hybrid", "self_hosted"].includes(normalized)) {
4966
- throw new Error(`${TODOS_STORAGE_ENV.databaseUrl} selects the backend. Deployment modes no longer exist: ` + `delete the storage-mode variable and set ${TODOS_STORAGE_ENV.databaseUrl} to select the ` + `postgresql backend, or leave it unset for sqlite.`);
4967
- }
4968
4972
  throw new Error(`Storage backend must be sqlite or postgres`);
4969
4973
  }
4970
- function parseStorageMode(value) {
4971
- return parseStorageBackend(value);
4972
- }
4973
4974
  function getTodosStorageBackend(env = process.env) {
4974
- for (const key of REMOVED_STORAGE_MODE_ENV_KEYS) {
4975
- if (Object.hasOwn(env, key) && env[key] !== undefined) {
4976
- throw new Error(`${key} was removed. Deployment modes no longer exist: delete the storage-mode variable. ` + `Set ${TODOS_STORAGE_ENV.databaseUrl} to select the postgresql backend, ` + `or leave it unset for sqlite.`);
4977
- }
4978
- }
4979
4975
  if (!getTodosStorageDatabaseUrl(env))
4980
4976
  return "sqlite";
4981
4977
  if (isTodosShadowEnabled(env))
4982
4978
  return "sqlite";
4983
4979
  return "postgres";
4984
4980
  }
4985
- function getTodosStorageMode(env = process.env) {
4986
- return getTodosStorageBackend(env);
4987
- }
4988
- function getStorageMode(env = process.env) {
4989
- return getTodosStorageBackend(env);
4990
- }
4991
4981
  function isTodosShadowEnabled(env = process.env) {
4992
4982
  return parseBoolean(readStorageEnv(env, "shadow").value, false);
4993
4983
  }
@@ -5054,7 +5044,7 @@ function parsePositiveInteger(value, fallback) {
5054
5044
  }
5055
5045
  return parsed;
5056
5046
  }
5057
- var TODOS_STORAGE_TABLES, STORAGE_TABLES, TODOS_STORAGE_ENV, TODOS_STORAGE_FALLBACK_ENV, REMOVED_STORAGE_MODE_ENV_KEYS, CANONICAL_TODOS_RDS_CLUSTER_ENV = "HASNA_TODOS_RDS_CLUSTER", CANONICAL_TODOS_RDS_RUNTIME_PATH_ENV = "HASNA_TODOS_RDS_RUNTIME_PATH", CANONICAL_TODOS_RDS_DATABASE = "todos";
5047
+ var TODOS_STORAGE_TABLES, STORAGE_TABLES, TODOS_STORAGE_ENV, TODOS_STORAGE_FALLBACK_ENV, CANONICAL_TODOS_RDS_CLUSTER_ENV = "HASNA_TODOS_RDS_CLUSTER", CANONICAL_TODOS_RDS_RUNTIME_PATH_ENV = "HASNA_TODOS_RDS_RUNTIME_PATH", CANONICAL_TODOS_RDS_DATABASE = "todos";
5058
5048
  var init_config2 = __esm(() => {
5059
5049
  TODOS_STORAGE_TABLES = [
5060
5050
  "todos_sync_records",
@@ -5093,12 +5083,6 @@ var init_config2 = __esm(() => {
5093
5083
  syncBatchSize: "TODOS_SYNC_BATCH_SIZE",
5094
5084
  syncDryRun: "TODOS_SYNC_DRY_RUN"
5095
5085
  };
5096
- REMOVED_STORAGE_MODE_ENV_KEYS = [
5097
- "HASNA_TODOS_STORAGE_MODE",
5098
- "HASNA_TODOS_MODE",
5099
- "TODOS_STORAGE_MODE",
5100
- "TODOS_MODE"
5101
- ];
5102
5086
  });
5103
5087
 
5104
5088
  // src/storage/shadow-outbox-schema.ts
@@ -7270,22 +7254,31 @@ function updateTaskList2(id, input, db) {
7270
7254
  throw new TaskListNotFoundError(id);
7271
7255
  const sets = ["updated_at = ?"];
7272
7256
  const params = [now()];
7273
- if (input.slug !== undefined) {
7274
- const slug = slugify(input.slug);
7275
- if (!slug)
7276
- throw new Error("Invalid task-list slug \u2014 must be non-empty kebab-case");
7277
- const duplicate = existing.project_id ? d.query("SELECT id FROM task_lists WHERE project_id = ? AND slug = ? AND id != ?").get(existing.project_id, slug, id) : d.query("SELECT id FROM task_lists WHERE project_id IS NULL AND slug = ? AND id != ?").get(slug, id);
7257
+ const projectId = input.project_id === "" || input.project_id === null ? null : input.project_id === undefined ? existing.project_id : input.project_id;
7258
+ const scopeChanged = projectId !== existing.project_id;
7259
+ const effectiveSlug = input.slug !== undefined ? slugify(input.slug) : existing.slug;
7260
+ if (input.slug !== undefined && !effectiveSlug) {
7261
+ throw new Error("Invalid task-list slug \u2014 must be non-empty kebab-case");
7262
+ }
7263
+ if (scopeChanged || input.slug !== undefined && effectiveSlug !== existing.slug) {
7264
+ const duplicate = projectId ? d.query("SELECT id FROM task_lists WHERE project_id = ? AND slug = ? AND id != ?").get(projectId, effectiveSlug, id) : d.query("SELECT id FROM task_lists WHERE project_id IS NULL AND slug = ? AND id != ?").get(effectiveSlug, id);
7278
7265
  if (duplicate) {
7279
- throw new ResourceConflictError("TASK_LIST_SLUG_CONFLICT", `Task list with slug "${slug}" already exists in this scope`);
7266
+ throw new ResourceConflictError("TASK_LIST_SLUG_CONFLICT", `Task list with slug "${effectiveSlug}" already exists in this scope`);
7280
7267
  }
7281
- if (slug !== existing.slug) {
7268
+ if (scopeChanged || effectiveSlug !== existing.slug) {
7282
7269
  releaseCanonicalSlugClaims("task_list", id, d);
7283
- if (!claimCanonicalSlug("task_list", taskListSlugScopeKey(existing.project_id), slug, id, d)) {
7284
- throw new ResourceConflictError("TASK_LIST_SLUG_CONFLICT", `Task list with slug "${slug}" already exists in this scope`);
7270
+ if (!claimCanonicalSlug("task_list", taskListSlugScopeKey(projectId), effectiveSlug, id, d)) {
7271
+ throw new ResourceConflictError("TASK_LIST_SLUG_CONFLICT", `Task list with slug "${effectiveSlug}" already exists in this scope`);
7285
7272
  }
7286
7273
  }
7274
+ }
7275
+ if (input.slug !== undefined) {
7287
7276
  sets.push("slug = ?");
7288
- params.push(slug);
7277
+ params.push(effectiveSlug);
7278
+ }
7279
+ if (projectId !== existing.project_id) {
7280
+ sets.push("project_id = ?");
7281
+ params.push(projectId);
7289
7282
  }
7290
7283
  if (input.name !== undefined) {
7291
7284
  sets.push("name = ?");
@@ -9321,8 +9314,8 @@ function failTask2(id, agentId, reason, options, db) {
9321
9314
  const safeMeta = sanitizePreWriteValue(meta, "task.failure.metadata");
9322
9315
  const timestamp2 = now();
9323
9316
  const failTx = d.transaction(() => {
9324
- const res = d.run(`UPDATE tasks SET status = 'failed', reason = ?, locked_by = NULL, locked_at = NULL, metadata = ?, version = version + 1, updated_at = ?
9325
- WHERE id = ? AND version = ?`, [safeReason, JSON.stringify(safeMeta), timestamp2, id, task.version]);
9317
+ const res = d.run(`UPDATE tasks SET status = 'failed', reason = ?, locked_by = NULL, locked_at = NULL, completed_at = COALESCE(completed_at, ?), metadata = ?, version = version + 1, updated_at = ?
9318
+ WHERE id = ? AND version = ?`, [safeReason, timestamp2, JSON.stringify(safeMeta), timestamp2, id, task.version]);
9326
9319
  if (res.changes === 0) {
9327
9320
  const current = getTask(id, d);
9328
9321
  throw new VersionConflictError(id, task.version, current?.version ?? -1);
@@ -9334,6 +9327,7 @@ function failTask2(id, agentId, reason, options, db) {
9334
9327
  status: "failed",
9335
9328
  locked_by: null,
9336
9329
  locked_at: null,
9330
+ completed_at: task.completed_at ?? timestamp2,
9337
9331
  reason: safeReason,
9338
9332
  metadata: safeMeta,
9339
9333
  version: task.version + 1,
@@ -9982,13 +9976,20 @@ function updateTaskStored(id, input, db) {
9982
9976
  if (isTerminalStatus(input.status)) {
9983
9977
  sets.push("locked_by = NULL");
9984
9978
  sets.push("locked_at = NULL");
9985
- }
9986
- if (input.status === "completed") {
9987
- sets.push("completed_at = ?");
9988
- params.push(completionTimestamp);
9979
+ if (input.status === "completed") {
9980
+ sets.push("completed_at = ?");
9981
+ params.push(completionTimestamp);
9982
+ } else {
9983
+ sets.push("completed_at = COALESCE(completed_at, ?)");
9984
+ params.push(completionTimestamp);
9985
+ }
9989
9986
  } else if (task.status === "completed" && input.completed_at === undefined) {
9990
9987
  sets.push("completed_at = NULL");
9991
9988
  }
9989
+ if (input.status === "in_progress") {
9990
+ sets.push("started_at = COALESCE(started_at, ?)");
9991
+ params.push(timestamp2);
9992
+ }
9992
9993
  }
9993
9994
  if (input.priority !== undefined) {
9994
9995
  sets.push("priority = ?");
@@ -10126,7 +10127,6 @@ function updateTaskStored(id, input, db) {
10126
10127
  if (input.approved_by !== undefined)
10127
10128
  logTaskChange2(id, "approve", "approved_by", null, input.approved_by, agentId, d);
10128
10129
  const reopened = input.status !== undefined && input.status !== "completed" && task.status === "completed" && input.completed_at === undefined;
10129
- const completedNow = input.status === "completed";
10130
10130
  const terminalNow = input.status !== undefined && isTerminalStatus(input.status);
10131
10131
  const updatedTask = {
10132
10132
  ...task,
@@ -10137,7 +10137,8 @@ function updateTaskStored(id, input, db) {
10137
10137
  updated_at: timestamp2,
10138
10138
  locked_by: terminalNow ? null : task.locked_by,
10139
10139
  locked_at: terminalNow ? null : task.locked_at,
10140
- completed_at: completedNow ? completionTimestamp : reopened ? null : input.completed_at !== undefined ? input.completed_at : task.completed_at,
10140
+ completed_at: input.status === "completed" ? completionTimestamp : input.completed_at !== undefined ? input.completed_at : terminalNow ? task.completed_at ?? completionTimestamp : reopened ? null : task.completed_at,
10141
+ started_at: input.status === "in_progress" ? task.started_at ?? timestamp2 : task.started_at,
10141
10142
  sla_minutes: input.sla_minutes !== undefined ? input.sla_minutes : task.sla_minutes,
10142
10143
  actual_minutes: input.actual_minutes ?? task.actual_minutes,
10143
10144
  confidence: input.confidence !== undefined ? input.confidence : task.confidence,
@@ -10198,6 +10199,9 @@ function deleteTask(id, db) {
10198
10199
  version: row.version
10199
10200
  }, d);
10200
10201
  const result = d.run("DELETE FROM tasks WHERE id = ?", [id]);
10202
+ if (result.changes > 0) {
10203
+ d.run("DELETE FROM task_dependencies WHERE task_id = ? OR depends_on = ?", [id, id]);
10204
+ }
10201
10205
  return result.changes > 0;
10202
10206
  }
10203
10207
  var init_task_crud = __esm(() => {
@@ -12808,7 +12812,7 @@ import { createHash as createHash7 } from "crypto";
12808
12812
  // package.json
12809
12813
  var package_default = {
12810
12814
  name: "@hasna/todos",
12811
- version: "0.15.35",
12815
+ version: "0.15.41",
12812
12816
  description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
12813
12817
  type: "module",
12814
12818
  main: "dist/index.js",
@@ -12854,6 +12858,10 @@ var package_default = {
12854
12858
  "./task-manifest": {
12855
12859
  types: "./dist/task-manifest.d.ts",
12856
12860
  import: "./dist/task-manifest.js"
12861
+ },
12862
+ "./task-subtree-transfer": {
12863
+ types: "./dist/task-subtree-transfer.d.ts",
12864
+ import: "./dist/task-subtree-transfer.js"
12857
12865
  }
12858
12866
  },
12859
12867
  workspaces: [
@@ -12867,8 +12875,8 @@ var package_default = {
12867
12875
  "README.md"
12868
12876
  ],
12869
12877
  scripts: {
12870
- build: "rm -rf dist dashboard/dist && cd dashboard && bun install --frozen-lockfile && bun run build && cd .. && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun && bun build src/sdk/index.ts --outdir dist/sdk --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/index.ts src/mcp.ts src/registry.ts src/contracts.ts src/storage.ts src/testing.ts src/project-registration.ts src/task-manifest.ts --outdir dist --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && tsc --emitDeclarationOnly --outDir dist",
12871
- "build:server": "rm -rf dist && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun && bun build src/sdk/index.ts --outdir dist/sdk --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/index.ts src/mcp.ts src/registry.ts src/contracts.ts src/storage.ts src/testing.ts src/project-registration.ts src/task-manifest.ts --outdir dist --target bun --external '@hasna/contracts' --external '@hasna/contracts/*'",
12878
+ build: "rm -rf dist dashboard/dist && cd dashboard && bun install --frozen-lockfile && bun run build && cd .. && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun && bun build src/sdk/index.ts --outdir dist/sdk --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/index.ts src/mcp.ts src/registry.ts src/contracts.ts src/storage.ts src/testing.ts src/project-registration.ts src/task-manifest.ts src/task-subtree-transfer.ts --outdir dist --root src --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && tsc --emitDeclarationOnly --outDir dist",
12879
+ "build:server": "rm -rf dist && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun && bun build src/sdk/index.ts --outdir dist/sdk --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/index.ts src/mcp.ts src/registry.ts src/contracts.ts src/storage.ts src/testing.ts src/project-registration.ts src/task-manifest.ts src/task-subtree-transfer.ts --outdir dist --target bun --external '@hasna/contracts' --external '@hasna/contracts/*'",
12872
12880
  migrate: "bun run src/server/index.ts migrate",
12873
12881
  "backfill:comment-redaction": "bun run src/server/index.ts redact-comments",
12874
12882
  "generate:sdk": "bun run scripts/generate-sdk.ts",
@@ -12922,7 +12930,7 @@ var package_default = {
12922
12930
  author: "Andrei Hasna <andrei@hasna.com>",
12923
12931
  license: "Apache-2.0",
12924
12932
  dependencies: {
12925
- "@hasna/contracts": "0.5.2",
12933
+ "@hasna/contracts": "0.13.3",
12926
12934
  "@hasna/events": "^0.1.11",
12927
12935
  "@modelcontextprotocol/sdk": "^1.12.1",
12928
12936
  chalk: "^5.4.1",
@@ -13783,7 +13791,26 @@ function createPostgresTodosStorageAdapter(options) {
13783
13791
  list: async (projectId) => (await store.list("plans")).filter((plan) => projectId === undefined || plan.project_id === projectId).sort((a, b) => a.name.localeCompare(b.name)),
13784
13792
  update: (id, input) => updatePlan(id, input, store),
13785
13793
  completeAtRevision: (id, expectedUpdatedAt, context) => store.completePlanAtRevision(id, expectedUpdatedAt, context),
13786
- delete: (id, context) => store.deletePlan(id, context)
13794
+ delete: (id, context) => store.deletePlan(id, context),
13795
+ addComment: (input, context) => addPlanComment(input, store, context),
13796
+ getComments: async (planId) => {
13797
+ const pages = [];
13798
+ let before;
13799
+ while (true) {
13800
+ const page = await store.listPlanComments(planId, { limit: 1000, ...before ? { before } : {} });
13801
+ if (page.length === 0)
13802
+ break;
13803
+ pages.unshift(page);
13804
+ if (page.length < 1000)
13805
+ break;
13806
+ const oldest = page[0];
13807
+ before = { created_at: oldest.created_at, id: oldest.id };
13808
+ }
13809
+ return pages.flat().map(redactPlanComment).sort((a, b) => a.created_at.localeCompare(b.created_at) || a.id.localeCompare(b.id));
13810
+ },
13811
+ getCommentsPage: async (planId, options2) => {
13812
+ return (await store.listPlanComments(planId, options2)).map(redactPlanComment).sort((a, b) => a.created_at.localeCompare(b.created_at) || a.id.localeCompare(b.id));
13813
+ }
13787
13814
  },
13788
13815
  planProjectLinks: {
13789
13816
  apply: (input, context) => store.applyPlanProjectLink(input, context),
@@ -14001,6 +14028,27 @@ class PostgresJsonRecordStore {
14001
14028
  LIMIT $${params.length}`, params);
14002
14029
  return result.rows.map((row) => payloadRecord2(row.payload)).reverse();
14003
14030
  }
14031
+ async listPlanComments(planId, options = {}) {
14032
+ await this.ensureSchema();
14033
+ const limit = options.limit ?? 100;
14034
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 1001) {
14035
+ throw new Error("Postgres plan comment limit must be an integer between 1 and 1001");
14036
+ }
14037
+ const params = [this.service, planId];
14038
+ let cursorPredicate = "";
14039
+ if (options.before) {
14040
+ params.push(options.before.created_at, options.before.id);
14041
+ cursorPredicate = `AND (payload->>'created_at', object_id) < ($3, $4)`;
14042
+ }
14043
+ params.push(limit);
14044
+ const result = await this.options.client.query(`/* todos:list-plan-comments */ SELECT payload FROM ${this.tableName}
14045
+ WHERE service = $1 AND object_type = 'plan_comments' AND deleted_at IS NULL
14046
+ AND payload->>'plan_id' = $2
14047
+ ${cursorPredicate}
14048
+ ORDER BY payload->>'created_at' DESC, object_id DESC
14049
+ LIMIT $${params.length}`, params);
14050
+ return result.rows.map((row) => payloadRecord2(row.payload)).reverse();
14051
+ }
14004
14052
  async listRecords(type) {
14005
14053
  await this.ensureSchema();
14006
14054
  const result = await this.options.client.query(`SELECT object_type, object_id, payload, updated_at
@@ -15162,6 +15210,15 @@ class PostgresJsonRecordStore {
15162
15210
  WHERE r.service = $1 AND r.object_type = 'tasks' AND r.deleted_at IS NULL
15163
15211
  AND r.payload->>'plan_id' = $2 AND EXISTS (SELECT 1 FROM target)
15164
15212
  RETURNING 1
15213
+ ), deleted_plan_comments AS (
15214
+ UPDATE ${this.tableName} r SET
15215
+ deleted_at = $3::timestamptz,
15216
+ updated_at = $3::timestamptz,
15217
+ source_machine_id = COALESCE($4, r.source_machine_id),
15218
+ version = COALESCE(r.version, 0) + 1
15219
+ WHERE r.service = $1 AND r.object_type = 'plan_comments' AND r.deleted_at IS NULL
15220
+ AND r.payload->>'plan_id' = $2 AND EXISTS (SELECT 1 FROM target)
15221
+ RETURNING 1
15165
15222
  ), deleted_plan AS (
15166
15223
  UPDATE ${this.tableName} r SET
15167
15224
  deleted_at = $3::timestamptz,
@@ -15337,7 +15394,8 @@ async function updateTask(id, input, store, context) {
15337
15394
  task_list_id: input.task_list_id !== undefined ? input.task_list_id : existing.task_list_id,
15338
15395
  parent_id: input.parent_id !== undefined ? input.parent_id : existing.parent_id,
15339
15396
  created_by: existing.created_by,
15340
- completed_at: reopened ? null : input.completed_at !== undefined ? input.completed_at : existing.completed_at
15397
+ completed_at: input.status === "completed" ? input.completed_at ?? new Date().toISOString() : input.completed_at !== undefined ? input.completed_at : input.status !== undefined && isTerminalStatus(input.status) ? existing.completed_at ?? new Date().toISOString() : reopened ? null : existing.completed_at,
15398
+ started_at: input.status === "in_progress" ? existing.started_at ?? new Date().toISOString() : existing.started_at
15341
15399
  };
15342
15400
  const storedTask = await store.upsertTaskWithPlanMembershipGuard(task, [existing.plan_id, effectivePlanId].filter((planId) => Boolean(planId)), input.project_id !== undefined, context, {
15343
15401
  operation: "update",
@@ -15382,7 +15440,8 @@ async function failTask(id, agentId, reason, options, store) {
15382
15440
  status: "failed",
15383
15441
  assigned_to: task.assigned_to ?? agentId ?? null,
15384
15442
  reason: reason ?? task.reason,
15385
- retry_after: options?.retry_after ?? task.retry_after
15443
+ retry_after: options?.retry_after ?? task.retry_after,
15444
+ completed_at: task.completed_at ?? new Date().toISOString()
15386
15445
  }, store);
15387
15446
  if (!options?.retry)
15388
15447
  return { task: failed };
@@ -15830,16 +15889,22 @@ async function createTaskList(input, store, context) {
15830
15889
  async function updateTaskList(id, input, store) {
15831
15890
  const list = await requireRecord("task_lists", id, store);
15832
15891
  const patch = definedPatch(input);
15892
+ const projectId = input.project_id === "" || input.project_id === null ? null : input.project_id === undefined ? list.project_id : input.project_id;
15833
15893
  if (input.slug !== undefined) {
15834
15894
  const slug = slugifyRaw(input.slug);
15835
15895
  if (!slug)
15836
15896
  throw new Error("Invalid task-list slug \u2014 must be non-empty kebab-case");
15837
- const duplicate = (await store.list("task_lists")).find((candidate) => candidate.id !== id && candidate.project_id === list.project_id && candidate.slug === slug);
15897
+ patch.slug = slug;
15898
+ }
15899
+ const effectiveSlug = patch.slug ?? list.slug;
15900
+ if (projectId !== list.project_id || effectiveSlug !== list.slug) {
15901
+ const duplicate = (await store.list("task_lists")).find((candidate) => candidate.id !== id && candidate.project_id === projectId && candidate.slug === effectiveSlug);
15838
15902
  if (duplicate) {
15839
- throw new ResourceConflictError("TASK_LIST_SLUG_CONFLICT", `Task list with slug "${slug}" already exists in this scope`);
15903
+ throw new ResourceConflictError("TASK_LIST_SLUG_CONFLICT", `Task list with slug "${effectiveSlug}" already exists in this scope`);
15840
15904
  }
15841
- patch.slug = slug;
15842
15905
  }
15906
+ if (projectId !== list.project_id)
15907
+ patch.project_id = projectId;
15843
15908
  return store.upsert("task_lists", {
15844
15909
  ...list,
15845
15910
  ...patch,
@@ -15932,6 +15997,22 @@ async function addComment(input, store, context) {
15932
15997
  function redactComment(comment) {
15933
15998
  return { ...comment, content: redactEvidenceText(comment.content) };
15934
15999
  }
16000
+ async function addPlanComment(input, store, context) {
16001
+ const comment = {
16002
+ id: randomUUID(),
16003
+ plan_id: input.plan_id,
16004
+ agent_id: input.agent_id ?? context?.agentId ?? null,
16005
+ session_id: input.session_id ?? context?.sessionId ?? null,
16006
+ content: redactEvidenceText(input.content),
16007
+ type: input.type ?? "comment",
16008
+ progress_pct: input.progress_pct ?? null,
16009
+ created_at: new Date().toISOString()
16010
+ };
16011
+ return store.upsert("plan_comments", comment, context);
16012
+ }
16013
+ function redactPlanComment(comment) {
16014
+ return { ...comment, content: redactEvidenceText(comment.content) };
16015
+ }
15935
16016
  async function exportSnapshot(store) {
15936
16017
  return {
15937
16018
  exportedAt: new Date().toISOString(),
@@ -16817,6 +16898,40 @@ init_tasks();
16817
16898
  init_projects();
16818
16899
  init_plans();
16819
16900
 
16901
+ // src/db/plan-comments.ts
16902
+ init_types();
16903
+ init_database();
16904
+ init_plans();
16905
+ init_prewrite_secrets();
16906
+ function addPlanComment2(input, db) {
16907
+ const d = db || getDatabase();
16908
+ if (!getPlan(input.plan_id, d)) {
16909
+ throw new PlanNotFoundError(input.plan_id);
16910
+ }
16911
+ const id = uuid();
16912
+ const timestamp2 = now();
16913
+ d.run(`INSERT INTO plan_comments (id, plan_id, agent_id, session_id, content, type, progress_pct, created_at)
16914
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
16915
+ id,
16916
+ input.plan_id,
16917
+ input.agent_id || null,
16918
+ input.session_id || null,
16919
+ sanitizePreWriteText(input.content, "comment.content"),
16920
+ input.type || "comment",
16921
+ input.progress_pct ?? null,
16922
+ timestamp2
16923
+ ]);
16924
+ return getPlanComment(id, d);
16925
+ }
16926
+ function getPlanComment(id, db) {
16927
+ const d = db || getDatabase();
16928
+ return d.query("SELECT * FROM plan_comments WHERE id = ?").get(id);
16929
+ }
16930
+ function listPlanComments(planId, db) {
16931
+ const d = db || getDatabase();
16932
+ return d.query("SELECT * FROM plan_comments WHERE plan_id = ? ORDER BY created_at, rowid").all(planId);
16933
+ }
16934
+
16820
16935
  // src/db/agents.ts
16821
16936
  init_types();
16822
16937
  init_database();
@@ -17469,6 +17584,20 @@ init_task_lists();
17469
17584
  init_templates();
17470
17585
  init_audit();
17471
17586
  init_comments();
17587
+
17588
+ // src/lib/comment-cursor.ts
17589
+ function isStrictlyOlder(comment, before) {
17590
+ return comment.created_at < before.created_at || comment.created_at === before.created_at && comment.id < before.id;
17591
+ }
17592
+ function compareCommentKeyset(left, right) {
17593
+ if (isStrictlyOlder(left, right))
17594
+ return -1;
17595
+ if (isStrictlyOlder(right, left))
17596
+ return 1;
17597
+ return 0;
17598
+ }
17599
+
17600
+ // src/storage/local-sqlite.ts
17472
17601
  init_database();
17473
17602
 
17474
17603
  // src/db/integrity.ts
@@ -18240,7 +18369,22 @@ function createLocalSqliteTodosStorageAdapter(options = {}) {
18240
18369
  list: (projectId) => listPlans(projectId, database()),
18241
18370
  update: (id, input) => updatePlan2(id, input, database()),
18242
18371
  completeAtRevision: (id, expectedUpdatedAt) => completePlanAtRevision(id, expectedUpdatedAt, database()),
18243
- delete: (id) => deletePlan(id, database())
18372
+ delete: (id) => deletePlan(id, database()),
18373
+ addComment: (input) => addPlanComment2(input, database()),
18374
+ getComments: (planId) => listPlanComments(planId, database()),
18375
+ getCommentsPage: (planId, options2) => {
18376
+ if (options2?.limit !== undefined && (!Number.isSafeInteger(options2.limit) || options2.limit < 1 || options2.limit > 1001)) {
18377
+ throw new Error("Plan comment limit must be an integer between 1 and 1001");
18378
+ }
18379
+ let comments = listPlanComments(planId, database());
18380
+ comments = comments.sort(compareCommentKeyset);
18381
+ if (options2?.before) {
18382
+ const before = options2.before;
18383
+ comments = comments.filter((comment) => isStrictlyOlder(comment, before));
18384
+ }
18385
+ const limit = options2?.limit ?? 100;
18386
+ return comments.slice(-limit);
18387
+ }
18244
18388
  },
18245
18389
  planProjectLinks: {
18246
18390
  apply: (input) => applyPlanProjectLinkSqlite(input, database()),
@@ -18281,10 +18425,10 @@ function createLocalSqliteTodosStorageAdapter(options = {}) {
18281
18425
  throw new Error("Comment limit must be an integer between 1 and 1001");
18282
18426
  }
18283
18427
  let comments = listComments(taskId, database());
18284
- comments = comments.sort((left, right) => left.created_at.localeCompare(right.created_at) || left.id.localeCompare(right.id));
18428
+ comments = comments.sort(compareCommentKeyset);
18285
18429
  if (options2?.before) {
18286
18430
  const before = options2.before;
18287
- comments = comments.filter((comment) => comment.created_at < before.created_at || comment.created_at === before.created_at && comment.id < before.id);
18431
+ comments = comments.filter((comment) => isStrictlyOlder(comment, before));
18288
18432
  }
18289
18433
  if (options2?.limit !== undefined)
18290
18434
  comments = comments.slice(-options2.limit);
@@ -12,7 +12,7 @@ export interface TodosPackageSource {
12
12
  version: string;
13
13
  }
14
14
  export interface TodosPackageExportContract {
15
- subpath: "." | "./sdk" | "./mcp" | "./registry" | "./contracts" | "./storage" | "./testing" | "./project-registration" | "./task-manifest";
15
+ subpath: "." | "./sdk" | "./mcp" | "./registry" | "./contracts" | "./storage" | "./testing" | "./project-registration" | "./task-manifest" | "./task-subtree-transfer";
16
16
  import: string;
17
17
  types: string;
18
18
  description: string;
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAEjE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAErE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAG7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEjD,MAAM,WAAW,0BAA0B;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,cAAc,CAAC;IAC5B,UAAU,EAAE,aAAa,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,0BAA0B;IACzC,OAAO,EACH,GAAG,GACH,OAAO,GACP,OAAO,GACP,YAAY,GACZ,aAAa,GACb,WAAW,GACX,WAAW,GACX,wBAAwB,GACxB,iBAAiB,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,QAAQ,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,CAAC,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,OAAO,EAAE,0BAA0B,EAAE,CAAC;IACtC,oBAAoB,EAAE,wBAAwB,CAAC;IAC/C,YAAY,EAAE,uBAAuB,CAAC;IACtC,SAAS,EAAE,sBAAsB,CAAC;IAClC,GAAG,EAAE,gBAAgB,CAAC;IACtB,YAAY,EAAE,yBAAyB,CAAC;CACzC;AAED,eAAO,MAAM,qBAAqB,EAAE,0BAA0B,EAgE7D,CAAC;AAUF,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,0BAA+B,GAAG,aAAa,CAc3F;AAED,eAAO,MAAM,cAAc,eAEzB,CAAC"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAEjE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAErE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAG7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEjD,MAAM,WAAW,0BAA0B;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,cAAc,CAAC;IAC5B,UAAU,EAAE,aAAa,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,0BAA0B;IACzC,OAAO,EACH,GAAG,GACH,OAAO,GACP,OAAO,GACP,YAAY,GACZ,aAAa,GACb,WAAW,GACX,WAAW,GACX,wBAAwB,GACxB,iBAAiB,GACjB,yBAAyB,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,QAAQ,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,CAAC,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,OAAO,EAAE,0BAA0B,EAAE,CAAC;IACtC,oBAAoB,EAAE,wBAAwB,CAAC;IAC/C,YAAY,EAAE,uBAAuB,CAAC;IACtC,SAAS,EAAE,sBAAsB,CAAC;IAClC,GAAG,EAAE,gBAAgB,CAAC;IACtB,YAAY,EAAE,yBAAyB,CAAC;CACzC;AAED,eAAO,MAAM,qBAAqB,EAAE,0BAA0B,EAuE7D,CAAC;AAUF,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,0BAA+B,GAAG,aAAa,CAc3F;AAED,eAAO,MAAM,cAAc,eAEzB,CAAC"}