@volter/supercode-teams 0.3.10 → 0.3.12
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 +6 -2
- package/machine.mjs +23 -4
- package/package.json +1 -1
package/bin/teams.mjs
CHANGED
|
@@ -52,7 +52,7 @@ import { NODE_PROTOCOL } from '@volter/teams/channel';
|
|
|
52
52
|
|
|
53
53
|
const MACHINE_VERBS = new Set(['machine', 'slow', 'describe', 'panes', 'input', 'suspend', 'resume', 'files', 'ports', 'port', 'browser', 'stream', 'jobs', 'workspace', 'title', 'attention', 'watch', 'rpc', 'launches', 'log', 'mail', 'health']);
|
|
54
54
|
// Every flag a machine verb reads; any other is refused rather than silently ignored.
|
|
55
|
-
const KNOWN_FLAGS = new Set(['home', 'since', 'machine', 'context', 'floor', 'supercode', 'tmux-socket', 'verbose', 'lines', 'input', 'name', 'for', 'urgency', 'reason', 'interrupt', 'query', 'out', 'in', 'interval', 'no-enter', 'when-composer-empty', 'key', 'listen', 'list', 'from', 'to', 'path', 'to-path', 'repo', 'branch', 'solo', 'card', 'create', 'presence-only', 'clear-draft', 'message-ids', 'json', 'all']);
|
|
55
|
+
const KNOWN_FLAGS = new Set(['home', 'since', 'machine', 'context', 'floor', 'supercode', 'tmux-socket', 'verbose', 'lines', 'input', 'name', 'for', 'urgency', 'reason', 'interrupt', 'query', 'out', 'in', 'interval', 'no-enter', 'when-composer-empty', 'key', 'listen', 'list', 'from', 'to', 'path', 'to-path', 'repo', 'branch', 'solo', 'card', 'create', 'presence-only', 'processes', 'panes', 'clear-draft', 'message-ids', 'json', 'all']);
|
|
56
56
|
|
|
57
57
|
const argv = process.argv.slice(2);
|
|
58
58
|
const flags = {};
|
|
@@ -218,7 +218,11 @@ async function main() {
|
|
|
218
218
|
case 'describe':
|
|
219
219
|
return withNode(async (rpc) => out(await rpc.call('describe')));
|
|
220
220
|
case 'panes': {
|
|
221
|
-
|
|
221
|
+
// `--processes`: each pane and its root pid (no screens read); `--presence-only [--panes a,b]`: whether each pane's
|
|
222
|
+
// composer is idle, for the named panes only when named.
|
|
223
|
+
if (sub === 'ls') return withNode(async (rpc) => out(await rpc.call(
|
|
224
|
+
flags.processes ? 'panes.processes' : flags['presence-only'] ? 'panes.present' : 'panes.list',
|
|
225
|
+
flags['presence-only'] && typeof flags.panes === 'string' ? { panes: flags.panes.split(',').filter(Boolean) } : {})));
|
|
222
226
|
if (sub === 'capture') return withNode(async (rpc) => out((await rpc.call('panes.capture', { pane: rest[0], lines: Number(flags.lines ?? 200) })).text));
|
|
223
227
|
if (sub === 'close') return withNode(async (rpc) => out(await rpc.call('panes.close', { pane: rest[0] })));
|
|
224
228
|
die('panes ls|capture|close');
|
package/machine.mjs
CHANGED
|
@@ -521,10 +521,12 @@ export class TeamsMachine extends MachineCore {
|
|
|
521
521
|
async #checkEnds() {
|
|
522
522
|
const pending = this.#pendingNotices();
|
|
523
523
|
if (!pending.length) { clearInterval(this.endWatch); this.endWatch = null; return; }
|
|
524
|
+
// One pane listing for every pending notice, not one per notice.
|
|
525
|
+
const panes = await this.host.listSessions();
|
|
524
526
|
for (const ask of pending) {
|
|
525
527
|
// A pane has ended when it is gone, or when its program has exited and the host keeps it for its last screen
|
|
526
528
|
// (a ConPTY pane whose program failed).
|
|
527
|
-
const session =
|
|
529
|
+
const session = panes.find((s) => s.contextKey === ask.pane) ?? null;
|
|
528
530
|
if (session && !session.dead) continue;
|
|
529
531
|
appendFileSync(this.#noticesPath(), JSON.stringify({ t: Date.now(), pane: ask.pane, told: true }) + '\n', { mode: 0o600 });
|
|
530
532
|
const exit = session?.dead ? deadPaneExit(session) : paneExit(ask.pane);
|
|
@@ -1725,7 +1727,9 @@ export class TeamsMachine extends MachineCore {
|
|
|
1725
1727
|
// No harness callback: discovery may be the harness's own caller.
|
|
1726
1728
|
const whole = operator || holds(admitted, 'view', '*');
|
|
1727
1729
|
if (!whole && !observesPanes(admitted)) need('view', '*');
|
|
1728
|
-
|
|
1730
|
+
// `panes`: only these are read (a caller that needs some panes' composers does not pay a capture of every pane).
|
|
1731
|
+
const asked = Array.isArray(params.panes) ? new Set(params.panes.map(String)) : null;
|
|
1732
|
+
const sessions = (await this.host.listSessions()).filter(s => s.contextKey && !s.dead && (!asked || asked.has(s.contextKey)) && (whole || holds(admitted, 'observe', `pane:${s.contextKey}`)));
|
|
1729
1733
|
return Promise.all(sessions.map(async session => {
|
|
1730
1734
|
const screen = await Promise.resolve().then(() => this.host.capture(session.id, { lines: 100, preserveEscapes: true })).catch(() => null);
|
|
1731
1735
|
const kind = this.#paneKind(session.contextKey, session);
|
|
@@ -1733,6 +1737,15 @@ export class TeamsMachine extends MachineCore {
|
|
|
1733
1737
|
return { pane: session.contextKey, idleComposer: composer != null && !/\besc to (?:interrupt|cancel)\b/iu.test(screen) };
|
|
1734
1738
|
}));
|
|
1735
1739
|
}
|
|
1740
|
+
case 'panes.processes': {
|
|
1741
|
+
// Each pane and its root process, from the pane listing alone: what a caller that maps processes to panes
|
|
1742
|
+
// needs, without panes.list's screen capture of every pane (message list asked for that, t_23e47b73).
|
|
1743
|
+
const whole = operator || holds(admitted, 'view', '*');
|
|
1744
|
+
if (!whole && !observesPanes(admitted)) need('view', '*');
|
|
1745
|
+
return (await this.host.listSessions())
|
|
1746
|
+
.filter(s => s.contextKey && !s.dead && (whole || holds(admitted, 'observe', `pane:${s.contextKey}`)))
|
|
1747
|
+
.map(s => ({ pane: s.contextKey, pid: s.rootPid ?? null }));
|
|
1748
|
+
}
|
|
1736
1749
|
case 'harness.v1.panes.list':
|
|
1737
1750
|
case 'panes.list': {
|
|
1738
1751
|
// A participant lists the panes its grants let it observe; view on the whole
|
|
@@ -1876,9 +1889,15 @@ export class TeamsMachine extends MachineCore {
|
|
|
1876
1889
|
// Everything this daemon launched, by key, with whether the pane still lives: how an
|
|
1877
1890
|
// operator tells its own launches from a person's panes without reading labels.
|
|
1878
1891
|
if (!operator) throw Object.assign(new Error('operators only'), { code: 403 });
|
|
1892
|
+
// One pane listing for the whole journal: one per launch (thousands of them) ran past the door's 30 s bound,
|
|
1893
|
+
// the slowest door the slow log named on yuerans-macbook-pro (t_23e47b73).
|
|
1894
|
+
// The journal first, then the panes: a launch that becomes ready while the panes are listed is in a listing
|
|
1895
|
+
// taken after it, so it never reads as not live.
|
|
1879
1896
|
const rows = [];
|
|
1880
|
-
|
|
1881
|
-
|
|
1897
|
+
const launched = this.launches.all();
|
|
1898
|
+
const panes = await this.host.listSessions();
|
|
1899
|
+
for (const found of launched) {
|
|
1900
|
+
const session = found.pane ? panes.find((s) => s.contextKey === found.pane) ?? null : null;
|
|
1882
1901
|
rows.push({ key: found.key, pane: found.pane ?? null, kind: found.kind ?? null, by: found.by ?? null, status: found.status ?? null, at: found.t, live: Boolean(session && !session.dead), ...initialInputFacts(found) });
|
|
1883
1902
|
}
|
|
1884
1903
|
return rows;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-teams",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.12",
|
|
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",
|