@mjasnikovs/pi-task 0.14.0 → 0.14.2
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/remote/ui-script.js
CHANGED
|
@@ -53,6 +53,7 @@ export function clientScript(wsUrl) {
|
|
|
53
53
|
let autoScroll = true;
|
|
54
54
|
let reconnectDelay = 1000;
|
|
55
55
|
let reconnectAnim = null;
|
|
56
|
+
let reconnectTimer = null;
|
|
56
57
|
let ws = null;
|
|
57
58
|
|
|
58
59
|
const BT = String.fromCharCode(96);
|
|
@@ -784,8 +785,15 @@ export function clientScript(wsUrl) {
|
|
|
784
785
|
});
|
|
785
786
|
|
|
786
787
|
function connect() {
|
|
787
|
-
|
|
788
|
-
|
|
788
|
+
// Capture the socket locally so a superseded socket's late events (a
|
|
789
|
+
// delayed 'close' after we already opened a replacement) can't touch the
|
|
790
|
+
// overlay or schedule a second reconnect — every handler bails unless it's
|
|
791
|
+
// still the current socket.
|
|
792
|
+
const sock = new WebSocket(WS_URL);
|
|
793
|
+
ws = sock;
|
|
794
|
+
sock.addEventListener('open', () => {
|
|
795
|
+
if (ws !== sock) return;
|
|
796
|
+
if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; }
|
|
789
797
|
if (reconnectAnim) { clearInterval(reconnectAnim); reconnectAnim = null; }
|
|
790
798
|
reconnectOverlay.classList.remove('visible');
|
|
791
799
|
reconnectDelay = 1000;
|
|
@@ -797,10 +805,12 @@ export function clientScript(wsUrl) {
|
|
|
797
805
|
// endpoint, so a redundant re-POST is harmless.
|
|
798
806
|
if (notifyEnabled()) { subscribePush().catch(function () {}); }
|
|
799
807
|
});
|
|
800
|
-
|
|
808
|
+
sock.addEventListener('message', (e) => {
|
|
809
|
+
if (ws !== sock) return;
|
|
801
810
|
try { handleMsg(JSON.parse(e.data)); } catch {}
|
|
802
811
|
});
|
|
803
|
-
|
|
812
|
+
sock.addEventListener('close', () => {
|
|
813
|
+
if (ws !== sock) return;
|
|
804
814
|
setEnabled(false);
|
|
805
815
|
reconnectOverlay.classList.add('visible');
|
|
806
816
|
// Animate the same braille spinner used elsewhere, with a live countdown.
|
|
@@ -816,9 +826,31 @@ export function clientScript(wsUrl) {
|
|
|
816
826
|
if (reconnectAnim) clearInterval(reconnectAnim);
|
|
817
827
|
paint();
|
|
818
828
|
reconnectAnim = setInterval(paint, 90);
|
|
819
|
-
|
|
829
|
+
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
830
|
+
reconnectTimer = setTimeout(() => {
|
|
831
|
+
reconnectTimer = null;
|
|
832
|
+
reconnectDelay = Math.min(reconnectDelay * 2, 30000);
|
|
833
|
+
connect();
|
|
834
|
+
}, reconnectDelay);
|
|
820
835
|
});
|
|
821
836
|
}
|
|
822
837
|
|
|
838
|
+
// Reconnect immediately instead of waiting out the exponential backoff. A
|
|
839
|
+
// phone that backgrounds the PWA throttles our retry timer and the radio
|
|
840
|
+
// drops, so by the time it foregrounds reconnectDelay can be pinned at 30s —
|
|
841
|
+
// leaving the user staring at a spinner (over an already-updated question)
|
|
842
|
+
// while the server is reachable RIGHT NOW. Returning to the tab, regaining
|
|
843
|
+
// network, or refocusing the window should all retry at once. No-op if a
|
|
844
|
+
// socket is already open or a connect is in flight.
|
|
845
|
+
function connectNow() {
|
|
846
|
+
if (ws && (ws.readyState === WebSocket.CONNECTING || ws.readyState === WebSocket.OPEN)) return;
|
|
847
|
+
if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; }
|
|
848
|
+
reconnectDelay = 1000; // a deliberate return shouldn't inherit a stale 30s backoff
|
|
849
|
+
connect();
|
|
850
|
+
}
|
|
851
|
+
document.addEventListener('visibilitychange', () => { if (!document.hidden) connectNow(); });
|
|
852
|
+
window.addEventListener('online', connectNow);
|
|
853
|
+
window.addEventListener('focus', connectNow);
|
|
854
|
+
|
|
823
855
|
connect();`;
|
|
824
856
|
}
|
|
@@ -74,6 +74,13 @@ export declare function classifyEnforceChildFailure(r: EnforceChildResult): stri
|
|
|
74
74
|
* names of any new (untracked) files. Non-destructive — it does not touch the
|
|
75
75
|
* index, so the later `git add -A` in gitCommitAll still stages everything
|
|
76
76
|
* (including fixes the enforcement child makes).
|
|
77
|
+
*
|
|
78
|
+
* The `.pi-tasks/` directory is excluded from both git commands. Those task
|
|
79
|
+
* files are committable (tracked) by design, so they show up in `git diff HEAD`
|
|
80
|
+
* and `git ls-files --others` — git does not honor the fd/ripgrep `.ignore` that
|
|
81
|
+
* keeps them out of the worker's find/grep discovery. Without this pathspec the
|
|
82
|
+
* enforce child is handed its own TASK_*.md / TASK_AUTO_*.md bookkeeping as
|
|
83
|
+
* "changes to verify" and edits them, corrupting the front matter mid-run.
|
|
77
84
|
*/
|
|
78
85
|
export declare function captureDiff(cwd: string, signal?: AbortSignal, spawnFn?: SpawnFn): Promise<string>;
|
|
79
86
|
export interface EnforcementDeps {
|
|
@@ -20,6 +20,7 @@ import * as fsp from 'node:fs/promises';
|
|
|
20
20
|
import * as path from 'node:path';
|
|
21
21
|
import { runChildDefault } from '../shared/child-process.js';
|
|
22
22
|
import { USER_CANCELLED } from './child-runner.js';
|
|
23
|
+
import { TASKS_DIR_NAME } from './task-types.js';
|
|
23
24
|
/** Filenames discovered in the working directory (cwd only — no tree walk). */
|
|
24
25
|
export const GUIDELINE_FILENAMES = ['AGENTS.md', 'CLAUDE.md'];
|
|
25
26
|
/** Tools the fix pass is allowed: read/search to inspect, edit/write to fix. */
|
|
@@ -131,11 +132,28 @@ export function classifyEnforceChildFailure(r) {
|
|
|
131
132
|
* names of any new (untracked) files. Non-destructive — it does not touch the
|
|
132
133
|
* index, so the later `git add -A` in gitCommitAll still stages everything
|
|
133
134
|
* (including fixes the enforcement child makes).
|
|
135
|
+
*
|
|
136
|
+
* The `.pi-tasks/` directory is excluded from both git commands. Those task
|
|
137
|
+
* files are committable (tracked) by design, so they show up in `git diff HEAD`
|
|
138
|
+
* and `git ls-files --others` — git does not honor the fd/ripgrep `.ignore` that
|
|
139
|
+
* keeps them out of the worker's find/grep discovery. Without this pathspec the
|
|
140
|
+
* enforce child is handed its own TASK_*.md / TASK_AUTO_*.md bookkeeping as
|
|
141
|
+
* "changes to verify" and edits them, corrupting the front matter mid-run.
|
|
134
142
|
*/
|
|
135
143
|
export async function captureDiff(cwd, signal, spawnFn) {
|
|
144
|
+
// `:(exclude)<dir>` is a git pathspec that drops everything under the tasks
|
|
145
|
+
// directory from the result, leaving only real source changes to verify.
|
|
146
|
+
const excludeTasks = `:(exclude)${TASKS_DIR_NAME}`;
|
|
136
147
|
const run = (args) => runChildDefault({ command: 'git', args }, cwd, signal, { mode: 'text' }, spawnFn);
|
|
137
|
-
const tracked = await run(['diff', 'HEAD']);
|
|
138
|
-
const untracked = await run([
|
|
148
|
+
const tracked = await run(['diff', 'HEAD', '--', '.', excludeTasks]);
|
|
149
|
+
const untracked = await run([
|
|
150
|
+
'ls-files',
|
|
151
|
+
'--others',
|
|
152
|
+
'--exclude-standard',
|
|
153
|
+
'--',
|
|
154
|
+
'.',
|
|
155
|
+
excludeTasks
|
|
156
|
+
]);
|
|
139
157
|
const parts = [];
|
|
140
158
|
if (tracked.exitCode === 0 && tracked.stdout.trim().length > 0)
|
|
141
159
|
parts.push(tracked.stdout.trim());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mjasnikovs/pi-task",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.2",
|
|
4
4
|
"description": "Deterministic spec-orchestration for local models, with a bundled real-time remote web view and web/docs/fetch/worker subagent tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|