@trevonistrevon/pi-loop 0.5.3 → 0.5.5

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 (87) hide show
  1. package/coverage/base.css +224 -0
  2. package/coverage/block-navigation.js +87 -0
  3. package/coverage/coverage-final.json +32 -0
  4. package/coverage/favicon.png +0 -0
  5. package/coverage/index.html +176 -0
  6. package/coverage/prettify.css +1 -0
  7. package/coverage/prettify.js +2 -0
  8. package/coverage/sort-arrow-sprite.png +0 -0
  9. package/coverage/sorter.js +210 -0
  10. package/coverage/src/commands/index.html +131 -0
  11. package/coverage/src/commands/loop-command.ts.html +634 -0
  12. package/coverage/src/commands/tasks-command.ts.html +490 -0
  13. package/coverage/src/coordinator.ts.html +430 -0
  14. package/coverage/src/goal-coordinator.ts.html +259 -0
  15. package/coverage/src/goal-reducer.ts.html +982 -0
  16. package/coverage/src/goal-store.ts.html +742 -0
  17. package/coverage/src/goal-verifier.ts.html +808 -0
  18. package/coverage/src/index.html +386 -0
  19. package/coverage/src/index.ts.html +1054 -0
  20. package/coverage/src/loop-parse.ts.html +574 -0
  21. package/coverage/src/loop-reducer.ts.html +559 -0
  22. package/coverage/src/monitor-completion-coordinator.ts.html +157 -0
  23. package/coverage/src/monitor-manager.ts.html +865 -0
  24. package/coverage/src/monitor-reducer.ts.html +583 -0
  25. package/coverage/src/notification-reducer.ts.html +550 -0
  26. package/coverage/src/reducer-backed-store.ts.html +589 -0
  27. package/coverage/src/runtime/index.html +191 -0
  28. package/coverage/src/runtime/monitor-ondone-runtime.ts.html +310 -0
  29. package/coverage/src/runtime/notification-runtime.ts.html +721 -0
  30. package/coverage/src/runtime/scope.ts.html +196 -0
  31. package/coverage/src/runtime/session-runtime.ts.html +589 -0
  32. package/coverage/src/runtime/task-backlog-runtime.ts.html +574 -0
  33. package/coverage/src/runtime/task-rpc.ts.html +535 -0
  34. package/coverage/src/scheduler.ts.html +400 -0
  35. package/coverage/src/store.ts.html +667 -0
  36. package/coverage/src/task-backlog-coordinator.ts.html +181 -0
  37. package/coverage/src/task-reducer.ts.html +550 -0
  38. package/coverage/src/task-store.ts.html +526 -0
  39. package/coverage/src/tools/index.html +146 -0
  40. package/coverage/src/tools/loop-tools.ts.html +1000 -0
  41. package/coverage/src/tools/monitor-tools.ts.html +547 -0
  42. package/coverage/src/tools/native-task-tools.ts.html +535 -0
  43. package/coverage/src/trigger-system.ts.html +547 -0
  44. package/coverage/src/ui/index.html +116 -0
  45. package/coverage/src/ui/widget.ts.html +292 -0
  46. package/dist/commands/loop-command.js +4 -5
  47. package/dist/commands/tasks-command.js +3 -3
  48. package/dist/goal-reducer.d.ts +9 -0
  49. package/dist/goal-reducer.js +11 -2
  50. package/dist/goal-store.d.ts +4 -15
  51. package/dist/goal-store.js +32 -154
  52. package/dist/index.d.ts +2 -2
  53. package/dist/index.js +4 -3
  54. package/dist/loop-reducer.d.ts +7 -0
  55. package/dist/loop-reducer.js +9 -0
  56. package/dist/monitor-manager.js +4 -4
  57. package/dist/reducer-backed-store.d.ts +65 -0
  58. package/dist/reducer-backed-store.js +160 -0
  59. package/dist/store.d.ts +4 -16
  60. package/dist/store.js +25 -156
  61. package/dist/task-reducer.js +3 -0
  62. package/dist/task-store.d.ts +4 -15
  63. package/dist/task-store.js +25 -147
  64. package/dist/tools/loop-tools.js +7 -5
  65. package/dist/tools/monitor-tools.js +12 -3
  66. package/dist/tools/native-task-tools.js +2 -2
  67. package/dist/trigger-system.js +2 -1
  68. package/dist/ui/widget.js +8 -1
  69. package/package.json +4 -1
  70. package/src/commands/loop-command.ts +4 -5
  71. package/src/commands/tasks-command.ts +3 -3
  72. package/src/goal-reducer.ts +20 -1
  73. package/src/goal-store.ts +35 -142
  74. package/src/index.ts +4 -3
  75. package/src/loop-reducer.ts +10 -0
  76. package/src/monitor-manager.ts +2 -3
  77. package/src/reducer-backed-store.ts +168 -0
  78. package/src/store.ts +28 -141
  79. package/src/task-reducer.ts +3 -0
  80. package/src/task-store.ts +28 -135
  81. package/src/tools/loop-tools.ts +6 -5
  82. package/src/tools/monitor-tools.ts +12 -3
  83. package/src/tools/native-task-tools.ts +2 -2
  84. package/src/trigger-system.ts +2 -1
  85. package/src/ui/widget.ts +8 -1
  86. package/vitest.config.ts +25 -0
  87. package/DIFFERENTIAL_REVIEW_REPORT.md +0 -81
@@ -0,0 +1,116 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for src/ui</title>
7
+ <meta charset="utf-8" />
8
+ <link rel="stylesheet" href="../../prettify.css" />
9
+ <link rel="stylesheet" href="../../base.css" />
10
+ <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
11
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
12
+ <style type='text/css'>
13
+ .coverage-summary .sorter {
14
+ background-image: url(../../sort-arrow-sprite.png);
15
+ }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <div class='wrapper'>
21
+ <div class='pad1'>
22
+ <h1><a href="../../index.html">All files</a> src/ui</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">100% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>31/31</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">100% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>25/25</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">100% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>9/9</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">100% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>24/24</span>
50
+ </div>
51
+
52
+
53
+ </div>
54
+ <p class="quiet">
55
+ Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
+ </p>
57
+ <template id="filterTemplate">
58
+ <div class="quiet">
59
+ Filter:
60
+ <input type="search" id="fileSearch">
61
+ </div>
62
+ </template>
63
+ </div>
64
+ <div class='status-line high'></div>
65
+ <div class="pad1">
66
+ <table class="coverage-summary">
67
+ <thead>
68
+ <tr>
69
+ <th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
70
+ <th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
71
+ <th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
72
+ <th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
73
+ <th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
74
+ <th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
75
+ <th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
76
+ <th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
77
+ <th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
78
+ <th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
79
+ </tr>
80
+ </thead>
81
+ <tbody><tr>
82
+ <td class="file high" data-value="widget.ts"><a href="widget.ts.html">widget.ts</a></td>
83
+ <td data-value="100" class="pic high">
84
+ <div class="chart"><div class="cover-fill cover-full" style="width: 100%"></div><div class="cover-empty" style="width: 0%"></div></div>
85
+ </td>
86
+ <td data-value="100" class="pct high">100%</td>
87
+ <td data-value="31" class="abs high">31/31</td>
88
+ <td data-value="100" class="pct high">100%</td>
89
+ <td data-value="25" class="abs high">25/25</td>
90
+ <td data-value="100" class="pct high">100%</td>
91
+ <td data-value="9" class="abs high">9/9</td>
92
+ <td data-value="100" class="pct high">100%</td>
93
+ <td data-value="24" class="abs high">24/24</td>
94
+ </tr>
95
+
96
+ </tbody>
97
+ </table>
98
+ </div>
99
+ <div class='push'></div><!-- for sticky footer -->
100
+ </div><!-- /wrapper -->
101
+ <div class='footer quiet pad2 space-top1 center small'>
102
+ Code coverage generated by
103
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
104
+ at 2026-06-10T03:38:12.908Z
105
+ </div>
106
+ <script src="../../prettify.js"></script>
107
+ <script>
108
+ window.onload = function () {
109
+ prettyPrint();
110
+ };
111
+ </script>
112
+ <script src="../../sorter.js"></script>
113
+ <script src="../../block-navigation.js"></script>
114
+ </body>
115
+ </html>
116
+
@@ -0,0 +1,292 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for src/ui/widget.ts</title>
7
+ <meta charset="utf-8" />
8
+ <link rel="stylesheet" href="../../prettify.css" />
9
+ <link rel="stylesheet" href="../../base.css" />
10
+ <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
11
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
12
+ <style type='text/css'>
13
+ .coverage-summary .sorter {
14
+ background-image: url(../../sort-arrow-sprite.png);
15
+ }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <div class='wrapper'>
21
+ <div class='pad1'>
22
+ <h1><a href="../../index.html">All files</a> / <a href="index.html">src/ui</a> widget.ts</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">100% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>31/31</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">100% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>25/25</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">100% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>9/9</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">100% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>24/24</span>
50
+ </div>
51
+
52
+
53
+ </div>
54
+ <p class="quiet">
55
+ Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
+ </p>
57
+ <template id="filterTemplate">
58
+ <div class="quiet">
59
+ Filter:
60
+ <input type="search" id="fileSearch">
61
+ </div>
62
+ </template>
63
+ </div>
64
+ <div class='status-line high'></div>
65
+ <pre><table class="coverage">
66
+ <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
+ <a name='L2'></a><a href='#L2'>2</a>
68
+ <a name='L3'></a><a href='#L3'>3</a>
69
+ <a name='L4'></a><a href='#L4'>4</a>
70
+ <a name='L5'></a><a href='#L5'>5</a>
71
+ <a name='L6'></a><a href='#L6'>6</a>
72
+ <a name='L7'></a><a href='#L7'>7</a>
73
+ <a name='L8'></a><a href='#L8'>8</a>
74
+ <a name='L9'></a><a href='#L9'>9</a>
75
+ <a name='L10'></a><a href='#L10'>10</a>
76
+ <a name='L11'></a><a href='#L11'>11</a>
77
+ <a name='L12'></a><a href='#L12'>12</a>
78
+ <a name='L13'></a><a href='#L13'>13</a>
79
+ <a name='L14'></a><a href='#L14'>14</a>
80
+ <a name='L15'></a><a href='#L15'>15</a>
81
+ <a name='L16'></a><a href='#L16'>16</a>
82
+ <a name='L17'></a><a href='#L17'>17</a>
83
+ <a name='L18'></a><a href='#L18'>18</a>
84
+ <a name='L19'></a><a href='#L19'>19</a>
85
+ <a name='L20'></a><a href='#L20'>20</a>
86
+ <a name='L21'></a><a href='#L21'>21</a>
87
+ <a name='L22'></a><a href='#L22'>22</a>
88
+ <a name='L23'></a><a href='#L23'>23</a>
89
+ <a name='L24'></a><a href='#L24'>24</a>
90
+ <a name='L25'></a><a href='#L25'>25</a>
91
+ <a name='L26'></a><a href='#L26'>26</a>
92
+ <a name='L27'></a><a href='#L27'>27</a>
93
+ <a name='L28'></a><a href='#L28'>28</a>
94
+ <a name='L29'></a><a href='#L29'>29</a>
95
+ <a name='L30'></a><a href='#L30'>30</a>
96
+ <a name='L31'></a><a href='#L31'>31</a>
97
+ <a name='L32'></a><a href='#L32'>32</a>
98
+ <a name='L33'></a><a href='#L33'>33</a>
99
+ <a name='L34'></a><a href='#L34'>34</a>
100
+ <a name='L35'></a><a href='#L35'>35</a>
101
+ <a name='L36'></a><a href='#L36'>36</a>
102
+ <a name='L37'></a><a href='#L37'>37</a>
103
+ <a name='L38'></a><a href='#L38'>38</a>
104
+ <a name='L39'></a><a href='#L39'>39</a>
105
+ <a name='L40'></a><a href='#L40'>40</a>
106
+ <a name='L41'></a><a href='#L41'>41</a>
107
+ <a name='L42'></a><a href='#L42'>42</a>
108
+ <a name='L43'></a><a href='#L43'>43</a>
109
+ <a name='L44'></a><a href='#L44'>44</a>
110
+ <a name='L45'></a><a href='#L45'>45</a>
111
+ <a name='L46'></a><a href='#L46'>46</a>
112
+ <a name='L47'></a><a href='#L47'>47</a>
113
+ <a name='L48'></a><a href='#L48'>48</a>
114
+ <a name='L49'></a><a href='#L49'>49</a>
115
+ <a name='L50'></a><a href='#L50'>50</a>
116
+ <a name='L51'></a><a href='#L51'>51</a>
117
+ <a name='L52'></a><a href='#L52'>52</a>
118
+ <a name='L53'></a><a href='#L53'>53</a>
119
+ <a name='L54'></a><a href='#L54'>54</a>
120
+ <a name='L55'></a><a href='#L55'>55</a>
121
+ <a name='L56'></a><a href='#L56'>56</a>
122
+ <a name='L57'></a><a href='#L57'>57</a>
123
+ <a name='L58'></a><a href='#L58'>58</a>
124
+ <a name='L59'></a><a href='#L59'>59</a>
125
+ <a name='L60'></a><a href='#L60'>60</a>
126
+ <a name='L61'></a><a href='#L61'>61</a>
127
+ <a name='L62'></a><a href='#L62'>62</a>
128
+ <a name='L63'></a><a href='#L63'>63</a>
129
+ <a name='L64'></a><a href='#L64'>64</a>
130
+ <a name='L65'></a><a href='#L65'>65</a>
131
+ <a name='L66'></a><a href='#L66'>66</a>
132
+ <a name='L67'></a><a href='#L67'>67</a>
133
+ <a name='L68'></a><a href='#L68'>68</a>
134
+ <a name='L69'></a><a href='#L69'>69</a>
135
+ <a name='L70'></a><a href='#L70'>70</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
136
+ <span class="cline-any cline-neutral">&nbsp;</span>
137
+ <span class="cline-any cline-neutral">&nbsp;</span>
138
+ <span class="cline-any cline-neutral">&nbsp;</span>
139
+ <span class="cline-any cline-neutral">&nbsp;</span>
140
+ <span class="cline-any cline-neutral">&nbsp;</span>
141
+ <span class="cline-any cline-neutral">&nbsp;</span>
142
+ <span class="cline-any cline-neutral">&nbsp;</span>
143
+ <span class="cline-any cline-neutral">&nbsp;</span>
144
+ <span class="cline-any cline-neutral">&nbsp;</span>
145
+ <span class="cline-any cline-neutral">&nbsp;</span>
146
+ <span class="cline-any cline-neutral">&nbsp;</span>
147
+ <span class="cline-any cline-neutral">&nbsp;</span>
148
+ <span class="cline-any cline-neutral">&nbsp;</span>
149
+ <span class="cline-any cline-neutral">&nbsp;</span>
150
+ <span class="cline-any cline-yes">67x</span>
151
+ <span class="cline-any cline-yes">67x</span>
152
+ <span class="cline-any cline-neutral">&nbsp;</span>
153
+ <span class="cline-any cline-neutral">&nbsp;</span>
154
+ <span class="cline-any cline-neutral">&nbsp;</span>
155
+ <span class="cline-any cline-yes">105x</span>
156
+ <span class="cline-any cline-neutral">&nbsp;</span>
157
+ <span class="cline-any cline-neutral">&nbsp;</span>
158
+ <span class="cline-any cline-neutral">&nbsp;</span>
159
+ <span class="cline-any cline-yes">45x</span>
160
+ <span class="cline-any cline-neutral">&nbsp;</span>
161
+ <span class="cline-any cline-neutral">&nbsp;</span>
162
+ <span class="cline-any cline-neutral">&nbsp;</span>
163
+ <span class="cline-any cline-yes">62x</span>
164
+ <span class="cline-any cline-neutral">&nbsp;</span>
165
+ <span class="cline-any cline-neutral">&nbsp;</span>
166
+ <span class="cline-any cline-neutral">&nbsp;</span>
167
+ <span class="cline-any cline-yes">174x</span>
168
+ <span class="cline-any cline-yes">158x</span>
169
+ <span class="cline-any cline-neutral">&nbsp;</span>
170
+ <span class="cline-any cline-neutral">&nbsp;</span>
171
+ <span class="cline-any cline-neutral">&nbsp;</span>
172
+ <span class="cline-any cline-yes">158x</span>
173
+ <span class="cline-any cline-yes">158x</span>
174
+ <span class="cline-any cline-yes">158x</span>
175
+ <span class="cline-any cline-neutral">&nbsp;</span>
176
+ <span class="cline-any cline-yes">158x</span>
177
+ <span class="cline-any cline-yes">66x</span>
178
+ <span class="cline-any cline-neutral">&nbsp;</span>
179
+ <span class="cline-any cline-neutral">&nbsp;</span>
180
+ <span class="cline-any cline-yes">92x</span>
181
+ <span class="cline-any cline-yes">92x</span>
182
+ <span class="cline-any cline-yes">92x</span>
183
+ <span class="cline-any cline-yes">92x</span>
184
+ <span class="cline-any cline-neutral">&nbsp;</span>
185
+ <span class="cline-any cline-yes">92x</span>
186
+ <span class="cline-any cline-yes">92x</span>
187
+ <span class="cline-any cline-yes">92x</span>
188
+ <span class="cline-any cline-neutral">&nbsp;</span>
189
+ <span class="cline-any cline-neutral">&nbsp;</span>
190
+ <span class="cline-any cline-neutral">&nbsp;</span>
191
+ <span class="cline-any cline-yes">7x</span>
192
+ <span class="cline-any cline-neutral">&nbsp;</span>
193
+ <span class="cline-any cline-neutral">&nbsp;</span>
194
+ <span class="cline-any cline-neutral">&nbsp;</span>
195
+ <span class="cline-any cline-neutral">&nbsp;</span>
196
+ <span class="cline-any cline-yes">116x</span>
197
+ <span class="cline-any cline-neutral">&nbsp;</span>
198
+ <span class="cline-any cline-neutral">&nbsp;</span>
199
+ <span class="cline-any cline-neutral">&nbsp;</span>
200
+ <span class="cline-any cline-yes">41x</span>
201
+ <span class="cline-any cline-yes">40x</span>
202
+ <span class="cline-any cline-yes">3x</span>
203
+ <span class="cline-any cline-neutral">&nbsp;</span>
204
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import type { ExtensionUIContext } from "@earendil-works/pi-coding-agent";
205
+ import type { MonitorManager } from "../monitor-manager.js";
206
+ import type { LoopStore } from "../store.js";
207
+ import type { LoopEntry } from "../types.js";
208
+ &nbsp;
209
+ interface TaskSummary {
210
+ count: number;
211
+ focusText?: string;
212
+ }
213
+ &nbsp;
214
+ export class LoopWidget {
215
+ private uiCtx: ExtensionUIContext | undefined;
216
+ private taskSummaryProvider: (() =&gt; TaskSummary) | undefined;
217
+ &nbsp;
218
+ constructor(
219
+ private store: LoopStore,
220
+ private monitorManager: MonitorManager,
221
+ ) {}
222
+ &nbsp;
223
+ setUICtx(ctx: ExtensionUIContext) {
224
+ this.uiCtx = ctx;
225
+ }
226
+ &nbsp;
227
+ setStore(store: LoopStore) {
228
+ this.store = store;
229
+ }
230
+ &nbsp;
231
+ setTaskSummaryProvider(provider: (() =&gt; TaskSummary) | undefined) {
232
+ this.taskSummaryProvider = provider;
233
+ }
234
+ &nbsp;
235
+ update() {
236
+ if (!this.uiCtx) return;
237
+ this.uiCtx.setStatus("loops", this.computeStatus());
238
+ }
239
+ &nbsp;
240
+ private computeStatus(): string | undefined {
241
+ const loops = this.store.list().filter(isStatusVisibleLoop);
242
+ const monitors = this.monitorManager.list();
243
+ const taskSummary = this.taskSummaryProvider?.() ?? { count: 0 };
244
+ &nbsp;
245
+ if (loops.length === 0 &amp;&amp; monitors.length === 0 &amp;&amp; taskSummary.count === 0) {
246
+ return undefined;
247
+ }
248
+ &nbsp;
249
+ const parts: string[] = [];
250
+ if (loops.length &gt; 0) parts.push(formatCount(loops.length, "loop"));
251
+ if (monitors.length &gt; 0) parts.push(formatCount(monitors.length, "monitor"));
252
+ if (taskSummary.count &gt; 0) parts.push(formatCount(taskSummary.count, "task"));
253
+ &nbsp;
254
+ let line = parts.join(" · ");
255
+ if (taskSummary.focusText) line += ` | ${taskSummary.focusText}`;
256
+ return line;
257
+ }
258
+ &nbsp;
259
+ dispose() {
260
+ this.uiCtx?.setStatus("loops", undefined);
261
+ }
262
+ }
263
+ &nbsp;
264
+ function formatCount(count: number, noun: string): string {
265
+ return `${count} ${noun}${count === 1 ? "" : "s"}`;
266
+ }
267
+ &nbsp;
268
+ function isStatusVisibleLoop(loop: LoopEntry): boolean {
269
+ if (loop.status !== "active") return false;
270
+ if (loop.recurring) return true;
271
+ return !(loop.trigger.type === "event" &amp;&amp; loop.trigger.source === "monitor:done");
272
+ }
273
+ &nbsp;</pre></td></tr></table></pre>
274
+
275
+ <div class='push'></div><!-- for sticky footer -->
276
+ </div><!-- /wrapper -->
277
+ <div class='footer quiet pad2 space-top1 center small'>
278
+ Code coverage generated by
279
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
280
+ at 2026-06-10T03:38:12.908Z
281
+ </div>
282
+ <script src="../../prettify.js"></script>
283
+ <script>
284
+ window.onload = function () {
285
+ prettyPrint();
286
+ };
287
+ </script>
288
+ <script src="../../sorter.js"></script>
289
+ <script src="../../block-navigation.js"></script>
290
+ </body>
291
+ </html>
292
+
@@ -36,7 +36,7 @@ export function registerLoopCommand(options) {
36
36
  async function viewLoops(ui) {
37
37
  const loops = getStore().list();
38
38
  if (loops.length === 0) {
39
- await ui.select("No active loops", ["< Back"]);
39
+ await ui.select("No loops configured", ["< Back"]);
40
40
  return;
41
41
  }
42
42
  const choices = loops.map((l) => {
@@ -49,7 +49,7 @@ export function registerLoopCommand(options) {
49
49
  return `${icon} #${l.id} [${l.status}] ${l.prompt.slice(0, 50)} (${triggerDesc})`;
50
50
  });
51
51
  choices.push("< Back");
52
- const selected = await ui.select("Active Loops", choices);
52
+ const selected = await ui.select("Loops", choices);
53
53
  if (!selected || selected === "< Back")
54
54
  return;
55
55
  const match = selected.match(/#(\d+)/);
@@ -99,7 +99,7 @@ export function registerLoopCommand(options) {
99
99
  const choice = await ui.select("Loop", [
100
100
  "Create scheduled loop",
101
101
  "Create event-triggered loop",
102
- "View active loops",
102
+ "View loops",
103
103
  "Settings",
104
104
  ]);
105
105
  if (!choice)
@@ -108,7 +108,7 @@ export function registerLoopCommand(options) {
108
108
  return scheduleLoop(ui);
109
109
  if (choice.startsWith("Create event"))
110
110
  return eventLoop(ui);
111
- if (choice.startsWith("View active"))
111
+ if (choice.startsWith("View loops"))
112
112
  return viewLoops(ui);
113
113
  return settings(ui);
114
114
  }
@@ -136,7 +136,6 @@ export function registerLoopCommand(options) {
136
136
  const choice = await ui.select("Loop mode", [
137
137
  `Scheduled: "${trimmed.slice(0, 50)}"`,
138
138
  `Event-triggered: "${trimmed.slice(0, 50)}"`,
139
- `Self-paced: "${trimmed.slice(0, 50)}"`,
140
139
  ]);
141
140
  if (!choice)
142
141
  return;
@@ -28,7 +28,7 @@ export function registerTasksCommand(options) {
28
28
  const backlog = await emitCreated(entry);
29
29
  ui.notify(`Task #${entry.id} created`, "info");
30
30
  if (backlog.created && backlog.entry) {
31
- ui.notify(`Worker loop #${backlog.entry.id} auto-created`, "info");
31
+ ui.notify(`Backlog worker loop #${backlog.entry.id} created`, "info");
32
32
  }
33
33
  }
34
34
  async function viewNativeTasks(ui) {
@@ -44,7 +44,7 @@ export function registerTasksCommand(options) {
44
44
  });
45
45
  choices.unshift("+ Create task");
46
46
  choices.push("< Back");
47
- const selected = await ui.select("Native Tasks", choices);
47
+ const selected = await ui.select("Tasks", choices);
48
48
  if (!selected || selected === "< Back")
49
49
  return;
50
50
  if (selected === "+ Create task") {
@@ -107,7 +107,7 @@ export function registerTasksCommand(options) {
107
107
  const backlog = await emitCreated(entry);
108
108
  ctx.ui.notify(`Task #${entry.id} created`, "info");
109
109
  if (backlog.created && backlog.entry) {
110
- ctx.ui.notify(`Worker loop #${backlog.entry.id} auto-created`, "info");
110
+ ctx.ui.notify(`Backlog worker loop #${backlog.entry.id} created`, "info");
111
111
  }
112
112
  return;
113
113
  }
@@ -81,6 +81,15 @@ export type GoalReducerEffect = {
81
81
  payload: {
82
82
  id: string;
83
83
  };
84
+ } | {
85
+ type: "GOAL_TRANSITION_REJECTED";
86
+ entityType: "goal";
87
+ entityId: string;
88
+ payload: {
89
+ id: string;
90
+ status: GoalEntry["status"];
91
+ attempted: string;
92
+ };
84
93
  };
85
94
  export interface GoalReduceResult {
86
95
  state: GoalReducerState;
@@ -64,8 +64,17 @@ export function reduceGoalState(state, event) {
64
64
  const current = state.goalsById[id];
65
65
  if (!current)
66
66
  return { state, effects: [] };
67
- if (isTerminal(current) && event.type !== "GOAL_ARCHIVED")
68
- return { state, effects: [] };
67
+ if (isTerminal(current) && event.type !== "GOAL_ARCHIVED") {
68
+ return {
69
+ state,
70
+ effects: [{
71
+ type: "GOAL_TRANSITION_REJECTED",
72
+ entityType: "goal",
73
+ entityId: id,
74
+ payload: { id, status: current.status, attempted: event.type },
75
+ }],
76
+ };
77
+ }
69
78
  const next = cloneState(state);
70
79
  const goal = {
71
80
  ...current,
@@ -1,20 +1,9 @@
1
- import type { GoalCriteria, GoalEntry, GoalProgressSnapshot, GoalScope } from "./goal-types.js";
2
- export declare class GoalStore {
3
- private filePath;
4
- private lockPath;
5
- private lastLoadedSignature;
6
- private nextId;
7
- private goals;
1
+ import { type GoalReducerEvent } from "./goal-reducer.js";
2
+ import type { GoalCriteria, GoalEntry, GoalProgressSnapshot, GoalReducerState, GoalScope, GoalStoreData } from "./goal-types.js";
3
+ import { ReducerBackedStore } from "./reducer-backed-store.js";
4
+ export declare class GoalStore extends ReducerBackedStore<GoalEntry, GoalReducerState, GoalReducerEvent, GoalStoreData> {
8
5
  constructor(listIdOrPath?: string);
9
- private getFileSignature;
10
- private load;
11
- private save;
12
- private withLock;
13
- private toReducerState;
14
- private applyReducerEvent;
15
6
  create(title: string, description: string, scope: GoalScope, criteria: GoalCriteria, metadata?: Record<string, unknown>): GoalEntry;
16
- get(id: string): GoalEntry | undefined;
17
- list(): GoalEntry[];
18
7
  activate(id: string): GoalEntry | undefined;
19
8
  recordProgress(id: string, progress: GoalProgressSnapshot): GoalEntry | undefined;
20
9
  markVerificationStarted(id: string): GoalEntry | undefined;