@volter/supercode-teams 0.2.101 → 0.2.103
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/fleet.mjs +13 -1
- package/bin/teams.mjs +21 -9
- package/package.json +1 -1
package/bin/fleet.mjs
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
// `--on` names an enrolled machine of the selected context, reached through
|
|
17
17
|
// its Teams server. Omitted, every verb acts on this OS user's own daemon, so
|
|
18
18
|
// the remote arm and the local arm are one code path.
|
|
19
|
+
import { spawnSync } from 'node:child_process';
|
|
19
20
|
import { attachPane, attachRuntime } from '../client.mjs';
|
|
20
21
|
import { openOn, harnessRequest, nodeRequest, fleetDiscover } from '../fleet.mjs';
|
|
21
22
|
|
|
@@ -45,6 +46,17 @@ function channelForOn() {
|
|
|
45
46
|
return openOn(onName(), { context: contextName() });
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
// Who starts a pane, as supercode answers it (`teams caller`); a launch nothing answers for records no starter, so no
|
|
50
|
+
// session may act on the pane.
|
|
51
|
+
let launcherAnswer;
|
|
52
|
+
function launcher() {
|
|
53
|
+
if (launcherAnswer === undefined) {
|
|
54
|
+
const r = spawnSync(process.env.SUPERCODE_BIN || 'supercode', ['teams', 'caller'], { encoding: 'utf8', shell: process.platform === 'win32', windowsHide: true });
|
|
55
|
+
try { launcherAnswer = JSON.parse(r.stdout.trim().split('\n').pop()).caller ?? null; } catch { launcherAnswer = null; }
|
|
56
|
+
}
|
|
57
|
+
return launcherAnswer;
|
|
58
|
+
}
|
|
59
|
+
|
|
48
60
|
async function main() {
|
|
49
61
|
switch (verb) {
|
|
50
62
|
case 'discover': {
|
|
@@ -87,7 +99,7 @@ async function main() {
|
|
|
87
99
|
...(flags.popup === 'false' ? { popup: false } : {}),
|
|
88
100
|
// Who starts the pane (the session or board supercode resolved; unset for a person), and whether the pane
|
|
89
101
|
// runs its one verb as that caller (`close`/`stop` on another machine).
|
|
90
|
-
...(
|
|
102
|
+
...(launcher() ? { caller: launcher() } : {}),
|
|
91
103
|
...(flags['act-for-caller'] ? { actForCaller: true } : {}),
|
|
92
104
|
// `open --notify-when-ended`: the launching session's address, told once when the pane ends, and the
|
|
93
105
|
// machine's mail name the notice comes from.
|
package/bin/teams.mjs
CHANGED
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
// members, groups, sources, sync, machines, sessions) is the Teams workspace
|
|
27
27
|
// CLI in ./workspace.mjs.
|
|
28
28
|
import { createWriteStream, readFileSync, writeFileSync } from 'node:fs';
|
|
29
|
+
import { spawnSync } from 'node:child_process';
|
|
29
30
|
import { SupercodeHarnessClient } from '@volter/supercode-harness-sdk';
|
|
30
31
|
|
|
31
32
|
// A Windows scheduled task keeps no output (launchd and systemd name log files), so its unit names one here.
|
|
@@ -106,9 +107,20 @@ async function machineChannel() {
|
|
|
106
107
|
return openMachine({ machine: flags.machine ? String(flags.machine) : null, context: flags.context ? String(flags.context) : null, home });
|
|
107
108
|
}
|
|
108
109
|
|
|
109
|
-
// The session (or board) this command acts for
|
|
110
|
-
//
|
|
111
|
-
|
|
110
|
+
// The session (or board) this command acts for: the pane doors refuse a session acting on a pane it did not start.
|
|
111
|
+
// supercode answers it (`teams caller`: the session in this process's ancestry first, a named caller only as supercode
|
|
112
|
+
// itself takes one), so this bin holds the same rule as \`supercode teams\`; a command nothing answers for is refused.
|
|
113
|
+
let callerAnswer;
|
|
114
|
+
function caller() {
|
|
115
|
+
if (callerAnswer === undefined) {
|
|
116
|
+
const r = spawnSync(process.env.SUPERCODE_BIN || 'supercode', ['teams', 'caller'], { encoding: 'utf8', shell: process.platform === 'win32', windowsHide: true });
|
|
117
|
+
let answer;
|
|
118
|
+
try { answer = JSON.parse(r.stdout.trim().split('\n').pop()); } catch { /* no answer */ }
|
|
119
|
+
if (!answer || !('caller' in answer)) die(`cannot tell which session runs this, so the pane doors cannot hold it to the panes it started; nothing was done (${(r.error?.message ?? r.stderr ?? '').trim().slice(0, 200)})`, 1);
|
|
120
|
+
callerAnswer = answer.caller ?? null;
|
|
121
|
+
}
|
|
122
|
+
return callerAnswer ?? undefined;
|
|
123
|
+
}
|
|
112
124
|
|
|
113
125
|
async function withNode(fn) {
|
|
114
126
|
const channel = await machineChannel();
|
|
@@ -153,7 +165,7 @@ async function main() {
|
|
|
153
165
|
case 'panes': {
|
|
154
166
|
if (sub === 'ls') return withNode(async (rpc) => out(await rpc.call('panes.list')));
|
|
155
167
|
if (sub === 'capture') return withNode(async (rpc) => out((await rpc.call('panes.capture', { pane: rest[0], lines: Number(flags.lines ?? 200) })).text));
|
|
156
|
-
if (sub === 'close') return withNode(async (rpc) => out(await rpc.call('panes.close', { pane: rest[0], caller })));
|
|
168
|
+
if (sub === 'close') return withNode(async (rpc) => out(await rpc.call('panes.close', { pane: rest[0], caller: caller() })));
|
|
157
169
|
die('panes ls|capture|close');
|
|
158
170
|
}
|
|
159
171
|
case 'title': {
|
|
@@ -177,9 +189,9 @@ async function main() {
|
|
|
177
189
|
die('attention ls | rank | request <pane> [--urgency now|soon|whenever] [--reason text] | clear <pane>');
|
|
178
190
|
}
|
|
179
191
|
case 'suspend':
|
|
180
|
-
return withNode(async (rpc) => out(await rpc.call('panes.suspend', { pane: sub, interrupt: Boolean(flags.interrupt), caller })));
|
|
192
|
+
return withNode(async (rpc) => out(await rpc.call('panes.suspend', { pane: sub, interrupt: Boolean(flags.interrupt), caller: caller() })));
|
|
181
193
|
case 'resume':
|
|
182
|
-
return withNode(async (rpc) => out(await rpc.call('panes.resume', { pane: sub, input: flags.input ? String(flags.input) : null, caller })));
|
|
194
|
+
return withNode(async (rpc) => out(await rpc.call('panes.resume', { pane: sub, input: flags.input ? String(flags.input) : null, caller: caller() })));
|
|
183
195
|
case 'files': {
|
|
184
196
|
const path = rest[0];
|
|
185
197
|
if (sub === 'ls') return withNode(async (rpc) => out(await rpc.call('files.list', { path })));
|
|
@@ -218,10 +230,10 @@ async function main() {
|
|
|
218
230
|
// (answers `delivered: false` with the reason when it holds a draft).
|
|
219
231
|
if (flags.key !== undefined) {
|
|
220
232
|
if (flags.key === true || rest.length) die('input <pane> --key NAMES: keys by tmux name, space- or comma-separated (Escape, Enter, Tab, BTab, BSpace, Space, Up, Down, Left, Right, Home, End, PPage, NPage, DC, C-a … C-z)');
|
|
221
|
-
return withNode(async (rpc) => out(await rpc.call('panes.input', { pane: sub, text: keyBytes(String(flags.key)), submit: false, keys: true, caller })));
|
|
233
|
+
return withNode(async (rpc) => out(await rpc.call('panes.input', { pane: sub, text: keyBytes(String(flags.key)), submit: false, keys: true, caller: caller() })));
|
|
222
234
|
}
|
|
223
|
-
if (flags['when-composer-empty']) return withNode(async (rpc) => out(await rpc.call('panes.turn', { pane: sub, text: rest.join(' '), caller })));
|
|
224
|
-
return withNode(async (rpc) => out(await rpc.call('panes.input', { pane: sub, text: rest.join(' '), submit: !flags['no-enter'], caller })));
|
|
235
|
+
if (flags['when-composer-empty']) return withNode(async (rpc) => out(await rpc.call('panes.turn', { pane: sub, text: rest.join(' '), caller: caller() })));
|
|
236
|
+
return withNode(async (rpc) => out(await rpc.call('panes.input', { pane: sub, text: rest.join(' '), submit: !flags['no-enter'], caller: caller() })));
|
|
225
237
|
case 'port': {
|
|
226
238
|
// `port <pane>/<n> [--listen host:port]`: a machine port forwarded here. Stays up until ctrl-c.
|
|
227
239
|
const spec = String(sub ?? '');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-teams",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.103",
|
|
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",
|