@hasna/todos 0.15.11 → 0.15.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -70,7 +70,7 @@ var package_default;
70
70
  var init_package = __esm(() => {
71
71
  package_default = {
72
72
  name: "@hasna/todos",
73
- version: "0.15.11",
73
+ version: "0.15.13",
74
74
  description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
75
75
  type: "module",
76
76
  main: "dist/index.js",
@@ -2466,6 +2466,7 @@ class PostgresJsonRecordStore {
2466
2466
  const current = await this.get(type, value.id);
2467
2467
  if (current)
2468
2468
  return current;
2469
+ throw new Error(`POSTGRES_WRITE_PERSISTENCE_UNVERIFIED: ${type} ${value.id} was not accepted and no persisted readback exists`);
2469
2470
  }
2470
2471
  return value;
2471
2472
  }
@@ -3237,6 +3238,9 @@ class PostgresJsonRecordStore {
3237
3238
  }
3238
3239
  async function createTask(input, store, context) {
3239
3240
  const timestamp = new Date().toISOString();
3241
+ if (input.parent_id && !await store.get("tasks", input.parent_id)) {
3242
+ throw new TaskNotFoundError(input.parent_id);
3243
+ }
3240
3244
  const linkedPlan = input.plan_id ? await store.get("plans", input.plan_id) : null;
3241
3245
  const requestedProjectId = input.project_id ?? context?.projectId ?? null;
3242
3246
  if (linkedPlan?.project_id && requestedProjectId && requestedProjectId !== linkedPlan.project_id) {
@@ -23703,6 +23707,7 @@ function buildV1OpenApiDocument(version = getPackageVersion()) {
23703
23707
  ProjectTaskListEnsureResult: projectTaskListEnsureResultSchema,
23704
23708
  ProjectTaskListRollbackResult: projectTaskListRollbackResultSchema,
23705
23709
  TaskComment: taskCommentSchema,
23710
+ TaskGitRef: taskGitRefSchema,
23706
23711
  Plan: planSchema,
23707
23712
  PlanProjectLinkReceipt: planProjectLinkReceiptSchema,
23708
23713
  PlanProjectLinkResult: planProjectLinkResultSchema,
@@ -23720,6 +23725,7 @@ function buildV1OpenApiDocument(version = getPackageVersion()) {
23720
23725
  status: { type: "string" },
23721
23726
  priority: { type: "string" },
23722
23727
  project_id: { type: "string" },
23728
+ parent_id: { type: "string" },
23723
23729
  plan_id: { type: "string" },
23724
23730
  assigned_to: { type: "string" },
23725
23731
  agent_id: { type: "string" },
@@ -24864,6 +24870,92 @@ function buildV1OpenApiDocument(version = getPackageVersion()) {
24864
24870
  }
24865
24871
  }
24866
24872
  },
24873
+ "/v1/tasks/{id}/refs": {
24874
+ get: {
24875
+ operationId: "listTaskGitRefs",
24876
+ summary: "List git branch and pull-request refs linked to a task",
24877
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
24878
+ responses: {
24879
+ "200": {
24880
+ content: {
24881
+ "application/json": {
24882
+ schema: {
24883
+ type: "object",
24884
+ additionalProperties: false,
24885
+ required: ["refs", "count"],
24886
+ properties: {
24887
+ refs: { type: "array", items: { $ref: "#/components/schemas/TaskGitRef" } },
24888
+ count: { type: "integer", minimum: 0 }
24889
+ }
24890
+ }
24891
+ }
24892
+ }
24893
+ }
24894
+ }
24895
+ },
24896
+ post: {
24897
+ operationId: "linkTaskGitRef",
24898
+ summary: "Link a git branch or pull-request ref to a task",
24899
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
24900
+ requestBody: {
24901
+ required: true,
24902
+ content: {
24903
+ "application/json": {
24904
+ schema: {
24905
+ type: "object",
24906
+ additionalProperties: false,
24907
+ required: ["ref_type", "name"],
24908
+ properties: {
24909
+ ref_type: { type: "string", enum: ["branch", "pull_request"] },
24910
+ name: { type: "string", minLength: 1 },
24911
+ url: { type: "string" },
24912
+ provider: { type: "string" },
24913
+ metadata: { type: "object", additionalProperties: true }
24914
+ }
24915
+ }
24916
+ }
24917
+ }
24918
+ },
24919
+ responses: {
24920
+ "201": {
24921
+ content: {
24922
+ "application/json": {
24923
+ schema: {
24924
+ type: "object",
24925
+ additionalProperties: false,
24926
+ required: ["ref"],
24927
+ properties: { ref: { $ref: "#/components/schemas/TaskGitRef" } }
24928
+ }
24929
+ }
24930
+ }
24931
+ }
24932
+ }
24933
+ }
24934
+ },
24935
+ "/v1/refs/{ref}": {
24936
+ get: {
24937
+ operationId: "findTaskGitRefs",
24938
+ summary: "Find task links by git branch or pull-request ref",
24939
+ parameters: [{ name: "ref", in: "path", required: true, schema: { type: "string" } }],
24940
+ responses: {
24941
+ "200": {
24942
+ content: {
24943
+ "application/json": {
24944
+ schema: {
24945
+ type: "object",
24946
+ additionalProperties: false,
24947
+ required: ["refs", "count"],
24948
+ properties: {
24949
+ refs: { type: "array", items: { $ref: "#/components/schemas/TaskGitRef" } },
24950
+ count: { type: "integer", minimum: 0 }
24951
+ }
24952
+ }
24953
+ }
24954
+ }
24955
+ }
24956
+ }
24957
+ }
24958
+ },
24867
24959
  "/v1/tasks/{id}/start": {
24868
24960
  post: {
24869
24961
  operationId: "startTask",
@@ -25315,7 +25407,7 @@ function buildV1OpenApiDocument(version = getPackageVersion()) {
25315
25407
  }
25316
25408
  };
25317
25409
  }
25318
- var taskSchema, projectSchema, taskListSchema, projectTaskListEnsureReceiptSchema, projectTaskListEnsureResultSchema, projectTaskListRollbackResultSchema, taskCommentSchema, planSchema, planProjectLinkReceiptSchema, planProjectLinkResultSchema, planProjectLinkRollbackResultSchema, templateTaskSchema, templateSchema, templateVariableSchema, createTemplateTaskInputSchema;
25410
+ var taskSchema, projectSchema, taskListSchema, projectTaskListEnsureReceiptSchema, projectTaskListEnsureResultSchema, projectTaskListRollbackResultSchema, taskCommentSchema, taskGitRefSchema, planSchema, planProjectLinkReceiptSchema, planProjectLinkResultSchema, planProjectLinkRollbackResultSchema, templateTaskSchema, templateSchema, templateVariableSchema, createTemplateTaskInputSchema;
25319
25411
  var init_openapi = __esm(() => {
25320
25412
  init_package_version();
25321
25413
  init_types();
@@ -25328,6 +25420,7 @@ var init_openapi = __esm(() => {
25328
25420
  status: { type: "string" },
25329
25421
  priority: { type: "string" },
25330
25422
  project_id: { type: "string", nullable: true },
25423
+ parent_id: { type: "string", nullable: true },
25331
25424
  assigned_to: { type: "string", nullable: true },
25332
25425
  agent_id: { type: "string", nullable: true },
25333
25426
  tags: { type: "array", items: { type: "string" } },
@@ -25451,6 +25544,32 @@ var init_openapi = __esm(() => {
25451
25544
  created_at: { type: "string", format: "date-time" }
25452
25545
  }
25453
25546
  };
25547
+ taskGitRefSchema = {
25548
+ type: "object",
25549
+ additionalProperties: false,
25550
+ required: [
25551
+ "id",
25552
+ "task_id",
25553
+ "ref_type",
25554
+ "name",
25555
+ "url",
25556
+ "provider",
25557
+ "metadata",
25558
+ "created_at",
25559
+ "updated_at"
25560
+ ],
25561
+ properties: {
25562
+ id: { type: "string", minLength: 1 },
25563
+ task_id: { type: "string", minLength: 1 },
25564
+ ref_type: { type: "string", enum: ["branch", "pull_request"] },
25565
+ name: { type: "string", minLength: 1 },
25566
+ url: { type: "string", nullable: true },
25567
+ provider: { type: "string", nullable: true },
25568
+ metadata: { type: "object", additionalProperties: true },
25569
+ created_at: { type: "string", format: "date-time" },
25570
+ updated_at: { type: "string", format: "date-time" }
25571
+ }
25572
+ };
25454
25573
  planSchema = {
25455
25574
  type: "object",
25456
25575
  required: ["id", "slug", "name", "status", "created_at", "updated_at"],
@@ -26543,8 +26662,25 @@ async function handleV1Request(req, url, dependencies = {}) {
26543
26662
  if (!body || typeof body.title !== "string" || !body.title.trim()) {
26544
26663
  return error(400, "title is required");
26545
26664
  }
26546
- const task = await store.tasks.create(body, contextFromPrincipal(principal, body));
26547
- return json4({ task }, 201);
26665
+ const storageContext = contextFromPrincipal(principal, body);
26666
+ if (body.parent_id !== undefined) {
26667
+ if (typeof body.parent_id !== "string" || !body.parent_id.trim()) {
26668
+ return error(400, "parent_id must be a non-empty task id", {
26669
+ code: "PARENT_TASK_ID_INVALID"
26670
+ });
26671
+ }
26672
+ if (!await store.tasks.get(body.parent_id, storageContext)) {
26673
+ return error(404, `parent task not found: ${body.parent_id}`, {
26674
+ code: "PARENT_TASK_NOT_FOUND"
26675
+ });
26676
+ }
26677
+ }
26678
+ const created = await store.tasks.create(body, storageContext);
26679
+ const persisted = created?.id ? await store.tasks.get(created.id, storageContext) : null;
26680
+ if (!persisted || persisted.id !== created.id || (persisted.parent_id ?? null) !== (body.parent_id ?? null)) {
26681
+ return error(500, "TASK_CREATE_PERSISTENCE_UNVERIFIED: task create was acknowledged but authoritative readback did not return the same stored task id and parent_id", { code: "TASK_CREATE_PERSISTENCE_UNVERIFIED" });
26682
+ }
26683
+ return json4({ task: persisted }, 201);
26548
26684
  }
26549
26685
  return error(405, `method ${method} not allowed on /v1/tasks`);
26550
26686
  }
@@ -27318,6 +27454,9 @@ async function handleV1Request(req, url, dependencies = {}) {
27318
27454
  candidate_task_ids: e.candidateTaskIds
27319
27455
  });
27320
27456
  }
27457
+ if (e instanceof TaskNotFoundError) {
27458
+ return error(404, e.message, { code: TaskNotFoundError.code });
27459
+ }
27321
27460
  if (e instanceof LockError)
27322
27461
  return error(409, e.message, { code: LockError.code });
27323
27462
  if (e instanceof TaskNotStartableError) {
@@ -62341,6 +62480,12 @@ function toListQuery(filter = {}) {
62341
62480
  query["offset"] = filter.offset;
62342
62481
  return query;
62343
62482
  }
62483
+ function priorityRank(priority) {
62484
+ return PRIORITY_RANK[priority ?? ""] ?? 4;
62485
+ }
62486
+ function compareCloudTaskOrder(a, b) {
62487
+ return priorityRank(a.priority) - priorityRank(b.priority) || b.created_at.localeCompare(a.created_at) || a.id.localeCompare(b.id);
62488
+ }
62344
62489
  async function fetchListTagsCapability(client) {
62345
62490
  const document = await requiredRemoteRoute(client, "/v1/openapi.json", () => client.transport.get("/openapi.json"));
62346
62491
  if (!document || typeof document !== "object" || Array.isArray(document))
@@ -62362,19 +62507,59 @@ async function requireTagsFilterCapability(client) {
62362
62507
  throw new Error(`REMOTE_TAGS_FILTER_UNSUPPORTED: configured Todos authority ${authority} does not advertise the tags ` + "query param on GET /v1/tasks; deploy the current @hasna/todos /v1 server to filter by tag; " + "no unfiltered task read was issued");
62363
62508
  }
62364
62509
  }
62365
- async function cloudListTasks(client, filter = {}) {
62366
- if (filter.tags?.length)
62367
- await requireTagsFilterCapability(client);
62510
+ async function requestCloudTaskPage(client, filter) {
62368
62511
  const res = await requiredRemoteRoute(client, "/v1/tasks", () => client.list("tasks", { query: toListQuery(filter) }));
62369
62512
  const envelope = res.raw;
62370
62513
  return Array.isArray(envelope?.tasks) ? envelope.tasks : res.items;
62371
62514
  }
62515
+ async function cloudListTasks(client, filter = {}) {
62516
+ if (filter.tags?.length)
62517
+ await requireTagsFilterCapability(client);
62518
+ const statuses = Array.isArray(filter.status) ? filter.status : undefined;
62519
+ if (!statuses)
62520
+ return requestCloudTaskPage(client, filter);
62521
+ if (statuses.length === 0) {
62522
+ const { status: _status2, ...unfiltered } = filter;
62523
+ return requestCloudTaskPage(client, unfiltered);
62524
+ }
62525
+ if (statuses.length === 1) {
62526
+ return requestCloudTaskPage(client, { ...filter, status: statuses[0] });
62527
+ }
62528
+ const { status: _status, limit, offset, ...baseFilter } = filter;
62529
+ const start = offset ?? 0;
62530
+ const windowEnd = typeof limit === "number" ? start + limit : undefined;
62531
+ const pages = await Promise.all(statuses.map((status) => requestCloudTaskPage(client, {
62532
+ ...baseFilter,
62533
+ status,
62534
+ ...windowEnd === undefined ? {} : { limit: windowEnd }
62535
+ })));
62536
+ const seen = new Set;
62537
+ const union3 = pages.flat().filter((task) => {
62538
+ if (seen.has(task.id))
62539
+ return false;
62540
+ seen.add(task.id);
62541
+ return true;
62542
+ });
62543
+ union3.sort(compareCloudTaskOrder);
62544
+ return union3.slice(start, windowEnd);
62545
+ }
62372
62546
  async function cloudGetTask(client, id) {
62373
62547
  const raw = await client.get("tasks", id);
62374
62548
  return raw == null ? null : unwrapTask(raw);
62375
62549
  }
62376
62550
  async function cloudCreateTask(client, input) {
62377
- return unwrapTask(await requiredRemoteRoute(client, "/v1/tasks", () => client.create("tasks", input)));
62551
+ const expectedParentId = typeof input["parent_id"] === "string" ? input["parent_id"] : null;
62552
+ const created = unwrapTask(await requiredRemoteRoute(client, "/v1/tasks", () => expectedParentId === null ? client.create("tasks", input) : client.create("tasks", input, { retry: false }), ["PARENT_TASK_NOT_FOUND"]));
62553
+ if (!created || typeof created.id !== "string" || !created.id.trim()) {
62554
+ throw new Error(`REMOTE_API_INCOMPATIBLE: configured Todos authority ${remoteAuthorityBase(client)} returned a task create ` + "response without a stored task id; no success row or local SQLite fallback is permitted");
62555
+ }
62556
+ if (expectedParentId === null)
62557
+ return created;
62558
+ const persisted = await cloudGetTask(client, created.id);
62559
+ if (!persisted || persisted.id !== created.id || (persisted.parent_id ?? null) !== expectedParentId) {
62560
+ throw new Error(`TASK_CREATE_PERSISTENCE_UNVERIFIED: configured Todos authority ${remoteAuthorityBase(client)} accepted ` + `POST /v1/tasks but authoritative GET /v1/tasks/${encodeURIComponent(created.id)} did not return the same ` + "stored task id and parent_id; no success row or local SQLite fallback is permitted");
62561
+ }
62562
+ return persisted;
62378
62563
  }
62379
62564
  async function cloudUpdateTask(client, id, patch) {
62380
62565
  return unwrapTask(await client.update("tasks", id, patch));
@@ -62583,7 +62768,7 @@ async function cloudResolveTaskListRef(client, ref, projectId) {
62583
62768
  }
62584
62769
  throw new Error(`Task list not found: "${input}"`);
62585
62770
  }
62586
- var UUID_RE, TRANSPORT_TOKENS, completionCapabilityCache, SERVER_MODE_CANDIDATES, cachedServerMode = null, listTagsCapabilityCache;
62771
+ var UUID_RE, TRANSPORT_TOKENS, completionCapabilityCache, gitRefCapabilityCache, SERVER_MODE_CANDIDATES, cachedServerMode = null, PRIORITY_RANK, listTagsCapabilityCache;
62587
62772
  var init_cloud_router = __esm(() => {
62588
62773
  init_storage();
62589
62774
  init_mode();
@@ -62602,7 +62787,9 @@ var init_cloud_router = __esm(() => {
62602
62787
  hybrid: "http"
62603
62788
  };
62604
62789
  completionCapabilityCache = new Map;
62790
+ gitRefCapabilityCache = new Map;
62605
62791
  SERVER_MODE_CANDIDATES = ["postgres", "cloud", "self_hosted"];
62792
+ PRIORITY_RANK = { critical: 0, high: 1, medium: 2, low: 3 };
62606
62793
  listTagsCapabilityCache = new Map;
62607
62794
  });
62608
62795
 
@@ -39,6 +39,10 @@ export declare function buildV1OpenApiDocument(version?: string): {
39
39
  readonly type: "string";
40
40
  readonly nullable: true;
41
41
  };
42
+ readonly parent_id: {
43
+ readonly type: "string";
44
+ readonly nullable: true;
45
+ };
42
46
  readonly assigned_to: {
43
47
  readonly type: "string";
44
48
  readonly nullable: true;
@@ -271,6 +275,49 @@ export declare function buildV1OpenApiDocument(version?: string): {
271
275
  };
272
276
  };
273
277
  };
278
+ TaskGitRef: {
279
+ readonly type: "object";
280
+ readonly additionalProperties: false;
281
+ readonly required: readonly ["id", "task_id", "ref_type", "name", "url", "provider", "metadata", "created_at", "updated_at"];
282
+ readonly properties: {
283
+ readonly id: {
284
+ readonly type: "string";
285
+ readonly minLength: 1;
286
+ };
287
+ readonly task_id: {
288
+ readonly type: "string";
289
+ readonly minLength: 1;
290
+ };
291
+ readonly ref_type: {
292
+ readonly type: "string";
293
+ readonly enum: readonly ["branch", "pull_request"];
294
+ };
295
+ readonly name: {
296
+ readonly type: "string";
297
+ readonly minLength: 1;
298
+ };
299
+ readonly url: {
300
+ readonly type: "string";
301
+ readonly nullable: true;
302
+ };
303
+ readonly provider: {
304
+ readonly type: "string";
305
+ readonly nullable: true;
306
+ };
307
+ readonly metadata: {
308
+ readonly type: "object";
309
+ readonly additionalProperties: true;
310
+ };
311
+ readonly created_at: {
312
+ readonly type: "string";
313
+ readonly format: "date-time";
314
+ };
315
+ readonly updated_at: {
316
+ readonly type: "string";
317
+ readonly format: "date-time";
318
+ };
319
+ };
320
+ };
274
321
  Plan: {
275
322
  readonly type: "object";
276
323
  readonly required: readonly ["id", "slug", "name", "status", "created_at", "updated_at"];
@@ -674,6 +721,9 @@ export declare function buildV1OpenApiDocument(version?: string): {
674
721
  project_id: {
675
722
  type: string;
676
723
  };
724
+ parent_id: {
725
+ type: string;
726
+ };
677
727
  plan_id: {
678
728
  type: string;
679
729
  };
@@ -2600,6 +2650,146 @@ export declare function buildV1OpenApiDocument(version?: string): {
2600
2650
  };
2601
2651
  };
2602
2652
  };
2653
+ "/v1/tasks/{id}/refs": {
2654
+ get: {
2655
+ operationId: string;
2656
+ summary: string;
2657
+ parameters: {
2658
+ name: string;
2659
+ in: string;
2660
+ required: boolean;
2661
+ schema: {
2662
+ type: string;
2663
+ };
2664
+ }[];
2665
+ responses: {
2666
+ "200": {
2667
+ content: {
2668
+ "application/json": {
2669
+ schema: {
2670
+ type: string;
2671
+ additionalProperties: boolean;
2672
+ required: string[];
2673
+ properties: {
2674
+ refs: {
2675
+ type: string;
2676
+ items: {
2677
+ $ref: string;
2678
+ };
2679
+ };
2680
+ count: {
2681
+ type: string;
2682
+ minimum: number;
2683
+ };
2684
+ };
2685
+ };
2686
+ };
2687
+ };
2688
+ };
2689
+ };
2690
+ };
2691
+ post: {
2692
+ operationId: string;
2693
+ summary: string;
2694
+ parameters: {
2695
+ name: string;
2696
+ in: string;
2697
+ required: boolean;
2698
+ schema: {
2699
+ type: string;
2700
+ };
2701
+ }[];
2702
+ requestBody: {
2703
+ required: boolean;
2704
+ content: {
2705
+ "application/json": {
2706
+ schema: {
2707
+ type: string;
2708
+ additionalProperties: boolean;
2709
+ required: string[];
2710
+ properties: {
2711
+ ref_type: {
2712
+ type: string;
2713
+ enum: string[];
2714
+ };
2715
+ name: {
2716
+ type: string;
2717
+ minLength: number;
2718
+ };
2719
+ url: {
2720
+ type: string;
2721
+ };
2722
+ provider: {
2723
+ type: string;
2724
+ };
2725
+ metadata: {
2726
+ type: string;
2727
+ additionalProperties: boolean;
2728
+ };
2729
+ };
2730
+ };
2731
+ };
2732
+ };
2733
+ };
2734
+ responses: {
2735
+ "201": {
2736
+ content: {
2737
+ "application/json": {
2738
+ schema: {
2739
+ type: string;
2740
+ additionalProperties: boolean;
2741
+ required: string[];
2742
+ properties: {
2743
+ ref: {
2744
+ $ref: string;
2745
+ };
2746
+ };
2747
+ };
2748
+ };
2749
+ };
2750
+ };
2751
+ };
2752
+ };
2753
+ };
2754
+ "/v1/refs/{ref}": {
2755
+ get: {
2756
+ operationId: string;
2757
+ summary: string;
2758
+ parameters: {
2759
+ name: string;
2760
+ in: string;
2761
+ required: boolean;
2762
+ schema: {
2763
+ type: string;
2764
+ };
2765
+ }[];
2766
+ responses: {
2767
+ "200": {
2768
+ content: {
2769
+ "application/json": {
2770
+ schema: {
2771
+ type: string;
2772
+ additionalProperties: boolean;
2773
+ required: string[];
2774
+ properties: {
2775
+ refs: {
2776
+ type: string;
2777
+ items: {
2778
+ $ref: string;
2779
+ };
2780
+ };
2781
+ count: {
2782
+ type: string;
2783
+ minimum: number;
2784
+ };
2785
+ };
2786
+ };
2787
+ };
2788
+ };
2789
+ };
2790
+ };
2791
+ };
2792
+ };
2603
2793
  "/v1/tasks/{id}/start": {
2604
2794
  post: {
2605
2795
  operationId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../../src/server/openapi.ts"],"names":[],"mappings":"AA0SA,wBAAgB,sBAAsB,CAAC,OAAO,SAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAi5CnE"}
1
+ {"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../../src/server/openapi.ts"],"names":[],"mappings":"AA+TA,wBAAgB,sBAAsB,CAAC,OAAO,SAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAy+CnE"}
@@ -1 +1 @@
1
- {"version":3,"file":"v1.d.ts","sourceRoot":"","sources":["../../src/server/v1.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAuB,oBAAoB,EAAmD,MAAM,0BAA0B,CAAC;AAC3I,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,oCAAoC,EACpC,sBAAsB,EACtB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAmBpB,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,OAAO,gBAAgB,CAAC;IACtC,YAAY,CAAC,EAAE,OAAO,iBAAiB,CAAC;IACxC,iBAAiB,CAAC,EAAE,OAAO,sBAAsB,CAAC;IAClD,gBAAgB,CAAC,EAAE,OAAO,qBAAqB,CAAC;IAChD,+BAA+B,CAAC,EAAE,OAAO,oCAAoC,CAAC;CAC/E;AAwVD;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,oBAAoB,CAiB1E;AAED,gFAAgF;AAChF,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAapE;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,YAAY,GAAE,qBAA0B,GACvC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAwiC1B"}
1
+ {"version":3,"file":"v1.d.ts","sourceRoot":"","sources":["../../src/server/v1.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAuB,oBAAoB,EAAmD,MAAM,0BAA0B,CAAC;AAC3I,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,oCAAoC,EACpC,sBAAsB,EACtB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAmBpB,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,OAAO,gBAAgB,CAAC;IACtC,YAAY,CAAC,EAAE,OAAO,iBAAiB,CAAC;IACxC,iBAAiB,CAAC,EAAE,OAAO,sBAAsB,CAAC;IAClD,gBAAgB,CAAC,EAAE,OAAO,qBAAqB,CAAC;IAChD,+BAA+B,CAAC,EAAE,OAAO,oCAAoC,CAAC;CAC/E;AAwVD;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,oBAAoB,CAiB1E;AAED,gFAAgF;AAChF,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAapE;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,YAAY,GAAE,qBAA0B,GACvC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAukC1B"}
package/dist/storage.js CHANGED
@@ -15114,6 +15114,7 @@ class PostgresJsonRecordStore {
15114
15114
  const current = await this.get(type, value.id);
15115
15115
  if (current)
15116
15116
  return current;
15117
+ throw new Error(`POSTGRES_WRITE_PERSISTENCE_UNVERIFIED: ${type} ${value.id} was not accepted and no persisted readback exists`);
15117
15118
  }
15118
15119
  return value;
15119
15120
  }
@@ -15885,6 +15886,9 @@ class PostgresJsonRecordStore {
15885
15886
  }
15886
15887
  async function createTask2(input, store, context) {
15887
15888
  const timestamp2 = new Date().toISOString();
15889
+ if (input.parent_id && !await store.get("tasks", input.parent_id)) {
15890
+ throw new TaskNotFoundError(input.parent_id);
15891
+ }
15888
15892
  const linkedPlan = input.plan_id ? await store.get("plans", input.plan_id) : null;
15889
15893
  const requestedProjectId = input.project_id ?? context?.projectId ?? null;
15890
15894
  if (linkedPlan?.project_id && requestedProjectId && requestedProjectId !== linkedPlan.project_id) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/todos",
3
- "version": "0.15.11",
3
+ "version": "0.15.13",
4
4
  "description": "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",