@mjasnikovs/pi-task 0.38.17 → 0.38.18
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.
- package/dist/config/config.d.ts +11 -0
- package/dist/config/config.js +13 -1
- package/dist/task/widget.js +41 -9
- package/package.json +1 -1
package/dist/config/config.d.ts
CHANGED
|
@@ -215,5 +215,16 @@ export declare const CONFIG_LOADERS: {
|
|
|
215
215
|
* into the config object.
|
|
216
216
|
*/
|
|
217
217
|
export declare function loadConfig(raw: unknown): PiTaskConfig;
|
|
218
|
+
/**
|
|
219
|
+
* Where the saved config lives. `PI_TASK_CONFIG_PATH` overrides it.
|
|
220
|
+
*
|
|
221
|
+
* The override exists because this module loads the real file at import time,
|
|
222
|
+
* which made every test that reads a config value depend on the developer's own
|
|
223
|
+
* `~/.config/pi-task/config.json` — a machine-local `"debugLogs": "off"` failed
|
|
224
|
+
* 12 tests here while CI (no config file at all) stayed green. The test preload
|
|
225
|
+
* points this at a path under the tmp dir that never exists, so tests always see
|
|
226
|
+
* DEFAULT_CONFIG. Read once at module eval: the preload runs before any import.
|
|
227
|
+
*/
|
|
228
|
+
export declare const CONFIG_PATH_ENV = "PI_TASK_CONFIG_PATH";
|
|
218
229
|
export declare function getConfig(): PiTaskConfig;
|
|
219
230
|
export declare function saveConfig(config: PiTaskConfig): Promise<void>;
|
package/dist/config/config.js
CHANGED
|
@@ -182,7 +182,19 @@ export function loadConfig(raw) {
|
|
|
182
182
|
}
|
|
183
183
|
return out;
|
|
184
184
|
}
|
|
185
|
-
|
|
185
|
+
/**
|
|
186
|
+
* Where the saved config lives. `PI_TASK_CONFIG_PATH` overrides it.
|
|
187
|
+
*
|
|
188
|
+
* The override exists because this module loads the real file at import time,
|
|
189
|
+
* which made every test that reads a config value depend on the developer's own
|
|
190
|
+
* `~/.config/pi-task/config.json` — a machine-local `"debugLogs": "off"` failed
|
|
191
|
+
* 12 tests here while CI (no config file at all) stayed green. The test preload
|
|
192
|
+
* points this at a path under the tmp dir that never exists, so tests always see
|
|
193
|
+
* DEFAULT_CONFIG. Read once at module eval: the preload runs before any import.
|
|
194
|
+
*/
|
|
195
|
+
export const CONFIG_PATH_ENV = 'PI_TASK_CONFIG_PATH';
|
|
196
|
+
const CONFIG_PATH = process.env[CONFIG_PATH_ENV]?.trim()
|
|
197
|
+
|| path.join(os.homedir(), '.config', 'pi-task', 'config.json');
|
|
186
198
|
const _g = globalThis;
|
|
187
199
|
if (!_g.__piTaskConfig) {
|
|
188
200
|
_g.__piTaskConfig = { config: { ...DEFAULT_CONFIG }, loaded: false };
|
package/dist/task/widget.js
CHANGED
|
@@ -115,21 +115,35 @@ export function buildWidgetData(s) {
|
|
|
115
115
|
export function startWidget(ctx, getState) {
|
|
116
116
|
if (!ctx.hasUI)
|
|
117
117
|
return () => { };
|
|
118
|
+
// `ctx.ui` THROWS once the ctx goes stale (/reload, session replacement), so
|
|
119
|
+
// the theme read belongs INSIDE the guard, not one line above it. render()
|
|
120
|
+
// runs from a timer, where an unguarded throw is an uncaughtException that
|
|
121
|
+
// kills the whole pi process — and a swallowed one would throw again on
|
|
122
|
+
// every tick, so a stale ctx latches and stops the timer. Issue #15.
|
|
123
|
+
let stale = false;
|
|
118
124
|
const render = () => {
|
|
125
|
+
if (stale)
|
|
126
|
+
return;
|
|
119
127
|
const s = getState();
|
|
120
|
-
const
|
|
121
|
-
const plain = s ? buildWidgetLines(s, undefined) : undefined; // un-themed for the wire
|
|
128
|
+
const plain = s ? buildWidgetLines(s, undefined) : undefined; // un-themed for the wire; needs no ctx
|
|
122
129
|
try {
|
|
130
|
+
const lines = s ? buildWidgetLines(s, ctx.ui.theme) : undefined;
|
|
123
131
|
ctx.ui.setWidget(WIDGET_KEY, lines);
|
|
124
132
|
}
|
|
125
133
|
catch {
|
|
126
|
-
|
|
134
|
+
stale = true;
|
|
135
|
+
clearInterval(timer);
|
|
136
|
+
return;
|
|
127
137
|
}
|
|
128
138
|
setTaskWidget(plain, s ? buildWidgetData(s) : null);
|
|
129
139
|
};
|
|
130
|
-
render
|
|
140
|
+
// The timer is created BEFORE the first render so `timer` is always bound
|
|
141
|
+
// when render's catch reaches for it: a ctx already stale on the very first
|
|
142
|
+
// paint now stops the loop there, instead of arming an interval that wakes
|
|
143
|
+
// up and returns early forever.
|
|
131
144
|
const timer = setInterval(render, WIDGET_REFRESH_MS);
|
|
132
145
|
timer.unref?.();
|
|
146
|
+
render();
|
|
133
147
|
return () => {
|
|
134
148
|
clearInterval(timer);
|
|
135
149
|
try {
|
|
@@ -192,21 +206,32 @@ export function buildAutoLoaderData(s) {
|
|
|
192
206
|
export function startAutoLoader(ctx, getState) {
|
|
193
207
|
if (!ctx.hasUI)
|
|
194
208
|
return () => { };
|
|
209
|
+
// Same staleness hazard as startWidget: the theme read must sit inside the
|
|
210
|
+
// guard, and a stale ctx stops the timer rather than throwing every tick.
|
|
211
|
+
let stale = false;
|
|
195
212
|
const render = () => {
|
|
213
|
+
if (stale)
|
|
214
|
+
return;
|
|
196
215
|
const s = getState();
|
|
197
|
-
const
|
|
198
|
-
const plain = s ? buildAutoLoaderLines(s, undefined) : undefined;
|
|
216
|
+
const plain = s ? buildAutoLoaderLines(s, undefined) : undefined; // needs no ctx
|
|
199
217
|
try {
|
|
218
|
+
const lines = s ? buildAutoLoaderLines(s, ctx.ui.theme) : undefined;
|
|
200
219
|
ctx.ui.setWidget(AUTO_WIDGET_KEY, lines);
|
|
201
220
|
}
|
|
202
221
|
catch {
|
|
203
|
-
|
|
222
|
+
stale = true;
|
|
223
|
+
clearInterval(timer);
|
|
224
|
+
return;
|
|
204
225
|
}
|
|
205
226
|
setTaskWidget(plain, s ? buildAutoLoaderData(s) : null);
|
|
206
227
|
};
|
|
207
|
-
render
|
|
228
|
+
// The timer is created BEFORE the first render so `timer` is always bound
|
|
229
|
+
// when render's catch reaches for it: a ctx already stale on the very first
|
|
230
|
+
// paint now stops the loop there, instead of arming an interval that wakes
|
|
231
|
+
// up and returns early forever.
|
|
208
232
|
const timer = setInterval(render, WIDGET_REFRESH_MS);
|
|
209
233
|
timer.unref?.();
|
|
234
|
+
render();
|
|
210
235
|
return () => {
|
|
211
236
|
clearInterval(timer);
|
|
212
237
|
try {
|
|
@@ -249,7 +274,14 @@ export function buildImplData(s) {
|
|
|
249
274
|
export function flashTerminalWidget(ctx, state, taskId, reason) {
|
|
250
275
|
if (!ctx.hasUI)
|
|
251
276
|
return;
|
|
252
|
-
|
|
277
|
+
// Same staleness hazard as the render timers: bail rather than throw.
|
|
278
|
+
let theme;
|
|
279
|
+
try {
|
|
280
|
+
theme = ctx.ui.theme;
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
253
285
|
let line;
|
|
254
286
|
let clearMs;
|
|
255
287
|
if (state === 'cancelled') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mjasnikovs/pi-task",
|
|
3
|
-
"version": "0.38.
|
|
3
|
+
"version": "0.38.18",
|
|
4
4
|
"description": "Deterministic task planning and spec-orchestration for local models — crash-safe /task pipelines with verify/enforce gates, a real-time remote web view, and web/docs/fetch/worker subagent tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|