@volter/supercode-teams 0.3.130 → 0.3.131

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.
Files changed (2) hide show
  1. package/bin/fleet.mjs +39 -8
  2. package/package.json +1 -1
package/bin/fleet.mjs CHANGED
@@ -162,19 +162,50 @@ async function main() {
162
162
  if (typeof flags.for === 'string') setTimeout(() => { fc.detachChannel(); channel.close(); process.exit(0); }, Number(flags.for));
163
163
  return;
164
164
  }
165
- const term = await attachPane(channel, { pane, mode, cols: process.stdout.columns ?? 120, rows: process.stdout.rows ?? 40, acting: await launcher() });
166
- term.on('hello', (frame) => process.stderr.write(`[attached ${pane} ${frame.cols}x${frame.rows}${mode === 'control' ? ' — ctrl-] detaches' : ''}]\n`));
167
- term.on('error-message', (message) => process.stderr.write(`[${message}]\n`));
168
- term.on('data', (text) => process.stdout.write(text));
169
- term.on('close', (reason) => { process.stderr.write(`\n[detached${reason ? `: ${reason}` : ''}]\n`); channel.close(); process.exit(0); });
165
+ // The view outlives a restart of the machine daemon (an upgrade restarts it; the pane itself lives in the pane
166
+ // host and goes on): when the daemon's connection drops, this window attaches again once it answers, for up to
167
+ // REATTACH_MS. The pane ending, a refusal, or ctrl-] ends the view as before.
168
+ const REATTACH_MS = 180_000;
169
+ let term = null;
170
+ let detaching = false;
171
+ const attach = async (into) => {
172
+ const next = await attachPane(into, { pane, mode, cols: process.stdout.columns ?? 120, rows: process.stdout.rows ?? 40, acting: await launcher() });
173
+ next.on('hello', (frame) => process.stderr.write(`[attached ${pane} ${frame.cols}x${frame.rows}${mode === 'control' ? ' — ctrl-] detaches' : ''}]\n`));
174
+ next.on('error-message', (message) => process.stderr.write(`[${message}]\n`));
175
+ next.on('data', (text) => process.stdout.write(text));
176
+ next.on('close', (reason) => {
177
+ into.close();
178
+ if (!detaching && typeof reason === 'string' && reason.startsWith('connection closed')) { void reattach(); return; }
179
+ process.stderr.write(`\n[detached${reason ? `: ${reason}` : ''}]\n`);
180
+ process.exit(0);
181
+ });
182
+ term = next;
183
+ };
184
+ const reattach = async () => {
185
+ process.stderr.write('\n[the machine daemon went away (an upgrade restarts it); attaching again when it is back…]\n');
186
+ const deadline = Date.now() + REATTACH_MS;
187
+ let last = null;
188
+ while (Date.now() < deadline) {
189
+ await new Promise((done) => setTimeout(done, 1_000));
190
+ try { await attach(await channelForOn()); return; } catch (error) {
191
+ last = error;
192
+ // the daemon saying this pane is gone (`terminal refused: no pane …`) will not change by waiting; a daemon not
193
+ // answering yet (ECONNREFUSED, no pipe) will
194
+ if (/terminal refused: .*(no pane|no \w+ on pane)/i.test(error?.message ?? '')) break;
195
+ }
196
+ }
197
+ process.stderr.write(`\n[detached: the machine daemon did not take this pane back${last ? ` (${last.message})` : ''}]\n`);
198
+ process.exit(1);
199
+ };
200
+ await attach(channel);
170
201
  if (mode === 'control' && process.stdin.isTTY) {
171
202
  process.stdin.setRawMode(true);
172
203
  process.stdin.on('data', (chunk) => {
173
- if (chunk[0] === 0x1d) { term.close(); return; } // ctrl-] detaches
174
- term.write(chunk.toString('utf8'));
204
+ if (chunk[0] === 0x1d) { detaching = true; term?.close(); return; } // ctrl-] detaches
205
+ term?.write(chunk.toString('utf8'));
175
206
  });
176
207
  }
177
- process.stdout.on('resize', () => term.resize(process.stdout.columns, process.stdout.rows));
208
+ process.stdout.on('resize', () => term?.resize(process.stdout.columns, process.stdout.rows));
178
209
  return;
179
210
  }
180
211
  default:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/supercode-teams",
3
- "version": "0.3.130",
3
+ "version": "0.3.131",
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",