@hasna/todos 0.11.75 → 0.11.81

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 (57) hide show
  1. package/README.md +8 -0
  2. package/dist/cli/cloud-router.d.ts +71 -0
  3. package/dist/cli/cloud-router.d.ts.map +1 -0
  4. package/dist/cli/commands/project-commands.d.ts.map +1 -1
  5. package/dist/cli/commands/storage-commands.d.ts.map +1 -1
  6. package/dist/cli/commands/task-commands.d.ts.map +1 -1
  7. package/dist/cli/helpers.d.ts +22 -0
  8. package/dist/cli/helpers.d.ts.map +1 -1
  9. package/dist/cli/index.js +72374 -62374
  10. package/dist/contracts.js +314 -14
  11. package/dist/db/database.d.ts.map +1 -1
  12. package/dist/index.js +1158 -236
  13. package/dist/lib/shadow-status.d.ts +38 -0
  14. package/dist/lib/shadow-status.d.ts.map +1 -0
  15. package/dist/mcp/index.js +10249 -340
  16. package/dist/mcp/tools/task-adv-tools.d.ts.map +1 -1
  17. package/dist/mcp/tools/task-crud.d.ts.map +1 -1
  18. package/dist/mcp/tools/task-project-tools.d.ts.map +1 -1
  19. package/dist/mcp/tools/task-workflow-tools.d.ts.map +1 -1
  20. package/dist/registry.js +314 -14
  21. package/dist/release-provenance.json +3 -3
  22. package/dist/sdk/index.d.ts +2 -0
  23. package/dist/sdk/index.d.ts.map +1 -1
  24. package/dist/sdk/index.js +135 -0
  25. package/dist/sdk/v1.generated.d.ts +124 -0
  26. package/dist/sdk/v1.generated.d.ts.map +1 -0
  27. package/dist/server/cloud.d.ts +50 -0
  28. package/dist/server/cloud.d.ts.map +1 -0
  29. package/dist/server/index.js +11944 -2012
  30. package/dist/server/openapi.d.ts +628 -0
  31. package/dist/server/openapi.d.ts.map +1 -0
  32. package/dist/server/serve.d.ts.map +1 -1
  33. package/dist/server/v1.d.ts +19 -0
  34. package/dist/server/v1.d.ts.map +1 -0
  35. package/dist/storage/cloud-client.d.ts +30 -0
  36. package/dist/storage/cloud-client.d.ts.map +1 -0
  37. package/dist/storage/config.d.ts +12 -0
  38. package/dist/storage/config.d.ts.map +1 -1
  39. package/dist/storage/factory.d.ts +2 -0
  40. package/dist/storage/factory.d.ts.map +1 -1
  41. package/dist/storage/index.d.ts +8 -1
  42. package/dist/storage/index.d.ts.map +1 -1
  43. package/dist/storage/postgres-adapter.d.ts.map +1 -1
  44. package/dist/storage/postgres-sync.d.ts.map +1 -1
  45. package/dist/storage/shadow-outbox-schema.d.ts +21 -0
  46. package/dist/storage/shadow-outbox-schema.d.ts.map +1 -0
  47. package/dist/storage/shadow-outbox.d.ts +125 -0
  48. package/dist/storage/shadow-outbox.d.ts.map +1 -0
  49. package/dist/storage/shadow-runtime.d.ts +29 -0
  50. package/dist/storage/shadow-runtime.d.ts.map +1 -0
  51. package/dist/storage/shadow.d.ts +118 -0
  52. package/dist/storage/shadow.d.ts.map +1 -0
  53. package/dist/storage.d.ts +2 -1
  54. package/dist/storage.d.ts.map +1 -1
  55. package/dist/storage.js +1157 -220
  56. package/package.json +6 -2
  57. package/vendor/hasna-contracts-0.5.1.tgz +0 -0
package/README.md CHANGED
@@ -477,6 +477,14 @@ version, compact workflow pointers, and an `automation` object containing only
477
477
  boolean routing gates such as `no_auto`, `manual_required`,
478
478
  `requires_approval`, and `approval_required`.
479
479
 
480
+ When running route smokes or tests with an explicit temp/in-memory task database
481
+ through `TODOS_DB_PATH` or `HASNA_TODOS_DB_PATH`, also set `HASNA_EVENTS_DIR` or
482
+ `HASNA_EVENTS_HOME` to a temp event store. Without an explicit event directory,
483
+ Todos suppresses shared event emission for temp task databases so route-enabled
484
+ scratch tasks cannot trigger global OpenLoops workers. Set
485
+ `HASNA_TODOS_ALLOW_GLOBAL_EVENTS_FROM_TEMP_DB=1` only for deliberate integration
486
+ tests that must exercise the global event bus.
487
+
480
488
  Production task-created routes should fail closed:
481
489
 
482
490
  - Require one explicit opt-in, either task metadata `route_enabled=true` or an
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Client-side self_hosted cloud routing for the `todos` CLI.
3
+ *
4
+ * THE MISSING PIECE (B2): historically the CLI always read/wrote the local
5
+ * SQLite store even when a machine was flipped to `self_hosted` — there was
6
+ * ZERO `/v1` / bearer / API-URL code on the client, so `HASNA_TODOS_*` env had
7
+ * no effect. This module wires the CLI's task data path to the cloud HTTP API
8
+ * (`https://todos.hasna.xyz/v1`) via the LOCKED `@hasna/contracts` HTTP storage
9
+ * client whenever the client-flip contract resolves to `cloud-http`:
10
+ *
11
+ * mode = self_hosted (or cloud) AND HASNA_TODOS_API_URL AND HASNA_TODOS_API_KEY
12
+ *
13
+ * When those are set, ALL task reads and writes go to the cloud with the bearer
14
+ * key — NOT local, NOT a DSN. When they are unset, the client falls straight
15
+ * back to the local SQLite store. Misconfigured cloud (mode set but URL/key
16
+ * missing) THROWS via the contracts resolver so we never silently drift back to
17
+ * the wrong dataset.
18
+ *
19
+ * SAFETY: reversible by construction (unset the two env vars -> local). Never
20
+ * logs or embeds the API key (it lives only inside the transport). No DSN, no
21
+ * subnet routing — pure API-client path per the locked architecture.
22
+ */
23
+ import { type HasnaStorageClient } from "@hasna/contracts/client/storage";
24
+ import type { Task, TaskFilter } from "../types/index.js";
25
+ type Env = Record<string, string | undefined>;
26
+ /**
27
+ * Resolve the todos cloud storage client from the environment. Returns a ready
28
+ * client when the flip resolves to `cloud-http`, or `null` for local. Throws
29
+ * when cloud is requested (mode=self_hosted/cloud) but the URL or key is missing
30
+ * — no silent local fallback for a misconfigured cloud request.
31
+ */
32
+ export declare function getTodosCloudClient(env?: Env): HasnaStorageClient | null;
33
+ /** True when the CLI should route task reads/writes to the cloud API. */
34
+ export declare function isCloudRouting(env?: Env): boolean;
35
+ /** Test hook: clear the memoized client (e.g. after mutating env in a test). */
36
+ export declare function resetTodosCloudClient(): void;
37
+ /** List tasks from the cloud (`GET /v1/tasks`). Returns the `tasks` array. */
38
+ export declare function cloudListTasks(client: HasnaStorageClient, filter?: TaskFilter): Promise<Task[]>;
39
+ /** Fetch one task by id (`GET /v1/tasks/:id`); `null` on 404. */
40
+ export declare function cloudGetTask(client: HasnaStorageClient, id: string): Promise<Task | null>;
41
+ /** Create a task (`POST /v1/tasks`, retry-safe idempotency key). */
42
+ export declare function cloudCreateTask(client: HasnaStorageClient, input: Record<string, unknown>): Promise<Task>;
43
+ /** Update a task (`PATCH /v1/tasks/:id`). */
44
+ export declare function cloudUpdateTask(client: HasnaStorageClient, id: string, patch: Record<string, unknown>): Promise<Task>;
45
+ /** Delete a task (`DELETE /v1/tasks/:id`); resolves for 2xx and 404. */
46
+ export declare function cloudDeleteTask(client: HasnaStorageClient, id: string): Promise<boolean>;
47
+ /** Run a task lifecycle action (`POST /v1/tasks/:id/{start|complete|fail|claim}`). */
48
+ export declare function cloudTaskAction(client: HasnaStorageClient, id: string, action: "start" | "complete" | "fail" | "claim", body?: Record<string, unknown>): Promise<Task>;
49
+ /** Queue status summary from the cloud (`GET /v1/stats`). */
50
+ export interface CloudStats {
51
+ tasks: number;
52
+ tasks_all?: number;
53
+ subtasks?: number;
54
+ projects?: number;
55
+ [key: string]: unknown;
56
+ }
57
+ /**
58
+ * Fetch the cloud queue summary (`GET /v1/stats`). Used by the MCP `get_status`
59
+ * tool so a flipped machine reports the shared cloud totals rather than its
60
+ * local SQLite island.
61
+ */
62
+ export declare function cloudGetStats(client: HasnaStorageClient): Promise<CloudStats>;
63
+ /**
64
+ * Count tasks matching a filter. The `/v1/tasks` list response now returns a
65
+ * SQL-side `total` (full match count, independent of limit/offset), so we ask for
66
+ * a single row and read `total` instead of pulling the whole result set into the
67
+ * client (which previously loaded every matching task over HTTP just to count).
68
+ */
69
+ export declare function cloudCountTasks(client: HasnaStorageClient, filter?: TaskFilter): Promise<number>;
70
+ export {};
71
+ //# sourceMappingURL=cloud-router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-router.d.ts","sourceRoot":"","sources":["../../src/cli/cloud-router.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAwB,KAAK,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAChG,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE1D,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAI9C;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,GAAwB,GAAG,kBAAkB,GAAG,IAAI,CAiB5F;AAED,yEAAyE;AACzE,wBAAgB,cAAc,CAAC,GAAG,GAAE,GAAwB,GAAG,OAAO,CAErE;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAwBD,8EAA8E;AAC9E,wBAAsB,cAAc,CAAC,MAAM,EAAE,kBAAkB,EAAE,MAAM,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAIzG;AAED,iEAAiE;AACjE,wBAAsB,YAAY,CAAC,MAAM,EAAE,kBAAkB,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAG/F;AAED,oEAAoE;AACpE,wBAAsB,eAAe,CAAC,MAAM,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/G;AAED,6CAA6C;AAC7C,wBAAsB,eAAe,CAAC,MAAM,EAAE,kBAAkB,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3H;AAED,wEAAwE;AACxE,wBAAsB,eAAe,CAAC,MAAM,EAAE,kBAAkB,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAG9F;AAED,sFAAsF;AACtF,wBAAsB,eAAe,CACnC,MAAM,EAAE,kBAAkB,EAC1B,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,EAC/C,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACjC,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,6DAA6D;AAC7D,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC,CAGnF;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,kBAAkB,EAAE,MAAM,GAAE,UAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ1G"}
@@ -1 +1 @@
1
- {"version":3,"file":"project-commands.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/project-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkIzC,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,QAq2BvD"}
1
+ {"version":3,"file":"project-commands.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/project-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoJzC,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,QA24BvD"}
@@ -1 +1 @@
1
- {"version":3,"file":"storage-commands.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/storage-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA8EzC,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe;;;;EAazF;AAYD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,QAyGvD"}
1
+ {"version":3,"file":"storage-commands.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/storage-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2HzC,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe;;;;EAazF;AAYD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,QA6LvD"}
@@ -1 +1 @@
1
- {"version":3,"file":"task-commands.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/task-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+LzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,QAs8BpD"}
1
+ {"version":3,"file":"task-commands.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/task-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwMzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,QA+jCpD"}
@@ -2,8 +2,30 @@ import { getPackageVersion } from "../lib/package-version.js";
2
2
  import type { Project, Task } from "../types/index.js";
3
3
  export { getPackageVersion };
4
4
  export declare function handleError(e: unknown): never;
5
+ /**
6
+ * Resolve a user-supplied task reference (full UUID, id prefix, or short_id) to a
7
+ * canonical task id, CONSISTENTLY across every `todos` subcommand.
8
+ *
9
+ * Two rules make this safe whether the machine is `local` or flipped to the shared
10
+ * `self_hosted` cloud store:
11
+ *
12
+ * 1. A full task UUID is authoritative on its own — it is returned verbatim and is
13
+ * NEVER required to exist in this box's local SQLite mirror. On a flipped
14
+ * machine the task lives in the cloud and may have never synced down; the
15
+ * downstream read/write (cloud `GET/PATCH/POST /v1/tasks/:id` or a local query)
16
+ * is the single source of truth for existence and reports a precise not-found.
17
+ * This is what previously broke: resolver-based commands (comment, inspect,
18
+ * lock, deps, …) demanded the row be present locally, so they failed on
19
+ * cloud-only tasks even with a valid full UUID, while raw-id commands (show,
20
+ * update, start, done) worked — the reported inconsistency.
21
+ *
22
+ * 2. A short prefix / short_id is expanded against the local mirror, the only
23
+ * prefix index available client-side (the `/v1` API has no prefix lookup).
24
+ * Ambiguous or unknown prefixes fail loudly with actionable guidance.
25
+ */
5
26
  export declare function resolveTaskId(partialId: string): string;
6
27
  export declare function detectGitRoot(): string | null;
28
+ export declare function shouldSkipAutoProjectForGitRoot(gitRoot: string): boolean;
7
29
  /**
8
30
  * Resolve an explicitly provided project reference by registered path, exact or
9
31
  * partial ID, task list ID, slug, or name. An unresolvable reference is a hard
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/cli/helpers.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAK7B,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,KAAK,CAG7C;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAcvD;AAED,wBAAgB,aAAa,IAAI,MAAM,GAAG,IAAI,CAM7C;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAgC7D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,GAAG,SAAS,CAUjF;AAMD,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,GAAG,SAAS,CAE1E;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAUjD;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,GAAG,MAAM,EAAE,CAGlF;AA0BD,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAE7C;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,CAI7D;AAED,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAM9D,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAKhE,CAAC;AAEF,wBAAgB,cAAc,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,CAQ9C"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/cli/helpers.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAK7B,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,KAAK,CAG7C;AAKD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CA8BvD;AAED,wBAAgB,aAAa,IAAI,MAAM,GAAG,IAAI,CAM7C;AAQD,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAMxE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAgC7D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,GAAG,SAAS,CAWjF;AAMD,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,GAAG,SAAS,CAE1E;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAUjD;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,GAAG,MAAM,EAAE,CAGlF;AA0BD,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAE7C;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,CAI7D;AAED,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAM9D,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAKhE,CAAC;AAEF,wBAAgB,cAAc,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,CAQ9C"}