@trevonistrevon/pi-loop 0.5.8 → 0.6.0

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 (127) hide show
  1. package/.release-please-manifest.json +3 -0
  2. package/AGENTS.md +52 -12
  3. package/CHANGELOG.md +59 -0
  4. package/CONTRIBUTING.md +13 -3
  5. package/Dockerfile +17 -0
  6. package/README.md +47 -0
  7. package/coverage/coverage-final.json +35 -31
  8. package/coverage/index.html +64 -49
  9. package/coverage/src/api.ts.html +193 -0
  10. package/coverage/src/commands/index.html +32 -32
  11. package/coverage/src/commands/loop-command.ts.html +170 -170
  12. package/coverage/src/commands/tasks-command.ts.html +135 -135
  13. package/coverage/src/coordinator.ts.html +26 -26
  14. package/coverage/src/index.html +61 -106
  15. package/coverage/src/index.ts.html +280 -94
  16. package/coverage/src/loop-parse.ts.html +90 -57
  17. package/coverage/src/loop-reducer.ts.html +25 -25
  18. package/coverage/src/monitor-completion-coordinator.ts.html +1 -1
  19. package/coverage/src/monitor-manager.ts.html +95 -71
  20. package/coverage/src/monitor-reducer.ts.html +15 -15
  21. package/coverage/src/notification-reducer.ts.html +7 -7
  22. package/coverage/src/reducer-backed-store.ts.html +57 -57
  23. package/coverage/src/rpc/channels.ts.html +376 -0
  24. package/coverage/src/rpc/cross-extension-rpc.ts.html +541 -0
  25. package/coverage/src/rpc/index.html +131 -0
  26. package/coverage/src/runtime/index.html +89 -29
  27. package/coverage/src/{goal-coordinator.ts.html → runtime/loop-events.ts.html} +79 -73
  28. package/coverage/src/runtime/monitor-ondone-runtime.ts.html +5 -5
  29. package/coverage/src/runtime/native-task-rpc.ts.html +502 -0
  30. package/coverage/src/runtime/notification-runtime.ts.html +14 -14
  31. package/coverage/src/runtime/scope.ts.html +17 -17
  32. package/coverage/src/runtime/session-runtime.ts.html +40 -40
  33. package/coverage/src/runtime/task-backlog-runtime.ts.html +66 -24
  34. package/coverage/src/runtime/task-events.ts.html +208 -0
  35. package/coverage/src/runtime/task-mutations.ts.html +394 -0
  36. package/coverage/src/runtime/task-rpc.ts.html +106 -118
  37. package/coverage/src/scheduler.ts.html +12 -12
  38. package/coverage/src/store.ts.html +20 -20
  39. package/coverage/src/task-backlog-coordinator.ts.html +8 -8
  40. package/coverage/src/task-reducer.ts.html +42 -42
  41. package/coverage/src/task-store.ts.html +49 -49
  42. package/coverage/src/tools/index.html +39 -24
  43. package/coverage/src/tools/loop-tools.ts.html +12 -21
  44. package/coverage/src/tools/monitor-tools.ts.html +12 -21
  45. package/coverage/src/tools/native-task-tools.ts.html +52 -94
  46. package/coverage/src/tools/tool-result.ts.html +97 -0
  47. package/coverage/src/trigger-system.ts.html +12 -12
  48. package/coverage/src/ui/index.html +1 -1
  49. package/coverage/src/ui/widget.ts.html +23 -23
  50. package/dist/api.d.ts +11 -0
  51. package/dist/api.js +10 -0
  52. package/dist/commands/loop-command.js +2 -2
  53. package/dist/commands/tasks-command.js +3 -3
  54. package/dist/coordinator.d.ts +1 -1
  55. package/dist/index.js +80 -20
  56. package/dist/loop-parse.js +14 -5
  57. package/dist/monitor-manager.d.ts +4 -1
  58. package/dist/monitor-manager.js +5 -3
  59. package/dist/reducer-backed-store.d.ts +1 -1
  60. package/dist/reducer-backed-store.js +1 -1
  61. package/dist/rpc/channels.d.ts +73 -0
  62. package/dist/rpc/channels.js +30 -0
  63. package/dist/rpc/cross-extension-rpc.d.ts +59 -0
  64. package/dist/rpc/cross-extension-rpc.js +117 -0
  65. package/dist/runtime/loop-events.d.ts +26 -0
  66. package/dist/runtime/loop-events.js +26 -0
  67. package/dist/runtime/native-task-rpc.d.ts +22 -0
  68. package/dist/runtime/native-task-rpc.js +50 -0
  69. package/dist/runtime/task-backlog-runtime.d.ts +3 -0
  70. package/dist/runtime/task-backlog-runtime.js +4 -1
  71. package/dist/runtime/task-mutations.d.ts +39 -0
  72. package/dist/runtime/task-mutations.js +68 -0
  73. package/dist/runtime/task-rpc.d.ts +4 -0
  74. package/dist/runtime/task-rpc.js +40 -58
  75. package/dist/scheduler.js +1 -1
  76. package/dist/tools/loop-tools.js +1 -3
  77. package/dist/tools/monitor-tools.js +1 -3
  78. package/dist/tools/native-task-tools.d.ts +2 -6
  79. package/dist/tools/native-task-tools.js +25 -55
  80. package/dist/tools/tool-result.d.ts +8 -0
  81. package/dist/tools/tool-result.js +4 -0
  82. package/docker-compose.yml +12 -0
  83. package/docs/architecture/state-machine-migration.md +0 -44
  84. package/docs/architecture/state-machine-reducer-event-model.md +2 -3
  85. package/package.json +6 -1
  86. package/release-please-config.json +9 -0
  87. package/src/api.ts +36 -0
  88. package/src/commands/loop-command.ts +2 -2
  89. package/src/commands/tasks-command.ts +3 -3
  90. package/src/coordinator.ts +1 -1
  91. package/src/index.ts +84 -22
  92. package/src/loop-parse.ts +18 -7
  93. package/src/monitor-manager.ts +11 -3
  94. package/src/reducer-backed-store.ts +3 -3
  95. package/src/rpc/channels.ts +97 -0
  96. package/src/rpc/cross-extension-rpc.ts +152 -0
  97. package/src/runtime/loop-events.ts +60 -0
  98. package/src/runtime/native-task-rpc.ts +139 -0
  99. package/src/runtime/task-backlog-runtime.ts +14 -0
  100. package/src/runtime/task-mutations.ts +103 -0
  101. package/src/runtime/task-rpc.ts +48 -54
  102. package/src/scheduler.ts +1 -1
  103. package/src/tools/loop-tools.ts +1 -4
  104. package/src/tools/monitor-tools.ts +1 -4
  105. package/src/tools/native-task-tools.ts +31 -52
  106. package/src/tools/tool-result.ts +4 -0
  107. package/src/trigger-system.ts +4 -4
  108. package/vitest.config.ts +11 -7
  109. package/coverage/src/goal-reducer.ts.html +0 -982
  110. package/coverage/src/goal-store.ts.html +0 -742
  111. package/coverage/src/goal-verifier.ts.html +0 -808
  112. package/dist/goal-coordinator.d.ts +0 -22
  113. package/dist/goal-coordinator.js +0 -28
  114. package/dist/goal-reducer.d.ts +0 -98
  115. package/dist/goal-reducer.js +0 -190
  116. package/dist/goal-store.d.ts +0 -22
  117. package/dist/goal-store.js +0 -188
  118. package/dist/goal-types.d.ts +0 -82
  119. package/dist/goal-types.js +0 -1
  120. package/dist/goal-verifier.d.ts +0 -20
  121. package/dist/goal-verifier.js +0 -198
  122. package/docs/architecture/goal-state-schema.md +0 -505
  123. package/src/goal-coordinator.ts +0 -58
  124. package/src/goal-reducer.ts +0 -299
  125. package/src/goal-store.ts +0 -219
  126. package/src/goal-types.ts +0 -104
  127. package/src/goal-verifier.ts +0 -241
@@ -23,30 +23,30 @@
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">20.23% </span>
26
+ <span class="strong">74.72% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>17/84</span>
28
+ <span class='fraction'>68/91</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">9.25% </span>
33
+ <span class="strong">61.66% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>5/54</span>
35
+ <span class='fraction'>37/60</span>
36
36
  </div>
37
37
 
38
38
 
39
39
  <div class='fl pad1y space-right2'>
40
- <span class="strong">50% </span>
40
+ <span class="strong">100% </span>
41
41
  <span class="quiet">Functions</span>
42
- <span class='fraction'>3/6</span>
42
+ <span class='fraction'>6/6</span>
43
43
  </div>
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">21.79% </span>
47
+ <span class="strong">80.48% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>17/78</span>
49
+ <span class='fraction'>66/82</span>
50
50
  </div>
51
51
 
52
52
 
@@ -61,7 +61,7 @@
61
61
  </div>
62
62
  </template>
63
63
  </div>
64
- <div class='status-line low'></div>
64
+ <div class='status-line medium'></div>
65
65
  <pre><table class="coverage">
66
66
  <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
67
  <a name='L2'></a><a href='#L2'>2</a>
@@ -215,125 +215,126 @@
215
215
  <span class="cline-any cline-neutral">&nbsp;</span>
216
216
  <span class="cline-any cline-neutral">&nbsp;</span>
217
217
  <span class="cline-any cline-neutral">&nbsp;</span>
218
- <span class="cline-any cline-yes">45x</span>
219
- <span class="cline-any cline-neutral">&nbsp;</span>
220
- <span class="cline-any cline-neutral">&nbsp;</span>
221
- <span class="cline-any cline-yes">1x</span>
222
- <span class="cline-any cline-neutral">&nbsp;</span>
223
- <span class="cline-any cline-neutral">&nbsp;</span>
224
218
  <span class="cline-any cline-neutral">&nbsp;</span>
219
+ <span class="cline-any cline-yes">60x</span>
225
220
  <span class="cline-any cline-neutral">&nbsp;</span>
226
221
  <span class="cline-any cline-neutral">&nbsp;</span>
227
- <span class="cline-any cline-yes">1x</span>
228
- <span class="cline-any cline-yes">1x</span>
229
- <span class="cline-any cline-yes">1x</span>
230
- <span class="cline-any cline-yes">1x</span>
231
- <span class="cline-any cline-yes">1x</span>
222
+ <span class="cline-any cline-yes">7x</span>
223
+ <span class="cline-any cline-yes">7x</span>
224
+ <span class="cline-any cline-yes">7x</span>
225
+ <span class="cline-any cline-yes">7x</span>
226
+ <span class="cline-any cline-yes">7x</span>
227
+ <span class="cline-any cline-yes">7x</span>
232
228
  <span class="cline-any cline-neutral">&nbsp;</span>
233
229
  <span class="cline-any cline-neutral">&nbsp;</span>
234
230
  <span class="cline-any cline-neutral">&nbsp;</span>
235
- <span class="cline-any cline-no">&nbsp;</span>
236
- <span class="cline-any cline-no">&nbsp;</span>
231
+ <span class="cline-any cline-yes">2x</span>
232
+ <span class="cline-any cline-yes">2x</span>
237
233
  <span class="cline-any cline-no">&nbsp;</span>
238
234
  <span class="cline-any cline-no">&nbsp;</span>
239
235
  <span class="cline-any cline-neutral">&nbsp;</span>
240
236
  <span class="cline-any cline-neutral">&nbsp;</span>
241
- <span class="cline-any cline-no">&nbsp;</span>
242
- <span class="cline-any cline-no">&nbsp;</span>
243
- <span class="cline-any cline-no">&nbsp;</span>
244
- <span class="cline-any cline-no">&nbsp;</span>
245
- <span class="cline-any cline-no">&nbsp;</span>
246
- <span class="cline-any cline-no">&nbsp;</span>
247
- <span class="cline-any cline-no">&nbsp;</span>
237
+ <span class="cline-any cline-yes">2x</span>
238
+ <span class="cline-any cline-yes">2x</span>
239
+ <span class="cline-any cline-yes">2x</span>
240
+ <span class="cline-any cline-yes">2x</span>
241
+ <span class="cline-any cline-yes">2x</span>
242
+ <span class="cline-any cline-yes">2x</span>
243
+ <span class="cline-any cline-yes">2x</span>
248
244
  <span class="cline-any cline-no">&nbsp;</span>
249
245
  <span class="cline-any cline-neutral">&nbsp;</span>
250
246
  <span class="cline-any cline-neutral">&nbsp;</span>
251
247
  <span class="cline-any cline-neutral">&nbsp;</span>
252
248
  <span class="cline-any cline-neutral">&nbsp;</span>
253
- <span class="cline-any cline-no">&nbsp;</span>
254
- <span class="cline-any cline-no">&nbsp;</span>
249
+ <span class="cline-any cline-yes">10x</span>
250
+ <span class="cline-any cline-yes">10x</span>
255
251
  <span class="cline-any cline-no">&nbsp;</span>
256
252
  <span class="cline-any cline-no">&nbsp;</span>
257
253
  <span class="cline-any cline-neutral">&nbsp;</span>
258
254
  <span class="cline-any cline-neutral">&nbsp;</span>
259
- <span class="cline-any cline-no">&nbsp;</span>
260
- <span class="cline-any cline-no">&nbsp;</span>
261
- <span class="cline-any cline-no">&nbsp;</span>
262
- <span class="cline-any cline-no">&nbsp;</span>
255
+ <span class="cline-any cline-yes">10x</span>
256
+ <span class="cline-any cline-yes">10x</span>
257
+ <span class="cline-any cline-yes">8x</span>
258
+ <span class="cline-any cline-yes">8x</span>
263
259
  <span class="cline-any cline-neutral">&nbsp;</span>
264
- <span class="cline-any cline-no">&nbsp;</span>
265
- <span class="cline-any cline-no">&nbsp;</span>
260
+ <span class="cline-any cline-yes">10x</span>
261
+ <span class="cline-any cline-yes">10x</span>
266
262
  <span class="cline-any cline-neutral">&nbsp;</span>
267
- <span class="cline-any cline-no">&nbsp;</span>
268
- <span class="cline-any cline-no">&nbsp;</span>
269
- <span class="cline-any cline-no">&nbsp;</span>
270
- <span class="cline-any cline-no">&nbsp;</span>
271
- <span class="cline-any cline-no">&nbsp;</span>
263
+ <span class="cline-any cline-yes">10x</span>
264
+ <span class="cline-any cline-yes">10x</span>
265
+ <span class="cline-any cline-yes">4x</span>
266
+ <span class="cline-any cline-yes">2x</span>
267
+ <span class="cline-any cline-yes">2x</span>
272
268
  <span class="cline-any cline-neutral">&nbsp;</span>
273
269
  <span class="cline-any cline-neutral">&nbsp;</span>
274
- <span class="cline-any cline-no">&nbsp;</span>
275
- <span class="cline-any cline-no">&nbsp;</span>
270
+ <span class="cline-any cline-yes">2x</span>
271
+ <span class="cline-any cline-yes">10x</span>
276
272
  <span class="cline-any cline-neutral">&nbsp;</span>
277
- <span class="cline-any cline-no">&nbsp;</span>
278
- <span class="cline-any cline-no">&nbsp;</span>
273
+ <span class="cline-any cline-yes">2x</span>
274
+ <span class="cline-any cline-yes">2x</span>
279
275
  <span class="cline-any cline-neutral">&nbsp;</span>
280
- <span class="cline-any cline-no">&nbsp;</span>
281
- <span class="cline-any cline-no">&nbsp;</span>
282
- <span class="cline-any cline-no">&nbsp;</span>
283
- <span class="cline-any cline-no">&nbsp;</span>
276
+ <span class="cline-any cline-yes">2x</span>
277
+ <span class="cline-any cline-yes">2x</span>
278
+ <span class="cline-any cline-yes">2x</span>
279
+ <span class="cline-any cline-yes">2x</span>
284
280
  <span class="cline-any cline-no">&nbsp;</span>
285
281
  <span class="cline-any cline-no">&nbsp;</span>
286
282
  <span class="cline-any cline-no">&nbsp;</span>
287
283
  <span class="cline-any cline-neutral">&nbsp;</span>
288
284
  <span class="cline-any cline-no">&nbsp;</span>
289
285
  <span class="cline-any cline-neutral">&nbsp;</span>
290
- <span class="cline-any cline-no">&nbsp;</span>
286
+ <span class="cline-any cline-yes">2x</span>
291
287
  <span class="cline-any cline-neutral">&nbsp;</span>
292
- <span class="cline-any cline-no">&nbsp;</span>
293
- <span class="cline-any cline-no">&nbsp;</span>
288
+ <span class="cline-any cline-yes">2x</span>
289
+ <span class="cline-any cline-yes">2x</span>
294
290
  <span class="cline-any cline-neutral">&nbsp;</span>
291
+ <span class="cline-any cline-yes">2x</span>
292
+ <span class="cline-any cline-yes">1x</span>
293
+ <span class="cline-any cline-yes">1x</span>
294
+ <span class="cline-any cline-yes">1x</span>
295
+ <span class="cline-any cline-yes">1x</span>
295
296
  <span class="cline-any cline-no">&nbsp;</span>
296
297
  <span class="cline-any cline-no">&nbsp;</span>
297
298
  <span class="cline-any cline-no">&nbsp;</span>
298
- <span class="cline-any cline-no">&nbsp;</span>
299
- <span class="cline-any cline-no">&nbsp;</span>
300
- <span class="cline-any cline-no">&nbsp;</span>
301
- <span class="cline-any cline-no">&nbsp;</span>
302
- <span class="cline-any cline-no">&nbsp;</span>
299
+ <span class="cline-any cline-yes">1x</span>
300
+ <span class="cline-any cline-yes">1x</span>
301
+ <span class="cline-any cline-yes">1x</span>
302
+ <span class="cline-any cline-yes">1x</span>
303
303
  <span class="cline-any cline-no">&nbsp;</span>
304
304
  <span class="cline-any cline-no">&nbsp;</span>
305
305
  <span class="cline-any cline-no">&nbsp;</span>
306
306
  <span class="cline-any cline-no">&nbsp;</span>
307
307
  <span class="cline-any cline-neutral">&nbsp;</span>
308
308
  <span class="cline-any cline-neutral">&nbsp;</span>
309
- <span class="cline-any cline-no">&nbsp;</span>
310
- <span class="cline-any cline-no">&nbsp;</span>
311
- <span class="cline-any cline-no">&nbsp;</span>
309
+ <span class="cline-any cline-yes">2x</span>
310
+ <span class="cline-any cline-yes">2x</span>
311
+ <span class="cline-any cline-yes">2x</span>
312
312
  <span class="cline-any cline-neutral">&nbsp;</span>
313
313
  <span class="cline-any cline-neutral">&nbsp;</span>
314
- <span class="cline-any cline-yes">45x</span>
314
+ <span class="cline-any cline-yes">60x</span>
315
315
  <span class="cline-any cline-neutral">&nbsp;</span>
316
316
  <span class="cline-any cline-neutral">&nbsp;</span>
317
+ <span class="cline-any cline-yes">12x</span>
318
+ <span class="cline-any cline-yes">12x</span>
319
+ <span class="cline-any cline-yes">12x</span>
317
320
  <span class="cline-any cline-yes">1x</span>
318
321
  <span class="cline-any cline-yes">1x</span>
319
- <span class="cline-any cline-yes">1x</span>
320
- <span class="cline-any cline-no">&nbsp;</span>
321
- <span class="cline-any cline-no">&nbsp;</span>
322
322
  <span class="cline-any cline-neutral">&nbsp;</span>
323
+ <span class="cline-any cline-yes">11x</span>
324
+ <span class="cline-any cline-yes">5x</span>
325
+ <span class="cline-any cline-yes">5x</span>
326
+ <span class="cline-any cline-yes">5x</span>
327
+ <span class="cline-any cline-yes">5x</span>
323
328
  <span class="cline-any cline-yes">1x</span>
324
- <span class="cline-any cline-yes">1x</span>
325
- <span class="cline-any cline-yes">1x</span>
326
- <span class="cline-any cline-yes">1x</span>
327
- <span class="cline-any cline-yes">1x</span>
328
- <span class="cline-any cline-no">&nbsp;</span>
329
329
  <span class="cline-any cline-neutral">&nbsp;</span>
330
- <span class="cline-any cline-yes">1x</span>
330
+ <span class="cline-any cline-yes">5x</span>
331
331
  <span class="cline-any cline-neutral">&nbsp;</span>
332
- <span class="cline-any cline-no">&nbsp;</span>
332
+ <span class="cline-any cline-yes">6x</span>
333
333
  <span class="cline-any cline-neutral">&nbsp;</span>
334
334
  <span class="cline-any cline-neutral">&nbsp;</span>
335
335
  <span class="cline-any cline-neutral">&nbsp;</span>
336
336
  <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import type { ExtensionAPI, ExtensionCommandContext, ExtensionUIContext } from "@earendil-works/pi-coding-agent";
337
+ import { emitNativeTaskEvent } from "../runtime/task-events.js";
337
338
  import { TaskStore } from "../task-store.js";
338
339
  import type { TaskEntry } from "../task-types.js";
339
340
  &nbsp;
@@ -353,12 +354,7 @@ export function registerTasksCommand(options: TasksCommandOptions): void {
353
354
  const { pi, getNativeTaskStore, evaluateTaskBacklog, updateWidget } = options;
354
355
  &nbsp;
355
356
  async function emitCreated(entry: TaskEntry) {
356
- pi.events.emit("tasks:created", {
357
- taskId: entry.id,
358
- subject: entry.subject,
359
- description: entry.description,
360
- status: entry.status,
361
- });
357
+ emitNativeTaskEvent(pi, "tasks:created", entry);
362
358
  const taskStore = getNativeTaskStore();
363
359
  <span class="missing-if-branch" title="if path not taken" >I</span>if (!taskStore) <span class="cstat-no" title="statement not covered" >return { created: false } satisfies TaskBacklogResult;</span>
364
360
  const backlog = await evaluateTaskBacklog(taskStore, taskStore.pendingCount());
@@ -366,84 +362,88 @@ export function registerTasksCommand(options: TasksCommandOptions): void {
366
362
  return backlog;
367
363
  }
368
364
  &nbsp;
369
- async function <span class="fstat-no" title="function not covered" >createNativeTaskInteractively(u</span>i: ExtensionUIContext) {
370
- const taskStore = <span class="cstat-no" title="statement not covered" >getNativeTaskStore();</span>
371
- <span class="cstat-no" title="statement not covered" > if (!taskStore) {</span>
365
+ async function createNativeTaskInteractively(ui: ExtensionUIContext) {
366
+ const taskStore = getNativeTaskStore();
367
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (!taskStore) {
372
368
  <span class="cstat-no" title="statement not covered" > ui.notify("Native tasks are unavailable while pi-tasks is active", "warning");</span>
373
369
  <span class="cstat-no" title="statement not covered" > return;</span>
374
370
  }
375
371
  &nbsp;
376
- const subject = <span class="cstat-no" title="statement not covered" >await ui.input("Task subject");</span>
377
- <span class="cstat-no" title="statement not covered" > if (!subject) <span class="cstat-no" title="statement not covered" >return;</span></span>
378
- const description = <span class="cstat-no" title="statement not covered" >await ui.input("Task description") || subject;</span>
379
- const entry = <span class="cstat-no" title="statement not covered" >taskStore.create(subject, description);</span>
380
- const backlog = <span class="cstat-no" title="statement not covered" >await emitCreated(entry);</span>
381
- <span class="cstat-no" title="statement not covered" > ui.notify(`Task #${entry.id} created`, "info");</span>
382
- <span class="cstat-no" title="statement not covered" > if (backlog.created &amp;&amp; backlog.entry) {</span>
372
+ const subject = await ui.input("Task subject");
373
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (!subject) <span class="cstat-no" title="statement not covered" >return;</span>
374
+ const description = await ui.input("Task description") || subject;
375
+ const entry = taskStore.create(subject, description);
376
+ const backlog = await emitCreated(entry);
377
+ ui.notify(`Task #${entry.id} created`, "info");
378
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (backlog.created &amp;&amp; <span class="branch-1 cbranch-no" title="branch not covered" >backlog.entry) {</span>
383
379
  <span class="cstat-no" title="statement not covered" > ui.notify(`Backlog worker loop #${backlog.entry.id} created`, "info");</span>
384
380
  }
385
381
  }
386
382
  &nbsp;
387
- async function <span class="fstat-no" title="function not covered" >viewNativeTasks(u</span>i: ExtensionUIContext): Promise&lt;void&gt; {
388
- const taskStore = <span class="cstat-no" title="statement not covered" >getNativeTaskStore();</span>
389
- <span class="cstat-no" title="statement not covered" > if (!taskStore) {</span>
383
+ async function viewNativeTasks(ui: ExtensionUIContext): Promise&lt;void&gt; {
384
+ const taskStore = getNativeTaskStore();
385
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (!taskStore) {
390
386
  <span class="cstat-no" title="statement not covered" > ui.notify("Native tasks are unavailable while pi-tasks is active", "warning");</span>
391
387
  <span class="cstat-no" title="statement not covered" > return;</span>
392
388
  }
393
389
  &nbsp;
394
- const tasks = <span class="cstat-no" title="statement not covered" >taskStore.list();</span>
395
- const choices = <span class="cstat-no" title="statement not covered" >tasks.<span class="fstat-no" title="function not covered" >map((t</span>ask) =&gt; {</span>
396
- const icon = <span class="cstat-no" title="statement not covered" >task.status === "in_progress" ? "&gt;" : task.status === "completed" ? "ok" : "*";</span>
397
- <span class="cstat-no" title="statement not covered" > return `${icon} #${task.id} [${task.status}] ${task.subject.slice(0, 60)}`;</span>
390
+ const tasks = taskStore.list();
391
+ const choices = tasks.map((task) =&gt; {
392
+ const icon = task.status === "in_progress" ? "&gt;" : task.status === "completed" ? "ok" : "*";
393
+ return `${icon} #${task.id} [${task.status}] ${task.subject.slice(0, 60)}`;
398
394
  });
399
- <span class="cstat-no" title="statement not covered" > choices.unshift("+ Create task");</span>
400
- <span class="cstat-no" title="statement not covered" > choices.push("&lt; Back");</span>
395
+ choices.unshift("+ Create task");
396
+ choices.push("&lt; Back");
401
397
  &nbsp;
402
- const selected = <span class="cstat-no" title="statement not covered" >await ui.select("Tasks", choices);</span>
403
- <span class="cstat-no" title="statement not covered" > if (!selected || selected === "&lt; Back") <span class="cstat-no" title="statement not covered" >return;</span></span>
404
- <span class="cstat-no" title="statement not covered" > if (selected === "+ Create task") {</span>
405
- <span class="cstat-no" title="statement not covered" > await createNativeTaskInteractively(ui);</span>
406
- <span class="cstat-no" title="statement not covered" > return viewNativeTasks(ui);</span>
398
+ const selected = await ui.select("Tasks", choices);
399
+ if (!selected || selected === "&lt; Back") return;
400
+ if (selected === "+ Create task") {
401
+ await createNativeTaskInteractively(ui);
402
+ return viewNativeTasks(ui);
407
403
  }
408
404
  &nbsp;
409
- const match = <span class="cstat-no" title="statement not covered" >selected.match(/#(\d+)/);</span>
410
- <span class="cstat-no" title="statement not covered" > if (!match) <span class="cstat-no" title="statement not covered" >return viewNativeTasks(ui);</span></span>
405
+ const taskId = selected.match(/#(\d+)/)?.[1];
406
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (!taskId) <span class="cstat-no" title="statement not covered" >return viewNativeTasks(ui);</span>
411
407
  &nbsp;
412
- const task = <span class="cstat-no" title="statement not covered" >taskStore.get(match[1]);</span>
413
- <span class="cstat-no" title="statement not covered" > if (!task) <span class="cstat-no" title="statement not covered" >return viewNativeTasks(ui);</span></span>
408
+ const task = taskStore.get(taskId);
409
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (!task) <span class="cstat-no" title="statement not covered" >return viewNativeTasks(ui);</span>
414
410
  &nbsp;
415
- const actions = <span class="cstat-no" title="statement not covered" >["x Delete"];</span>
416
- <span class="cstat-no" title="statement not covered" > if (task.status === "pending") {</span>
417
- <span class="cstat-no" title="statement not covered" > actions.unshift("ok Complete");</span>
418
- <span class="cstat-no" title="statement not covered" > actions.unshift("&gt; Start");</span>
419
- } else <span class="cstat-no" title="statement not covered" >if (task.status === "in_progress") {</span>
411
+ const actions = ["x Delete"];
412
+ if (task.status === "pending") {
413
+ actions.unshift("ok Complete");
414
+ actions.unshift("&gt; Start");
415
+ } else <span class="cstat-no" title="statement not covered" ><span class="missing-if-branch" title="else path not taken" >E</span>if (task.status === "in_progress") {</span>
420
416
  <span class="cstat-no" title="statement not covered" > actions.unshift("ok Complete");</span>
421
417
  <span class="cstat-no" title="statement not covered" > actions.unshift("* Return to pending");</span>
422
418
  } else {
423
419
  <span class="cstat-no" title="statement not covered" > actions.unshift("* Reopen");</span>
424
420
  }
425
- <span class="cstat-no" title="statement not covered" > actions.push("&lt; Back");</span>
421
+ actions.push("&lt; Back");
426
422
  &nbsp;
427
- const action = <span class="cstat-no" title="statement not covered" >await ui.select(`#${task.id}: ${task.subject}\n\n${task.description}`, actions);</span>
428
- <span class="cstat-no" title="statement not covered" > if (!action || action === "&lt; Back") <span class="cstat-no" title="statement not covered" >return viewNativeTasks(ui);</span></span>
423
+ const action = await ui.select(`#${task.id}: ${task.subject}\n\n${task.description}`, actions);
424
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (!action || action === "&lt; Back") <span class="cstat-no" title="statement not covered" >return viewNativeTasks(ui);</span>
429
425
  &nbsp;
430
- <span class="cstat-no" title="statement not covered" > if (action === "x Delete") {</span>
431
- <span class="cstat-no" title="statement not covered" > taskStore.delete(task.id);</span>
432
- <span class="cstat-no" title="statement not covered" > ui.notify(`Task #${task.id} deleted`, "info");</span>
433
- } else <span class="cstat-no" title="statement not covered" >if (action === "&gt; Start") {</span>
434
- <span class="cstat-no" title="statement not covered" > taskStore.start(task.id);</span>
426
+ if (action === "x Delete") {
427
+ taskStore.delete(task.id);
428
+ emitNativeTaskEvent(pi, "tasks:deleted", task, task.status);
429
+ ui.notify(`Task #${task.id} deleted`, "info");
430
+ } else <span class="missing-if-branch" title="if path not taken" >I</span>if (action === "&gt; Start") {
431
+ const next = <span class="cstat-no" title="statement not covered" >taskStore.start(task.id);</span>
432
+ <span class="cstat-no" title="statement not covered" > if (<span class="cstat-no" title="statement not covered" >next) emitNativeTaskEvent(pi, "tasks:started", next, task.status);</span></span>
435
433
  <span class="cstat-no" title="statement not covered" > ui.notify(`Task #${task.id} started`, "info");</span>
436
- } else <span class="cstat-no" title="statement not covered" >if (action === "ok Complete") {</span>
437
- <span class="cstat-no" title="statement not covered" > taskStore.complete(task.id);</span>
438
- <span class="cstat-no" title="statement not covered" > ui.notify(`Task #${task.id} completed`, "info");</span>
439
- } else <span class="cstat-no" title="statement not covered" >if (action === "* Return to pending" || action === "* Reopen") {</span>
440
- <span class="cstat-no" title="statement not covered" > taskStore.reopen(task.id);</span>
434
+ } else if (action === "ok Complete") {
435
+ const next = taskStore.complete(task.id);
436
+ <span class="missing-if-branch" title="else path not taken" >E</span>if (next) emitNativeTaskEvent(pi, "tasks:completed", next, task.status);
437
+ ui.notify(`Task #${task.id} completed`, "info");
438
+ } else <span class="cstat-no" title="statement not covered" ><span class="missing-if-branch" title="else path not taken" >E</span>if (action === "* Return to pending" || action === "* Reopen") {</span>
439
+ const next = <span class="cstat-no" title="statement not covered" >taskStore.reopen(task.id);</span>
440
+ <span class="cstat-no" title="statement not covered" > if (<span class="cstat-no" title="statement not covered" >next) emitNativeTaskEvent(pi, "tasks:reopened", next, task.status);</span></span>
441
441
  <span class="cstat-no" title="statement not covered" > ui.notify(`Task #${task.id} reopened`, "info");</span>
442
442
  }
443
443
  &nbsp;
444
- <span class="cstat-no" title="statement not covered" > updateWidget();</span>
445
- <span class="cstat-no" title="statement not covered" > await evaluateTaskBacklog(taskStore, taskStore.pendingCount());</span>
446
- <span class="cstat-no" title="statement not covered" > return viewNativeTasks(ui);</span>
444
+ updateWidget();
445
+ await evaluateTaskBacklog(taskStore, taskStore.pendingCount());
446
+ return viewNativeTasks(ui);
447
447
  }
448
448
  &nbsp;
449
449
  pi.registerCommand("tasks", {
@@ -451,20 +451,20 @@ export function registerTasksCommand(options: TasksCommandOptions): void {
451
451
  handler: async (args: string, ctx: ExtensionCommandContext) =&gt; {
452
452
  const trimmed = args.trim();
453
453
  const taskStore = getNativeTaskStore();
454
- <span class="missing-if-branch" title="if path not taken" >I</span>if (!taskStore) {
455
- <span class="cstat-no" title="statement not covered" > ctx.ui.notify("Native tasks are unavailable while pi-tasks is active", "warning");</span>
456
- <span class="cstat-no" title="statement not covered" > return;</span>
454
+ if (!taskStore) {
455
+ ctx.ui.notify("Native tasks are unavailable while pi-tasks is active", "warning");
456
+ return;
457
457
  }
458
- <span class="missing-if-branch" title="else path not taken" >E</span>if (trimmed) {
458
+ if (trimmed) {
459
459
  const entry = taskStore.create(trimmed.slice(0, 80), trimmed);
460
460
  const backlog = await emitCreated(entry);
461
461
  ctx.ui.notify(`Task #${entry.id} created`, "info");
462
- <span class="missing-if-branch" title="if path not taken" >I</span>if (backlog.created &amp;&amp; <span class="branch-1 cbranch-no" title="branch not covered" >backlog.entry) {</span>
463
- <span class="cstat-no" title="statement not covered" > ctx.ui.notify(`Backlog worker loop #${backlog.entry.id} created`, "info");</span>
462
+ if (backlog.created &amp;&amp; backlog.entry) {
463
+ ctx.ui.notify(`Backlog worker loop #${backlog.entry.id} created`, "info");
464
464
  }
465
465
  return;
466
466
  }
467
- <span class="cstat-no" title="statement not covered" > await viewNativeTasks(ctx.ui);</span>
467
+ await viewNativeTasks(ctx.ui);
468
468
  },
469
469
  });
470
470
  }
@@ -475,7 +475,7 @@ export function registerTasksCommand(options: TasksCommandOptions): void {
475
475
  <div class='footer quiet pad2 space-top1 center small'>
476
476
  Code coverage generated by
477
477
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
478
- at 2026-06-19T00:56:38.236Z
478
+ at 2026-07-02T19:31:50.067Z
479
479
  </div>
480
480
  <script src="../../prettify.js"></script>
481
481
  <script>
@@ -30,9 +30,9 @@
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">92% </span>
33
+ <span class="strong">88% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>23/25</span>
35
+ <span class='fraction'>22/25</span>
36
36
  </div>
37
37
 
38
38
 
@@ -239,55 +239,55 @@
239
239
  <span class="cline-any cline-neutral">&nbsp;</span>
240
240
  <span class="cline-any cline-neutral">&nbsp;</span>
241
241
  <span class="cline-any cline-neutral">&nbsp;</span>
242
- <span class="cline-any cline-yes">212x</span>
242
+ <span class="cline-any cline-yes">222x</span>
243
243
  <span class="cline-any cline-neutral">&nbsp;</span>
244
244
  <span class="cline-any cline-neutral">&nbsp;</span>
245
- <span class="cline-any cline-yes">263x</span>
245
+ <span class="cline-any cline-yes">248x</span>
246
246
  <span class="cline-any cline-neutral">&nbsp;</span>
247
247
  <span class="cline-any cline-neutral">&nbsp;</span>
248
248
  <span class="cline-any cline-neutral">&nbsp;</span>
249
- <span class="cline-any cline-yes">99x</span>
250
- <span class="cline-any cline-yes">10x</span>
251
- <span class="cline-any cline-yes">10x</span>
252
- <span class="cline-any cline-yes">10x</span>
249
+ <span class="cline-any cline-yes">84x</span>
250
+ <span class="cline-any cline-yes">4x</span>
251
+ <span class="cline-any cline-yes">4x</span>
252
+ <span class="cline-any cline-yes">4x</span>
253
253
  <span class="cline-any cline-no">&nbsp;</span>
254
254
  <span class="cline-any cline-neutral">&nbsp;</span>
255
- <span class="cline-any cline-yes">10x</span>
256
- <span class="cline-any cline-yes">7x</span>
255
+ <span class="cline-any cline-yes">4x</span>
256
+ <span class="cline-any cline-yes">1x</span>
257
257
  <span class="cline-any cline-neutral">&nbsp;</span>
258
258
  <span class="cline-any cline-neutral">&nbsp;</span>
259
- <span class="cline-any cline-yes">89x</span>
260
- <span class="cline-any cline-yes">89x</span>
259
+ <span class="cline-any cline-yes">80x</span>
260
+ <span class="cline-any cline-yes">80x</span>
261
261
  <span class="cline-any cline-yes">72x</span>
262
262
  <span class="cline-any cline-yes">72x</span>
263
263
  <span class="cline-any cline-yes">72x</span>
264
264
  <span class="cline-any cline-neutral">&nbsp;</span>
265
265
  <span class="cline-any cline-neutral">&nbsp;</span>
266
- <span class="cline-any cline-yes">17x</span>
266
+ <span class="cline-any cline-yes">8x</span>
267
267
  <span class="cline-any cline-yes">8x</span>
268
268
  <span class="cline-any cline-yes">8x</span>
269
269
  <span class="cline-any cline-neutral">&nbsp;</span>
270
270
  <span class="cline-any cline-neutral">&nbsp;</span>
271
271
  <span class="cline-any cline-neutral">&nbsp;</span>
272
272
  <span class="cline-any cline-neutral">&nbsp;</span>
273
- <span class="cline-any cline-yes">174x</span>
273
+ <span class="cline-any cline-yes">168x</span>
274
274
  <span class="cline-any cline-yes">1x</span>
275
275
  <span class="cline-any cline-neutral">&nbsp;</span>
276
276
  <span class="cline-any cline-neutral">&nbsp;</span>
277
- <span class="cline-any cline-yes">173x</span>
278
- <span class="cline-any cline-yes">173x</span>
279
- <span class="cline-any cline-yes">183x</span>
280
- <span class="cline-any cline-yes">183x</span>
281
- <span class="cline-any cline-yes">183x</span>
282
- <span class="cline-any cline-yes">90x</span>
277
+ <span class="cline-any cline-yes">167x</span>
278
+ <span class="cline-any cline-yes">167x</span>
279
+ <span class="cline-any cline-yes">168x</span>
280
+ <span class="cline-any cline-yes">168x</span>
281
+ <span class="cline-any cline-yes">168x</span>
282
+ <span class="cline-any cline-yes">80x</span>
283
283
  <span class="cline-any cline-neutral">&nbsp;</span>
284
284
  <span class="cline-any cline-neutral">&nbsp;</span>
285
- <span class="cline-any cline-yes">173x</span>
286
- <span class="cline-any cline-yes">99x</span>
285
+ <span class="cline-any cline-yes">167x</span>
286
+ <span class="cline-any cline-yes">84x</span>
287
287
  <span class="cline-any cline-neutral">&nbsp;</span>
288
288
  <span class="cline-any cline-neutral">&nbsp;</span>
289
289
  <span class="cline-any cline-neutral">&nbsp;</span>
290
- <span class="cline-any cline-yes">212x</span>
290
+ <span class="cline-any cline-yes">222x</span>
291
291
  <span class="cline-any cline-neutral">&nbsp;</span>
292
292
  <span class="cline-any cline-yes">164x</span>
293
293
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -303,7 +303,7 @@
303
303
  | "coordinator"
304
304
  | "system";
305
305
  &nbsp;
306
- export type ReducerEntityType = "task" | "loop" | "monitor" | "notification" | "goal";
306
+ export type ReducerEntityType = "task" | "loop" | "monitor" | "notification";
307
307
  &nbsp;
308
308
  export interface ReducerEvent&lt;TType extends string = string, TPayload = unknown&gt; {
309
309
  type: TType;
@@ -378,7 +378,7 @@ export function createCoordinator(options: CoordinatorOptions): Coordinator {
378
378
  return;
379
379
  }
380
380
  &nbsp;
381
- if (effectExecutor) {
381
+ <span class="missing-if-branch" title="else path not taken" >E</span>if (effectExecutor) {
382
382
  const handled = effectExecutor(effect);
383
383
  <span class="missing-if-branch" title="else path not taken" >E</span>if (isPromiseLike(handled)) await handled;
384
384
  }
@@ -415,7 +415,7 @@ export function createCoordinator(options: CoordinatorOptions): Coordinator {
415
415
  <div class='footer quiet pad2 space-top1 center small'>
416
416
  Code coverage generated by
417
417
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
418
- at 2026-06-19T00:56:38.236Z
418
+ at 2026-07-02T19:31:50.067Z
419
419
  </div>
420
420
  <script src="../prettify.js"></script>
421
421
  <script>