@volter/supercode-teams 0.2.64 → 0.2.66
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/bin/teams.mjs +2 -1
- package/machine.mjs +22 -5
- package/package.json +1 -1
package/bin/teams.mjs
CHANGED
|
@@ -80,7 +80,8 @@ if (workspaceVerb) {
|
|
|
80
80
|
process.stderr.write(JSON.stringify({ version: 1, error: { code: error.code ?? 'invalid_request', message: error.message } }) + '\n');
|
|
81
81
|
process.exitCode = (error.exitCode ?? ({ invalid_request: 2, ambiguous_reference: 2, authentication_required: 3, not_found: 4, forbidden: 4, unsupported: 5, machine_offline: 5, controller_busy: 6, conflict: 6, resync_required: 6, revision_mismatch: 6, idempotency_conflict: 6, batch_gap: 6, capture_conflict: 6, source_paused: 6 }[error.code] ?? 1));
|
|
82
82
|
});
|
|
83
|
-
|
|
83
|
+
// Exit only once stdout has drained: a pipe takes 64 KB at a time, and exiting sooner cut a large --json answer off.
|
|
84
|
+
if (process.platform !== 'win32') { await new Promise((resolve) => process.stdout.write('', resolve)); process.exit(); }
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
const home = flags.home ? String(flags.home) : teamsHome();
|
package/machine.mjs
CHANGED
|
@@ -116,6 +116,11 @@ function launchCommand(program, args) {
|
|
|
116
116
|
* user's ~/.config/supercode when the server's environment has none): { failed, how } or null when nothing is
|
|
117
117
|
* recorded. A pane that failed has a `died` line with its status or signal; one that ended cleanly only `closed`.
|
|
118
118
|
*/
|
|
119
|
+
/** How a pane the host keeps after its program ended (`dead`) ended, as `paneExit` says it. */
|
|
120
|
+
function deadPaneExit(session) {
|
|
121
|
+
return Number.isInteger(session.exitCode) ? { failed: session.exitCode !== 0, how: `status ${session.exitCode}` } : { failed: true, how: 'failed' };
|
|
122
|
+
}
|
|
123
|
+
|
|
119
124
|
/** How often a pane whose launcher asked to be told of its end is looked for. */
|
|
120
125
|
const LAUNCH_END_POLL_MS = 5000;
|
|
121
126
|
|
|
@@ -408,9 +413,12 @@ export class TeamsMachine extends MachineCore {
|
|
|
408
413
|
const pending = this.#pendingNotices();
|
|
409
414
|
if (!pending.length) { clearInterval(this.endWatch); this.endWatch = null; return; }
|
|
410
415
|
for (const ask of pending) {
|
|
411
|
-
|
|
416
|
+
// A pane has ended when it is gone, or when its program has exited and the host keeps it for its last screen
|
|
417
|
+
// (a ConPTY pane whose program failed).
|
|
418
|
+
const session = await this.#paneByContext(ask.pane);
|
|
419
|
+
if (session && !session.dead) continue;
|
|
412
420
|
appendFileSync(this.#noticesPath(), JSON.stringify({ t: Date.now(), pane: ask.pane, told: true }) + '\n', { mode: 0o600 });
|
|
413
|
-
const exit = paneExit(ask.pane);
|
|
421
|
+
const exit = session?.dead ? deadPaneExit(session) : paneExit(ask.pane);
|
|
414
422
|
const how = !exit ? 'ended (this machine keeps no exit status for it)' : exit.failed ? `failed (${exit.how})` : 'finished (status 0)';
|
|
415
423
|
this.#sendMail(ask.notify.to, {
|
|
416
424
|
op: 'send', from: `sc:${ask.notify.machine}:pane:${ask.pane}`, from_name: `pane ${ask.pane}@${ask.notify.machine}`, to: ask.notify.to, queue: false,
|
|
@@ -1129,7 +1137,9 @@ export class TeamsMachine extends MachineCore {
|
|
|
1129
1137
|
contextKey,
|
|
1130
1138
|
cwd: params.cwd,
|
|
1131
1139
|
env: this.#paneEnv(contextKey, params.env),
|
|
1132
|
-
|
|
1140
|
+
// The pane's own tmux session is always its key: the exit hooks record and clean up p_* sessions only, and
|
|
1141
|
+
// a pane named otherwise lingered dead with its exit status lost. A launch's name is its title.
|
|
1142
|
+
name: contextKey,
|
|
1133
1143
|
});
|
|
1134
1144
|
} catch (error) {
|
|
1135
1145
|
this.launches.record({ key, pane: contextKey, kind: params.kind ?? null, status: 'failed', error: error.message });
|
|
@@ -1138,6 +1148,12 @@ export class TeamsMachine extends MachineCore {
|
|
|
1138
1148
|
}
|
|
1139
1149
|
this.launches.record({ key, pane: contextKey, kind: params.kind ?? null, status: 'ready' });
|
|
1140
1150
|
act('launch', `pane:${contextKey}`, 'ok', params.kind ?? params.program);
|
|
1151
|
+
if (typeof params.name === 'string' && params.name.trim()) {
|
|
1152
|
+
const titles = readJson(this.p.titles, { v: 1, titles: {} });
|
|
1153
|
+
titles.titles[`pane:${contextKey}`] = params.name.trim();
|
|
1154
|
+
writeJson(this.p.titles, titles);
|
|
1155
|
+
await this.#renameWindow(contextKey, params.name.trim()).catch(() => null);
|
|
1156
|
+
}
|
|
1141
1157
|
// The first input is delivered when the pane can TAKE it, not when the
|
|
1142
1158
|
// pane exists: a program that is still painting its banner has no
|
|
1143
1159
|
// input box yet, and text sent into one lands half in the scrollback and
|
|
@@ -1150,9 +1166,10 @@ export class TeamsMachine extends MachineCore {
|
|
|
1150
1166
|
// A program that ends at once (not found, not runnable, failing on its first line) takes its pane with it:
|
|
1151
1167
|
// the caller is told, with its exit status, instead of being handed a pane that is already gone.
|
|
1152
1168
|
await new Promise((resolve) => setTimeout(resolve, LAUNCH_SETTLE_MS));
|
|
1153
|
-
|
|
1169
|
+
const settled = await this.#paneByContext(contextKey);
|
|
1170
|
+
if (!settled || settled.dead) {
|
|
1154
1171
|
// Finished (it ran to a clean end) is an answer; exited (it failed at once) is the caller's error.
|
|
1155
|
-
const exit = paneExit(contextKey);
|
|
1172
|
+
const exit = settled?.dead ? deadPaneExit(settled) : paneExit(contextKey);
|
|
1156
1173
|
const status = exit && !exit.failed ? 'finished' : 'exited';
|
|
1157
1174
|
this.launches.record({ key, pane: contextKey, kind: params.kind ?? null, status, error: exit?.failed ? exit.how : undefined });
|
|
1158
1175
|
return { key, pane: contextKey, reused: false, status, exit: exit?.how ?? null };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-teams",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.66",
|
|
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",
|