@volter/supercode-teams 0.2.172 → 0.2.173
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 +3 -2
- package/machine.mjs +43 -14
- package/package.json +1 -1
package/bin/teams.mjs
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
// title set <pane> <text> | title ls
|
|
20
20
|
// attention ls | rank | request <pane> [--urgency now|soon|whenever] [--reason text] | clear <pane>
|
|
21
21
|
// watch [--interval ms] [--for ms]
|
|
22
|
-
// launches get <key> | list
|
|
22
|
+
// launches get <key> | cancel <key> | list operators: keyed receipts; cancel only unissued keys
|
|
23
23
|
// rpc <harness.v1 method> [json-params] operators: one harness.v1 request
|
|
24
24
|
// log verify
|
|
25
25
|
//
|
|
@@ -323,8 +323,9 @@ async function main() {
|
|
|
323
323
|
return withNode(async (rpc) => out(await rpc.call('jobs.list', {})));
|
|
324
324
|
case 'launches': {
|
|
325
325
|
if (sub === 'get' && rest[0]) return withNode(async (rpc) => out(await rpc.call('launches.get', { key: rest[0] })));
|
|
326
|
+
if (sub === 'cancel' && rest[0]) return withNode(async (rpc) => out(await rpc.call('launches.cancel', { key: rest[0] })));
|
|
326
327
|
if (sub === 'list') return withNode(async (rpc) => out(await rpc.call('launches.list', {})));
|
|
327
|
-
die('launches get <key> |
|
|
328
|
+
die('launches get <key> | cancel <key> | list [--machine NAME]');
|
|
328
329
|
return;
|
|
329
330
|
}
|
|
330
331
|
case 'rpc': {
|
package/machine.mjs
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// request ids rewritten per connection, notifications routed
|
|
8
8
|
// by the subscription/connection they name (never fanned out)
|
|
9
9
|
// stream "terminal" a pane attachment under observe|control
|
|
10
|
-
// stream "node" describe, launch, launches.get|list, panes.*, files.*,
|
|
10
|
+
// stream "node" describe, launch, launches.get|cancel|list, panes.*, files.*,
|
|
11
11
|
// ports.*, attention.*, title.*
|
|
12
12
|
// stream "frontend" frontend.v2 to a hosted runtime, one client id per caller
|
|
13
13
|
// stream "port" one TCP connection to an announced port
|
|
@@ -1345,6 +1345,19 @@ export class TeamsMachine extends MachineCore {
|
|
|
1345
1345
|
});
|
|
1346
1346
|
}
|
|
1347
1347
|
|
|
1348
|
+
async #launchReceipt(found) {
|
|
1349
|
+
const session = found.pane ? await this.#paneByContext(found.pane) : null;
|
|
1350
|
+
return {
|
|
1351
|
+
key: found.key, pane: found.pane ?? null, status: found.status, by: found.by ?? null,
|
|
1352
|
+
cancelled: found.status === 'cancelled', outcome: found.outcome ?? null,
|
|
1353
|
+
cancelled_at: found.cancelled_at ?? null,
|
|
1354
|
+
live: Boolean(session && !session.dead), label: session?.label ?? null, activeCommand: session?.activeCommand ?? null,
|
|
1355
|
+
exit_output: found.pane && (!session || session.dead) ? paneExitOutput(found.pane) : null,
|
|
1356
|
+
exit: session?.dead ? deadPaneExit(session) : found.pane && !session ? paneExit(found.pane) : null,
|
|
1357
|
+
...initialInputFacts(found),
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1348
1361
|
async #dispatch(entry, method, params) {
|
|
1349
1362
|
// A server-forwarded caller is re-admitted on every door: a grant revoked or expired
|
|
1350
1363
|
// since the stream opened stops mattering NOW, not at the next stream.
|
|
@@ -1439,16 +1452,24 @@ export class TeamsMachine extends MachineCore {
|
|
|
1439
1452
|
const programName = String(params.program).split(/[\\/]/).pop().replace(/\.(?:exe|cmd)$/i, '');
|
|
1440
1453
|
if (programName === 'codex') params = { ...params, kind: 'codex' };
|
|
1441
1454
|
const key = params.key ?? `lk_${randomBytes(9).toString('base64url')}`;
|
|
1442
|
-
const
|
|
1443
|
-
//
|
|
1444
|
-
//
|
|
1445
|
-
|
|
1446
|
-
|
|
1455
|
+
const by = await this.#callerOf(entry, params).catch(() => null);
|
|
1456
|
+
// No await between the final journal check and issuance: cancellation and issuance
|
|
1457
|
+
// serialize in this daemon even when caller resolution or pane reads yielded.
|
|
1458
|
+
let existing = this.launches.find(key);
|
|
1459
|
+
while (existing) {
|
|
1460
|
+
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' });
|
|
1461
|
+
if (existing.status === 'issued') return { key, pane: existing.pane, reused: true, status: existing.status };
|
|
1462
|
+
if (existing.status === 'ready') {
|
|
1463
|
+
const session = await this.#paneByContext(existing.pane);
|
|
1464
|
+
const latest = this.launches.find(key);
|
|
1465
|
+
if (JSON.stringify(latest) !== JSON.stringify(existing)) { existing = latest; continue; }
|
|
1466
|
+
if (session && !session.dead) return { key, pane: existing.pane, reused: true, status: existing.status };
|
|
1467
|
+
}
|
|
1468
|
+
break;
|
|
1447
1469
|
}
|
|
1448
1470
|
const contextKey = params.pane ?? `p_${randomBytes(9).toString('base64url')}`;
|
|
1449
1471
|
// Who started the pane: the launching session's (or board's) address, null for a person. A session's later
|
|
1450
1472
|
// input on the pane is refused unless it is this one (#refuseForeign); close is not creator-restricted.
|
|
1451
|
-
const by = await this.#callerOf(entry, params).catch(() => null);
|
|
1452
1473
|
// Who to tell when the pane ends (`open --new … --notify-when-ended`): a session's mail address, and this
|
|
1453
1474
|
// machine's name as the address a notice from its pane comes from.
|
|
1454
1475
|
if (params.notify !== undefined && !(params.notify && typeof params.notify.to === 'string' && /^sc:[^:\s]+:[^:\s]+:\S+$/.test(params.notify.to) && typeof params.notify.machine === 'string' && /^[a-z0-9][a-z0-9-]*$/.test(params.notify.machine))) throw Object.assign(new Error('launch notify is { to: <sc: address>, machine: <this machine\'s mail name> }'), { code: 400 });
|
|
@@ -1523,13 +1544,21 @@ export class TeamsMachine extends MachineCore {
|
|
|
1523
1544
|
if (!operator) throw Object.assign(new Error('operators only'), { code: 403 });
|
|
1524
1545
|
const found = this.launches.find(params.key);
|
|
1525
1546
|
if (!found) return null;
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1547
|
+
return this.#launchReceipt(found);
|
|
1548
|
+
}
|
|
1549
|
+
case 'launches.cancel': {
|
|
1550
|
+
if (!operator) throw Object.assign(new Error('operators only'), { code: 403 });
|
|
1551
|
+
if (typeof params.key !== 'string' || !params.key.trim()) throw Object.assign(new Error('launch cancellation requires a nonempty key'), { code: 400 });
|
|
1552
|
+
const by = await this.#callerOf(entry, params).catch(() => null);
|
|
1553
|
+
// Retire only an absent key. An issued, live or failed launch keeps its actual
|
|
1554
|
+
// receipt; cancellation never closes a pane or guesses that issuance did not happen.
|
|
1555
|
+
let found = this.launches.find(params.key);
|
|
1556
|
+
if (!found) {
|
|
1557
|
+
this.launches.record({ key: params.key, pane: null, by, status: 'cancelled', outcome: 'not_issued', cancelled_at: Date.now() });
|
|
1558
|
+
found = this.launches.find(params.key);
|
|
1559
|
+
act('launches.cancel', params.key, 'ok', 'not issued; key retired');
|
|
1560
|
+
} else act('launches.cancel', params.key, found.status === 'cancelled' ? 'ok' : 'refused', found.status);
|
|
1561
|
+
return this.#launchReceipt(found);
|
|
1533
1562
|
}
|
|
1534
1563
|
case 'launches.list': {
|
|
1535
1564
|
// Everything this daemon launched, by key, with whether the pane still lives: how an
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-teams",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.173",
|
|
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",
|