@bumpyclock/pi-tasque 0.1.0 → 0.2.1

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 (34) hide show
  1. package/README.md +168 -140
  2. package/package.json +24 -6
  3. package/src/bridge/bridge-tool.ts +10 -13
  4. package/src/bridge/import-tsq.ts +5 -30
  5. package/src/bridge/promote-todo.ts +1 -4
  6. package/src/bridge/types.ts +11 -12
  7. package/src/durable-tasks/bulk-contract.ts +176 -0
  8. package/src/durable-tasks/cache.ts +1 -4
  9. package/src/durable-tasks/change-command-builder.ts +315 -0
  10. package/src/durable-tasks/handoff-guard.ts +329 -0
  11. package/src/durable-tasks/project.ts +71 -0
  12. package/src/durable-tasks/runner.ts +1 -4
  13. package/src/durable-tasks/status.ts +20 -5
  14. package/src/durable-tasks/task-mappers.ts +160 -0
  15. package/src/durable-tasks/task-schema.ts +193 -0
  16. package/src/durable-tasks/task-tool.ts +197 -0
  17. package/src/durable-tasks/task-validation.ts +123 -0
  18. package/src/durable-tasks/tools-bulk.ts +141 -0
  19. package/src/durable-tasks/tools-change.ts +111 -382
  20. package/src/durable-tasks/tools-claim.ts +15 -43
  21. package/src/durable-tasks/tools-handoff.ts +95 -0
  22. package/src/durable-tasks/tools-query.ts +58 -29
  23. package/src/durable-tasks/tools-spec.ts +230 -0
  24. package/src/durable-tasks/tools-tree-create.ts +221 -0
  25. package/src/guidelines/internal-tools.ts +33 -0
  26. package/src/guidelines/task.ts +5 -0
  27. package/src/guidelines/todo.ts +5 -0
  28. package/src/index.ts +2 -13
  29. package/src/session-todos/state/replay.ts +10 -13
  30. package/src/session-todos/todo-overlay.ts +1 -1
  31. package/src/session-todos/todo.ts +11 -15
  32. package/src/session-todos/tool/types.ts +7 -7
  33. package/src/shared/error-utils.ts +29 -0
  34. package/src/shared/validation.ts +25 -0
package/README.md CHANGED
@@ -1,15 +1,15 @@
1
1
  # pi-tasque
2
2
 
3
- Pi extension package for Tasque durable tasks plus branch-replayed in-session todos.
3
+ Pi extension for durable project tasks plus in-session todos.
4
4
 
5
5
  ## What this package provides
6
6
 
7
7
  `pi-tasque` gives agents two task layers:
8
8
 
9
- - **Session todos**: current-session execution checklist for inspect/edit/verify/handoff steps.
10
- - **Durable Tasque tasks**: repo-local backlog, specs, dependencies, notes, and ownership through `tsq --format json`.
9
+ - **Session todos**: current-session execution checklist for inspect, edit, verify, and handoff steps.
10
+ - **Durable tasks**: repo-local backlog, specs, dependencies, notes, and ownership.
11
11
 
12
- The bridge between the layers is explicit. `pi-tasque` can link, promote, or import tasks, but it does **not** automatically sync lifecycle state between todos and Tasque.
12
+ The bridge between the layers is explicit. `pi-tasque` can link, promote, or import tasks, but it does **not** automatically sync lifecycle state between todos and durable tasks.
13
13
 
14
14
  ## Install
15
15
 
@@ -33,52 +33,23 @@ edit TypeScript files -> /reload -> test behavior
33
33
 
34
34
  Pi loads the extension entrypoint from the installed package path, so TypeScript source edits do not require reinstalling the local package. Use `/reload` in the Pi session after changing files under `src/`.
35
35
 
36
- ### Remove `@juicesharp/rpiv-todo`
37
-
38
- Remove or disable `@juicesharp/rpiv-todo` before enabling `pi-tasque`:
39
-
40
- ```bash
41
- pi remove npm:@juicesharp/rpiv-todo
42
- ```
43
-
44
- `pi-tasque` owns the same user-facing session todo surface:
45
-
46
- - `todo` tool
47
- - `/todos` command
48
- - above-editor todo overlay
49
-
50
- Running both packages together can register duplicate tools, commands, or widgets.
51
-
52
36
  ## Agent guidance
53
37
 
54
- Use the smallest task layer that matches the work:
55
-
56
- - Use `todo` for tactical steps inside the current session: inspect, edit, verify, and handoff.
57
- - Use `tsq_query` for fresh read-only Tasque state.
58
- - Use `tsq_change` for explicit durable Tasque mutations, including lifecycle changes and block/order edges.
59
- - Use `block`/`unblock` for hard dependency edges and `order`/`unorder` for sequencing edges via `tsq_change`.
60
- - Use `tsq_claim` when taking ownership of a named durable Tasque task.
61
- - Pass an explicit `assignee` when the agent has a role/name, such as `developer`, `oracle`, or a worker name.
62
- - If no `assignee` is provided, `tsq_claim` defaults to `pi`.
63
- - `tsq_claim` defaults `start` to true. Use `requireSpec` when the durable task must have an attached spec before work begins.
64
- - Use `tsq_claim` with `createTodo: true` when claiming durable work should also create one linked session todo.
65
- - Use `task_bridge promote_todo` when a session todo should become durable Tasque work.
66
- - Use `task_bridge import_tsq` when a durable Tasque task should become current-session todo work.
67
- - Do not create durable Tasque tasks for every session todo.
68
- - Do not mark a Tasque task done just because linked todos are completed; durable completion requires explicit verification and an explicit Tasque mutation.
38
+ Use `todo` for current-session checklists; use `task` for durable project work, ownership, notes, specs, dependencies, and explicit todo links.
69
39
 
70
40
  ## Lifecycle boundaries
71
41
 
72
- There is no automatic lifecycle sync between session todos and Tasque:
42
+ There is no automatic lifecycle sync between session todos and durable tasks:
73
43
 
74
- - Completing a `todo` does not mark a Tasque task done.
75
- - Marking a Tasque task done does not complete linked todos.
76
- - `task_bridge link` records a relationship only.
77
- - `task_bridge promote_todo` creates a Tasque task, links it, and completes the source todo as part of the explicit promotion flow.
78
- - `task_bridge import_tsq` creates or reuses session todos for Tasque tasks, but later status changes remain explicit.
44
+ - Completing a `todo` does not mark a durable task done.
45
+ - Marking a durable task done does not complete linked todos.
46
+ - `task` link actions record relationships only.
47
+ - `task` promote/import actions are explicit bridge operations.
79
48
 
80
49
  ## Example workflow
81
50
 
51
+ Create a session todo:
52
+
82
53
  ```json
83
54
  {
84
55
  "action": "create",
@@ -87,43 +58,51 @@ There is no automatic lifecycle sync between session todos and Tasque:
87
58
  }
88
59
  ```
89
60
 
61
+ Claim durable work and create one linked todo:
62
+
90
63
  ```json
91
- { "id": "tsq-349aqgsj.12", "assignee": "developer", "createTodo": true }
64
+ {
65
+ "action": "claim",
66
+ "task": "task-123",
67
+ "for": "developer",
68
+ "todo": true
69
+ }
92
70
  ```
93
71
 
72
+ List links:
73
+
94
74
  ```json
95
75
  { "action": "list_links" }
96
76
  ```
97
77
 
78
+ Finish durable work after verification:
79
+
98
80
  ```json
99
81
  {
100
- "action": "done",
101
- "id": "tsq-349aqgsj.12",
102
- "note": "Verified docs and package checks."
82
+ "action": "finish",
83
+ "task": "task-123",
84
+ "because": "Docs and package checks passed."
103
85
  }
104
86
  ```
105
87
 
106
- ## v1 tool and command reference
88
+ ## Tool and command reference
107
89
 
108
- | Surface | Purpose | Notes |
109
- | -------------------- | --------------------------------------------- | --------------------------------------------------------------- |
110
- | `todo` | Manage current-session tactical todos. | Session-local; branch-replayed from successful tool results. |
111
- | `/todos` | Show grouped current-session todos. | Interactive UI only. |
112
- | `tsq_query` | Read fresh Tasque state. | Read-only; does not mutate Tasque. |
113
- | `tsq_change` | Run explicit durable Tasque mutations. | Mutations are queued per cwd. |
114
- | `tsq_claim` | Claim a named durable Tasque task. | `id` required; `assignee` defaults `pi`; `start` defaults true. |
115
- | `task_bridge` | Link/promote/import between todos and Tasque. | Explicit bridge only; no automatic lifecycle sync. |
116
- | Todo overlay | Show active session todos above the editor. | Completed todos hide on next turn. |
117
- | Tasque status footer | Show cached durable-task status. | Display-only; agents should call `tsq_query` for fresh data. |
90
+ | Surface | Purpose | Notes |
91
+ | ------------------ | -------------------------------------------- | ------------------------------------------------------------------ |
92
+ | `todo` | Manage current-session tactical todos. | Session-local; replayed from successful `todo` and `task` results. |
93
+ | `/todos` | Show grouped current-session todos. | Interactive UI only. |
94
+ | `task` | Manage durable project tasks and todo links. | Resolves operations to the current git project root. |
95
+ | Todo overlay | Show active session todos above the editor. | Completed todos hide on the next turn. |
96
+ | Task status footer | Show cached durable-task status. | Display-only; agents should call `task` for fresh data. |
118
97
 
119
98
  ### `todo`
120
99
 
121
- Manage current-session tactical todos. Todos are branch-replayed from previous successful `todo` results in the current session branch.
100
+ Manage current-session todos. Todos are branch-replayed from previous successful `todo` results in the current session branch.
122
101
 
123
102
  Actions:
124
103
 
125
- - `create`: add a todo.
126
- - `update`: change status, text, owner, metadata, or dependencies.
104
+ - `create`: add a todo, with optional description, owner, metadata, and blockers.
105
+ - `update`: change status, text, owner, metadata, or dependencies with `blockedBy`, `addBlockedBy`, and `removeBlockedBy`.
127
106
  - `list`: list visible todos; deleted tombstones are hidden unless `includeDeleted` is true.
128
107
  - `get`: fetch one todo by id.
129
108
  - `delete`: tombstone one todo.
@@ -160,151 +139,200 @@ Example:
160
139
 
161
140
  ### Above-editor todo overlay
162
141
 
163
- Shows active session todos above the editor. The overlay rebuilds from branch replay on session lifecycle events and updates after successful `todo`, `task_bridge`, and `tsq_claim` executions that affect todo state.
142
+ Shows active session todos above the editor. The overlay rebuilds on session start, compaction, and tree switches, then updates after successful `todo` and `task` executions that affect todo state.
164
143
 
165
144
  Completed todos remain visible until the next turn, then hide from the overlay.
166
145
 
167
- ### `tsq_query`
146
+ ### `task`
168
147
 
169
- Run read-only Tasque queries through `tsq --format json`. Use this for fresh durable task state without mutating Tasque.
148
+ Manage durable project tasks. Most durable task operations run from the current git project root; `handoff_check` resolves the root only when linked todos exist.
170
149
 
171
- Actions:
150
+ Read actions:
172
151
 
173
- - `doctor`
174
- - `find_ready`
175
- - `find_open`
176
- - `show`
177
- - `show_with_spec`
178
- - `deps`
179
- - `notes`
180
- - `find_tree`
181
- - `similar`
152
+ - `doctor`: check task-system health.
153
+ - `find`: find `ready` or `open` tasks. `lane` applies only to `ready`; use `view: "tree"` for an open-task tree. With `view: "tree"`, `task` filters the tree to a parent task.
154
+ - `show`: show one task. Use `with: ["spec"]` to include spec content in the display.
155
+ - `deps`: show dependency tree for one task.
156
+ - `notes`: show notes for one task.
157
+ - `similar`: search for similar tasks by text.
158
+ - `handoff_check`: check whether current-session todos and linked durable tasks are ready for final handoff. Not-ready returns `ok: true, ready: false`; internal failures return `ok: false`.
159
+ - `spec`: operate on the spec attached to a task. `mode` is required and must be `show`, `check`, `set`, or `update`.
160
+ - `show` returns the attached spec content.
161
+ - `check` validates the attached spec against the task. Returns `ok: true` when validation passes; returns `ok: false` with `error.code: "spec_check_failed"` and diagnostics when validation fails.
162
+ - `set` attaches a new spec using the `text` field. Overwrites any existing spec.
163
+ - `update` updates the existing spec using the `text` field.
164
+ - `text` is required for `set` and `update`; rejected for `show` and `check`.
165
+ - `show` and `check` are read-only. `set` and `update` are mutations serialized through the per-project queue.
182
166
 
183
- Examples:
167
+ **`show` with `with:["spec"]` vs `spec` action:** `show` with `with:["spec"]` includes spec content as extra context in the task display — useful for reading the spec alongside other task fields. The `spec` action with `mode:"show"` returns spec content alone; `spec` action with `mode:"check"` validates the attached spec and reports pass/fail with diagnostics. Use `show` for display context, `spec check` for validation.
184
168
 
185
- ```json
186
- { "action": "find_ready", "lane": "coding", "assignee": "developer" }
187
- ```
169
+ **Failed check semantics:** When `spec check` reports validation failures, the tool result has `details.ok: false`, `error.code: "spec_check_failed"`, and a `details.diagnostics` object with the issues. The CLI process exits successfully (no thrown error); the failure is reported in structured details so agents can inspect and react to individual check failures without catching exceptions.
188
170
 
189
- ```json
190
- { "action": "show_with_spec", "id": "tsq-349aqgsj.12" }
191
- ```
171
+ **Handoff check semantics:** `handoff_check` is read-only. It checks pending/in-progress/blocked todos plus linked durable task status. `closed` linked tasks are ready; `open`, `in_progress`, `blocked`, `deferred`, and unknown statuses block handoff; `canceled` is a warning. Missing/invalid linked tasks are reported as `readErrors` with `ready:false`.
192
172
 
193
- ### `tsq_change`
173
+ Mutation actions:
194
174
 
195
- Run approved durable Tasque mutations. Mutations are queued per working directory so concurrent agents do not race `tsq` writes.
175
+ - `create`: create a durable task, with optional `description`, `under`, `planned`, or `needsPlan`.
176
+ - `note`: add a note.
177
+ - `finish`: mark done.
178
+ - `reopen`: reopen a task.
179
+ - `defer`: defer a task.
180
+ - `start`: mark started.
181
+ - `claim`: assign ownership; `start` defaults to true, `requireSpec` enforces an attached spec, and `todo: true` creates one linked session todo.
182
+ - `block` / `unblock`: manage hard blocker edges.
183
+ - `order` / `unorder`: manage sequencing edges.
196
184
 
197
- Actions:
185
+ Lifecycle mutation actions:
198
186
 
199
- - `create`
200
- - `note`
201
- - `done`
202
- - `reopen`
203
- - `defer`
204
- - `start`
205
- - `claim_assign_only`
206
- - `block`: make `child` blocked by `blocker`.
207
- - `unblock`: remove a block edge between `child` and `blocker`.
208
- - `order`: make `later` start after `earlier`.
209
- - `unorder`: remove an order edge between `later` and `earlier`.
187
+ - `mark_planned`: mark an existing task as planned. Requires `task` (non-empty id). Runs through the mutation queue.
210
188
 
211
- Use `block` for hard blockers and `order` for sequencing. Use `tsq_query` with `deps` or `show` to inspect durable graph state. Edge actions cannot create self-edges.
189
+ Batch actions:
190
+
191
+ - `bulk`: run multiple lifecycle/note mutations sequentially with fail-fast semantics. Requires `items` — an array of `{ action, task, because? }` objects. Supported item actions: `start`, `finish`, `reopen`, `defer`, `note`, `mark_planned`. `because` is required for `note`, optional for `finish`/`defer`. On first failure, remaining items are skipped. No rollback of completed mutations. Result details contain `completed` (task ids), optional `failed` (task + error), and `skipped` (task ids).
192
+ - `create_tree`: create a nested tree of durable tasks in one call. Requires `root` — a node object `{ title, kind, priority, description?, planned?, needsPlan?, children? }`. Children are recursive nodes. Creates parent before children, wiring generated parent ids. On first failure, remaining subtree is skipped — no orphan children are created. No rollback. Result details contain `created` (id + title), optional `failed` (title + error), and `skipped` (titles).
193
+
194
+ Bridge actions:
195
+
196
+ - `link`: associate an existing todo with an existing durable task via todo metadata.
197
+ - `list_links`: inspect current todo ↔ durable task associations.
198
+ - `promote`: create a durable task from an existing todo, add a promotion note, link metadata, and complete the source todo.
199
+ - `import`: import a durable task, or an open-tree task plus children when available, into session todos with metadata links. `to` currently accepts only `"todo"`.
212
200
 
213
201
  Examples:
214
202
 
215
203
  ```json
216
- {
217
- "action": "note",
218
- "id": "tsq-349aqgsj.12",
219
- "note": "README docs updated; running verification."
220
- }
204
+ { "action": "find", "tasks": "ready", "lane": "coding", "for": "developer" }
221
205
  ```
222
206
 
223
207
  ```json
224
- {
225
- "action": "done",
226
- "id": "tsq-349aqgsj.12",
227
- "note": "Docs and typecheck/test verification passed."
228
- }
208
+ { "action": "find", "view": "tree", "task": "task-parent" }
229
209
  ```
230
210
 
231
211
  ```json
232
- { "action": "block", "child": "tsq-abc123.2", "blocker": "tsq-abc123.1" }
212
+ { "action": "show", "task": "task-123", "with": ["spec"] }
233
213
  ```
234
214
 
235
215
  ```json
236
- { "action": "order", "later": "tsq-abc123.3", "earlier": "tsq-abc123.2" }
216
+ { "action": "spec", "task": "task-123", "mode": "show" }
237
217
  ```
238
218
 
239
- ### `tsq_claim`
240
-
241
- Claim a named durable Tasque task. This never auto-selects work; callers must provide the task id. `start` defaults to true, `assignee` defaults to `pi`, and `createTodo` optionally creates one linked session todo for the claimed task.
242
-
243
- Example:
219
+ ```json
220
+ { "action": "spec", "task": "task-123", "mode": "check" }
221
+ ```
244
222
 
245
223
  ```json
246
224
  {
247
- "id": "tsq-349aqgsj.12",
248
- "assignee": "developer",
249
- "requireSpec": true,
250
- "createTodo": true
225
+ "action": "spec",
226
+ "task": "task-123",
227
+ "mode": "set",
228
+ "text": "# Spec\n\nAcceptance criteria..."
251
229
  }
252
230
  ```
253
231
 
254
- ### `task_bridge`
255
-
256
- Explicitly connect session todos and durable Tasque tasks. Bridge actions do not create implicit lifecycle sync.
257
-
258
- Actions:
232
+ ```json
233
+ {
234
+ "action": "spec",
235
+ "task": "task-123",
236
+ "mode": "update",
237
+ "text": "## Updated section\n\nRevised details..."
238
+ }
239
+ ```
259
240
 
260
- - `link`: associate an existing todo with an existing Tasque task via todo metadata.
261
- - `list_links`: inspect current session todo ↔ Tasque associations.
262
- - `promote_todo`: create a Tasque task from an existing todo, add a promotion note, link metadata, and complete the source todo.
263
- - `import_tsq`: import a Tasque task, or an open-tree task plus children when available, into session todos with `tsqId` metadata links.
241
+ ```json
242
+ { "action": "mark_planned", "task": "task-456" }
243
+ ```
264
244
 
265
- Link example:
245
+ ```json
246
+ {
247
+ "action": "bulk",
248
+ "items": [
249
+ { "action": "finish", "task": "task-1", "because": "Verified" },
250
+ { "action": "start", "task": "task-2" },
251
+ { "action": "mark_planned", "task": "task-3" }
252
+ ]
253
+ }
254
+ ```
266
255
 
267
256
  ```json
268
- { "action": "link", "todoId": 3, "tsqId": "tsq-349aqgsj.12" }
257
+ {
258
+ "action": "create_tree",
259
+ "root": {
260
+ "title": "Add auth module",
261
+ "kind": "task",
262
+ "priority": 2,
263
+ "planned": true,
264
+ "children": [
265
+ {
266
+ "title": "Design auth API",
267
+ "kind": "task",
268
+ "priority": 2,
269
+ "needsPlan": true
270
+ },
271
+ { "title": "Implement token refresh", "kind": "task", "priority": 3 }
272
+ ]
273
+ }
274
+ }
269
275
  ```
270
276
 
271
- Promote example:
277
+ ```json
278
+ { "action": "handoff_check" }
279
+ ```
272
280
 
273
281
  ```json
274
282
  {
275
- "action": "promote_todo",
276
- "todoId": 4,
283
+ "action": "create",
284
+ "task": "Add cwd guard tests",
277
285
  "kind": "task",
278
286
  "priority": 2,
279
- "assignee": "developer",
280
- "parent": "tsq-349aqgsj"
287
+ "under": "task-parent",
288
+ "planned": true
281
289
  }
282
290
  ```
283
291
 
284
- Import example:
292
+ ```json
293
+ { "action": "block", "task": "task-child", "by": "task-blocker" }
294
+ ```
285
295
 
286
296
  ```json
287
- { "action": "import_tsq", "tsqId": "tsq-349aqgsj.12", "owner": "developer" }
297
+ { "action": "order", "task": "task-later", "after": "task-earlier" }
288
298
  ```
289
299
 
290
- List links example:
300
+ ```json
301
+ { "action": "link", "todo": 3, "task": "task-123" }
302
+ ```
291
303
 
292
304
  ```json
293
- { "action": "list_links" }
305
+ {
306
+ "action": "promote",
307
+ "todo": 4,
308
+ "kind": "task",
309
+ "priority": 2,
310
+ "under": "task-parent",
311
+ "for": "developer"
312
+ }
313
+ ```
314
+
315
+ ```json
316
+ {
317
+ "action": "import",
318
+ "task": "task-123",
319
+ "to": "todo",
320
+ "for": "developer"
321
+ }
294
322
  ```
295
323
 
296
- ### Tasque status footer
324
+ ### Task status footer
297
325
 
298
- The status footer shows cached Tasque status in interactive UI:
326
+ The status footer shows cached durable-task status in interactive UI:
299
327
 
300
328
  - ready coding count
301
329
  - ready planning count
302
- - `mine` count for tasks assigned to `pi`
330
+ - `mine` count for in-progress tasks assigned to `pi`
303
331
  - loading, stale, and error states
304
332
 
305
- It refreshes on session start, periodically, and after successful durable mutations from `tsq_change`, `tsq_claim`, or `task_bridge`.
333
+ It refreshes on session start, periodically, and after successful durable mutations from `task`.
306
334
 
307
- The footer is display-only. Refreshed status is not injected into the model context; agents should use `tsq_query` for fresh durable task data. If agents claim with a non-`pi` assignee, those tasks may not appear in the footer's `mine` count.
335
+ The footer is display-only. Refreshed status is not injected into the model context; agents should use `task` for fresh durable task data. If agents claim with a non-`pi` assignee, those tasks may not appear in the footer's `mine` count.
308
336
 
309
337
  ## Verification
310
338
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bumpyclock/pi-tasque",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "Pi extension package for Tasque durable tasks plus in-session todos.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -12,18 +12,35 @@
12
12
  "url": "https://github.com/BumpyClock/pi-tasque/issues"
13
13
  },
14
14
  "homepage": "https://github.com/BumpyClock/pi-tasque#readme",
15
- "keywords": ["pi-package", "pi-extension", "tasque", "tsq", "todo"],
15
+ "keywords": [
16
+ "pi-package",
17
+ "pi-extension",
18
+ "tasque",
19
+ "tsq",
20
+ "todo"
21
+ ],
16
22
  "scripts": {
17
23
  "typecheck": "tsc --noEmit",
18
- "test": "vitest run"
24
+ "test": "vitest run",
25
+ "bump:patch": "node scripts/bump-version.js patch",
26
+ "bump:minor": "node scripts/bump-version.js minor",
27
+ "bump:major": "node scripts/bump-version.js major",
28
+ "bump:set": "node scripts/bump-version.js"
19
29
  },
20
- "files": ["src/", "README.md", "LICENSE", "NOTICE.md"],
30
+ "files": [
31
+ "src/",
32
+ "README.md",
33
+ "LICENSE",
34
+ "NOTICE.md"
35
+ ],
21
36
  "publishConfig": {
22
37
  "access": "public",
23
38
  "provenance": true
24
39
  },
25
40
  "pi": {
26
- "extensions": ["./src/index.ts"]
41
+ "extensions": [
42
+ "./src/index.ts"
43
+ ]
27
44
  },
28
45
  "peerDependencies": {
29
46
  "@earendil-works/pi-ai": "*",
@@ -35,5 +52,6 @@
35
52
  "@types/node": "latest",
36
53
  "typescript": "latest",
37
54
  "vitest": "latest"
38
- }
55
+ },
56
+ "packageManager": "npm@11.12.0"
39
57
  }
@@ -4,6 +4,10 @@ import {
4
4
  type ExtensionAPI,
5
5
  type ExtensionContext,
6
6
  } from "@earendil-works/pi-coding-agent";
7
+ import {
8
+ TASK_TODO_BRIDGE_PROMPT_GUIDELINES,
9
+ TASK_TODO_BRIDGE_PROMPT_SNIPPET,
10
+ } from "../guidelines/internal-tools.js";
7
11
  import {
8
12
  errorToolDetails,
9
13
  okToolDetails,
@@ -32,18 +36,11 @@ export function registerTaskBridgeTool(
32
36
  pi.registerTool(
33
37
  defineTool({
34
38
  name: TASK_BRIDGE_TOOL_NAME,
35
- label: "Task Bridge",
39
+ label: "Task Todo Bridge",
36
40
  description:
37
- "Explicitly link, list, promote, or import between session todos and durable Tasque tasks. No automatic lifecycle sync.",
38
- promptSnippet:
39
- "task_bridge links, lists, promotes, and imports between session todos and durable Tasque tasks; it never auto-completes one layer from the other.",
40
- promptGuidelines: [
41
- "Use link to associate an existing todo with an existing Tasque task via todo metadata tsqId.",
42
- "Use list_links to inspect current session todo ↔ Tasque associations.",
43
- "Use promote_todo to create a Tasque task from a todo and link the promoted todo explicitly.",
44
- "Use import_tsq to create or reuse session todos from Tasque task state and link them explicitly.",
45
- "Todo completion does not mark Tasque done; durable completion stays explicit.",
46
- ],
41
+ "Link session todos and durable tasks. No automatic lifecycle sync.",
42
+ promptSnippet: TASK_TODO_BRIDGE_PROMPT_SNIPPET,
43
+ promptGuidelines: TASK_TODO_BRIDGE_PROMPT_GUIDELINES,
47
44
  parameters: TaskBridgeParamsSchema,
48
45
  executionMode: "sequential",
49
46
 
@@ -83,7 +80,7 @@ export async function executeTaskBridge(
83
80
  default:
84
81
  return errorResult(
85
82
  "validation_error",
86
- "action must be a supported task_bridge action",
83
+ "action must be a supported task/todo bridge action",
87
84
  );
88
85
  }
89
86
  }
@@ -160,7 +157,7 @@ function notImplementedResult(
160
157
  ): AgentToolResult<TaskBridgeDetails> {
161
158
  return errorResult(
162
159
  "not_implemented",
163
- `task_bridge action ${action} handler is not configured`,
160
+ `task/todo bridge action ${action} handler is not configured`,
164
161
  );
165
162
  }
166
163
 
@@ -20,6 +20,11 @@ import {
20
20
  } from "../session-todos/state/state-reducer.js";
21
21
  import { commitState, getState } from "../session-todos/state/store.js";
22
22
  import type { Task, TaskStatus } from "../session-todos/tool/types.js";
23
+ import {
24
+ asRecord,
25
+ copyKnownErrorFields,
26
+ isRecord,
27
+ } from "../shared/error-utils.js";
23
28
  import {
24
29
  errorToolDetails,
25
30
  okToolDetails,
@@ -470,33 +475,3 @@ function serializeError(error: unknown): Record<string, unknown> {
470
475
  }
471
476
  return { value: String(error) };
472
477
  }
473
-
474
- function copyKnownErrorFields(error: Error): Record<string, unknown> {
475
- const record = error as unknown as Record<string, unknown>;
476
- const output: Record<string, unknown> = {};
477
- for (const key of [
478
- "code",
479
- "command",
480
- "details",
481
- "stderr",
482
- "stdout",
483
- "killed",
484
- "args",
485
- ] as const) {
486
- if (record[key] !== undefined) {
487
- output[key] = record[key];
488
- }
489
- }
490
- return output;
491
- }
492
-
493
- function asRecord(value: unknown): Record<string, unknown> | undefined {
494
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
495
- return undefined;
496
- }
497
- return value as Record<string, unknown>;
498
- }
499
-
500
- function isRecord(value: unknown): value is Record<string, unknown> {
501
- return asRecord(value) !== undefined;
502
- }
@@ -5,6 +5,7 @@ import { cloneTaskState } from "../session-todos/state/state.js";
5
5
  import { applyTaskMutation } from "../session-todos/state/state-reducer.js";
6
6
  import { commitState, getState } from "../session-todos/state/store.js";
7
7
  import type { Task } from "../session-todos/tool/types.js";
8
+ import { isRecord } from "../shared/error-utils.js";
8
9
  import {
9
10
  errorToolDetails,
10
11
  okToolDetails,
@@ -325,7 +326,3 @@ function serializeError(error: unknown): unknown {
325
326
  }
326
327
  return error;
327
328
  }
328
-
329
- function isRecord(value: unknown): value is Record<string, unknown> {
330
- return typeof value === "object" && value !== null && !Array.isArray(value);
331
- }