@hasna/todos 0.15.15 → 0.15.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/contracts.js CHANGED
@@ -8949,8 +8949,8 @@ function failTask(id, agentId, reason, options, db) {
8949
8949
  const safeMeta = sanitizePreWriteValue(meta, "task.failure.metadata");
8950
8950
  const timestamp2 = now();
8951
8951
  const failTx = d.transaction(() => {
8952
- const res = d.run(`UPDATE tasks SET status = 'failed', locked_by = NULL, locked_at = NULL, metadata = ?, version = version + 1, updated_at = ?
8953
- WHERE id = ? AND version = ?`, [JSON.stringify(safeMeta), timestamp2, id, task.version]);
8952
+ const res = d.run(`UPDATE tasks SET status = 'failed', reason = ?, locked_by = NULL, locked_at = NULL, metadata = ?, version = version + 1, updated_at = ?
8953
+ WHERE id = ? AND version = ?`, [safeReason, JSON.stringify(safeMeta), timestamp2, id, task.version]);
8954
8954
  if (res.changes === 0) {
8955
8955
  const current = getTask(id, d);
8956
8956
  throw new VersionConflictError(id, task.version, current?.version ?? -1);
@@ -8962,6 +8962,7 @@ function failTask(id, agentId, reason, options, db) {
8962
8962
  status: "failed",
8963
8963
  locked_by: null,
8964
8964
  locked_at: null,
8965
+ reason: safeReason,
8965
8966
  metadata: safeMeta,
8966
8967
  version: task.version + 1,
8967
8968
  updated_at: timestamp2
@@ -12379,7 +12380,7 @@ var init_tasks = __esm(() => {
12379
12380
  // package.json
12380
12381
  var package_default = {
12381
12382
  name: "@hasna/todos",
12382
- version: "0.15.15",
12383
+ version: "0.15.17",
12383
12384
  description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
12384
12385
  type: "module",
12385
12386
  main: "dist/index.js",
@@ -1 +1 @@
1
- {"version":3,"file":"task-lifecycle.d.ts","sourceRoot":"","sources":["../../src/db/task-lifecycle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"task-lifecycle.d.ts","sourceRoot":"","sources":["../../src/db/task-lifecycle.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -8949,8 +8949,8 @@ function failTask(id, agentId, reason, options, db) {
8949
8949
  const safeMeta = sanitizePreWriteValue(meta, "task.failure.metadata");
8950
8950
  const timestamp2 = now();
8951
8951
  const failTx = d.transaction(() => {
8952
- const res = d.run(`UPDATE tasks SET status = 'failed', locked_by = NULL, locked_at = NULL, metadata = ?, version = version + 1, updated_at = ?
8953
- WHERE id = ? AND version = ?`, [JSON.stringify(safeMeta), timestamp2, id, task.version]);
8952
+ const res = d.run(`UPDATE tasks SET status = 'failed', reason = ?, locked_by = NULL, locked_at = NULL, metadata = ?, version = version + 1, updated_at = ?
8953
+ WHERE id = ? AND version = ?`, [safeReason, JSON.stringify(safeMeta), timestamp2, id, task.version]);
8954
8954
  if (res.changes === 0) {
8955
8955
  const current = getTask(id, d);
8956
8956
  throw new VersionConflictError(id, task.version, current?.version ?? -1);
@@ -8962,6 +8962,7 @@ function failTask(id, agentId, reason, options, db) {
8962
8962
  status: "failed",
8963
8963
  locked_by: null,
8964
8964
  locked_at: null,
8965
+ reason: safeReason,
8965
8966
  metadata: safeMeta,
8966
8967
  version: task.version + 1,
8967
8968
  updated_at: timestamp2
@@ -12492,7 +12493,7 @@ var init_dispatches = __esm(() => {
12492
12493
  // package.json
12493
12494
  var package_default = {
12494
12495
  name: "@hasna/todos",
12495
- version: "0.15.15",
12496
+ version: "0.15.17",
12496
12497
  description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
12497
12498
  type: "module",
12498
12499
  main: "dist/index.js",
@@ -39090,6 +39091,9 @@ init_types();
39090
39091
  // src/task-manifest/types.ts
39091
39092
  var TODOS_TASK_MANIFEST_ROUTE = "todos.task-manifest.v1";
39092
39093
  var TODOS_TASK_MANIFEST_SCHEMA_VERSION = 1;
39094
+ function supportsIdempotentOutboxDelivery(capability2) {
39095
+ return capability2 !== null && typeof capability2 === "object" && capability2["idempotent_outbox_delivery"] === true;
39096
+ }
39093
39097
 
39094
39098
  class TodosTaskManifestError extends Error {
39095
39099
  code;
@@ -39735,10 +39739,27 @@ class SqliteTodosTaskManifestBackend {
39735
39739
  SELECT 1 FROM todos_task_manifest_receipts r
39736
39740
  WHERE r.receipt_id = todos_task_manifest_outbox.apply_receipt_id
39737
39741
  AND r.tenant_id = ?
39742
+ AND r.authority = 'todos'
39743
+ AND r.route = 'todos.task-manifest.v1'
39744
+ AND r.schema_version = 1
39745
+ AND r.kind = 'apply'
39738
39746
  )`).run(deliveredAt, outboxId, this.tenantId);
39739
- if (result.changes !== 1) {
39740
- throw new TodosTaskManifestError("TODOS_TASK_MANIFEST_GRAPH_CONFLICT", `Pending outbox row not found: ${outboxId}`);
39741
- }
39747
+ if (result.changes === 1)
39748
+ return;
39749
+ const existing = this.db.query(`SELECT o.status
39750
+ FROM todos_task_manifest_outbox o
39751
+ JOIN todos_task_manifest_receipts r
39752
+ ON r.receipt_id = o.apply_receipt_id
39753
+ WHERE r.tenant_id = ?
39754
+ AND r.authority = 'todos'
39755
+ AND r.route = 'todos.task-manifest.v1'
39756
+ AND r.schema_version = 1
39757
+ AND r.kind = 'apply'
39758
+ AND o.id = ?
39759
+ LIMIT 1`).get(this.tenantId, outboxId);
39760
+ if (existing?.status === "delivered")
39761
+ return;
39762
+ throw new TodosTaskManifestError("TODOS_TASK_MANIFEST_GRAPH_CONFLICT", `Pending outbox row not found: ${outboxId}`);
39742
39763
  });
39743
39764
  }
39744
39765
  async compensate(input, receipt, compensationReceiptId, requestDigest, now4) {
@@ -40270,6 +40291,22 @@ class PostgresTodosTaskManifestBackend {
40270
40291
  async markOutboxDelivered(outboxId, deliveredAt) {
40271
40292
  await this.ensureSchema();
40272
40293
  await this.client.transaction(async (tx) => {
40294
+ const owned = await tx.query(`SELECT r.operation_id
40295
+ FROM todos_task_manifest_outbox o
40296
+ JOIN todos_task_manifest_receipts r
40297
+ ON r.receipt_id = o.apply_receipt_id
40298
+ WHERE r.tenant_id = $1
40299
+ AND r.authority = 'todos'
40300
+ AND r.route = 'todos.task-manifest.v1'
40301
+ AND r.schema_version = 1
40302
+ AND r.kind = 'apply'
40303
+ AND o.id = $2
40304
+ LIMIT 1`, [this.tenantId, outboxId]);
40305
+ const operationId = owned.rows[0]?.operation_id;
40306
+ if (operationId == null) {
40307
+ throw new TodosTaskManifestError("TODOS_TASK_MANIFEST_GRAPH_CONFLICT", `Pending outbox row not found: ${outboxId}`);
40308
+ }
40309
+ await tx.query("SELECT pg_advisory_xact_lock(hashtextextended($1, 0))", [`${this.service}\x1F${String(operationId)}`]);
40273
40310
  const result = await tx.query(`UPDATE todos_task_manifest_outbox
40274
40311
  SET status = 'delivered', delivered_at = $1, attempts = attempts + 1
40275
40312
  WHERE id = $2 AND status = 'pending'
@@ -40277,10 +40314,28 @@ class PostgresTodosTaskManifestBackend {
40277
40314
  SELECT 1 FROM todos_task_manifest_receipts r
40278
40315
  WHERE r.receipt_id = todos_task_manifest_outbox.apply_receipt_id
40279
40316
  AND r.tenant_id = $3
40317
+ AND r.authority = 'todos'
40318
+ AND r.route = 'todos.task-manifest.v1'
40319
+ AND r.schema_version = 1
40320
+ AND r.kind = 'apply'
40280
40321
  )
40281
40322
  RETURNING id`, [deliveredAt, outboxId, this.tenantId]);
40282
- if (!result.rows[0])
40283
- throw new TodosTaskManifestError("TODOS_TASK_MANIFEST_GRAPH_CONFLICT", `Pending outbox row not found: ${outboxId}`);
40323
+ if (result.rows[0])
40324
+ return;
40325
+ const existing = await tx.query(`SELECT o.status
40326
+ FROM todos_task_manifest_outbox o
40327
+ JOIN todos_task_manifest_receipts r
40328
+ ON r.receipt_id = o.apply_receipt_id
40329
+ WHERE r.tenant_id = $1
40330
+ AND r.authority = 'todos'
40331
+ AND r.route = 'todos.task-manifest.v1'
40332
+ AND r.schema_version = 1
40333
+ AND r.kind = 'apply'
40334
+ AND o.id = $2
40335
+ LIMIT 1`, [this.tenantId, outboxId]);
40336
+ if (existing.rows[0]?.status === "delivered")
40337
+ return;
40338
+ throw new TodosTaskManifestError("TODOS_TASK_MANIFEST_GRAPH_CONFLICT", `Pending outbox row not found: ${outboxId}`);
40284
40339
  });
40285
40340
  }
40286
40341
  async compensate(input, receipt, compensationReceiptId, requestDigest, now4) {
@@ -40312,7 +40367,13 @@ class PostgresTodosTaskManifestBackend {
40312
40367
  throw new TodosTaskManifestError("TODOS_TASK_MANIFEST_COMPENSATION_REFUSED", "Graph is not applied");
40313
40368
  const delivered = await tx.query(`SELECT o.id FROM todos_task_manifest_outbox o
40314
40369
  JOIN todos_task_manifest_receipts r ON r.receipt_id = o.apply_receipt_id
40315
- WHERE r.tenant_id = $1 AND o.apply_receipt_id = $2 AND o.status = 'delivered'
40370
+ WHERE r.tenant_id = $1
40371
+ AND r.authority = 'todos'
40372
+ AND r.route = 'todos.task-manifest.v1'
40373
+ AND r.schema_version = 1
40374
+ AND r.kind = 'apply'
40375
+ AND o.apply_receipt_id = $2
40376
+ AND o.status = 'delivered'
40316
40377
  LIMIT 1`, [this.tenantId, input.receipt_id]);
40317
40378
  if (delivered.rows[0])
40318
40379
  throw new TodosTaskManifestError("TODOS_TASK_MANIFEST_COMPENSATION_REFUSED", "Compensation refused: delivered outbox row exists");
@@ -40325,15 +40386,20 @@ class PostgresTodosTaskManifestBackend {
40325
40386
  },
40326
40387
  ...(manifest.effects ?? []).map((effect2) => ({ topic: effect2.topic, payload: effect2.payload }))
40327
40388
  ];
40328
- const outboxRows = await tx.query(`SELECT id, topic, payload, payload_digest, status, attempts, delivered_at
40329
- FROM todos_task_manifest_outbox
40330
- WHERE apply_receipt_id = $1
40389
+ const outboxRows = await tx.query(`SELECT o.id, o.topic, o.payload, o.payload_digest, o.status, o.attempts, o.delivered_at
40390
+ FROM todos_task_manifest_outbox o
40391
+ WHERE o.apply_receipt_id = $1
40331
40392
  AND EXISTS (
40332
40393
  SELECT 1 FROM todos_task_manifest_receipts r
40333
- WHERE r.receipt_id = todos_task_manifest_outbox.apply_receipt_id
40394
+ WHERE r.receipt_id = o.apply_receipt_id
40334
40395
  AND r.tenant_id = $2
40396
+ AND r.authority = 'todos'
40397
+ AND r.route = 'todos.task-manifest.v1'
40398
+ AND r.schema_version = 1
40399
+ AND r.kind = 'apply'
40335
40400
  )
40336
- ORDER BY id`, [input.receipt_id, this.tenantId]);
40401
+ ORDER BY o.id
40402
+ FOR UPDATE OF o`, [input.receipt_id, this.tenantId]);
40337
40403
  if (outboxRows.rows.length !== expectedEffects.length) {
40338
40404
  throw new TodosTaskManifestError("TODOS_TASK_MANIFEST_COMPENSATION_REFUSED", "Compensation refused: outbox changed since apply");
40339
40405
  }
@@ -40433,14 +40499,23 @@ class PostgresTodosTaskManifestBackend {
40433
40499
  }
40434
40500
  if (stored.rows.length !== managedIds.length)
40435
40501
  throw new TodosTaskManifestError("TODOS_TASK_MANIFEST_COMPENSATION_REFUSED", "Compensation refused: managed graph is incomplete");
40436
- await tx.query(`UPDATE todos_task_manifest_outbox
40502
+ const cancelled = await tx.query(`UPDATE todos_task_manifest_outbox
40437
40503
  SET status = 'cancelled'
40438
40504
  WHERE apply_receipt_id = $1 AND status = 'pending'
40439
40505
  AND EXISTS (
40440
40506
  SELECT 1 FROM todos_task_manifest_receipts r
40441
40507
  WHERE r.receipt_id = todos_task_manifest_outbox.apply_receipt_id
40442
40508
  AND r.tenant_id = $2
40443
- )`, [input.receipt_id, this.tenantId]);
40509
+ AND r.authority = 'todos'
40510
+ AND r.route = 'todos.task-manifest.v1'
40511
+ AND r.schema_version = 1
40512
+ AND r.kind = 'apply'
40513
+ )
40514
+ RETURNING id`, [input.receipt_id, this.tenantId]);
40515
+ const cancelledIds = new Set(cancelled.rows.map((row) => String(row.id)));
40516
+ if (cancelledIds.size !== applyResult.outbox_ids.length || applyResult.outbox_ids.some((id) => !cancelledIds.has(id))) {
40517
+ throw new TodosTaskManifestError("TODOS_TASK_MANIFEST_COMPENSATION_REFUSED", "Compensation refused: failed to cancel every expected outbox row");
40518
+ }
40444
40519
  const typedIds = [
40445
40520
  ["dependencies", applyResult.graph.dependency_ids],
40446
40521
  ["comments", applyResult.graph.comment_ids],
@@ -40627,6 +40702,7 @@ class PackageOwnedTodosTaskManifestAuthority {
40627
40702
  deterministic_ids: true,
40628
40703
  immutable_receipts: true,
40629
40704
  transactional_outbox: true,
40705
+ idempotent_outbox_delivery: true,
40630
40706
  exact_bounded_readback: true,
40631
40707
  conditional_compensation: true,
40632
40708
  transcript_safe: false,
@@ -62008,6 +62084,7 @@ export {
62008
62084
  syncWithAgents,
62009
62085
  syncWithAgent,
62010
62086
  syncKgEdges,
62087
+ supportsIdempotentOutboxDelivery,
62011
62088
  supersedeDecisionRecord,
62012
62089
  summarizeTaskRun,
62013
62090
  summarizeRoadmap,
@@ -6,6 +6,16 @@ import { GOAL_COMMAND_RECIPES } from "./goal-workflow.js";
6
6
  export declare const ADAPTER_DOCS_SCHEMA_VERSION = "todos.agent_adapter_docs.v1";
7
7
  export declare const AGENT_ADAPTER_HOSTS: readonly ["codex", "claude-code", "takumi"];
8
8
  export type AgentAdapterHost = (typeof AGENT_ADAPTER_HOSTS)[number];
9
+ /**
10
+ * Agents accepted by `todos mcp --register` / `--unregister`. Kept beside the
11
+ * adapter docs so the docs can never advertise a host the CLI rejects — the
12
+ * reader of a recovery field is an agent, and a recovery command that exits 1
13
+ * strands it. `todos mcp --register takumi` shipped in doc metadata while the
14
+ * CLI rejected it; the consistency test in agent-adapter-docs.test.ts pins
15
+ * every advertised `--register <agent>` to this list.
16
+ */
17
+ export declare const MCP_REGISTRABLE_CLI_AGENTS: readonly ["claude", "codex", "gemini", "cursor", "takumi"];
18
+ export type McpRegistrableCliAgent = (typeof MCP_REGISTRABLE_CLI_AGENTS)[number];
9
19
  export interface AdapterWorkflowStep {
10
20
  step: number;
11
21
  title: string;
@@ -1 +1 @@
1
- {"version":3,"file":"agent-adapter-docs.d.ts","sourceRoot":"","sources":["../../src/lib/agent-adapter-docs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,eAAO,MAAM,2BAA2B,gCAAgC,CAAC;AAEzE,eAAO,MAAM,mBAAmB,6CAA8C,CAAC;AAC/E,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpE,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,OAAO,2BAA2B,CAAC;IACnD,IAAI,EAAE,gBAAgB,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,GAAG,EAAE;QACH,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;QACvB,WAAW,EAAE,MAAM,CAAC;QACpB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,GAAG,EAAE,MAAM,EAAE,CAAC;KACf,CAAC;IACF,aAAa,EAAE,OAAO,oBAAoB,CAAC;IAC3C,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,aAAa,EAAE;QACb,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;KACpC,CAAC;IACF,YAAY,EAAE;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,aAAa,EAAE,kBAAkB,EAAE,CAAC;IACpC,QAAQ,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAgCD,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,gBAAgB,EAAE,eAAe,CA0IxE,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAM3E;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAGvE;AAED,wBAAgB,oBAAoB,IAAI,eAAe,EAAE,CAExD;AAED,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CA6B9C;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA6EpE;AAED,wBAAgB,4BAA4B,IAAI,MAAM,CAIrD;AAED,gFAAgF;AAChF,wBAAgB,yBAAyB,IAAI,MAAM,CAoBlD"}
1
+ {"version":3,"file":"agent-adapter-docs.d.ts","sourceRoot":"","sources":["../../src/lib/agent-adapter-docs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,eAAO,MAAM,2BAA2B,gCAAgC,CAAC;AAEzE,eAAO,MAAM,mBAAmB,6CAA8C,CAAC;AAC/E,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpE;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,4DAA6D,CAAC;AACrG,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjF,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,OAAO,2BAA2B,CAAC;IACnD,IAAI,EAAE,gBAAgB,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,GAAG,EAAE;QACH,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;QACvB,WAAW,EAAE,MAAM,CAAC;QACpB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,GAAG,EAAE,MAAM,EAAE,CAAC;KACf,CAAC;IACF,aAAa,EAAE,OAAO,oBAAoB,CAAC;IAC3C,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,aAAa,EAAE;QACb,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;KACpC,CAAC;IACF,YAAY,EAAE;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,aAAa,EAAE,kBAAkB,EAAE,CAAC;IACpC,QAAQ,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAgCD,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,gBAAgB,EAAE,eAAe,CA0IxE,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAM3E;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAGvE;AAED,wBAAgB,oBAAoB,IAAI,eAAe,EAAE,CAExD;AAED,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CA6B9C;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA6EpE;AAED,wBAAgB,4BAA4B,IAAI,MAAM,CAIrD;AAED,gFAAgF;AAChF,wBAAgB,yBAAyB,IAAI,MAAM,CAoBlD"}