@trevonistrevon/pi-loop 0.5.9 → 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 (121) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/AGENTS.md +52 -12
  3. package/CHANGELOG.md +59 -0
  4. package/CONTRIBUTING.md +13 -3
  5. package/README.md +47 -0
  6. package/coverage/coverage-final.json +35 -32
  7. package/coverage/index.html +64 -49
  8. package/coverage/src/api.ts.html +193 -0
  9. package/coverage/src/commands/index.html +32 -32
  10. package/coverage/src/commands/loop-command.ts.html +170 -170
  11. package/coverage/src/commands/tasks-command.ts.html +129 -129
  12. package/coverage/src/coordinator.ts.html +26 -26
  13. package/coverage/src/index.html +61 -106
  14. package/coverage/src/index.ts.html +224 -86
  15. package/coverage/src/loop-parse.ts.html +106 -73
  16. package/coverage/src/loop-reducer.ts.html +21 -21
  17. package/coverage/src/monitor-completion-coordinator.ts.html +1 -1
  18. package/coverage/src/monitor-manager.ts.html +95 -71
  19. package/coverage/src/monitor-reducer.ts.html +15 -15
  20. package/coverage/src/notification-reducer.ts.html +6 -6
  21. package/coverage/src/reducer-backed-store.ts.html +57 -57
  22. package/coverage/src/rpc/channels.ts.html +376 -0
  23. package/coverage/src/rpc/cross-extension-rpc.ts.html +541 -0
  24. package/coverage/src/rpc/index.html +131 -0
  25. package/coverage/src/runtime/index.html +68 -23
  26. package/coverage/src/{goal-coordinator.ts.html → runtime/loop-events.ts.html} +79 -73
  27. package/coverage/src/runtime/monitor-ondone-runtime.ts.html +5 -5
  28. package/coverage/src/runtime/native-task-rpc.ts.html +502 -0
  29. package/coverage/src/runtime/notification-runtime.ts.html +22 -22
  30. package/coverage/src/runtime/scope.ts.html +14 -14
  31. package/coverage/src/runtime/session-runtime.ts.html +32 -32
  32. package/coverage/src/runtime/task-backlog-runtime.ts.html +65 -23
  33. package/coverage/src/runtime/task-events.ts.html +2 -2
  34. package/coverage/src/runtime/task-mutations.ts.html +394 -0
  35. package/coverage/src/runtime/task-rpc.ts.html +102 -120
  36. package/coverage/src/scheduler.ts.html +29 -29
  37. package/coverage/src/store.ts.html +27 -27
  38. package/coverage/src/task-backlog-coordinator.ts.html +8 -8
  39. package/coverage/src/task-reducer.ts.html +42 -42
  40. package/coverage/src/task-store.ts.html +49 -49
  41. package/coverage/src/tools/index.html +39 -24
  42. package/coverage/src/tools/loop-tools.ts.html +12 -21
  43. package/coverage/src/tools/monitor-tools.ts.html +12 -21
  44. package/coverage/src/tools/native-task-tools.ts.html +57 -120
  45. package/coverage/src/tools/tool-result.ts.html +97 -0
  46. package/coverage/src/trigger-system.ts.html +12 -12
  47. package/coverage/src/ui/index.html +1 -1
  48. package/coverage/src/ui/widget.ts.html +23 -23
  49. package/dist/api.d.ts +11 -0
  50. package/dist/api.js +10 -0
  51. package/dist/commands/loop-command.js +2 -2
  52. package/dist/commands/tasks-command.js +3 -3
  53. package/dist/coordinator.d.ts +1 -1
  54. package/dist/index.js +48 -3
  55. package/dist/loop-parse.js +14 -5
  56. package/dist/reducer-backed-store.d.ts +1 -1
  57. package/dist/reducer-backed-store.js +1 -1
  58. package/dist/rpc/channels.d.ts +73 -0
  59. package/dist/rpc/channels.js +30 -0
  60. package/dist/rpc/cross-extension-rpc.d.ts +59 -0
  61. package/dist/rpc/cross-extension-rpc.js +117 -0
  62. package/dist/runtime/loop-events.d.ts +26 -0
  63. package/dist/runtime/loop-events.js +26 -0
  64. package/dist/runtime/native-task-rpc.d.ts +22 -0
  65. package/dist/runtime/native-task-rpc.js +50 -0
  66. package/dist/runtime/task-backlog-runtime.d.ts +3 -0
  67. package/dist/runtime/task-backlog-runtime.js +4 -1
  68. package/dist/runtime/task-mutations.d.ts +39 -0
  69. package/dist/runtime/task-mutations.js +68 -0
  70. package/dist/runtime/task-rpc.d.ts +4 -0
  71. package/dist/runtime/task-rpc.js +40 -58
  72. package/dist/scheduler.js +1 -1
  73. package/dist/tools/loop-tools.js +1 -3
  74. package/dist/tools/monitor-tools.js +1 -3
  75. package/dist/tools/native-task-tools.d.ts +2 -6
  76. package/dist/tools/native-task-tools.js +25 -55
  77. package/dist/tools/tool-result.d.ts +8 -0
  78. package/dist/tools/tool-result.js +4 -0
  79. package/docs/architecture/state-machine-migration.md +0 -44
  80. package/docs/architecture/state-machine-reducer-event-model.md +2 -3
  81. package/package.json +6 -1
  82. package/src/api.ts +36 -0
  83. package/src/commands/loop-command.ts +2 -2
  84. package/src/commands/tasks-command.ts +3 -3
  85. package/src/coordinator.ts +1 -1
  86. package/src/index.ts +49 -3
  87. package/src/loop-parse.ts +18 -7
  88. package/src/reducer-backed-store.ts +3 -3
  89. package/src/rpc/channels.ts +97 -0
  90. package/src/rpc/cross-extension-rpc.ts +152 -0
  91. package/src/runtime/loop-events.ts +60 -0
  92. package/src/runtime/native-task-rpc.ts +139 -0
  93. package/src/runtime/task-backlog-runtime.ts +14 -0
  94. package/src/runtime/task-mutations.ts +103 -0
  95. package/src/runtime/task-rpc.ts +48 -54
  96. package/src/scheduler.ts +1 -1
  97. package/src/tools/loop-tools.ts +1 -4
  98. package/src/tools/monitor-tools.ts +1 -4
  99. package/src/tools/native-task-tools.ts +31 -52
  100. package/src/tools/tool-result.ts +4 -0
  101. package/src/trigger-system.ts +4 -4
  102. package/vitest.config.ts +7 -7
  103. package/coverage/src/goal-reducer.ts.html +0 -982
  104. package/coverage/src/goal-store.ts.html +0 -742
  105. package/coverage/src/goal-verifier.ts.html +0 -808
  106. package/dist/goal-coordinator.d.ts +0 -22
  107. package/dist/goal-coordinator.js +0 -28
  108. package/dist/goal-reducer.d.ts +0 -98
  109. package/dist/goal-reducer.js +0 -190
  110. package/dist/goal-store.d.ts +0 -22
  111. package/dist/goal-store.js +0 -188
  112. package/dist/goal-types.d.ts +0 -82
  113. package/dist/goal-types.js +0 -1
  114. package/dist/goal-verifier.d.ts +0 -20
  115. package/dist/goal-verifier.js +0 -198
  116. package/docs/architecture/goal-state-schema.md +0 -505
  117. package/src/goal-coordinator.ts +0 -58
  118. package/src/goal-reducer.ts +0 -299
  119. package/src/goal-store.ts +0 -219
  120. package/src/goal-types.ts +0 -104
  121. 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">17.14% </span>
26
+ <span class="strong">86.66% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>18/105</span>
28
+ <span class='fraction'>91/105</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">5.17% </span>
33
+ <span class="strong">70% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>3/58</span>
35
+ <span class='fraction'>42/60</span>
36
36
  </div>
37
37
 
38
38
 
39
39
  <div class='fl pad1y space-right2'>
40
- <span class="strong">25% </span>
40
+ <span class="strong">87.5% </span>
41
41
  <span class="quiet">Functions</span>
42
- <span class='fraction'>2/8</span>
42
+ <span class='fraction'>7/8</span>
43
43
  </div>
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">19.78% </span>
47
+ <span class="strong">92.3% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>18/91</span>
49
+ <span class='fraction'>84/91</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 high'></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>
@@ -276,156 +276,156 @@
276
276
  <span class="cline-any cline-neutral">&nbsp;</span>
277
277
  <span class="cline-any cline-neutral">&nbsp;</span>
278
278
  <span class="cline-any cline-neutral">&nbsp;</span>
279
- <span class="cline-any cline-yes">63x</span>
279
+ <span class="cline-any cline-yes">78x</span>
280
280
  <span class="cline-any cline-neutral">&nbsp;</span>
281
281
  <span class="cline-any cline-neutral">&nbsp;</span>
282
- <span class="cline-any cline-no">&nbsp;</span>
283
- <span class="cline-any cline-no">&nbsp;</span>
282
+ <span class="cline-any cline-yes">3x</span>
283
+ <span class="cline-any cline-yes">2x</span>
284
284
  <span class="cline-any cline-neutral">&nbsp;</span>
285
- <span class="cline-any cline-no">&nbsp;</span>
286
- <span class="cline-any cline-no">&nbsp;</span>
285
+ <span class="cline-any cline-yes">3x</span>
286
+ <span class="cline-any cline-yes">3x</span>
287
287
  <span class="cline-any cline-neutral">&nbsp;</span>
288
- <span class="cline-any cline-no">&nbsp;</span>
289
- <span class="cline-any cline-no">&nbsp;</span>
290
- <span class="cline-any cline-no">&nbsp;</span>
291
- <span class="cline-any cline-no">&nbsp;</span>
292
- <span class="cline-any cline-no">&nbsp;</span>
293
- <span class="cline-any cline-no">&nbsp;</span>
294
- <span class="cline-any cline-no">&nbsp;</span>
288
+ <span class="cline-any cline-yes">3x</span>
289
+ <span class="cline-any cline-yes">3x</span>
290
+ <span class="cline-any cline-yes">3x</span>
291
+ <span class="cline-any cline-yes">3x</span>
292
+ <span class="cline-any cline-yes">3x</span>
293
+ <span class="cline-any cline-yes">3x</span>
294
+ <span class="cline-any cline-yes">3x</span>
295
295
  <span class="cline-any cline-neutral">&nbsp;</span>
296
- <span class="cline-any cline-no">&nbsp;</span>
296
+ <span class="cline-any cline-yes">1x</span>
297
297
  <span class="cline-any cline-neutral">&nbsp;</span>
298
298
  <span class="cline-any cline-neutral">&nbsp;</span>
299
299
  <span class="cline-any cline-neutral">&nbsp;</span>
300
300
  <span class="cline-any cline-neutral">&nbsp;</span>
301
- <span class="cline-any cline-no">&nbsp;</span>
302
- <span class="cline-any cline-no">&nbsp;</span>
301
+ <span class="cline-any cline-yes">2x</span>
302
+ <span class="cline-any cline-yes">1x</span>
303
303
  <span class="cline-any cline-neutral">&nbsp;</span>
304
- <span class="cline-any cline-no">&nbsp;</span>
305
- <span class="cline-any cline-no">&nbsp;</span>
304
+ <span class="cline-any cline-yes">2x</span>
305
+ <span class="cline-any cline-yes">2x</span>
306
306
  <span class="cline-any cline-neutral">&nbsp;</span>
307
- <span class="cline-any cline-no">&nbsp;</span>
308
- <span class="cline-any cline-no">&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>
307
+ <span class="cline-any cline-yes">2x</span>
308
+ <span class="cline-any cline-yes">2x</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
314
  <span class="cline-any cline-neutral">&nbsp;</span>
315
- <span class="cline-any cline-no">&nbsp;</span>
316
- <span class="cline-any cline-no">&nbsp;</span>
317
- <span class="cline-any cline-no">&nbsp;</span>
318
- <span class="cline-any cline-no">&nbsp;</span>
315
+ <span class="cline-any cline-yes">5x</span>
316
+ <span class="cline-any cline-yes">5x</span>
317
+ <span class="cline-any cline-yes">2x</span>
318
+ <span class="cline-any cline-yes">2x</span>
319
319
  <span class="cline-any cline-neutral">&nbsp;</span>
320
320
  <span class="cline-any cline-neutral">&nbsp;</span>
321
- <span class="cline-any cline-no">&nbsp;</span>
322
- <span class="cline-any cline-no">&nbsp;</span>
323
- <span class="cline-any cline-no">&nbsp;</span>
321
+ <span class="cline-any cline-yes">3x</span>
322
+ <span class="cline-any cline-yes">3x</span>
323
+ <span class="cline-any cline-yes">3x</span>
324
324
  <span class="cline-any cline-neutral">&nbsp;</span>
325
325
  <span class="cline-any cline-neutral">&nbsp;</span>
326
326
  <span class="cline-any cline-neutral">&nbsp;</span>
327
327
  <span class="cline-any cline-neutral">&nbsp;</span>
328
- <span class="cline-any cline-no">&nbsp;</span>
328
+ <span class="cline-any cline-yes">3x</span>
329
329
  <span class="cline-any cline-neutral">&nbsp;</span>
330
- <span class="cline-any cline-no">&nbsp;</span>
330
+ <span class="cline-any cline-yes">3x</span>
331
331
  <span class="cline-any cline-neutral">&nbsp;</span>
332
- <span class="cline-any cline-no">&nbsp;</span>
333
- <span class="cline-any cline-no">&nbsp;</span>
332
+ <span class="cline-any cline-yes">3x</span>
333
+ <span class="cline-any cline-yes">3x</span>
334
334
  <span class="cline-any cline-neutral">&nbsp;</span>
335
+ <span class="cline-any cline-yes">2x</span>
336
+ <span class="cline-any cline-yes">2x</span>
337
+ <span class="cline-any cline-yes">2x</span>
338
+ <span class="cline-any cline-yes">2x</span>
339
+ <span class="cline-any cline-yes">2x</span>
340
+ <span class="cline-any cline-yes">2x</span>
335
341
  <span class="cline-any cline-no">&nbsp;</span>
336
- <span class="cline-any cline-no">&nbsp;</span>
337
- <span class="cline-any cline-no">&nbsp;</span>
338
- <span class="cline-any cline-no">&nbsp;</span>
339
- <span class="cline-any cline-no">&nbsp;</span>
340
- <span class="cline-any cline-no">&nbsp;</span>
341
- <span class="cline-any cline-no">&nbsp;</span>
342
- <span class="cline-any cline-no">&nbsp;</span>
342
+ <span class="cline-any cline-yes">2x</span>
343
343
  <span class="cline-any cline-neutral">&nbsp;</span>
344
- <span class="cline-any cline-no">&nbsp;</span>
344
+ <span class="cline-any cline-yes">2x</span>
345
345
  <span class="cline-any cline-neutral">&nbsp;</span>
346
346
  <span class="cline-any cline-neutral">&nbsp;</span>
347
347
  <span class="cline-any cline-neutral">&nbsp;</span>
348
348
  <span class="cline-any cline-neutral">&nbsp;</span>
349
+ <span class="cline-any cline-yes">2x</span>
350
+ <span class="cline-any cline-yes">1x</span>
351
+ <span class="cline-any cline-yes">1x</span>
352
+ <span class="cline-any cline-yes">1x</span>
353
+ <span class="cline-any cline-yes">1x</span>
354
+ <span class="cline-any cline-yes">1x</span>
355
+ <span class="cline-any cline-yes">1x</span>
356
+ <span class="cline-any cline-yes">1x</span>
357
+ <span class="cline-any cline-yes">1x</span>
358
+ <span class="cline-any cline-yes">1x</span>
349
359
  <span class="cline-any cline-no">&nbsp;</span>
350
360
  <span class="cline-any cline-no">&nbsp;</span>
351
361
  <span class="cline-any cline-no">&nbsp;</span>
352
362
  <span class="cline-any cline-no">&nbsp;</span>
353
363
  <span class="cline-any cline-no">&nbsp;</span>
354
- <span class="cline-any cline-no">&nbsp;</span>
355
- <span class="cline-any cline-no">&nbsp;</span>
356
- <span class="cline-any cline-no">&nbsp;</span>
357
- <span class="cline-any cline-no">&nbsp;</span>
358
- <span class="cline-any cline-no">&nbsp;</span>
359
- <span class="cline-any cline-no">&nbsp;</span>
360
- <span class="cline-any cline-no">&nbsp;</span>
361
- <span class="cline-any cline-no">&nbsp;</span>
362
- <span class="cline-any cline-no">&nbsp;</span>
363
- <span class="cline-any cline-no">&nbsp;</span>
364
- <span class="cline-any cline-neutral">&nbsp;</span>
365
- <span class="cline-any cline-neutral">&nbsp;</span>
366
- <span class="cline-any cline-neutral">&nbsp;</span>
367
- <span class="cline-any cline-neutral">&nbsp;</span>
368
- <span class="cline-any cline-no">&nbsp;</span>
369
364
  <span class="cline-any cline-neutral">&nbsp;</span>
370
365
  <span class="cline-any cline-neutral">&nbsp;</span>
371
366
  <span class="cline-any cline-neutral">&nbsp;</span>
372
- <span class="cline-any cline-no">&nbsp;</span>
373
- <span class="cline-any cline-no">&nbsp;</span>
374
- <span class="cline-any cline-no">&nbsp;</span>
375
367
  <span class="cline-any cline-neutral">&nbsp;</span>
368
+ <span class="cline-any cline-yes">2x</span>
376
369
  <span class="cline-any cline-neutral">&nbsp;</span>
377
- <span class="cline-any cline-yes">63x</span>
378
370
  <span class="cline-any cline-neutral">&nbsp;</span>
379
371
  <span class="cline-any cline-neutral">&nbsp;</span>
380
372
  <span class="cline-any cline-yes">1x</span>
381
373
  <span class="cline-any cline-yes">1x</span>
382
- <span class="cline-any cline-neutral">&nbsp;</span>
383
374
  <span class="cline-any cline-yes">1x</span>
384
- <span class="cline-any cline-no">&nbsp;</span>
385
375
  <span class="cline-any cline-neutral">&nbsp;</span>
386
376
  <span class="cline-any cline-neutral">&nbsp;</span>
377
+ <span class="cline-any cline-yes">78x</span>
387
378
  <span class="cline-any cline-neutral">&nbsp;</span>
388
379
  <span class="cline-any cline-neutral">&nbsp;</span>
380
+ <span class="cline-any cline-yes">15x</span>
381
+ <span class="cline-any cline-yes">15x</span>
389
382
  <span class="cline-any cline-neutral">&nbsp;</span>
383
+ <span class="cline-any cline-yes">15x</span>
384
+ <span class="cline-any cline-yes">8x</span>
390
385
  <span class="cline-any cline-neutral">&nbsp;</span>
391
- <span class="cline-any cline-no">&nbsp;</span>
392
- <span class="cline-any cline-no">&nbsp;</span>
393
- <span class="cline-any cline-no">&nbsp;</span>
394
- <span class="cline-any cline-no">&nbsp;</span>
395
- <span class="cline-any cline-no">&nbsp;</span>
396
386
  <span class="cline-any cline-neutral">&nbsp;</span>
397
387
  <span class="cline-any cline-neutral">&nbsp;</span>
398
- <span class="cline-any cline-yes">1x</span>
399
- <span class="cline-any cline-yes">1x</span>
400
- <span class="cline-any cline-yes">1x</span>
401
- <span class="cline-any cline-yes">1x</span>
402
388
  <span class="cline-any cline-neutral">&nbsp;</span>
403
- <span class="cline-any cline-yes">1x</span>
404
- <span class="cline-any cline-no">&nbsp;</span>
405
- <span class="cline-any cline-no">&nbsp;</span>
406
389
  <span class="cline-any cline-neutral">&nbsp;</span>
407
390
  <span class="cline-any cline-neutral">&nbsp;</span>
391
+ <span class="cline-any cline-yes">8x</span>
392
+ <span class="cline-any cline-yes">7x</span>
393
+ <span class="cline-any cline-yes">5x</span>
394
+ <span class="cline-any cline-yes">4x</span>
408
395
  <span class="cline-any cline-yes">1x</span>
409
- <span class="cline-any cline-yes">1x</span>
410
- <span class="cline-any cline-yes">1x</span>
411
- <span class="cline-any cline-yes">1x</span>
412
- <span class="cline-any cline-yes">1x</span>
396
+ <span class="cline-any cline-neutral">&nbsp;</span>
397
+ <span class="cline-any cline-neutral">&nbsp;</span>
398
+ <span class="cline-any cline-yes">7x</span>
399
+ <span class="cline-any cline-yes">7x</span>
400
+ <span class="cline-any cline-yes">5x</span>
401
+ <span class="cline-any cline-yes">5x</span>
402
+ <span class="cline-any cline-neutral">&nbsp;</span>
403
+ <span class="cline-any cline-yes">5x</span>
413
404
  <span class="cline-any cline-yes">1x</span>
414
405
  <span class="cline-any cline-yes">1x</span>
415
406
  <span class="cline-any cline-neutral">&nbsp;</span>
407
+ <span class="cline-any cline-neutral">&nbsp;</span>
408
+ <span class="cline-any cline-yes">4x</span>
409
+ <span class="cline-any cline-yes">4x</span>
410
+ <span class="cline-any cline-yes">4x</span>
411
+ <span class="cline-any cline-yes">4x</span>
412
+ <span class="cline-any cline-yes">4x</span>
413
+ <span class="cline-any cline-yes">4x</span>
414
+ <span class="cline-any cline-yes">4x</span>
415
+ <span class="cline-any cline-neutral">&nbsp;</span>
416
416
  <span class="cline-any cline-no">&nbsp;</span>
417
417
  <span class="cline-any cline-neutral">&nbsp;</span>
418
- <span class="cline-any cline-yes">1x</span>
418
+ <span class="cline-any cline-yes">4x</span>
419
419
  <span class="cline-any cline-neutral">&nbsp;</span>
420
420
  <span class="cline-any cline-neutral">&nbsp;</span>
421
- <span class="cline-any cline-no">&nbsp;</span>
421
+ <span class="cline-any cline-yes">2x</span>
422
422
  <span class="cline-any cline-neutral">&nbsp;</span>
423
423
  <span class="cline-any cline-neutral">&nbsp;</span>
424
424
  <span class="cline-any cline-neutral">&nbsp;</span>
425
425
  <span class="cline-any cline-neutral">&nbsp;</span>
426
- <span class="cline-any cline-no">&nbsp;</span>
427
- <span class="cline-any cline-no">&nbsp;</span>
428
- <span class="cline-any cline-no">&nbsp;</span>
426
+ <span class="cline-any cline-yes">2x</span>
427
+ <span class="cline-any cline-yes">2x</span>
428
+ <span class="cline-any cline-yes">1x</span>
429
429
  <span class="cline-any cline-neutral">&nbsp;</span>
430
430
  <span class="cline-any cline-neutral">&nbsp;</span>
431
431
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -461,85 +461,85 @@ export interface LoopCommandOptions {
461
461
  export function registerLoopCommand(options: LoopCommandOptions): void {
462
462
  const { pi, getStore, getTriggerSystem, updateWidget } = options;
463
463
  &nbsp;
464
- async function <span class="fstat-no" title="function not covered" >scheduleLoop(u</span>i: ExtensionUIContext, prompt?: string) {
465
- const p = <span class="cstat-no" title="statement not covered" >prompt || await ui.input("Prompt (what should the agent check?)");</span>
466
- <span class="cstat-no" title="statement not covered" > if (!p) <span class="cstat-no" title="statement not covered" >return;</span></span>
464
+ async function scheduleLoop(ui: ExtensionUIContext, prompt?: string) {
465
+ const p = prompt || await ui.input("Prompt (what should the agent check?)");
466
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (!p) <span class="cstat-no" title="statement not covered" >return;</span>
467
467
  &nbsp;
468
- const interval = <span class="cstat-no" title="statement not covered" >await ui.input("Interval (e.g., 5m, 2h, 1d)");</span>
469
- <span class="cstat-no" title="statement not covered" > if (!interval) <span class="cstat-no" title="statement not covered" >return;</span></span>
468
+ const interval = await ui.input("Interval (e.g., 5m, 2h, 1d)");
469
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (!interval) <span class="cstat-no" title="statement not covered" >return;</span>
470
470
  &nbsp;
471
- <span class="cstat-no" title="statement not covered" > try {</span>
472
- const <span class="cstat-no" title="statement not covered" >parsed = parseInterval(interval);</span>
473
- const trigger: Trigger = <span class="cstat-no" title="statement not covered" >{ type: "cron", schedule: parsed.cron };</span>
474
- const entry = <span class="cstat-no" title="statement not covered" >getStore().create(trigger, p, { recurring: true });</span>
475
- <span class="cstat-no" title="statement not covered" > getTriggerSystem().add(entry);</span>
476
- <span class="cstat-no" title="statement not covered" > updateWidget();</span>
477
- <span class="cstat-no" title="statement not covered" > ui.notify(`Loop #${entry.id} created: every ${parsed.description}`, "info");</span>
471
+ try {
472
+ const parsed = parseInterval(interval);
473
+ const trigger: Trigger = { type: "cron", schedule: parsed.cron };
474
+ const entry = getStore().create(trigger, p, { recurring: true });
475
+ getTriggerSystem().add(entry);
476
+ updateWidget();
477
+ ui.notify(`Loop #${entry.id} created: every ${parsed.description}`, "info");
478
478
  } catch (err: unknown) {
479
- <span class="cstat-no" title="statement not covered" > ui.notify((err as Error).message, "error");</span>
479
+ ui.notify((err as Error).message, "error");
480
480
  }
481
481
  }
482
482
  &nbsp;
483
- async function <span class="fstat-no" title="function not covered" >eventLoop(u</span>i: ExtensionUIContext, prompt?: string) {
484
- const p = <span class="cstat-no" title="statement not covered" >prompt || await ui.input("Prompt");</span>
485
- <span class="cstat-no" title="statement not covered" > if (!p) <span class="cstat-no" title="statement not covered" >return;</span></span>
483
+ async function eventLoop(ui: ExtensionUIContext, prompt?: string) {
484
+ const p = prompt || await ui.input("Prompt");
485
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (!p) <span class="cstat-no" title="statement not covered" >return;</span>
486
486
  &nbsp;
487
- const source = <span class="cstat-no" title="statement not covered" >await ui.input("Pi event source (e.g., tool_execution_start, before_agent_start)");</span>
488
- <span class="cstat-no" title="statement not covered" > if (!source) <span class="cstat-no" title="statement not covered" >return;</span></span>
487
+ const source = await ui.input("Pi event source (e.g., tool_execution_start, before_agent_start)");
488
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (!source) <span class="cstat-no" title="statement not covered" >return;</span>
489
489
  &nbsp;
490
- const trigger: Trigger = <span class="cstat-no" title="statement not covered" >{ type: "event", source };</span>
491
- const entry = <span class="cstat-no" title="statement not covered" >getStore().create(trigger, p, { recurring: true });</span>
492
- <span class="cstat-no" title="statement not covered" > getTriggerSystem().add(entry);</span>
493
- <span class="cstat-no" title="statement not covered" > updateWidget();</span>
494
- <span class="cstat-no" title="statement not covered" > ui.notify(`Event loop #${entry.id} created: fires on "${source}"`, "info");</span>
490
+ const trigger: Trigger = { type: "event", source };
491
+ const entry = getStore().create(trigger, p, { recurring: true });
492
+ getTriggerSystem().add(entry);
493
+ updateWidget();
494
+ ui.notify(`Event loop #${entry.id} created: fires on "${source}"`, "info");
495
495
  }
496
496
  &nbsp;
497
- async function <span class="fstat-no" title="function not covered" >viewLoops(u</span>i: ExtensionUIContext) {
498
- const loops = <span class="cstat-no" title="statement not covered" >getStore().list();</span>
499
- <span class="cstat-no" title="statement not covered" > if (loops.length === 0) {</span>
500
- <span class="cstat-no" title="statement not covered" > await ui.select("No loops configured", ["&lt; Back"]);</span>
501
- <span class="cstat-no" title="statement not covered" > return;</span>
497
+ async function viewLoops(ui: ExtensionUIContext) {
498
+ const loops = getStore().list();
499
+ if (loops.length === 0) {
500
+ await ui.select("No loops configured", ["&lt; Back"]);
501
+ return;
502
502
  }
503
503
  &nbsp;
504
- const choices = <span class="cstat-no" title="statement not covered" >loops.<span class="fstat-no" title="function not covered" >map((l</span>) =&gt; {</span>
505
- const icon = <span class="cstat-no" title="statement not covered" >l.status === "active" ? "*" : l.status === "paused" ? "-" : "x";</span>
506
- const triggerDesc = <span class="cstat-no" title="statement not covered" >l.trigger.type === "cron"</span>
504
+ const choices = loops.map((l) =&gt; {
505
+ const icon = l.status === "active" ? "*" : l.status === "paused" ? "-" : <span class="branch-1 cbranch-no" title="branch not covered" >"x";</span>
506
+ const triggerDesc = l.trigger.type === "cron"
507
507
  ? `cron: ${l.trigger.schedule}`
508
- : l.trigger.type === "event"
508
+ : <span class="branch-1 cbranch-no" title="branch not covered" >l.trigger.type === "event"</span>
509
509
  ? `event: ${l.trigger.source}`
510
510
  : `hybrid: ${l.trigger.cron}`;
511
- <span class="cstat-no" title="statement not covered" > return `${icon} #${l.id} [${l.status}] ${l.prompt.slice(0, 50)} (${triggerDesc})`;</span>
511
+ return `${icon} #${l.id} [${l.status}] ${l.prompt.slice(0, 50)} (${triggerDesc})`;
512
512
  });
513
- <span class="cstat-no" title="statement not covered" > choices.push("&lt; Back");</span>
513
+ choices.push("&lt; Back");
514
514
  &nbsp;
515
- const selected = <span class="cstat-no" title="statement not covered" >await ui.select("Loops", choices);</span>
516
- <span class="cstat-no" title="statement not covered" > if (!selected || selected === "&lt; Back") <span class="cstat-no" title="statement not covered" >return;</span></span>
515
+ const selected = await ui.select("Loops", choices);
516
+ if (!selected || selected === "&lt; Back") return;
517
517
  &nbsp;
518
- const match = <span class="cstat-no" title="statement not covered" >selected.match(/#(\d+)/);</span>
519
- <span class="cstat-no" title="statement not covered" > if (match) {</span>
520
- const entry = <span class="cstat-no" title="statement not covered" >getStore().get(match[1]);</span>
521
- <span class="cstat-no" title="statement not covered" > if (entry) {</span>
522
- const actions = <span class="cstat-no" title="statement not covered" >["x Delete"];</span>
523
- <span class="cstat-no" title="statement not covered" > if (entry.status === "active") <span class="cstat-no" title="statement not covered" >actions.unshift("- Pause");</span></span>
524
- else <span class="cstat-no" title="statement not covered" >if (entry.status === "paused") <span class="cstat-no" title="statement not covered" >actions.unshift("* Resume");</span></span>
525
- <span class="cstat-no" title="statement not covered" > actions.push("&lt; Back");</span>
518
+ const match = selected.match(/#(\d+)/);
519
+ <span class="missing-if-branch" title="else path not taken" >E</span>if (match?.[1]) {
520
+ const entry = getStore().get(match[1]);
521
+ <span class="missing-if-branch" title="else path not taken" >E</span>if (entry) {
522
+ const actions = ["x Delete"];
523
+ if (entry.status === "active") actions.unshift("- Pause");
524
+ else <span class="cstat-no" title="statement not covered" ><span class="missing-if-branch" title="else path not taken" >E</span>if (entry.status === "paused") <span class="cstat-no" title="statement not covered" >actions.unshift("* Resume");</span></span>
525
+ actions.push("&lt; Back");
526
526
  &nbsp;
527
- const action = <span class="cstat-no" title="statement not covered" >await ui.select(</span>
527
+ const action = await ui.select(
528
528
  `#${entry.id}: ${entry.prompt}\nTrigger: ${JSON.stringify(entry.trigger)}`,
529
529
  actions,
530
530
  );
531
531
  &nbsp;
532
- <span class="cstat-no" title="statement not covered" > if (action === "x Delete") {</span>
533
- <span class="cstat-no" title="statement not covered" > getTriggerSystem().remove(entry.id);</span>
534
- <span class="cstat-no" title="statement not covered" > getStore().delete(entry.id);</span>
535
- <span class="cstat-no" title="statement not covered" > updateWidget();</span>
536
- <span class="cstat-no" title="statement not covered" > ui.notify(`Loop #${entry.id} deleted`, "info");</span>
537
- } else <span class="cstat-no" title="statement not covered" >if (action === "- Pause") {</span>
538
- <span class="cstat-no" title="statement not covered" > getStore().pause(entry.id);</span>
539
- <span class="cstat-no" title="statement not covered" > getTriggerSystem().remove(entry.id);</span>
540
- <span class="cstat-no" title="statement not covered" > updateWidget();</span>
541
- <span class="cstat-no" title="statement not covered" > ui.notify(`Loop #${entry.id} paused`, "info");</span>
542
- } else <span class="cstat-no" title="statement not covered" >if (action === "* Resume") {</span>
532
+ if (action === "x Delete") {
533
+ getTriggerSystem().remove(entry.id);
534
+ getStore().delete(entry.id);
535
+ updateWidget();
536
+ ui.notify(`Loop #${entry.id} deleted`, "info");
537
+ } else if (action === "- Pause") {
538
+ getStore().pause(entry.id);
539
+ getTriggerSystem().remove(entry.id);
540
+ updateWidget();
541
+ ui.notify(`Loop #${entry.id} paused`, "info");
542
+ } else <span class="cstat-no" title="statement not covered" ><span class="missing-if-branch" title="else path not taken" >E</span>if (action === "* Resume") {</span>
543
543
  <span class="cstat-no" title="statement not covered" > getStore().resume(entry.id);</span>
544
544
  <span class="cstat-no" title="statement not covered" > getTriggerSystem().add(entry);</span>
545
545
  <span class="cstat-no" title="statement not covered" > updateWidget();</span>
@@ -548,13 +548,13 @@ export function registerLoopCommand(options: LoopCommandOptions): void {
548
548
  }
549
549
  }
550
550
  &nbsp;
551
- <span class="cstat-no" title="statement not covered" > return viewLoops(ui);</span>
551
+ return viewLoops(ui);
552
552
  }
553
553
  &nbsp;
554
- async function <span class="fstat-no" title="function not covered" >settings(u</span>i: ExtensionUIContext) {
555
- const loops = <span class="cstat-no" title="statement not covered" >getStore().list();</span>
556
- const active = <span class="cstat-no" title="statement not covered" >loops.<span class="fstat-no" title="function not covered" >filter((l</span>) =&gt; <span class="cstat-no" title="statement not covered" >l.status === "active")</span>.length;</span>
557
- <span class="cstat-no" title="statement not covered" > ui.notify(`${active}/${loops.length} active loops (max 25)`, "info");</span>
554
+ async function settings(ui: ExtensionUIContext) {
555
+ const loops = getStore().list();
556
+ const active = loops.<span class="fstat-no" title="function not covered" >filter((l</span>) =&gt; <span class="cstat-no" title="statement not covered" >l.status === "active")</span>.length;
557
+ ui.notify(`${active}/${loops.length} active loops (max 25)`, "info");
558
558
  }
559
559
  &nbsp;
560
560
  pi.registerCommand("loop", {
@@ -563,29 +563,29 @@ export function registerLoopCommand(options: LoopCommandOptions): void {
563
563
  const trimmed = args.trim();
564
564
  const ui = ctx.ui;
565
565
  &nbsp;
566
- <span class="missing-if-branch" title="if path not taken" >I</span>if (!trimmed) {
567
- const choice = <span class="cstat-no" title="statement not covered" >await ui.select("Loop", [</span>
566
+ if (!trimmed) {
567
+ const choice = await ui.select("Loop", [
568
568
  "Create scheduled loop",
569
569
  "Create event-triggered loop",
570
570
  "View loops",
571
571
  "Settings",
572
572
  ]);
573
573
  &nbsp;
574
- <span class="cstat-no" title="statement not covered" > if (!choice) <span class="cstat-no" title="statement not covered" >return;</span></span>
575
- <span class="cstat-no" title="statement not covered" > if (choice.startsWith("Create scheduled")) <span class="cstat-no" title="statement not covered" >return scheduleLoop(ui);</span></span>
576
- <span class="cstat-no" title="statement not covered" > if (choice.startsWith("Create event")) <span class="cstat-no" title="statement not covered" >return eventLoop(ui);</span></span>
577
- <span class="cstat-no" title="statement not covered" > if (choice.startsWith("View loops")) <span class="cstat-no" title="statement not covered" >return viewLoops(ui);</span></span>
578
- <span class="cstat-no" title="statement not covered" > return settings(ui);</span>
574
+ if (!choice) return;
575
+ if (choice.startsWith("Create scheduled")) return scheduleLoop(ui);
576
+ if (choice.startsWith("Create event")) return eventLoop(ui);
577
+ if (choice.startsWith("View loops")) return viewLoops(ui);
578
+ return settings(ui);
579
579
  }
580
580
  &nbsp;
581
581
  const intervalMatch = trimmed.match(/^(\d+\s*[smhdS]\b)/i);
582
- <span class="missing-if-branch" title="else path not taken" >E</span>if (intervalMatch) {
583
- const interval = intervalMatch[1];
582
+ if (intervalMatch) {
583
+ const interval = intervalMatch[1] ?? <span class="branch-1 cbranch-no" title="branch not covered" >intervalMatch[0];</span>
584
584
  const prompt = trimmed.slice(intervalMatch[0].length).trim();
585
585
  &nbsp;
586
- <span class="missing-if-branch" title="if path not taken" >I</span>if (!prompt) {
587
- <span class="cstat-no" title="statement not covered" > ui.notify("Provide a prompt after the interval, e.g., /loop 5m check the deploy", "warning");</span>
588
- <span class="cstat-no" title="statement not covered" > return;</span>
586
+ if (!prompt) {
587
+ ui.notify("Provide a prompt after the interval, e.g., /loop 5m check the deploy", "warning");
588
+ return;
589
589
  }
590
590
  &nbsp;
591
591
  try {
@@ -601,14 +601,14 @@ export function registerLoopCommand(options: LoopCommandOptions): void {
601
601
  return;
602
602
  }
603
603
  &nbsp;
604
- const choice = <span class="cstat-no" title="statement not covered" >await ui.select("Loop mode", [</span>
604
+ const choice = await ui.select("Loop mode", [
605
605
  `Scheduled: "${trimmed.slice(0, 50)}"`,
606
606
  `Event-triggered: "${trimmed.slice(0, 50)}"`,
607
607
  ]);
608
608
  &nbsp;
609
- <span class="cstat-no" title="statement not covered" > if (!choice) <span class="cstat-no" title="statement not covered" >return;</span></span>
610
- <span class="cstat-no" title="statement not covered" > if (choice.startsWith("Event")) <span class="cstat-no" title="statement not covered" >return eventLoop(ui, trimmed);</span></span>
611
- <span class="cstat-no" title="statement not covered" > return scheduleLoop(ui, trimmed);</span>
609
+ <span class="missing-if-branch" title="if path not taken" >I</span>if (!choice) <span class="cstat-no" title="statement not covered" >return;</span>
610
+ if (choice.startsWith("Event")) return eventLoop(ui, trimmed);
611
+ return scheduleLoop(ui, trimmed);
612
612
  },
613
613
  });
614
614
  }
@@ -619,7 +619,7 @@ export function registerLoopCommand(options: LoopCommandOptions): void {
619
619
  <div class='footer quiet pad2 space-top1 center small'>
620
620
  Code coverage generated by
621
621
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
622
- at 2026-06-23T21:49:18.784Z
622
+ at 2026-07-02T19:31:50.067Z
623
623
  </div>
624
624
  <script src="../../prettify.js"></script>
625
625
  <script>