@proagentstore/cli 0.4.25 → 0.4.26
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.
|
@@ -42,6 +42,8 @@ export class HeadlessSession {
|
|
|
42
42
|
sawOutputSinceInput = false;
|
|
43
43
|
/** Raw-mode: when the current turn started (absolute idle backstop). */
|
|
44
44
|
turnStartedAt = 0;
|
|
45
|
+
/** Set by stop() — the only thing that ends a one-shot session (see `alive`). */
|
|
46
|
+
stopped = false;
|
|
45
47
|
constructor(config) {
|
|
46
48
|
this.config = config;
|
|
47
49
|
this.sessionName = `pags-${config.clientType}-${config.id}`;
|
|
@@ -60,13 +62,36 @@ export class HeadlessSession {
|
|
|
60
62
|
this.cmdArgs = bin ? args : fallback.args;
|
|
61
63
|
this.binName = (this.cmdBin.split("/").pop() || this.cmdBin) || "cli";
|
|
62
64
|
}
|
|
63
|
-
/**
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
65
|
+
/**
|
|
66
|
+
* Can this session take a turn? — NOT "is a process executing right now".
|
|
67
|
+
*
|
|
68
|
+
* The distinction only appeared with one-shot engines. A persistent Claude session has a
|
|
69
|
+
* process alive between turns, so the two questions had the same answer and one getter served
|
|
70
|
+
* both. A one-shot engine has NO process between turns — that is its resting state — so the
|
|
71
|
+
* process-liveness answer is `false` for every question asked while the session sits idle,
|
|
72
|
+
* which is exactly when the Pilot asks.
|
|
73
|
+
*
|
|
74
|
+
* The cost of conflating them was total: `runCodingLoop` opens with
|
|
75
|
+
* `if (!snap.alive) return failed("coding session is not running")`, so every delegated goal
|
|
76
|
+
* on codex/grok/gemini/ollama died at iteration 0 having done nothing, reporting a dead
|
|
77
|
+
* session that was in fact healthy and answering interactive turns fine.
|
|
78
|
+
*
|
|
79
|
+
* So: a one-shot session is alive until `stop()`. Whether a turn is currently executing is
|
|
80
|
+
* `runState`, which is the question the loop actually has a use for.
|
|
81
|
+
*
|
|
82
|
+
* NOTE for the persistent path: do NOT use `proc.killed` — Node sets it true the instant a
|
|
83
|
+
* signal is DELIVERED, not when the process exits. interrupt() SIGINTs to abort a turn while
|
|
84
|
+
* the process keeps running, so `killed` gave a false "dead" → input() then spawned a SECOND
|
|
85
|
+
* process (orphaning the first). exitCode is null while running and set on normal exit;
|
|
86
|
+
* signalCode is set when a signal actually terminated it — together they're the real signal.
|
|
87
|
+
*/
|
|
69
88
|
get alive() {
|
|
89
|
+
if (this.oneShot)
|
|
90
|
+
return !this.stopped;
|
|
91
|
+
return this.procAlive;
|
|
92
|
+
}
|
|
93
|
+
/** Is a process running THIS instant? The persistent engine's liveness, and the spawn guard. */
|
|
94
|
+
get procAlive() {
|
|
70
95
|
return this.proc !== null && this.proc.exitCode === null && this.proc.signalCode === null;
|
|
71
96
|
}
|
|
72
97
|
/** Idle = ready for the next instruction. */
|
|
@@ -125,13 +150,16 @@ export class HeadlessSession {
|
|
|
125
150
|
return this.mode === "raw";
|
|
126
151
|
}
|
|
127
152
|
start() {
|
|
153
|
+
// Starting always un-stops: `stop()` is what ends a one-shot session, so a (re)start
|
|
154
|
+
// after one has to bring it back or the session is permanently unusable.
|
|
155
|
+
this.stopped = false;
|
|
128
156
|
// A one-shot engine has nothing to start until there is a turn to run; starting it here
|
|
129
157
|
// is what produced the instant "exited with code 1".
|
|
130
158
|
if (this.oneShot) {
|
|
131
159
|
this.run = "idle";
|
|
132
160
|
return;
|
|
133
161
|
}
|
|
134
|
-
if (this.
|
|
162
|
+
if (this.procAlive)
|
|
135
163
|
return;
|
|
136
164
|
// stream-json: we own the structural flags + --resume; merge the user's extras
|
|
137
165
|
// (e.g. --model) without letting them clobber or orphan-value our flags. raw:
|
|
@@ -262,7 +290,7 @@ export class HeadlessSession {
|
|
|
262
290
|
this.run = "idle";
|
|
263
291
|
this.lastOutputAt = Date.now();
|
|
264
292
|
}
|
|
265
|
-
/** Tear the process down. */
|
|
293
|
+
/** Tear the process down. For a one-shot engine this is the ONLY thing that ends the session. */
|
|
266
294
|
stop() {
|
|
267
295
|
try {
|
|
268
296
|
this.proc?.kill();
|
|
@@ -272,6 +300,7 @@ export class HeadlessSession {
|
|
|
272
300
|
}
|
|
273
301
|
this.proc = null;
|
|
274
302
|
this.run = "idle";
|
|
303
|
+
this.stopped = true;
|
|
275
304
|
}
|
|
276
305
|
// ── internals ────────────────────────────────────────────────────────────
|
|
277
306
|
onStdout(chunk) {
|