@hasna/todos 0.11.90 → 0.11.92

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 (37) hide show
  1. package/README.md +7 -2
  2. package/dist/cli/cloud-router.d.ts +57 -25
  3. package/dist/cli/cloud-router.d.ts.map +1 -1
  4. package/dist/cli/commands/agent-commands.d.ts.map +1 -1
  5. package/dist/cli/commands/plan-template-commands.d.ts.map +1 -1
  6. package/dist/cli/commands/project-commands.d.ts.map +1 -1
  7. package/dist/cli/commands/query-commands.d.ts.map +1 -1
  8. package/dist/cli/commands/storage-commands.d.ts.map +1 -1
  9. package/dist/cli/commands/task-commands.d.ts.map +1 -1
  10. package/dist/cli/helpers.d.ts +15 -1
  11. package/dist/cli/helpers.d.ts.map +1 -1
  12. package/dist/cli/index.js +19594 -30654
  13. package/dist/cli/output-redaction.d.ts +5 -0
  14. package/dist/cli/output-redaction.d.ts.map +1 -0
  15. package/dist/cli/stage-a.d.ts +45 -0
  16. package/dist/cli/stage-a.d.ts.map +1 -0
  17. package/dist/contracts.js +196 -97
  18. package/dist/index.js +517 -313
  19. package/dist/lib/package-version.d.ts +1 -1
  20. package/dist/lib/package-version.d.ts.map +1 -1
  21. package/dist/lib/redaction.d.ts.map +1 -1
  22. package/dist/lib/tmux.d.ts.map +1 -1
  23. package/dist/mcp/index.js +837 -6847
  24. package/dist/mcp.js +118 -20
  25. package/dist/registry.js +196 -97
  26. package/dist/release-provenance.json +5 -3
  27. package/dist/sdk/index.js +37 -2
  28. package/dist/sdk/v1.generated.d.ts +72 -3
  29. package/dist/sdk/v1.generated.d.ts.map +1 -1
  30. package/dist/server/index.js +2213 -8136
  31. package/dist/server/openapi.d.ts +366 -2
  32. package/dist/server/openapi.d.ts.map +1 -1
  33. package/dist/server/v1.d.ts.map +1 -1
  34. package/dist/storage.js +112 -14
  35. package/dist/types/index.d.ts +2 -2
  36. package/dist/types/index.d.ts.map +1 -1
  37. package/package.json +9 -6
@@ -166,6 +166,50 @@ export declare function buildV1OpenApiDocument(version?: string): {
166
166
  };
167
167
  };
168
168
  };
169
+ Plan: {
170
+ readonly type: "object";
171
+ readonly required: readonly ["id", "slug", "name", "status", "created_at", "updated_at"];
172
+ readonly properties: {
173
+ readonly id: {
174
+ readonly type: "string";
175
+ };
176
+ readonly slug: {
177
+ readonly type: "string";
178
+ readonly nullable: true;
179
+ };
180
+ readonly project_id: {
181
+ readonly type: "string";
182
+ readonly nullable: true;
183
+ };
184
+ readonly task_list_id: {
185
+ readonly type: "string";
186
+ readonly nullable: true;
187
+ };
188
+ readonly agent_id: {
189
+ readonly type: "string";
190
+ readonly nullable: true;
191
+ };
192
+ readonly name: {
193
+ readonly type: "string";
194
+ };
195
+ readonly description: {
196
+ readonly type: "string";
197
+ readonly nullable: true;
198
+ };
199
+ readonly status: {
200
+ readonly type: "string";
201
+ readonly enum: readonly ["active", "completed", "archived"];
202
+ };
203
+ readonly created_at: {
204
+ readonly type: "string";
205
+ readonly format: "date-time";
206
+ };
207
+ readonly updated_at: {
208
+ readonly type: "string";
209
+ readonly format: "date-time";
210
+ };
211
+ };
212
+ };
169
213
  CreateTaskInput: {
170
214
  type: string;
171
215
  required: string[];
@@ -222,6 +266,44 @@ export declare function buildV1OpenApiDocument(version?: string): {
222
266
  };
223
267
  };
224
268
  };
269
+ CompleteTaskInput: {
270
+ type: string;
271
+ additionalProperties: boolean;
272
+ properties: {
273
+ agent_id: {
274
+ type: string;
275
+ minLength: number;
276
+ };
277
+ attachment_ids: {
278
+ type: string;
279
+ items: {
280
+ type: string;
281
+ minLength: number;
282
+ };
283
+ };
284
+ files_changed: {
285
+ type: string;
286
+ items: {
287
+ type: string;
288
+ minLength: number;
289
+ };
290
+ };
291
+ test_results: {
292
+ type: string;
293
+ };
294
+ commit_hash: {
295
+ type: string;
296
+ };
297
+ notes: {
298
+ type: string;
299
+ };
300
+ confidence: {
301
+ type: string;
302
+ minimum: number;
303
+ maximum: number;
304
+ };
305
+ };
306
+ };
225
307
  CreateProjectInput: {
226
308
  type: string;
227
309
  additionalProperties: boolean;
@@ -372,6 +454,72 @@ export declare function buildV1OpenApiDocument(version?: string): {
372
454
  };
373
455
  };
374
456
  };
457
+ CreatePlanInput: {
458
+ type: string;
459
+ additionalProperties: boolean;
460
+ required: string[];
461
+ properties: {
462
+ name: {
463
+ type: string;
464
+ minLength: number;
465
+ };
466
+ slug: {
467
+ type: string;
468
+ minLength: number;
469
+ pattern: string;
470
+ };
471
+ description: {
472
+ type: string;
473
+ };
474
+ project_id: {
475
+ type: string;
476
+ minLength: number;
477
+ };
478
+ task_list_id: {
479
+ type: string;
480
+ minLength: number;
481
+ };
482
+ agent_id: {
483
+ type: string;
484
+ minLength: number;
485
+ };
486
+ status: {
487
+ type: string;
488
+ enum: string[];
489
+ };
490
+ };
491
+ };
492
+ UpdatePlanInput: {
493
+ type: string;
494
+ additionalProperties: boolean;
495
+ minProperties: number;
496
+ properties: {
497
+ name: {
498
+ type: string;
499
+ minLength: number;
500
+ };
501
+ slug: {
502
+ type: string;
503
+ minLength: number;
504
+ pattern: string;
505
+ };
506
+ description: {
507
+ type: string;
508
+ };
509
+ task_list_id: {
510
+ type: string;
511
+ minLength: number;
512
+ };
513
+ agent_id: {
514
+ type: string;
515
+ minLength: number;
516
+ };
517
+ status: {
518
+ type: string;
519
+ enum: string[];
520
+ };
521
+ };
522
+ };
375
523
  };
376
524
  };
377
525
  security: {
@@ -382,19 +530,38 @@ export declare function buildV1OpenApiDocument(version?: string): {
382
530
  get: {
383
531
  operationId: string;
384
532
  summary: string;
385
- parameters: {
533
+ parameters: ({
386
534
  name: string;
387
535
  in: string;
388
536
  schema: {
389
537
  type: string;
538
+ nullable?: undefined;
539
+ minimum?: undefined;
390
540
  };
391
- }[];
541
+ } | {
542
+ name: string;
543
+ in: string;
544
+ schema: {
545
+ type: string;
546
+ nullable: boolean;
547
+ minimum?: undefined;
548
+ };
549
+ } | {
550
+ name: string;
551
+ in: string;
552
+ schema: {
553
+ type: string;
554
+ minimum: number;
555
+ nullable?: undefined;
556
+ };
557
+ })[];
392
558
  responses: {
393
559
  "200": {
394
560
  content: {
395
561
  "application/json": {
396
562
  schema: {
397
563
  type: string;
564
+ required: string[];
398
565
  properties: {
399
566
  tasks: {
400
567
  type: string;
@@ -404,6 +571,11 @@ export declare function buildV1OpenApiDocument(version?: string): {
404
571
  };
405
572
  count: {
406
573
  type: string;
574
+ minimum: number;
575
+ };
576
+ total: {
577
+ type: string;
578
+ minimum: number;
407
579
  };
408
580
  };
409
581
  };
@@ -697,6 +869,16 @@ export declare function buildV1OpenApiDocument(version?: string): {
697
869
  type: string;
698
870
  };
699
871
  }[];
872
+ requestBody: {
873
+ required: boolean;
874
+ content: {
875
+ "application/json": {
876
+ schema: {
877
+ $ref: string;
878
+ };
879
+ };
880
+ };
881
+ };
700
882
  responses: {
701
883
  "200": {
702
884
  content: {
@@ -933,6 +1115,188 @@ export declare function buildV1OpenApiDocument(version?: string): {
933
1115
  };
934
1116
  };
935
1117
  };
1118
+ "/v1/plans": {
1119
+ get: {
1120
+ operationId: string;
1121
+ summary: string;
1122
+ parameters: {
1123
+ name: string;
1124
+ in: string;
1125
+ schema: {
1126
+ type: string;
1127
+ };
1128
+ }[];
1129
+ responses: {
1130
+ "200": {
1131
+ content: {
1132
+ "application/json": {
1133
+ schema: {
1134
+ type: string;
1135
+ properties: {
1136
+ plans: {
1137
+ type: string;
1138
+ items: {
1139
+ $ref: string;
1140
+ };
1141
+ };
1142
+ count: {
1143
+ type: string;
1144
+ };
1145
+ };
1146
+ };
1147
+ };
1148
+ };
1149
+ };
1150
+ };
1151
+ };
1152
+ post: {
1153
+ operationId: string;
1154
+ summary: string;
1155
+ requestBody: {
1156
+ required: boolean;
1157
+ content: {
1158
+ "application/json": {
1159
+ schema: {
1160
+ $ref: string;
1161
+ };
1162
+ };
1163
+ };
1164
+ };
1165
+ responses: {
1166
+ "201": {
1167
+ content: {
1168
+ "application/json": {
1169
+ schema: {
1170
+ type: string;
1171
+ properties: {
1172
+ plan: {
1173
+ $ref: string;
1174
+ };
1175
+ };
1176
+ };
1177
+ };
1178
+ };
1179
+ };
1180
+ "409": {
1181
+ content: {
1182
+ "application/json": {
1183
+ schema: {
1184
+ $ref: string;
1185
+ };
1186
+ };
1187
+ };
1188
+ };
1189
+ };
1190
+ };
1191
+ };
1192
+ "/v1/plans/{id}": {
1193
+ get: {
1194
+ operationId: string;
1195
+ summary: string;
1196
+ parameters: {
1197
+ name: string;
1198
+ in: string;
1199
+ required: boolean;
1200
+ schema: {
1201
+ type: string;
1202
+ };
1203
+ }[];
1204
+ responses: {
1205
+ "200": {
1206
+ content: {
1207
+ "application/json": {
1208
+ schema: {
1209
+ type: string;
1210
+ properties: {
1211
+ plan: {
1212
+ $ref: string;
1213
+ };
1214
+ };
1215
+ };
1216
+ };
1217
+ };
1218
+ };
1219
+ };
1220
+ };
1221
+ patch: {
1222
+ operationId: string;
1223
+ summary: string;
1224
+ parameters: {
1225
+ name: string;
1226
+ in: string;
1227
+ required: boolean;
1228
+ schema: {
1229
+ type: string;
1230
+ };
1231
+ }[];
1232
+ requestBody: {
1233
+ required: boolean;
1234
+ content: {
1235
+ "application/json": {
1236
+ schema: {
1237
+ $ref: string;
1238
+ };
1239
+ };
1240
+ };
1241
+ };
1242
+ responses: {
1243
+ "200": {
1244
+ content: {
1245
+ "application/json": {
1246
+ schema: {
1247
+ type: string;
1248
+ properties: {
1249
+ plan: {
1250
+ $ref: string;
1251
+ };
1252
+ };
1253
+ };
1254
+ };
1255
+ };
1256
+ };
1257
+ "409": {
1258
+ content: {
1259
+ "application/json": {
1260
+ schema: {
1261
+ $ref: string;
1262
+ };
1263
+ };
1264
+ };
1265
+ };
1266
+ };
1267
+ };
1268
+ delete: {
1269
+ operationId: string;
1270
+ summary: string;
1271
+ parameters: {
1272
+ name: string;
1273
+ in: string;
1274
+ required: boolean;
1275
+ schema: {
1276
+ type: string;
1277
+ };
1278
+ }[];
1279
+ responses: {
1280
+ "200": {
1281
+ content: {
1282
+ "application/json": {
1283
+ schema: {
1284
+ type: string;
1285
+ properties: {
1286
+ deleted: {
1287
+ type: string;
1288
+ };
1289
+ id: {
1290
+ type: string;
1291
+ };
1292
+ };
1293
+ };
1294
+ };
1295
+ };
1296
+ };
1297
+ };
1298
+ };
1299
+ };
936
1300
  "/v1/task-lists": {
937
1301
  get: {
938
1302
  operationId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../../src/server/openapi.ts"],"names":[],"mappings":"AAqEA,wBAAgB,sBAAsB,CAAC,OAAO,SAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAydnE"}
1
+ {"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../../src/server/openapi.ts"],"names":[],"mappings":"AAsFA,wBAAgB,sBAAsB,CAAC,OAAO,SAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+jBnE"}
@@ -1 +1 @@
1
- {"version":3,"file":"v1.d.ts","sourceRoot":"","sources":["../../src/server/v1.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAuB,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAC1F,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAIzF,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,OAAO,gBAAgB,CAAC;IACtC,YAAY,CAAC,EAAE,OAAO,iBAAiB,CAAC;IACxC,iBAAiB,CAAC,EAAE,OAAO,sBAAsB,CAAC;CACnD;AA4FD;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,oBAAoB,CAgB1E;AAED,gFAAgF;AAChF,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAYpE;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,YAAY,GAAE,qBAA0B,GACvC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAyuB1B"}
1
+ {"version":3,"file":"v1.d.ts","sourceRoot":"","sources":["../../src/server/v1.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAuB,oBAAoB,EAA8B,MAAM,0BAA0B,CAAC;AACtH,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAIzF,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,OAAO,gBAAgB,CAAC;IACtC,YAAY,CAAC,EAAE,OAAO,iBAAiB,CAAC;IACxC,iBAAiB,CAAC,EAAE,OAAO,sBAAsB,CAAC;CACnD;AAuLD;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,oBAAoB,CAgB1E;AAED,gFAAgF;AAChF,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAYpE;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,YAAY,GAAE,qBAA0B,GACvC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAozB1B"}
package/dist/storage.js CHANGED
@@ -4139,7 +4139,8 @@ var init_redaction = __esm(() => {
4139
4139
  "input_tokens",
4140
4140
  "output_tokens",
4141
4141
  "prompt_tokens",
4142
- "completion_tokens"
4142
+ "completion_tokens",
4143
+ "cost_tokens"
4143
4144
  ]);
4144
4145
  });
4145
4146
 
@@ -12352,7 +12353,7 @@ function createPostgresTodosStorageAdapter(options) {
12352
12353
  get: (id) => store.get("plans", id),
12353
12354
  list: async (projectId) => (await store.list("plans")).filter((plan) => projectId === undefined || plan.project_id === projectId).sort((a, b) => a.name.localeCompare(b.name)),
12354
12355
  update: (id, input) => updatePlan2(id, input, store),
12355
- delete: (id, context) => store.delete("plans", id, context)
12356
+ delete: (id, context) => store.deletePlan(id, context)
12356
12357
  },
12357
12358
  agents: {
12358
12359
  register: (input, context) => registerAgent2(input, store, context),
@@ -12636,6 +12637,62 @@ class PostgresJsonRecordStore {
12636
12637
  }
12637
12638
  return value;
12638
12639
  }
12640
+ async completeTask(id, agentId, options) {
12641
+ await this.ensureSchema();
12642
+ const operationTimestamp = new Date().toISOString();
12643
+ const completedAt = options?.completed_at ?? operationTimestamp;
12644
+ const evidence = options ? {
12645
+ ...options.files_changed !== undefined ? { files_changed: options.files_changed } : {},
12646
+ ...options.test_results !== undefined ? { test_results: options.test_results } : {},
12647
+ ...options.commit_hash !== undefined ? { commit_hash: options.commit_hash } : {},
12648
+ ...options.notes !== undefined ? { notes: options.notes } : {},
12649
+ ...options.attachment_ids !== undefined ? { attachment_ids: options.attachment_ids } : {}
12650
+ } : {};
12651
+ const hasEvidence = Object.keys(evidence).length > 0;
12652
+ const hasConfidence = options?.confidence !== undefined;
12653
+ const result = await this.options.client.query(`/* todos:complete-task-atomic */ UPDATE ${this.tableName}
12654
+ SET payload = payload || jsonb_build_object(
12655
+ 'status', 'completed',
12656
+ 'assigned_to', CASE
12657
+ WHEN jsonb_typeof(payload->'assigned_to') = 'string' THEN payload->'assigned_to'
12658
+ ELSE COALESCE(to_jsonb($3::text), 'null'::jsonb)
12659
+ END,
12660
+ 'completed_at', $4::text,
12661
+ 'updated_at', $9::text,
12662
+ 'version', COALESCE((payload->>'version')::integer, 0) + 1,
12663
+ 'metadata',
12664
+ (CASE WHEN jsonb_typeof(payload->'metadata') = 'object'
12665
+ THEN payload->'metadata' ELSE '{}'::jsonb END)
12666
+ || CASE WHEN $5::boolean THEN jsonb_build_object(
12667
+ '_evidence',
12668
+ (CASE WHEN jsonb_typeof(payload->'metadata'->'_evidence') = 'object'
12669
+ THEN payload->'metadata'->'_evidence' ELSE '{}'::jsonb END) || $6::jsonb
12670
+ ) ELSE '{}'::jsonb END
12671
+ || CASE WHEN $7::boolean THEN jsonb_build_object(
12672
+ '_completion',
12673
+ (CASE WHEN jsonb_typeof(payload->'metadata'->'_completion') = 'object'
12674
+ THEN payload->'metadata'->'_completion' ELSE '{}'::jsonb END)
12675
+ || jsonb_build_object('confidence', $8::double precision)
12676
+ ) ELSE '{}'::jsonb END
12677
+ ) || CASE WHEN $7::boolean
12678
+ THEN jsonb_build_object('confidence', $8::double precision)
12679
+ ELSE '{}'::jsonb END,
12680
+ updated_at = $9::timestamptz,
12681
+ version = COALESCE(version, 0) + 1
12682
+ WHERE service = $1 AND object_type = 'tasks' AND object_id = $2 AND deleted_at IS NULL
12683
+ RETURNING payload`, [
12684
+ this.service,
12685
+ id,
12686
+ agentId ?? null,
12687
+ completedAt,
12688
+ hasEvidence,
12689
+ jsonbParam(evidence),
12690
+ hasConfidence,
12691
+ options?.confidence ?? null,
12692
+ operationTimestamp
12693
+ ]);
12694
+ return result.rows[0] ? payloadRecord2(result.rows[0].payload) : null;
12695
+ }
12639
12696
  async renameProject(id, newSlug, name, context = {}) {
12640
12697
  await this.ensureSchema();
12641
12698
  const normalizedSlug = slugifyRaw(newSlug);
@@ -12752,6 +12809,41 @@ class PostgresJsonRecordStore {
12752
12809
  version: numberValue2(existing["version"])
12753
12810
  }, context);
12754
12811
  }
12812
+ async deletePlan(id, context = {}) {
12813
+ await this.ensureSchema();
12814
+ const timestamp = new Date().toISOString();
12815
+ const result = await this.options.client.query(`/* todos:delete-plan-atomic */ WITH target AS (
12816
+ SELECT payload FROM ${this.tableName}
12817
+ WHERE service = $1 AND object_type = 'plans' AND object_id = $2 AND deleted_at IS NULL
12818
+ FOR UPDATE
12819
+ ), updated_tasks AS (
12820
+ UPDATE ${this.tableName} r SET
12821
+ payload = jsonb_set(
12822
+ jsonb_set(r.payload, '{plan_id}', 'null'::jsonb, true),
12823
+ '{version}',
12824
+ to_jsonb(COALESCE((r.payload->>'version')::int, 0) + 1),
12825
+ true
12826
+ ) || jsonb_build_object('updated_at', $3::text),
12827
+ updated_at = $3::timestamptz,
12828
+ source_machine_id = COALESCE($4, r.source_machine_id),
12829
+ version = COALESCE(r.version, 0) + 1
12830
+ WHERE r.service = $1 AND r.object_type = 'tasks' AND r.deleted_at IS NULL
12831
+ AND r.payload->>'plan_id' = $2 AND EXISTS (SELECT 1 FROM target)
12832
+ RETURNING 1
12833
+ ), deleted_plan AS (
12834
+ UPDATE ${this.tableName} r SET
12835
+ deleted_at = $3::timestamptz,
12836
+ updated_at = $3::timestamptz,
12837
+ source_machine_id = COALESCE($4, r.source_machine_id),
12838
+ version = COALESCE(r.version, 0) + 1
12839
+ FROM target
12840
+ WHERE r.service = $1 AND r.object_type = 'plans' AND r.object_id = $2 AND r.deleted_at IS NULL
12841
+ RETURNING 1
12842
+ ) SELECT
12843
+ EXISTS (SELECT 1 FROM target) AS found,
12844
+ (SELECT count(*) FROM updated_tasks) AS tasks_updated`, [this.service, id, timestamp, this.machineId(context)]);
12845
+ return Boolean(result.rows[0]?.found);
12846
+ }
12755
12847
  async tombstone(tombstone, context = {}) {
12756
12848
  await this.ensureSchema();
12757
12849
  const deletedAt = stringValue2(tombstone.deleted_at) ?? new Date().toISOString();
@@ -12905,14 +12997,10 @@ async function startTask2(id, agentId, store) {
12905
12997
  }, store);
12906
12998
  }
12907
12999
  async function completeTask2(id, agentId, options, store) {
12908
- const task = await requireRecord("tasks", id, store);
12909
- return patchTask(task, {
12910
- status: "completed",
12911
- assigned_to: task.assigned_to ?? agentId ?? null,
12912
- completed_at: options?.completed_at ?? new Date().toISOString(),
12913
- actual_minutes: task.actual_minutes,
12914
- confidence: options?.confidence ?? task.confidence
12915
- }, store);
13000
+ const task = await store.completeTask(id, agentId, options);
13001
+ if (!task)
13002
+ throw new Error(`tasks record not found: ${id}`);
13003
+ return task;
12916
13004
  }
12917
13005
  async function failTask2(id, agentId, reason, options, store) {
12918
13006
  const task = await requireRecord("tasks", id, store);
@@ -13486,8 +13574,9 @@ async function resolvePostgresPlanSlug(options) {
13486
13574
  const used = new Set(plans.filter((plan) => plan.project_id === options.projectId && plan.id !== options.excludeId && plan.slug).map((plan) => plan.slug));
13487
13575
  if (options.slug !== undefined) {
13488
13576
  const slug = normalizePlanSlug2(options.slug);
13489
- if (used.has(slug))
13490
- throw new Error(`Plan slug already exists in this scope: ${slug}`);
13577
+ if (used.has(slug)) {
13578
+ throw new ResourceConflictError("PLAN_SLUG_CONFLICT", `Plan slug already exists in this scope: ${slug}`);
13579
+ }
13491
13580
  return slug;
13492
13581
  }
13493
13582
  const base = planSlugBase3(options.name);
@@ -13525,13 +13614,22 @@ function numberValue2(value) {
13525
13614
  return typeof value === "number" && Number.isSafeInteger(value) ? value : null;
13526
13615
  }
13527
13616
  function isPostgresUniqueViolation(error) {
13528
- return typeof error === "object" && error !== null && error.code === "23505";
13617
+ if (typeof error !== "object" || error === null)
13618
+ return false;
13619
+ const candidate = error;
13620
+ const states = [candidate.code, candidate.errno, candidate.sqlState, candidate.sqlstate];
13621
+ if (typeof candidate.cause === "object" && candidate.cause !== null) {
13622
+ const cause = candidate.cause;
13623
+ states.push(cause.code, cause.errno, cause.sqlState, cause.sqlstate);
13624
+ }
13625
+ return states.some((state) => String(state) === "23505");
13529
13626
  }
13530
13627
  function postgresConstraintName(error) {
13531
13628
  if (typeof error !== "object" || error === null)
13532
13629
  return "";
13533
13630
  const candidate = error;
13534
- const constraint = candidate.constraint ?? candidate.constraint_name;
13631
+ const cause = typeof candidate.cause === "object" && candidate.cause !== null ? candidate.cause : undefined;
13632
+ const constraint = candidate.constraint ?? candidate.constraint_name ?? cause?.constraint ?? cause?.constraint_name;
13535
13633
  return typeof constraint === "string" ? constraint : "";
13536
13634
  }
13537
13635
 
@@ -904,8 +904,8 @@ export declare class ProjectNotFoundError extends Error {
904
904
  constructor(projectId: string);
905
905
  }
906
906
  export declare class ResourceConflictError extends Error {
907
- readonly code: "PROJECT_SLUG_CONFLICT" | "TASK_LIST_SLUG_CONFLICT";
908
- constructor(code: "PROJECT_SLUG_CONFLICT" | "TASK_LIST_SLUG_CONFLICT", message: string);
907
+ readonly code: "PROJECT_SLUG_CONFLICT" | "TASK_LIST_SLUG_CONFLICT" | "PLAN_SLUG_CONFLICT";
908
+ constructor(code: "PROJECT_SLUG_CONFLICT" | "TASK_LIST_SLUG_CONFLICT" | "PLAN_SLUG_CONFLICT", message: string);
909
909
  }
910
910
  export declare class PlanNotFoundError extends Error {
911
911
  planId: string;