@volter/supercode-teams 0.3.140 → 0.3.141
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/machine.mjs +38 -10
- package/package.json +1 -1
package/machine.mjs
CHANGED
|
@@ -2390,6 +2390,13 @@ export class TeamsMachine extends MachineCore {
|
|
|
2390
2390
|
*/
|
|
2391
2391
|
#deliverInitialInput({ key, contextKey, session, kind, by, input, act, nativeInput, executable = {}, resumed = {} }) {
|
|
2392
2392
|
if (this.pendingInitialInputs.has(key)) return;
|
|
2393
|
+
// Input confirmation can finish after the child. Keep the launch's latest
|
|
2394
|
+
// status and completion; a late input receipt must not make it ready again.
|
|
2395
|
+
const recordInput = facts => {
|
|
2396
|
+
const launch = this.launches.find(key);
|
|
2397
|
+
if (launch?.pane !== contextKey) return;
|
|
2398
|
+
this.launches.record({ ...launch, ...facts, status: launch.status });
|
|
2399
|
+
};
|
|
2393
2400
|
const abort = new AbortController();
|
|
2394
2401
|
const task = (async () => {
|
|
2395
2402
|
let nativeReadyBy = 'native-prompt';
|
|
@@ -2399,7 +2406,7 @@ export class TeamsMachine extends MachineCore {
|
|
|
2399
2406
|
const result = nativeReadyBy === 'pane-gone' || nativeReadyBy === 'deadline'
|
|
2400
2407
|
? { delivered: false, refused: true, reason: nativeReadyBy }
|
|
2401
2408
|
: await this.#deliverClaudeInitialInput(session, contextKey, nativeInput, abort.signal);
|
|
2402
|
-
|
|
2409
|
+
recordInput({ key, pane: contextKey, kind, by, ...resumed, ...executable, inputDelivered: result.delivered,
|
|
2403
2410
|
inputReadyBy: nativeReadyBy, ...(result.delivered ? { inputReceipt: result.receipt } : { inputError: result.reason }),
|
|
2404
2411
|
inputRefused: result.refused === true, inputPending: result.queued === true,
|
|
2405
2412
|
...(result.native_session ? { native_session: result.native_session } : {}) });
|
|
@@ -2415,7 +2422,7 @@ export class TeamsMachine extends MachineCore {
|
|
|
2415
2422
|
const typed = nativeReadyBy === 'pane-gone' || nativeReadyBy === 'deadline' ? { delivered: false, reason: nativeReadyBy }
|
|
2416
2423
|
: await this.#typeCodexFirstInput(session, input, abort.signal);
|
|
2417
2424
|
if (!typed.delivered) {
|
|
2418
|
-
|
|
2425
|
+
recordInput({ key, pane: contextKey, kind, by, ...resumed, ...executable, inputDelivered: false,
|
|
2419
2426
|
inputReadyBy: nativeReadyBy, inputError: typed.reason });
|
|
2420
2427
|
act('launch', `pane:${contextKey}`, 'failed', `first input undelivered: ${typed.reason}`);
|
|
2421
2428
|
return;
|
|
@@ -2424,7 +2431,7 @@ export class TeamsMachine extends MachineCore {
|
|
|
2424
2431
|
if (nativeInput) {
|
|
2425
2432
|
const result = await confirmNativeInitialInput(nativeInput, { signal: abort.signal,
|
|
2426
2433
|
deadlineMs: Date.now() + INITIAL_INPUT_READY_DEADLINE_MS, live: async () => Boolean(await this.#paneByContext(contextKey)) });
|
|
2427
|
-
|
|
2434
|
+
recordInput({ key, pane: contextKey, kind, by, ...resumed, ...executable, inputDelivered: result.delivered,
|
|
2428
2435
|
inputReadyBy: nativeReadyBy, ...(result.delivered ? { inputReceipt: result.receipt } : { inputError: result.reason }),
|
|
2429
2436
|
...(result.native_session ? { native_session: result.native_session } : {}) });
|
|
2430
2437
|
act('launch', `pane:${contextKey}`, result.delivered ? 'ok' : result.queued ? 'input-pending' : 'failed',
|
|
@@ -2434,19 +2441,19 @@ export class TeamsMachine extends MachineCore {
|
|
|
2434
2441
|
const readyBy = await this.#awaitInputReady(session, contextKey, kind, abort.signal);
|
|
2435
2442
|
if (readyBy === 'aborted') return;
|
|
2436
2443
|
if (readyBy === 'pane-gone' || readyBy === 'deadline') {
|
|
2437
|
-
|
|
2444
|
+
recordInput({ key, pane: contextKey, kind, by, ...resumed, ...executable, inputDelivered: false, inputReadyBy: readyBy });
|
|
2438
2445
|
act('launch', `pane:${contextKey}`, 'failed', `first input undelivered: ${readyBy}`);
|
|
2439
2446
|
return;
|
|
2440
2447
|
}
|
|
2441
2448
|
const result = await this.#deliverPaneText(session, contextKey, input, { signal: abort.signal });
|
|
2442
|
-
|
|
2449
|
+
recordInput({ key, pane: contextKey, kind, by, ...resumed, ...executable, inputDelivered: result.delivered,
|
|
2443
2450
|
inputReadyBy: readyBy, ...(!result.delivered ? { inputError: result.reason } : {}) });
|
|
2444
2451
|
act('launch', `pane:${contextKey}`, result.delivered ? 'ok' : result.queued ? 'input-pending' : 'failed',
|
|
2445
2452
|
result.delivered ? `first input delivered (${readyBy})` : `first input unconfirmed: ${result.reason}`);
|
|
2446
2453
|
})().catch((error) => {
|
|
2447
2454
|
// Nothing above is expected to throw; if something does, the launch record
|
|
2448
2455
|
// is where it is answerable, not a crashed daemon.
|
|
2449
|
-
|
|
2456
|
+
recordInput({ key, pane: contextKey, kind, by, ...resumed, ...executable, inputDelivered: false, inputError: error?.message ?? String(error) });
|
|
2450
2457
|
}).finally(() => {
|
|
2451
2458
|
if (this.pendingInitialInputs.get(key)?.task === task) this.pendingInitialInputs.delete(key);
|
|
2452
2459
|
});
|
|
@@ -3202,7 +3209,8 @@ export class TeamsMachine extends MachineCore {
|
|
|
3202
3209
|
cancelled_at: found.cancelled_at ?? null,
|
|
3203
3210
|
live: Boolean(session && !session.dead), label: session?.label ?? null, activeCommand: session?.activeCommand ?? null,
|
|
3204
3211
|
exit_output: found.pane && (!session || session.dead) ? paneExitOutput(found.pane) : null,
|
|
3205
|
-
exit:
|
|
3212
|
+
exit: found.completion ?? (found.status === 'finished' ? { failed: false, how: 'status 0' }
|
|
3213
|
+
: session?.dead ? deadPaneExit(session) : found.pane && !session ? paneExit(found.pane) : null),
|
|
3206
3214
|
...initialInputFacts(found),
|
|
3207
3215
|
};
|
|
3208
3216
|
}
|
|
@@ -3502,6 +3510,11 @@ export class TeamsMachine extends MachineCore {
|
|
|
3502
3510
|
let existing = this.launches.find(key);
|
|
3503
3511
|
while (existing) {
|
|
3504
3512
|
if (existing.status === 'cancelled') throw Object.assign(new Error(`launch key ${key} was cancelled before issuance; use a new key`), { code: 409, reason: 'launch_key_cancelled' });
|
|
3513
|
+
// Finished itself records an observed clean exit, including older
|
|
3514
|
+
// journals that did not keep a separate completion field.
|
|
3515
|
+
if (existing.status === 'finished') {
|
|
3516
|
+
return { key, pane: existing.pane, reused: true, status: 'finished', exit: existing.completion?.how ?? 'status 0' };
|
|
3517
|
+
}
|
|
3505
3518
|
if (existing.status === 'issued') return { key, pane: existing.pane, reused: true, status: existing.status };
|
|
3506
3519
|
if (existing.status === 'ready') {
|
|
3507
3520
|
const session = await this.#paneByContext(existing.pane);
|
|
@@ -3511,6 +3524,14 @@ export class TeamsMachine extends MachineCore {
|
|
|
3511
3524
|
this.#recoverClaudeInitialInputs([session], key);
|
|
3512
3525
|
return { key, pane: existing.pane, reused: true, status: existing.status };
|
|
3513
3526
|
}
|
|
3527
|
+
// The child can finish after creation but before the original
|
|
3528
|
+
// caller's settlement read. Retain its observed exit before a
|
|
3529
|
+
// concurrent or restarted caller can issue this key again.
|
|
3530
|
+
const exit = session?.dead ? deadPaneExit(session) : paneExit(existing.pane);
|
|
3531
|
+
if (exit?.failed === false) {
|
|
3532
|
+
this.launches.record({ ...existing, status: 'finished', completion: exit });
|
|
3533
|
+
return { key, pane: existing.pane, reused: true, status: 'finished', exit: exit.how };
|
|
3534
|
+
}
|
|
3514
3535
|
}
|
|
3515
3536
|
break;
|
|
3516
3537
|
}
|
|
@@ -3561,7 +3582,13 @@ export class TeamsMachine extends MachineCore {
|
|
|
3561
3582
|
// The agent the launch's environment names is kept with the launch: the pane's session is bound to it once the
|
|
3562
3583
|
// session is seen in the pane (sessionBindings).
|
|
3563
3584
|
const agent = launchAgent(params.env);
|
|
3564
|
-
|
|
3585
|
+
// createSession can return a retained exit descriptor with no pane.
|
|
3586
|
+
// Its first journal write must already contain that completion, before
|
|
3587
|
+
// any title/input/settlement await lets another caller see the key.
|
|
3588
|
+
const createdExit = session.dead ? deadPaneExit(session) : null;
|
|
3589
|
+
this.launches.record({ key, pane: contextKey, kind: params.kind ?? null, by, ...resumed, ...executable,
|
|
3590
|
+
status: createdExit ? createdExit.failed ? 'exited' : 'finished' : 'ready',
|
|
3591
|
+
...(createdExit?.failed === false ? { completion: createdExit } : {}), ...(agent ? { agent } : {}) });
|
|
3565
3592
|
if (params.kind === 'codex' && (params.arguments ?? []).includes('--dangerously-bypass-hook-trust')) this.#settleCodexStartup(key, contextKey, session, act);
|
|
3566
3593
|
act('launch', `pane:${contextKey}`, 'ok', params.kind ?? params.program);
|
|
3567
3594
|
if (typeof params.name === 'string' && params.name.trim()) {
|
|
@@ -3585,9 +3612,10 @@ export class TeamsMachine extends MachineCore {
|
|
|
3585
3612
|
const settled = await this.#paneByContext(contextKey);
|
|
3586
3613
|
if (!settled || settled.dead) {
|
|
3587
3614
|
// Finished (it ran to a clean end) is an answer; exited (it failed at once) is the caller's error.
|
|
3588
|
-
const exit = settled?.dead ? deadPaneExit(settled) : paneExit(contextKey);
|
|
3615
|
+
const exit = settled?.dead ? deadPaneExit(settled) : session.dead ? deadPaneExit(session) : paneExit(contextKey);
|
|
3589
3616
|
const status = exit && !exit.failed ? 'finished' : 'exited';
|
|
3590
|
-
this.launches.record({ key, pane: contextKey, kind: params.kind ?? null, by, ...resumed, ...executable, status,
|
|
3617
|
+
this.launches.record({ ...this.launches.find(key), key, pane: contextKey, kind: params.kind ?? null, by, ...resumed, ...executable, status,
|
|
3618
|
+
...(exit && !exit.failed ? { completion: exit } : {}), error: exit?.failed ? exit.how : undefined });
|
|
3591
3619
|
this.#panesChanged();
|
|
3592
3620
|
return { key, pane: contextKey, reused: false, status, exit: exit?.how ?? null };
|
|
3593
3621
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-teams",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.141",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A machine daemon serving this machine's doors, and a local or remote Teams server for shared session discovery, OpenTelemetry ingestion and access to enrolled machines.",
|
|
6
6
|
"license": "MIT",
|