@vibelet/cli 1.2.137 → 1.2.139

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.
@@ -1,2 +1,2 @@
1
- var c=require("node:fs"),n=require("node:path"),p="@vibelet/cli";function i(r){try{let e=JSON.parse((0,c.readFileSync)(r,"utf8"));if(e.name===p&&typeof e.version=="string"&&e.version.length>0)return e.version}catch{}return null}function l(){return"1.2.137"}var a=l();process.stdout.write(`${a}
1
+ var c=require("node:fs"),n=require("node:path"),p="@vibelet/cli";function i(r){try{let e=JSON.parse((0,c.readFileSync)(r,"utf8"));if(e.name===p&&typeof e.version=="string"&&e.version.length>0)return e.version}catch{}return null}function l(){return"1.2.139"}var a=l();process.stdout.write(`${a}
2
2
  `);
package/dist/vibelet.mjs CHANGED
@@ -11768,7 +11768,7 @@ __nccwpck_require__.d(__webpack_exports__, {
11768
11768
  gJ: () => (/* binding */ terminalControlTokenPath)
11769
11769
  });
11770
11770
 
11771
- // UNUSED EXPORTS: buildClaudeSessionIdArgs, buildClaudeTerminalArgs, buildResumeNativeArgs, cleanupClaudeTerminalHookFiles, collectProcessTreePids, createClaudeTerminalHookFiles, createTerminalModeState, exitCodeFromChildExit, extractInitialSessionId, formatTerminalControlScreen, hasClaudeContinueArg, hasClaudeResumePickerArg, hasClaudeSettingsArg, requestSwitchBackWhenReady, resolveNativeAgentCommand, stopNativeChild
11771
+ // UNUSED EXPORTS: buildClaudeSessionIdArgs, buildClaudeTerminalArgs, buildResumeNativeArgs, cleanupClaudeTerminalHookFiles, collectProcessTreePids, connectTerminalControl, createClaudeTerminalHookFiles, createTerminalModeState, exitCodeFromChildExit, extractInitialSessionId, formatTerminalControlScreen, hasClaudeContinueArg, hasClaudeResumePickerArg, hasClaudeSettingsArg, monitorTerminalControlUntilChildExit, requestSwitchBackWhenReady, resolveNativeAgentCommand, stopNativeChild
11772
11772
 
11773
11773
  // EXTERNAL MODULE: external "node:child_process"
11774
11774
  var external_node_child_process_ = __nccwpck_require__(1421);
@@ -11814,13 +11814,13 @@ const TAKEOVER_STOP_TIMEOUT_MS = 3000;
11814
11814
  const TAKEOVER_MODE_SETTLE_TIMEOUT_MS = TAKEOVER_STOP_TIMEOUT_MS + 2000;
11815
11815
  const SWITCHBACK_RESTORE_NOTICE_MS = 1200;
11816
11816
  const SWITCHBACK_BUSY_RETRY_DELAY_MS = 750;
11817
+ const TERMINAL_CONTROL_RECONNECT_DELAY_MS = 1000;
11817
11818
  const CLAUDE_HOOK_SECRET_HEADER = 'x-vibelet-claude-hook-secret';
11818
11819
  const ANSI_CLEAR_SCREEN = '\x1b[2J\x1b[H';
11819
11820
  const ANSI_HIDE_CURSOR = '\x1b[?25l';
11820
11821
  const ANSI_SHOW_CURSOR = '\x1b[?25h';
11821
11822
  const ANSI_RESET = '\x1b[0m';
11822
11823
  const ANSI_BOLD = '\x1b[1m';
11823
- const ANSI_DIM = '\x1b[2m';
11824
11824
  const ANSI_CYAN = '\x1b[36m';
11825
11825
  const ANSI_GREEN = '\x1b[32m';
11826
11826
  const ANSI_YELLOW = '\x1b[33m';
@@ -12226,13 +12226,6 @@ function wrapText(text, width) {
12226
12226
  return lines;
12227
12227
  }
12228
12228
 
12229
- function centerText(text, width) {
12230
- const value = String(text);
12231
- if (value.length >= width) return value.slice(0, width);
12232
- const left = Math.floor((width - value.length) / 2);
12233
- return `${' '.repeat(left)}${value}`;
12234
- }
12235
-
12236
12229
  function padRight(text, width) {
12237
12230
  const value = String(text);
12238
12231
  if (value.length >= width) return value.slice(0, width);
@@ -12240,7 +12233,7 @@ function padRight(text, width) {
12240
12233
  }
12241
12234
 
12242
12235
  function colorize(enabled, style, text) {
12243
- if (!enabled) return text;
12236
+ if (!enabled || !style) return text;
12244
12237
  return `${style}${text}${ANSI_RESET}`;
12245
12238
  }
12246
12239
 
@@ -12257,7 +12250,7 @@ function getTerminalControlScreenPalette(tone) {
12257
12250
  subtitle: ANSI_RED,
12258
12251
  separator: ANSI_RED,
12259
12252
  label: ANSI_YELLOW,
12260
- body: ANSI_WHITE,
12253
+ body: '',
12261
12254
  footer: `${ANSI_BOLD}${ANSI_YELLOW}`,
12262
12255
  };
12263
12256
  }
@@ -12267,7 +12260,7 @@ function getTerminalControlScreenPalette(tone) {
12267
12260
  subtitle: ANSI_CYAN,
12268
12261
  separator: ANSI_CYAN,
12269
12262
  label: ANSI_CYAN,
12270
- body: ANSI_WHITE,
12263
+ body: '',
12271
12264
  footer: `${ANSI_BOLD}${ANSI_GREEN}`,
12272
12265
  };
12273
12266
  }
@@ -12276,7 +12269,7 @@ function getTerminalControlScreenPalette(tone) {
12276
12269
  subtitle: ANSI_GREEN,
12277
12270
  separator: ANSI_GREEN,
12278
12271
  label: ANSI_CYAN,
12279
- body: ANSI_WHITE,
12272
+ body: '',
12280
12273
  footer: `${ANSI_BOLD}${ANSI_YELLOW}`,
12281
12274
  };
12282
12275
  }
@@ -12305,7 +12298,6 @@ function formatTerminalControlScreen({
12305
12298
  const width = screenWidth < 60 ? screenWidth : Math.min(100, screenWidth);
12306
12299
  const height = Math.max(20, Number(rows) || 24);
12307
12300
  const innerWidth = width - 8;
12308
- const gutter = ' '.repeat(Math.max(0, Math.floor((screenWidth - width) / 2)));
12309
12301
  const separator = '='.repeat(width);
12310
12302
  const tone = getTerminalControlScreenTone(title);
12311
12303
  const palette = getTerminalControlScreenPalette(tone);
@@ -12315,12 +12307,12 @@ function formatTerminalControlScreen({
12315
12307
  ['Directory', cwd || process.cwd()],
12316
12308
  ].map(([label, value]) => {
12317
12309
  const parts = formatTerminalFieldParts(label, value, innerWidth);
12318
- return `${colorize(color, palette.label, parts.label)}${colorize(color, ANSI_DIM, parts.value)}`;
12310
+ return `${colorize(color, palette.label, parts.label)}${parts.value}`;
12319
12311
  });
12320
12312
  const block = [
12321
12313
  colorize(color, palette.separator, separator),
12322
- colorize(color, palette.title, padRight(centerText(title, width), width)),
12323
- subtitle ? colorize(color, palette.subtitle, padRight(centerText(subtitle, width), width)) : '',
12314
+ colorize(color, palette.title, padRight(title, width)),
12315
+ subtitle ? colorize(color, palette.subtitle, padRight(subtitle, width)) : '',
12324
12316
  colorize(color, palette.separator, separator),
12325
12317
  '',
12326
12318
  ...fieldLines,
@@ -12329,20 +12321,20 @@ function formatTerminalControlScreen({
12329
12321
 
12330
12322
  for (const line of bodyLines) {
12331
12323
  for (const wrapped of wrapText(line, innerWidth)) {
12332
- block.push(colorize(color, palette.body, padRight(centerText(wrapped, width), width)));
12324
+ block.push(colorize(color, palette.body, padRight(wrapped, width)));
12333
12325
  }
12334
12326
  }
12335
12327
 
12336
12328
  block.push('');
12337
12329
  for (const line of footerLines) {
12338
12330
  for (const wrapped of wrapText(line, innerWidth)) {
12339
- block.push(colorize(color, palette.footer, padRight(centerText(wrapped, width), width)));
12331
+ block.push(colorize(color, palette.footer, padRight(wrapped, width)));
12340
12332
  }
12341
12333
  }
12342
12334
  block.push(colorize(color, palette.separator, separator));
12343
12335
 
12344
12336
  const verticalPadding = Math.max(0, Math.floor((height - block.length) / 3));
12345
- return `${'\n'.repeat(verticalPadding)}${block.map((line) => `${gutter}${line}`).join('\n')}\n`;
12337
+ return `${'\n'.repeat(verticalPadding)}${block.join('\n')}\n`;
12346
12338
  }
12347
12339
 
12348
12340
  function renderTerminalControlScreen(stream, options) {
@@ -12549,6 +12541,25 @@ async function connectTerminalControl({
12549
12541
  let activeChild = child;
12550
12542
  let activeChildExit = childExit;
12551
12543
  let heartbeatTimer = null;
12544
+ let resolveClosed;
12545
+ let closedResolved = false;
12546
+ const closed = new Promise((resolve) => {
12547
+ resolveClosed = resolve;
12548
+ });
12549
+
12550
+ function resolveCloseOnce(code, reason) {
12551
+ if (heartbeatTimer) {
12552
+ clearInterval(heartbeatTimer);
12553
+ heartbeatTimer = null;
12554
+ }
12555
+ requester.rejectAll('terminal_control_closed');
12556
+ if (closedResolved) return;
12557
+ closedResolved = true;
12558
+ resolveClosed({
12559
+ code,
12560
+ reason: Buffer.isBuffer(reason) ? reason.toString('utf8') : String(reason ?? ''),
12561
+ });
12562
+ }
12552
12563
 
12553
12564
  async function sendSession(mode = getMode()) {
12554
12565
  if (!terminalId || !currentSessionId) return { ok: true };
@@ -12613,9 +12624,8 @@ async function connectTerminalControl({
12613
12624
  sendResponse(msg.id, true, { mode: 'remoteDaemon' });
12614
12625
  });
12615
12626
 
12616
- ws.on('close', () => {
12617
- if (heartbeatTimer) clearInterval(heartbeatTimer);
12618
- requester.rejectAll('terminal_control_closed');
12627
+ ws.on('close', (code, reason) => {
12628
+ resolveCloseOnce(code, reason);
12619
12629
  });
12620
12630
 
12621
12631
  const hello = await requester.sendRequest('terminal.hello', {
@@ -12651,6 +12661,10 @@ async function connectTerminalControl({
12651
12661
  if (typeof heartbeatTimer.unref === 'function') heartbeatTimer.unref();
12652
12662
 
12653
12663
  return {
12664
+ closed,
12665
+ getTerminalId() {
12666
+ return terminalId;
12667
+ },
12654
12668
  getSessionId() {
12655
12669
  return currentSessionId;
12656
12670
  },
@@ -12673,12 +12687,68 @@ async function connectTerminalControl({
12673
12687
  });
12674
12688
  },
12675
12689
  close() {
12676
- if (heartbeatTimer) clearInterval(heartbeatTimer);
12677
- ws.close();
12690
+ if (heartbeatTimer) {
12691
+ clearInterval(heartbeatTimer);
12692
+ heartbeatTimer = null;
12693
+ }
12694
+ if (ws.readyState === wrapper.OPEN || ws.readyState === wrapper.CONNECTING) {
12695
+ ws.close();
12696
+ }
12678
12697
  },
12679
12698
  };
12680
12699
  }
12681
12700
 
12701
+ async function monitorTerminalControlUntilChildExit({
12702
+ childExit,
12703
+ getControl,
12704
+ setControl,
12705
+ connectControl,
12706
+ shouldReconnect = () => true,
12707
+ retryDelayMs = TERMINAL_CONTROL_RECONNECT_DELAY_MS,
12708
+ onControlDisconnected,
12709
+ onReconnectFailure,
12710
+ }) {
12711
+ const delayMs = Math.max(1, Number(retryDelayMs) || TERMINAL_CONTROL_RECONNECT_DELAY_MS);
12712
+ const childExitEvent = childExit.then((exit) => ({ type: 'childExit', exit }));
12713
+
12714
+ while (true) {
12715
+ const currentControl = getControl();
12716
+ const waiters = [childExitEvent];
12717
+ if (currentControl?.closed) {
12718
+ waiters.push(
12719
+ currentControl.closed.then((closeInfo) => ({
12720
+ type: 'controlClosed',
12721
+ control: currentControl,
12722
+ closeInfo,
12723
+ })),
12724
+ );
12725
+ }
12726
+ if (!currentControl || !shouldReconnect()) {
12727
+ waiters.push(waitMs(delayMs).then(() => ({ type: 'retry' })));
12728
+ }
12729
+
12730
+ const event = await Promise.race(waiters);
12731
+ if (event.type === 'childExit') {
12732
+ return event.exit;
12733
+ }
12734
+
12735
+ if (event.type === 'controlClosed' && getControl() === event.control) {
12736
+ setControl(null);
12737
+ onControlDisconnected?.(event.control, event.closeInfo);
12738
+ }
12739
+
12740
+ if (getControl() || !shouldReconnect()) {
12741
+ continue;
12742
+ }
12743
+
12744
+ try {
12745
+ setControl(await connectControl());
12746
+ } catch (error) {
12747
+ onReconnectFailure?.(error);
12748
+ }
12749
+ }
12750
+ }
12751
+
12682
12752
  async function runManagedNativeTerminal({
12683
12753
  agent,
12684
12754
  args,
@@ -12716,11 +12786,49 @@ async function runManagedNativeTerminal({
12716
12786
  let signalHandlers = null;
12717
12787
  const modeState = createTerminalModeState('localNative');
12718
12788
  let control = null;
12789
+ let terminalId = claudeHookFiles?.terminalId ?? null;
12790
+
12791
+ function rememberControlState(nextControl) {
12792
+ const nextTerminalId = nextControl?.getTerminalId?.();
12793
+ if (nextTerminalId) terminalId = nextTerminalId;
12794
+ const nextSessionId = nextControl?.getSessionId?.();
12795
+ if (nextSessionId) initialSessionId = nextSessionId;
12796
+ }
12719
12797
 
12720
12798
  try {
12721
12799
  while (true) {
12722
12800
  activeChild = await spawnNativeChild(command, nativeArgs, { cwd, env });
12723
12801
  const childExit = waitForChildExit(activeChild);
12802
+ let reportedTerminalControlFailure = false;
12803
+ const reportTerminalControlFailure = (prefix, error) => {
12804
+ if (reportedTerminalControlFailure) return;
12805
+ reportedTerminalControlFailure = true;
12806
+ stderr.write(`${prefix}: ${error instanceof Error ? error.message : String(error)}\n`);
12807
+ };
12808
+ const connectActiveControl = async () => {
12809
+ const nextControl = await connectTerminalControl({
12810
+ agent,
12811
+ cwd,
12812
+ argv,
12813
+ child: activeChild,
12814
+ childExit,
12815
+ cliVersion,
12816
+ port,
12817
+ token,
12818
+ initialSessionId,
12819
+ requestedTerminalId: terminalId ?? claudeHookFiles?.terminalId,
12820
+ getMode: () => modeState.getMode(),
12821
+ setMode: (nextMode) => modeState.setMode(nextMode),
12822
+ stderr,
12823
+ });
12824
+ rememberControlState(nextControl);
12825
+ reportedTerminalControlFailure = false;
12826
+ return nextControl;
12827
+ };
12828
+ const setActiveControl = (nextControl) => {
12829
+ control = nextControl;
12830
+ rememberControlState(nextControl);
12831
+ };
12724
12832
  if (!signalHandlers) {
12725
12833
  signalHandlers = installTerminalSignalHandlers(
12726
12834
  () => activeChild,
@@ -12732,30 +12840,32 @@ async function runManagedNativeTerminal({
12732
12840
  stderr.write('Vibelet terminal control is unavailable; running native TUI without App takeover.\n');
12733
12841
  } else if (!control) {
12734
12842
  try {
12735
- control = await connectTerminalControl({
12736
- agent,
12737
- cwd,
12738
- argv,
12739
- child: activeChild,
12740
- childExit,
12741
- cliVersion,
12742
- port,
12743
- token,
12744
- initialSessionId,
12745
- requestedTerminalId: claudeHookFiles?.terminalId,
12746
- getMode: () => modeState.getMode(),
12747
- setMode: (nextMode) => modeState.setMode(nextMode),
12748
- stderr,
12749
- });
12843
+ setActiveControl(await connectActiveControl());
12750
12844
  } catch (error) {
12751
- stderr.write(`Vibelet terminal control failed: ${error instanceof Error ? error.message : String(error)}\n`);
12845
+ reportTerminalControlFailure('Vibelet terminal control failed', error);
12752
12846
  }
12753
12847
  } else {
12754
12848
  control.setChild(activeChild, childExit);
12755
12849
  await control.sendSession('localNative');
12850
+ rememberControlState(control);
12756
12851
  }
12757
12852
 
12758
- const exit = await childExit;
12853
+ const exit = token
12854
+ ? await monitorTerminalControlUntilChildExit({
12855
+ childExit,
12856
+ getControl: () => control,
12857
+ setControl: setActiveControl,
12858
+ connectControl: connectActiveControl,
12859
+ shouldReconnect: () => modeState.getMode() === 'localNative',
12860
+ onControlDisconnected: (closedControl) => {
12861
+ rememberControlState(closedControl);
12862
+ stderr.write('Vibelet terminal control disconnected; reconnecting so App takeover can resume.\n');
12863
+ },
12864
+ onReconnectFailure: (error) => {
12865
+ reportTerminalControlFailure('Vibelet terminal control reconnect failed', error);
12866
+ },
12867
+ })
12868
+ : await childExit;
12759
12869
  if (modeState.getMode() === 'switchingToRemote') {
12760
12870
  await modeState.waitUntilModeLeaves('switchingToRemote', TAKEOVER_MODE_SETTLE_TIMEOUT_MS);
12761
12871
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibelet/cli",
3
- "version": "1.2.137",
3
+ "version": "1.2.139",
4
4
  "description": "Cross-platform CLI for installing and running the Vibelet daemon",
5
5
  "homepage": "https://vibelet.icu",
6
6
  "files": [