vibelet 1.2.183 → 1.2.185

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 (35) hide show
  1. package/README.md +38 -0
  2. package/dist/index.cjs +1 -1
  3. package/dist/inventory-scan-worker.cjs +1 -1
  4. package/dist/runtime-version.cjs +1 -1
  5. package/dist/tailcat/vibelet-tailcat-darwin-amd64 +0 -0
  6. package/dist/tailcat/vibelet-tailcat-darwin-arm64 +0 -0
  7. package/dist/tailcat/vibelet-tailcat-linux-amd64 +0 -0
  8. package/dist/tailcat/vibelet-tailcat-linux-arm64 +0 -0
  9. package/dist/tailcat/vibelet-tailcat-win32-amd64.exe +0 -0
  10. package/dist/tailcat/vibelet-tailcat-win32-arm64.exe +0 -0
  11. package/dist/vibelet.mjs +356 -220
  12. package/dist/web/assets/App-1V1UoQkP.js +12 -0
  13. package/dist/web/assets/{ArchiveSyncPanel-Dnkaspmd.js → ArchiveSyncPanel-HfbSbAJT.js} +1 -1
  14. package/dist/web/assets/{ConnectionSettingsPanel-Br7qHYvB.js → ConnectionSettingsPanel-Y8Um-67e.js} +1 -1
  15. package/dist/web/assets/{DaemonSettingsPanel-BANgginY.js → DaemonSettingsPanel--znFJEC6.js} +1 -1
  16. package/dist/web/assets/{DiffDrawer-DtuLETbo.js → DiffDrawer-BI-wtkQ_.js} +1 -1
  17. package/dist/web/assets/FilesControlPanel-B5M5ueO9.js +2 -0
  18. package/dist/web/assets/LanguageSettingsPanel-BLwzc7Dm.js +1 -0
  19. package/dist/web/assets/{NotificationSettingsPanel-CwhRDEyv.js → NotificationSettingsPanel-IgZdwrhi.js} +1 -1
  20. package/dist/web/assets/{SavedTargetsPanel-BPdvJF_n.js → SavedTargetsPanel-DggmoRgT.js} +1 -1
  21. package/dist/web/assets/ThemeSettingsPanel-vB2Ox3sA.js +1 -0
  22. package/dist/web/assets/{file-text-C6lQdXN2.js → file-text-NAVq0aqX.js} +1 -1
  23. package/dist/web/assets/highlighted-body-TPN3WLV5-ClieluW-.js +1 -0
  24. package/dist/web/assets/{index-uoLYFezU.js → index-CXts92Zv.js} +10 -10
  25. package/dist/web/assets/index-D8mZeSsk.css +1 -0
  26. package/dist/web/assets/{mermaid-O7DHMXV3-nvIRGE2J.js → mermaid-O7DHMXV3-D0ujIgIK.js} +49 -49
  27. package/dist/web/assets/splash-logo-SQcOtj-8.png +0 -0
  28. package/dist/web/index.html +2 -2
  29. package/dist/web/logo.svg +13 -0
  30. package/package.json +2 -1
  31. package/dist/web/assets/App-CVkhf43f.js +0 -11
  32. package/dist/web/assets/FilesControlPanel-DIVZPGG9.js +0 -2
  33. package/dist/web/assets/LanguageSettingsPanel-B-MqFdLO.js +0 -1
  34. package/dist/web/assets/highlighted-body-TPN3WLV5-BMFXSJ1c.js +0 -1
  35. package/dist/web/assets/index-D3gAUQHc.css +0 -1
package/dist/vibelet.mjs CHANGED
@@ -12369,7 +12369,7 @@ function canUseSystemdUserManager({ spawnSyncImpl = node_child_process__WEBPACK_
12369
12369
 
12370
12370
  /***/ }),
12371
12371
 
12372
- /***/ 636:
12372
+ /***/ 2629:
12373
12373
  /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __nccwpck_require__) => {
12374
12374
 
12375
12375
 
@@ -12422,6 +12422,112 @@ var websocket_server = __nccwpck_require__(3261);
12422
12422
 
12423
12423
  /* harmony default export */ const wrapper = (websocket);
12424
12424
 
12425
+ ;// CONCATENATED MODULE: ./bin/terminal-process-tree.mjs
12426
+
12427
+
12428
+ const TAKEOVER_STOP_TIMEOUT_MS = 3000;
12429
+
12430
+ function terminal_process_tree_sendSignal(child, signal) {
12431
+ if (!child.pid || child.exitCode !== null || child.signalCode !== null) return;
12432
+ try {
12433
+ process.kill(child.pid, signal);
12434
+ } catch {
12435
+ // Already exited.
12436
+ }
12437
+ }
12438
+
12439
+ function isPidAlive(pid) {
12440
+ if (!pid) return false;
12441
+ try {
12442
+ process.kill(pid, 0);
12443
+ return true;
12444
+ } catch {
12445
+ return false;
12446
+ }
12447
+ }
12448
+
12449
+ function collectProcessTreePids(rootPid) {
12450
+ if (!rootPid) return [];
12451
+ let rows;
12452
+ try {
12453
+ rows = (0,external_node_child_process_.execFileSync)('ps', ['-axo', 'pid=,ppid='], {
12454
+ encoding: 'utf8',
12455
+ stdio: ['ignore', 'pipe', 'ignore'],
12456
+ });
12457
+ } catch {
12458
+ return [rootPid];
12459
+ }
12460
+ const childrenByParent = new Map();
12461
+ for (const line of rows.split('\n')) {
12462
+ const [pidText, ppidText] = line.trim().split(/\s+/);
12463
+ const pid = Number(pidText);
12464
+ const ppid = Number(ppidText);
12465
+ if (!Number.isFinite(pid) || !Number.isFinite(ppid)) continue;
12466
+ const children = childrenByParent.get(ppid) ?? [];
12467
+ children.push(pid);
12468
+ childrenByParent.set(ppid, children);
12469
+ }
12470
+ const out = [];
12471
+ const visit = (pid) => {
12472
+ out.push(pid);
12473
+ for (const childPid of childrenByParent.get(pid) ?? []) {
12474
+ visit(childPid);
12475
+ }
12476
+ };
12477
+ visit(rootPid);
12478
+ return out;
12479
+ }
12480
+
12481
+ function sendSignalToPids(pids, signal) {
12482
+ for (const pid of [...pids].reverse()) {
12483
+ try {
12484
+ process.kill(pid, signal);
12485
+ } catch {
12486
+ // Already exited.
12487
+ }
12488
+ }
12489
+ }
12490
+
12491
+ async function waitForProcessTreeExit(pids, timeoutMs) {
12492
+ const deadline = Date.now() + timeoutMs;
12493
+ while ([...pids].some(isPidAlive)) {
12494
+ const remainingMs = deadline - Date.now();
12495
+ if (remainingMs <= 0) return false;
12496
+ await new Promise((resolve) => setTimeout(resolve, Math.min(remainingMs, 10)));
12497
+ }
12498
+ return true;
12499
+ }
12500
+
12501
+ async function waitForExitOrTimeout(childExit, timeoutMs) {
12502
+ let timer;
12503
+ const timeout = new Promise((resolve) => {
12504
+ timer = setTimeout(() => resolve(null), timeoutMs);
12505
+ });
12506
+ const result = await Promise.race([childExit, timeout]);
12507
+ clearTimeout(timer);
12508
+ return result;
12509
+ }
12510
+
12511
+ async function stopNativeChild(
12512
+ child,
12513
+ childExit,
12514
+ { interruptTimeoutMs = TAKEOVER_STOP_TIMEOUT_MS, terminateTimeoutMs = 1000, killTimeoutMs = 1000 } = {},
12515
+ ) {
12516
+ if (child.exitCode !== null || child.signalCode !== null) return true;
12517
+ const trackedPids = new Set(collectProcessTreePids(child.pid));
12518
+ terminal_process_tree_sendSignal(child, 'SIGINT');
12519
+ await waitForExitOrTimeout(childExit, interruptTimeoutMs);
12520
+ if (await waitForProcessTreeExit(trackedPids, 0)) return true;
12521
+
12522
+ for (const pid of collectProcessTreePids(child.pid)) trackedPids.add(pid);
12523
+ sendSignalToPids(trackedPids, 'SIGTERM');
12524
+ if (await waitForProcessTreeExit(trackedPids, terminateTimeoutMs)) return true;
12525
+
12526
+ for (const pid of collectProcessTreePids(child.pid)) trackedPids.add(pid);
12527
+ sendSignalToPids(trackedPids, 'SIGKILL');
12528
+ return waitForProcessTreeExit(trackedPids, killTimeoutMs);
12529
+ }
12530
+
12425
12531
  ;// CONCATENATED MODULE: ./bin/terminal-wrapper.mjs
12426
12532
 
12427
12533
 
@@ -12430,10 +12536,13 @@ var websocket_server = __nccwpck_require__(3261);
12430
12536
 
12431
12537
 
12432
12538
 
12539
+
12540
+
12541
+
12433
12542
  const terminalControlTokenPath = (0,external_node_path_.join)((0,external_node_os_.homedir)(), '.vibelet', 'runtime', 'terminal-control-token');
12434
12543
 
12435
- const TAKEOVER_STOP_TIMEOUT_MS = 3000;
12436
- const TAKEOVER_MODE_SETTLE_TIMEOUT_MS = TAKEOVER_STOP_TIMEOUT_MS + 2000;
12544
+ const terminal_wrapper_TAKEOVER_STOP_TIMEOUT_MS = 3000;
12545
+ const TAKEOVER_MODE_SETTLE_TIMEOUT_MS = terminal_wrapper_TAKEOVER_STOP_TIMEOUT_MS + 2000;
12437
12546
  const SWITCHBACK_RESTORE_NOTICE_MS = 1200;
12438
12547
  const SWITCHBACK_BUSY_RETRY_DELAY_MS = 750;
12439
12548
  const TERMINAL_CONTROL_RECONNECT_DELAY_MS = 1000;
@@ -12765,94 +12874,6 @@ function waitForChildExit(child) {
12765
12874
  });
12766
12875
  }
12767
12876
 
12768
- function sendSignal(child, signal) {
12769
- if (!child.pid || child.exitCode !== null || child.signalCode !== null) return;
12770
- try {
12771
- process.kill(child.pid, signal);
12772
- } catch {
12773
- // Already exited.
12774
- }
12775
- }
12776
-
12777
- function isPidAlive(pid) {
12778
- if (!pid) return false;
12779
- try {
12780
- process.kill(pid, 0);
12781
- return true;
12782
- } catch {
12783
- return false;
12784
- }
12785
- }
12786
-
12787
- function collectProcessTreePids(rootPid) {
12788
- if (!rootPid) return [];
12789
- let rows;
12790
- try {
12791
- rows = (0,external_node_child_process_.execFileSync)('ps', ['-axo', 'pid=,ppid='], {
12792
- encoding: 'utf8',
12793
- stdio: ['ignore', 'pipe', 'ignore'],
12794
- });
12795
- } catch {
12796
- return [rootPid];
12797
- }
12798
- const childrenByParent = new Map();
12799
- for (const line of rows.split('\n')) {
12800
- const [pidText, ppidText] = line.trim().split(/\s+/);
12801
- const pid = Number(pidText);
12802
- const ppid = Number(ppidText);
12803
- if (!Number.isFinite(pid) || !Number.isFinite(ppid)) continue;
12804
- const children = childrenByParent.get(ppid) ?? [];
12805
- children.push(pid);
12806
- childrenByParent.set(ppid, children);
12807
- }
12808
- const out = [];
12809
- const visit = (pid) => {
12810
- out.push(pid);
12811
- for (const childPid of childrenByParent.get(pid) ?? []) {
12812
- visit(childPid);
12813
- }
12814
- };
12815
- visit(rootPid);
12816
- return out;
12817
- }
12818
-
12819
- function sendSignalToProcessTree(child, signal) {
12820
- if (!child.pid || child.exitCode !== null || child.signalCode !== null) return;
12821
- const pids = collectProcessTreePids(child.pid);
12822
- for (const pid of pids.reverse()) {
12823
- try {
12824
- process.kill(pid, signal);
12825
- } catch {
12826
- // Already exited.
12827
- }
12828
- }
12829
- }
12830
-
12831
- async function waitForExitOrTimeout(childExit, timeoutMs) {
12832
- let timer;
12833
- const timeout = new Promise((resolve) => {
12834
- timer = setTimeout(() => resolve(null), timeoutMs);
12835
- });
12836
- const result = await Promise.race([childExit, timeout]);
12837
- clearTimeout(timer);
12838
- return result;
12839
- }
12840
-
12841
- async function stopNativeChild(
12842
- child,
12843
- childExit,
12844
- { interruptTimeoutMs = TAKEOVER_STOP_TIMEOUT_MS, terminateTimeoutMs = 1000, killTimeoutMs = 1000 } = {},
12845
- ) {
12846
- if (child.exitCode !== null || child.signalCode !== null) return true;
12847
- sendSignal(child, 'SIGINT');
12848
- if (await waitForExitOrTimeout(childExit, interruptTimeoutMs)) return true;
12849
- sendSignalToProcessTree(child, 'SIGTERM');
12850
- if (await waitForExitOrTimeout(childExit, terminateTimeoutMs)) return true;
12851
- sendSignalToProcessTree(child, 'SIGKILL');
12852
- if (await waitForExitOrTimeout(childExit, killTimeoutMs)) return true;
12853
- return !isPidAlive(child.pid);
12854
- }
12855
-
12856
12877
  function waitMs(ms) {
12857
12878
  return new Promise((resolve) => {
12858
12879
  setTimeout(resolve, ms);
@@ -14083,6 +14104,72 @@ async function tryUpdateRunningDaemonRelay({
14083
14104
  }
14084
14105
 
14085
14106
 
14107
+ /***/ }),
14108
+
14109
+ /***/ 4162:
14110
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __nccwpck_require__) => {
14111
+
14112
+ /* harmony export */ __nccwpck_require__.d(__webpack_exports__, {
14113
+ /* harmony export */ n: () => (/* binding */ printCliHelp)
14114
+ /* harmony export */ });
14115
+ function printCliHelp({ packageJson, port }) {
14116
+ process.stdout.write(`Vibelet ${packageJson.version}\n\n`);
14117
+ process.stdout.write(`Package names:\n`);
14118
+ process.stdout.write(` @vibelet/cli\n`);
14119
+ process.stdout.write(` vibelet\n\n`);
14120
+ process.stdout.write(`Usage:\n`);
14121
+ process.stdout.write(
14122
+ ` npx ${packageJson.name} Install/start the daemon, auto-enable remote access, and print a pairing QR code\n`,
14123
+ );
14124
+ process.stdout.write(` npx ${packageJson.name} start Same as above\n`);
14125
+ process.stdout.write(
14126
+ ` npx ${packageJson.name} --access=local Use LAN/local pairing only; skip Cloudflare and Tailscale\n`,
14127
+ );
14128
+ process.stdout.write(` npx ${packageJson.name} --access=remote --force Force a new Cloudflare Tunnel URL\n`);
14129
+ process.stdout.write(` npx ${packageJson.name} --access=https://<url> Use a custom tunnel URL for remote access\n`);
14130
+ process.stdout.write(` npx ${packageJson.name} --access=<host> Set the primary LAN/Tailscale host/IP address\n`);
14131
+ process.stdout.write(
14132
+ ` npx ${packageJson.name} --tailcat Enable userspace Tailcat direct access (keeps existing fallbacks)\n`,
14133
+ );
14134
+ process.stdout.write(` npx ${packageJson.name} --no-tailcat Disable previously enabled Tailcat access\n`);
14135
+ process.stdout.write(` npx ${packageJson.name} --port <port> Start or query the daemon on a custom port\n`);
14136
+ process.stdout.write(
14137
+ ` npx ${packageJson.name} --claude-driver tui Drive the interactive Claude TUI (subscription) instead of \`claude -p\`\n`,
14138
+ );
14139
+ process.stdout.write(` npx ${packageJson.name} --access=<host>,<fallbacks> Set fallback LAN/Tailscale hosts\n`);
14140
+ process.stdout.write(` npx ${packageJson.name} stop Stop the daemon\n`);
14141
+ process.stdout.write(` npx ${packageJson.name} restart Restart the daemon\n`);
14142
+ process.stdout.write(` npx ${packageJson.name} status Show service and daemon status\n`);
14143
+ process.stdout.write(` npx ${packageJson.name} logs Print recent daemon logs\n`);
14144
+ process.stdout.write(` npx ${packageJson.name} reset Reset pairings and print a fresh QR code\n`);
14145
+ process.stdout.write(` npx ${packageJson.name} claude [...args] Start Claude Code with Vibelet App takeover\n`);
14146
+ process.stdout.write(` npx ${packageJson.name} codex [...args] Start Codex with Vibelet App takeover\n`);
14147
+ process.stdout.write(` npx ${packageJson.name} --help Show this help text\n`);
14148
+ process.stdout.write(` npx ${packageJson.name} --version Show the installed CLI version\n`);
14149
+ process.stdout.write(`\n`);
14150
+ process.stdout.write(`You can also invoke the published alias with:\n`);
14151
+ process.stdout.write(` npx ${packageJson.name === 'vibelet' ? '@vibelet/cli' : 'vibelet'}\n`);
14152
+ process.stdout.write(` vibelet\n\n`);
14153
+ process.stdout.write(`Remote access:\n`);
14154
+ process.stdout.write(` # Remote access is on by default for start/reset/restart\n`);
14155
+ process.stdout.write(` npx ${packageJson.name}\n\n`);
14156
+ process.stdout.write(` # Want LAN/local-only pairing for this run?\n`);
14157
+ process.stdout.write(` npx ${packageJson.name} --access=local\n\n`);
14158
+ process.stdout.write(` # Need a fresh Cloudflare Tunnel URL?\n`);
14159
+ process.stdout.write(` npx ${packageJson.name} --access=remote --force\n\n`);
14160
+ process.stdout.write(` # Or bring your own tunnel and pass the URL manually:\n`);
14161
+ process.stdout.write(` npx cloudflared tunnel --protocol auto --url http://localhost:${port}\n`);
14162
+ process.stdout.write(` ngrok http ${port}\n`);
14163
+ process.stdout.write(` npx ${packageJson.name} --access=https://<your-tunnel-url>\n\n`);
14164
+ process.stdout.write(` # Tailscale (P2P VPN, no tunnel needed)\n`);
14165
+ process.stdout.write(` npx ${packageJson.name} --access=<tailscale-ip>\n\n`);
14166
+ process.stdout.write(`\nTailcat direct access:\n`);
14167
+ process.stdout.write(` npx ${packageJson.name} --tailcat\n`);
14168
+ process.stdout.write(` # Tailcat runs inside Vibelet and does not change system VPN, DNS, or routes.\n\n`);
14169
+ process.stdout.write(`Legacy aliases still work: --local, --relay, --host, --fallback-hosts, --remote, --tunnel.\n`);
14170
+ }
14171
+
14172
+
14086
14173
  /***/ }),
14087
14174
 
14088
14175
  /***/ 1010:
@@ -14286,21 +14373,40 @@ function normalizePairingConnections(pairingPayload) {
14286
14373
  typeof target.source === 'string' &&
14287
14374
  typeof target.stability === 'string',
14288
14375
  )
14289
- .map((target) => ({
14290
- kind: target.kind === 'relay' ? 'relay' : 'direct',
14291
- host: normalizeHostValue(target.host),
14292
- port: Math.floor(Number(target.port)),
14293
- ...(target.secure === true ? { secure: true } : {}),
14294
- source: target.source,
14295
- stability: target.stability,
14296
- }))
14376
+ .map((target) => {
14377
+ const tailcat =
14378
+ target.tailcat &&
14379
+ typeof target.tailcat.serverAddress === 'string' &&
14380
+ target.tailcat.serverAddress.startsWith('tc') &&
14381
+ target.tailcat.serverAddress.length <= 4096 &&
14382
+ Number.isInteger(target.tailcat.remotePort) &&
14383
+ target.tailcat.remotePort > 0 &&
14384
+ target.tailcat.remotePort <= 65535
14385
+ ? {
14386
+ serverAddress: target.tailcat.serverAddress,
14387
+ remotePort: target.tailcat.remotePort,
14388
+ }
14389
+ : null;
14390
+ return {
14391
+ kind: target.kind === 'relay' ? 'relay' : 'direct',
14392
+ host: normalizeHostValue(target.host),
14393
+ port: Math.floor(Number(target.port)),
14394
+ ...(target.secure === true ? { secure: true } : {}),
14395
+ source: target.source,
14396
+ stability: target.stability,
14397
+ ...(tailcat ? { tailcat } : {}),
14398
+ };
14399
+ })
14297
14400
  .filter((target) => target.host && target.port > 0)
14298
14401
  : [];
14299
14402
 
14300
14403
  const dedupe = (targets) => {
14301
14404
  const seen = new Set();
14302
14405
  return targets.filter((target) => {
14303
- const key = `${target.host}:${target.port}:${target.secure === true ? 'secure' : 'plain'}`;
14406
+ const key =
14407
+ target.source === 'tailcat' && target.tailcat
14408
+ ? `tailcat:${target.tailcat.remotePort}`
14409
+ : `${target.host}:${target.port}:${target.secure === true ? 'secure' : 'plain'}`;
14304
14410
  if (seen.has(key)) {
14305
14411
  return false;
14306
14412
  }
@@ -14400,14 +14506,13 @@ function createCompactPairingPayload(pairingPayload) {
14400
14506
  };
14401
14507
  if (pairingPayload.fallbackHosts) compactPayload.f = pairingPayload.fallbackHosts;
14402
14508
  if (connections.length > 0) {
14403
- compactPayload.o = connections.map((target) => [
14404
- target.kind,
14405
- target.host,
14406
- target.port,
14407
- target.source,
14408
- target.stability,
14409
- target.secure === true,
14410
- ]);
14509
+ compactPayload.o = connections.map((target) => {
14510
+ const tuple = [target.kind, target.host, target.port, target.source, target.stability, target.secure === true];
14511
+ if (target.tailcat) {
14512
+ tuple.push(target.tailcat.serverAddress, target.tailcat.remotePort);
14513
+ }
14514
+ return tuple;
14515
+ });
14411
14516
  }
14412
14517
  return compactPayload;
14413
14518
  }
@@ -14422,6 +14527,8 @@ function formatConnectionSourceLabel(source) {
14422
14527
  return 'Manual Host';
14423
14528
  case 'tailscale':
14424
14529
  return 'Tailscale';
14530
+ case 'tailcat':
14531
+ return 'Tailcat Direct';
14425
14532
  case 'local_network':
14426
14533
  return 'LAN';
14427
14534
  case 'fallback':
@@ -14490,6 +14597,7 @@ function buildWebUiUrl(target, pairingPayload) {
14490
14597
  /* harmony export */ Ne: () => (/* binding */ shouldRefuseRuntimeDowngrade),
14491
14598
  /* harmony export */ Pg: () => (/* binding */ shouldRetireManagedQuickTunnel),
14492
14599
  /* harmony export */ ZN: () => (/* binding */ shouldReuseHealthyDaemon),
14600
+ /* harmony export */ Zg: () => (/* binding */ isTailcatConfigurationMismatch),
14493
14601
  /* harmony export */ gm: () => (/* binding */ shouldManageQuickTunnel),
14494
14602
  /* harmony export */ iX: () => (/* binding */ doesHealthSupportTerminalControl),
14495
14603
  /* harmony export */ nW: () => (/* binding */ doesHealthMatchRequestedConnectionConfig)
@@ -14535,6 +14643,12 @@ function shouldReuseHealthyDaemon({
14535
14643
  return !hasExplicitConfigOverrides || canApplyConnectionConfigWithoutRestart;
14536
14644
  }
14537
14645
 
14646
+ function isTailcatConfigurationMismatch({ health, tailcatEnabled }) {
14647
+ if (!health) return false;
14648
+ const reportedEnabled = health?.tailcat?.enabled;
14649
+ return typeof reportedEnabled === 'boolean' ? reportedEnabled !== tailcatEnabled : tailcatEnabled;
14650
+ }
14651
+
14538
14652
  function doesHealthSupportTerminalControl(health) {
14539
14653
  if (!health || typeof health !== 'object') return false;
14540
14654
  const terminals = health.terminals;
@@ -14633,9 +14747,15 @@ function doesHealthMatchRequestedConnectionConfig({
14633
14747
  canonicalHost = '',
14634
14748
  fallbackHosts = '',
14635
14749
  localMode = false,
14750
+ tailcatEnabled,
14636
14751
  }) {
14637
14752
  if (!health) return false;
14638
14753
 
14754
+ if (typeof tailcatEnabled === 'boolean') {
14755
+ const runningTailcatEnabled = health.tailcat?.enabled === true;
14756
+ if (runningTailcatEnabled !== tailcatEnabled) return false;
14757
+ }
14758
+
14639
14759
  const currentRelayUrl = typeof health.relayUrl === 'string' ? health.relayUrl : '';
14640
14760
  if (relayUrl) {
14641
14761
  return currentRelayUrl === relayUrl;
@@ -14696,6 +14816,34 @@ async function stopDaemonWithHooks({
14696
14816
  }
14697
14817
 
14698
14818
 
14819
+ /***/ }),
14820
+
14821
+ /***/ 5798:
14822
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __nccwpck_require__) => {
14823
+
14824
+ /* harmony export */ __nccwpck_require__.d(__webpack_exports__, {
14825
+ /* harmony export */ S: () => (/* binding */ createTailcatConfigStore)
14826
+ /* harmony export */ });
14827
+ /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0__ = __nccwpck_require__(3024);
14828
+
14829
+
14830
+ function createTailcatConfigStore(configPath, dataDirectory) {
14831
+ return {
14832
+ load() {
14833
+ try {
14834
+ return JSON.parse((0,node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync)(configPath, 'utf8')).enabled === true;
14835
+ } catch {
14836
+ return false;
14837
+ }
14838
+ },
14839
+ save(enabled) {
14840
+ (0,node_fs__WEBPACK_IMPORTED_MODULE_0__.mkdirSync)(dataDirectory, { recursive: true });
14841
+ (0,node_fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync)(configPath, `${JSON.stringify({ enabled }, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 });
14842
+ },
14843
+ };
14844
+ }
14845
+
14846
+
14699
14847
  /***/ }),
14700
14848
 
14701
14849
  /***/ 4566:
@@ -14709,15 +14857,19 @@ __nccwpck_require__.a(__webpack_module__, async (__webpack_handle_async_dependen
14709
14857
  /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_4__ = __nccwpck_require__(6760);
14710
14858
  /* harmony import */ var node_url__WEBPACK_IMPORTED_MODULE_5__ = __nccwpck_require__(3136);
14711
14859
  /* harmony import */ var qrcode__WEBPACK_IMPORTED_MODULE_6__ = __nccwpck_require__(7514);
14712
- /* harmony import */ var _vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_15__ = __nccwpck_require__(6927);
14860
+ /* harmony import */ var _vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_17__ = __nccwpck_require__(6927);
14713
14861
  /* harmony import */ var _cloudflared_tunnel_manager_mjs__WEBPACK_IMPORTED_MODULE_7__ = __nccwpck_require__(2755);
14714
14862
  /* harmony import */ var _vibelet_cloudflare_runtime_mjs__WEBPACK_IMPORTED_MODULE_8__ = __nccwpck_require__(3869);
14715
- /* harmony import */ var _vibelet_launchd_mjs__WEBPACK_IMPORTED_MODULE_12__ = __nccwpck_require__(1010);
14863
+ /* harmony import */ var _vibelet_launchd_mjs__WEBPACK_IMPORTED_MODULE_13__ = __nccwpck_require__(1010);
14716
14864
  /* harmony import */ var _linux_systemd_mjs__WEBPACK_IMPORTED_MODULE_9__ = __nccwpck_require__(4217);
14717
- /* harmony import */ var _vibelet_stop_logic_mjs__WEBPACK_IMPORTED_MODULE_13__ = __nccwpck_require__(6274);
14718
- /* harmony import */ var _vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_11__ = __nccwpck_require__(4);
14719
- /* harmony import */ var _terminal_wrapper_mjs__WEBPACK_IMPORTED_MODULE_10__ = __nccwpck_require__(636);
14720
- /* harmony import */ var _vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_14__ = __nccwpck_require__(7721);
14865
+ /* harmony import */ var _vibelet_stop_logic_mjs__WEBPACK_IMPORTED_MODULE_14__ = __nccwpck_require__(6274);
14866
+ /* harmony import */ var _vibelet_help_mjs__WEBPACK_IMPORTED_MODULE_16__ = __nccwpck_require__(4162);
14867
+ /* harmony import */ var _vibelet_tailcat_config_mjs__WEBPACK_IMPORTED_MODULE_10__ = __nccwpck_require__(5798);
14868
+ /* harmony import */ var _vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_12__ = __nccwpck_require__(4);
14869
+ /* harmony import */ var _terminal_wrapper_mjs__WEBPACK_IMPORTED_MODULE_11__ = __nccwpck_require__(2629);
14870
+ /* harmony import */ var _vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_15__ = __nccwpck_require__(7721);
14871
+
14872
+
14721
14873
 
14722
14874
 
14723
14875
 
@@ -14750,11 +14902,12 @@ const runtimeDir = (0,node_path__WEBPACK_IMPORTED_MODULE_4__.join)(vibeletDir, '
14750
14902
  const runtimeCurrentDir = (0,node_path__WEBPACK_IMPORTED_MODULE_4__.join)(runtimeDir, 'current');
14751
14903
  const runtimeMetadataPath = (0,node_path__WEBPACK_IMPORTED_MODULE_4__.join)(runtimeCurrentDir, 'runtime.json');
14752
14904
  const runtimeDaemonEntryPath = (0,node_path__WEBPACK_IMPORTED_MODULE_4__.join)(runtimeCurrentDir, 'dist', 'index.cjs');
14753
- const runtimeTerminalControlTokenPath = _terminal_wrapper_mjs__WEBPACK_IMPORTED_MODULE_10__/* .terminalControlTokenPath */ .gJ;
14905
+ const runtimeTerminalControlTokenPath = _terminal_wrapper_mjs__WEBPACK_IMPORTED_MODULE_11__/* .terminalControlTokenPath */ .gJ;
14754
14906
  const stdoutLogPath = (0,node_path__WEBPACK_IMPORTED_MODULE_4__.join)(logDir, 'daemon.stdout.log');
14755
14907
  const stderrLogPath = (0,node_path__WEBPACK_IMPORTED_MODULE_4__.join)(logDir, 'daemon.stderr.log');
14756
14908
  const pidFilePath = (0,node_path__WEBPACK_IMPORTED_MODULE_4__.join)(vibeletDir, 'daemon.pid');
14757
14909
  const relayConfig = (0,_vibelet_cloudflare_runtime_mjs__WEBPACK_IMPORTED_MODULE_8__/* .createRelayConfigStore */ .T7)((0,node_path__WEBPACK_IMPORTED_MODULE_4__.join)(vibeletDir, 'relay.json'));
14910
+ const tailcatConfig = (0,_vibelet_tailcat_config_mjs__WEBPACK_IMPORTED_MODULE_10__/* .createTailcatConfigStore */ .S)((0,node_path__WEBPACK_IMPORTED_MODULE_4__.join)(vibeletDir, 'tailcat.json'), vibeletDir);
14758
14911
  const tunnelStatePath = (0,node_path__WEBPACK_IMPORTED_MODULE_4__.join)(vibeletDir, 'tunnel.json');
14759
14912
  const cloudflaredUpdateStatePath = (0,node_path__WEBPACK_IMPORTED_MODULE_4__.join)(vibeletDir, 'cloudflared-update.json');
14760
14913
  const updateCheckPath = (0,node_path__WEBPACK_IMPORTED_MODULE_4__.join)(vibeletDir, 'update-check.json');
@@ -14907,7 +15060,7 @@ function ensureRuntimeInstalled() {
14907
15060
  const runtimeMetadata = readRuntimeMetadata();
14908
15061
 
14909
15062
  if (
14910
- (0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_11__/* .shouldRefuseRuntimeDowngrade */ .Ne)({
15063
+ (0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_12__/* .shouldRefuseRuntimeDowngrade */ .Ne)({
14911
15064
  cliVersion: packageJson.version,
14912
15065
  runtimeVersion: runtimeMetadata?.version,
14913
15066
  runtimeEntryExists: (0,node_fs__WEBPACK_IMPORTED_MODULE_1__.existsSync)(runtimeDaemonEntryPath),
@@ -15111,7 +15264,7 @@ function createDarwinBackend() {
15111
15264
  }
15112
15265
 
15113
15266
  function bootoutService() {
15114
- return (0,_vibelet_launchd_mjs__WEBPACK_IMPORTED_MODULE_12__/* .bootoutLaunchdService */ .B)({
15267
+ return (0,_vibelet_launchd_mjs__WEBPACK_IMPORTED_MODULE_13__/* .bootoutLaunchdService */ .B)({
15115
15268
  launchctl,
15116
15269
  launchDomain,
15117
15270
  label,
@@ -15136,6 +15289,7 @@ function createDarwinBackend() {
15136
15289
  if (process.env.VIBELET_CANONICAL_HOST) envVars.VIBELET_CANONICAL_HOST = process.env.VIBELET_CANONICAL_HOST;
15137
15290
  if (process.env.VIBELET_FALLBACK_HOSTS) envVars.VIBELET_FALLBACK_HOSTS = process.env.VIBELET_FALLBACK_HOSTS;
15138
15291
  if (process.env.VIBELET_LOCAL_ONLY) envVars.VIBELET_LOCAL_ONLY = process.env.VIBELET_LOCAL_ONLY;
15292
+ if (process.env.VIBELET_TAILCAT) envVars.VIBELET_TAILCAT = process.env.VIBELET_TAILCAT;
15139
15293
  if (process.env.VIBE_CLAUDE_DRIVER) envVars.VIBE_CLAUDE_DRIVER = process.env.VIBE_CLAUDE_DRIVER;
15140
15294
  if (process.env.CODEX_PATH) envVars.CODEX_PATH = process.env.CODEX_PATH;
15141
15295
  if (process.env.CLAUDE_PATH) envVars.CLAUDE_PATH = process.env.CLAUDE_PATH;
@@ -15200,7 +15354,7 @@ ${envSection}
15200
15354
  if (result.status !== 0) {
15201
15355
  fail(
15202
15356
  'Failed to bootstrap vibelet launch agent.',
15203
- [(0,_vibelet_launchd_mjs__WEBPACK_IMPORTED_MODULE_12__/* .describeLaunchctlResult */ .N)(bootoutResult.result), (0,_vibelet_launchd_mjs__WEBPACK_IMPORTED_MODULE_12__/* .describeLaunchctlResult */ .N)(result)].filter(Boolean).join('\n'),
15357
+ [(0,_vibelet_launchd_mjs__WEBPACK_IMPORTED_MODULE_13__/* .describeLaunchctlResult */ .N)(bootoutResult.result), (0,_vibelet_launchd_mjs__WEBPACK_IMPORTED_MODULE_13__/* .describeLaunchctlResult */ .N)(result)].filter(Boolean).join('\n'),
15204
15358
  );
15205
15359
  }
15206
15360
  }
@@ -15216,7 +15370,7 @@ ${envSection}
15216
15370
  stop() {
15217
15371
  const bootoutResult = bootoutService();
15218
15372
  if (!bootoutResult.ok) {
15219
- fail('Failed to unload vibelet launch agent.', (0,_vibelet_launchd_mjs__WEBPACK_IMPORTED_MODULE_12__/* .describeLaunchctlResult */ .N)(bootoutResult.result));
15373
+ fail('Failed to unload vibelet launch agent.', (0,_vibelet_launchd_mjs__WEBPACK_IMPORTED_MODULE_13__/* .describeLaunchctlResult */ .N)(bootoutResult.result));
15220
15374
  }
15221
15375
  // bootout returns before launchd actually finishes unloading. Poll
15222
15376
  // until the service is gone so a follow-up install() doesn't see a
@@ -15272,7 +15426,7 @@ RestartSec=3
15272
15426
  StandardOutput=append:${stdoutLogPath}
15273
15427
  StandardError=append:${stderrLogPath}
15274
15428
  Environment=PATH=${servicePath}
15275
- Environment=VIBE_PORT=${port}${process.env.VIBELET_RELAY_URL ? `\nEnvironment=VIBELET_RELAY_URL=${process.env.VIBELET_RELAY_URL}` : ''}${process.env.VIBELET_CANONICAL_HOST ? `\nEnvironment=VIBELET_CANONICAL_HOST=${process.env.VIBELET_CANONICAL_HOST}` : ''}${process.env.VIBELET_FALLBACK_HOSTS ? `\nEnvironment=VIBELET_FALLBACK_HOSTS=${process.env.VIBELET_FALLBACK_HOSTS}` : ''}${process.env.VIBELET_LOCAL_ONLY ? `\nEnvironment=VIBELET_LOCAL_ONLY=${process.env.VIBELET_LOCAL_ONLY}` : ''}${process.env.VIBE_CLAUDE_DRIVER ? `\nEnvironment=VIBE_CLAUDE_DRIVER=${process.env.VIBE_CLAUDE_DRIVER}` : ''}${process.env.CODEX_PATH ? `\nEnvironment=CODEX_PATH=${process.env.CODEX_PATH}` : ''}${process.env.CLAUDE_PATH ? `\nEnvironment=CLAUDE_PATH=${process.env.CLAUDE_PATH}` : ''}
15429
+ Environment=VIBE_PORT=${port}${process.env.VIBELET_RELAY_URL ? `\nEnvironment=VIBELET_RELAY_URL=${process.env.VIBELET_RELAY_URL}` : ''}${process.env.VIBELET_CANONICAL_HOST ? `\nEnvironment=VIBELET_CANONICAL_HOST=${process.env.VIBELET_CANONICAL_HOST}` : ''}${process.env.VIBELET_FALLBACK_HOSTS ? `\nEnvironment=VIBELET_FALLBACK_HOSTS=${process.env.VIBELET_FALLBACK_HOSTS}` : ''}${process.env.VIBELET_LOCAL_ONLY ? `\nEnvironment=VIBELET_LOCAL_ONLY=${process.env.VIBELET_LOCAL_ONLY}` : ''}${process.env.VIBELET_TAILCAT ? `\nEnvironment=VIBELET_TAILCAT=${process.env.VIBELET_TAILCAT}` : ''}${process.env.VIBE_CLAUDE_DRIVER ? `\nEnvironment=VIBE_CLAUDE_DRIVER=${process.env.VIBE_CLAUDE_DRIVER}` : ''}${process.env.CODEX_PATH ? `\nEnvironment=CODEX_PATH=${process.env.CODEX_PATH}` : ''}${process.env.CLAUDE_PATH ? `\nEnvironment=CLAUDE_PATH=${process.env.CLAUDE_PATH}` : ''}
15276
15430
 
15277
15431
  [Install]
15278
15432
  WantedBy=default.target
@@ -15539,8 +15693,7 @@ async function requestShutdown() {
15539
15693
  signal: AbortSignal.timeout(2000),
15540
15694
  });
15541
15695
  } catch {
15542
- // Request timed out or connection refused daemon may be deadlocked or
15543
- // already gone. Either way, fall through to polling for actual exit.
15696
+ // A timeout or refusal means the daemon may be deadlocked or gone; poll for its actual exit.
15544
15697
  }
15545
15698
  return waitForDaemonExit(5_000);
15546
15699
  }
@@ -15560,7 +15713,7 @@ function retireTrackedQuickTunnel({ required = false } = {}) {
15560
15713
 
15561
15714
  async function stopRunningDaemon(backend) {
15562
15715
  try {
15563
- await (0,_vibelet_stop_logic_mjs__WEBPACK_IMPORTED_MODULE_13__/* .stopDaemonWithHooks */ .v)({
15716
+ await (0,_vibelet_stop_logic_mjs__WEBPACK_IMPORTED_MODULE_14__/* .stopDaemonWithHooks */ .v)({
15564
15717
  requestShutdown,
15565
15718
  backendStop: () => backend.stop(),
15566
15719
  waitForDaemonExit,
@@ -15573,15 +15726,13 @@ async function stopRunningDaemon(backend) {
15573
15726
  async function ensureDaemonForTerminalControl(backend) {
15574
15727
  const healthyDaemon = await probeHealth(1_500);
15575
15728
  const tokenReady = (0,node_fs__WEBPACK_IMPORTED_MODULE_1__.existsSync)(runtimeTerminalControlTokenPath);
15576
- const terminalControlReady = healthyDaemon && tokenReady && (0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_11__/* .doesHealthSupportTerminalControl */ .iX)(healthyDaemon);
15577
- if (terminalControlReady) {
15578
- return healthyDaemon;
15579
- }
15729
+ const terminalControlReady = healthyDaemon && tokenReady && (0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_12__/* .doesHealthSupportTerminalControl */ .iX)(healthyDaemon);
15730
+ if (terminalControlReady) return healthyDaemon;
15580
15731
 
15581
15732
  if (healthyDaemon && !terminalControlReady) {
15582
15733
  const activeSessions = typeof healthyDaemon.activeSessions === 'number' ? healthyDaemon.activeSessions : 0;
15583
15734
  if (activeSessions > 0) {
15584
- const reason = (0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_11__/* .doesHealthSupportTerminalControl */ .iX)(healthyDaemon)
15735
+ const reason = (0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_12__/* .doesHealthSupportTerminalControl */ .iX)(healthyDaemon)
15585
15736
  ? 'terminal-control token is missing'
15586
15737
  : 'the running daemon does not advertise terminal-control support';
15587
15738
  process.stderr.write(
@@ -15600,24 +15751,19 @@ async function ensureDaemonForTerminalControl(backend) {
15600
15751
  }
15601
15752
 
15602
15753
  function validateExplicitCleartextHosts({ hostArg, fallbackHostsArg }) {
15603
- const unsafeHosts = (0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_14__/* .findUnsafeCleartextHosts */ .dE)({ hostArg, fallbackHostsArg });
15604
- if (unsafeHosts.length === 0) {
15605
- return;
15606
- }
15607
- fail(
15608
- `Refusing public cleartext host ${unsafeHosts[0]}. Use --access=https://..., a Tailscale host, or a LAN/local address.`,
15609
- );
15754
+ const [unsafeHost] = (0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_15__/* .findUnsafeCleartextHosts */ .dE)({ hostArg, fallbackHostsArg });
15755
+ if (unsafeHost) fail(`Refusing public cleartext host ${unsafeHost}. Use HTTPS, Tailscale, LAN, or local access.`);
15610
15756
  }
15611
15757
 
15612
15758
  async function printPairingQr(pairingPayload) {
15613
- const payload = JSON.stringify((0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_14__/* .createCompactPairingPayload */ .YP)(pairingPayload));
15614
- const deepLink = (0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_14__/* .buildPairingDeepLink */ .N7)(payload);
15759
+ const payload = JSON.stringify((0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_15__/* .createCompactPairingPayload */ .YP)(pairingPayload));
15760
+ const deepLink = (0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_15__/* .buildPairingDeepLink */ .N7)(payload);
15615
15761
  (0,node_fs__WEBPACK_IMPORTED_MODULE_1__.mkdirSync)(vibeletDir, { recursive: true });
15616
15762
  await qrcode__WEBPACK_IMPORTED_MODULE_6__.toFile(pairingQrPngPath, payload, {
15617
15763
  type: 'png',
15618
15764
  errorCorrectionLevel: 'M',
15619
15765
  margin: 1,
15620
- scale: 8,
15766
+ scale: 4,
15621
15767
  });
15622
15768
  const qr = await qrcode__WEBPACK_IMPORTED_MODULE_6__.toString(payload, {
15623
15769
  type: 'terminal',
@@ -15640,10 +15786,11 @@ async function printPairingSummary(existingHealth = null, { relayUrlOverride = n
15640
15786
  const pairingPayload =
15641
15787
  relayUrlOverride === null
15642
15788
  ? daemonPairingPayload
15643
- : (0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_14__/* .applyRelayUrlToPairingPayload */ .mp)(daemonPairingPayload, relayUrlOverride);
15644
- const connections = (0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_14__/* .normalizePairingConnections */ .No)(pairingPayload);
15789
+ : (0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_15__/* .applyRelayUrlToPairingPayload */ .mp)(daemonPairingPayload, relayUrlOverride);
15790
+ const connections = (0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_15__/* .normalizePairingConnections */ .No)(pairingPayload);
15645
15791
  const [preferredConnection, ...otherConnections] = connections;
15646
- const webUiConnection = (0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_14__/* .selectWebUiConnectionTarget */ .SF)(connections);
15792
+ const webUiConnection = (0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_15__/* .selectWebUiConnectionTarget */ .SF)(connections);
15793
+ const compactPairingPayload = (0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_15__/* .createCompactPairingPayload */ .YP)(pairingPayload);
15647
15794
 
15648
15795
  process.stdout.write(`Vibelet daemon is ready.\n\n`);
15649
15796
  process.stdout.write(`Device: ${health.displayName}\n`);
@@ -15651,73 +15798,26 @@ async function printPairingSummary(existingHealth = null, { relayUrlOverride = n
15651
15798
  process.stdout.write(`Host: ${pairingPayload.canonicalHost}\n`);
15652
15799
  process.stdout.write(`Port: ${pairingPayload.port}\n`);
15653
15800
  if (preferredConnection) {
15654
- process.stdout.write(`Preferred path: ${(0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_14__/* .formatConnectionSummary */ .uR)(preferredConnection)}\n`);
15801
+ process.stdout.write(`Preferred path: ${(0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_15__/* .formatConnectionSummary */ .uR)(preferredConnection)}\n`);
15655
15802
  }
15656
15803
  if (otherConnections.length > 0) {
15657
15804
  process.stdout.write(`Other paths:\n`);
15658
15805
  otherConnections.forEach((target) => {
15659
- process.stdout.write(` - ${(0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_14__/* .formatConnectionSummary */ .uR)(target)}\n`);
15806
+ process.stdout.write(` - ${(0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_15__/* .formatConnectionSummary */ .uR)(target)}\n`);
15660
15807
  });
15661
15808
  }
15662
- if (webUiConnection) {
15663
- process.stdout.write(`Web UI: ${(0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_14__/* .buildWebUiUrl */ .Gv)(webUiConnection, (0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_14__/* .createCompactPairingPayload */ .YP)(pairingPayload))}\n`);
15809
+ process.stdout.write(`Web UI: ${(0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_15__/* .buildWebUiUrl */ .Gv)({ host: 'localhost', port }, compactPairingPayload)}\n`);
15810
+ if (webUiConnection && webUiConnection.host !== 'localhost') {
15811
+ process.stdout.write(`Web UI (other devices): ${(0,_vibelet_pairing_connections_mjs__WEBPACK_IMPORTED_MODULE_15__/* .buildWebUiUrl */ .Gv)(webUiConnection, compactPairingPayload)}\n`);
15664
15812
  }
15665
15813
  process.stdout.write(`Paired devices: ${health.pairedDevices}\n`);
15666
15814
  await printPairingQr(pairingPayload);
15667
15815
  }
15668
15816
 
15669
- function printHelp() {
15670
- process.stdout.write(`Vibelet ${packageJson.version}\n\n`);
15671
- process.stdout.write(`Package names:\n`);
15672
- process.stdout.write(` @vibelet/cli\n`);
15673
- process.stdout.write(` vibelet\n\n`);
15674
- process.stdout.write(`Usage:\n`);
15675
- process.stdout.write(
15676
- ` npx ${packageJson.name} Install/start the daemon, auto-enable remote access, and print a pairing QR code\n`,
15677
- );
15678
- process.stdout.write(` npx ${packageJson.name} start Same as above\n`);
15679
- process.stdout.write(
15680
- ` npx ${packageJson.name} --access=local Use LAN/local pairing only; skip Cloudflare and Tailscale\n`,
15681
- );
15682
- process.stdout.write(` npx ${packageJson.name} --access=remote --force Force a new Cloudflare Tunnel URL\n`);
15683
- process.stdout.write(` npx ${packageJson.name} --access=https://<url> Use a custom tunnel URL for remote access\n`);
15684
- process.stdout.write(` npx ${packageJson.name} --access=<host> Set the primary LAN/Tailscale host/IP address\n`);
15685
- process.stdout.write(` npx ${packageJson.name} --port <port> Start or query the daemon on a custom port\n`);
15686
- process.stdout.write(
15687
- ` npx ${packageJson.name} --claude-driver tui Drive the interactive Claude TUI (subscription) instead of \`claude -p\`\n`,
15688
- );
15689
- process.stdout.write(` npx ${packageJson.name} --access=<host>,<fallbacks> Set fallback LAN/Tailscale hosts\n`);
15690
- process.stdout.write(` npx ${packageJson.name} stop Stop the daemon\n`);
15691
- process.stdout.write(` npx ${packageJson.name} restart Restart the daemon\n`);
15692
- process.stdout.write(` npx ${packageJson.name} status Show service and daemon status\n`);
15693
- process.stdout.write(` npx ${packageJson.name} logs Print recent daemon logs\n`);
15694
- process.stdout.write(` npx ${packageJson.name} reset Reset pairings and print a fresh QR code\n`);
15695
- process.stdout.write(` npx ${packageJson.name} claude [...args] Start Claude Code with Vibelet App takeover\n`);
15696
- process.stdout.write(` npx ${packageJson.name} codex [...args] Start Codex with Vibelet App takeover\n`);
15697
- process.stdout.write(` npx ${packageJson.name} --help Show this help text\n`);
15698
- process.stdout.write(` npx ${packageJson.name} --version Show the installed CLI version\n`);
15699
- process.stdout.write(`\n`);
15700
- process.stdout.write(`You can also invoke the published alias with:\n`);
15701
- process.stdout.write(` npx ${packageJson.name === 'vibelet' ? '@vibelet/cli' : 'vibelet'}\n`);
15702
- process.stdout.write(` vibelet\n\n`);
15703
- process.stdout.write(`Remote access:\n`);
15704
- process.stdout.write(` # Remote access is on by default for start/reset/restart\n`);
15705
- process.stdout.write(` npx ${packageJson.name}\n\n`);
15706
- process.stdout.write(` # Want LAN/local-only pairing for this run?\n`);
15707
- process.stdout.write(` npx ${packageJson.name} --access=local\n\n`);
15708
- process.stdout.write(` # Need a fresh Cloudflare Tunnel URL?\n`);
15709
- process.stdout.write(` npx ${packageJson.name} --access=remote --force\n\n`);
15710
- process.stdout.write(` # Or bring your own tunnel and pass the URL manually:\n`);
15711
- process.stdout.write(` npx cloudflared tunnel --protocol auto --url http://localhost:${port}\n`);
15712
- process.stdout.write(` ngrok http ${port}\n`);
15713
- process.stdout.write(` npx ${packageJson.name} --access=https://<your-tunnel-url>\n\n`);
15714
- process.stdout.write(` # Tailscale (P2P VPN, no tunnel needed)\n`);
15715
- process.stdout.write(` npx ${packageJson.name} --access=<tailscale-ip>\n\n`);
15716
- process.stdout.write(`Legacy aliases still work: --local, --relay, --host, --fallback-hosts, --remote, --tunnel.\n`);
15717
- }
15817
+ const printHelp = () => (0,_vibelet_help_mjs__WEBPACK_IMPORTED_MODULE_16__/* .printCliHelp */ .n)({ packageJson, port });
15718
15818
 
15719
15819
  function parseNamedArg(name, errorHint) {
15720
- return (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_15__/* .parseNamedArg */ .nE)(process.argv, name, errorHint, fail);
15820
+ return (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_17__/* .parseNamedArg */ .nE)(process.argv, name, errorHint, fail);
15721
15821
  }
15722
15822
 
15723
15823
  function parseRelayArg() {
@@ -15767,7 +15867,14 @@ function parseCommandArg(argv) {
15767
15867
  ) {
15768
15868
  continue;
15769
15869
  }
15770
- if (arg === '--local' || arg === '--remote' || arg === '--tunnel' || arg === '--force') {
15870
+ if (
15871
+ arg === '--local' ||
15872
+ arg === '--remote' ||
15873
+ arg === '--tunnel' ||
15874
+ arg === '--force' ||
15875
+ arg === '--tailcat' ||
15876
+ arg === '--no-tailcat'
15877
+ ) {
15771
15878
  continue;
15772
15879
  }
15773
15880
  return arg;
@@ -15792,9 +15899,7 @@ async function main() {
15792
15899
  process.env.VIBE_PORT = String(portArg);
15793
15900
  }
15794
15901
 
15795
- // Select the Claude driver: 'print' (claude -p, default) or 'tui' (interactive
15796
- // TUI). Forwarded to the daemon via env so every backend (detached/launchd/
15797
- // systemd) picks it up.
15902
+ // Forward the selected Claude driver to every daemon backend.
15798
15903
  const claudeDriverArg = parseNamedArg('claude-driver', 'tui');
15799
15904
  if (claudeDriverArg !== null) {
15800
15905
  process.env.VIBE_CLAUDE_DRIVER = claudeDriverArg;
@@ -15812,10 +15917,10 @@ async function main() {
15812
15917
  return;
15813
15918
  }
15814
15919
 
15815
- if ((0,_terminal_wrapper_mjs__WEBPACK_IMPORTED_MODULE_10__/* .isTerminalAgentCommand */ .$c)(command)) {
15920
+ if ((0,_terminal_wrapper_mjs__WEBPACK_IMPORTED_MODULE_11__/* .isTerminalAgentCommand */ .$c)(command)) {
15816
15921
  const backend = resolveBackend();
15817
15922
  await ensureDaemonForTerminalControl(backend);
15818
- process.exitCode = await (0,_terminal_wrapper_mjs__WEBPACK_IMPORTED_MODULE_10__/* .runManagedNativeTerminal */ .WA)({
15923
+ process.exitCode = await (0,_terminal_wrapper_mjs__WEBPACK_IMPORTED_MODULE_11__/* .runManagedNativeTerminal */ .WA)({
15819
15924
  agent: command,
15820
15925
  args: process.argv.slice(3),
15821
15926
  port,
@@ -15824,26 +15929,40 @@ async function main() {
15824
15929
  return;
15825
15930
  }
15826
15931
 
15827
- const accessTarget = (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_15__/* .parseAccessTargetArg */ .tY)(process.argv, fail);
15828
- if (accessTarget && (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_15__/* .hasLegacyAccessArgs */ .NT)(process.argv, process.env)) {
15932
+ const accessTarget = (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_17__/* .parseAccessTargetArg */ .tY)(process.argv, fail);
15933
+ if (accessTarget && (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_17__/* .hasLegacyAccessArgs */ .NT)(process.argv, process.env)) {
15829
15934
  fail(
15830
15935
  'Do not combine --access with legacy access flags.',
15831
15936
  'Use one form, for example `--access=local`, `--access=remote`, `--access=https://...`, or `--access=<host>`.',
15832
15937
  );
15833
15938
  }
15834
15939
  if (!accessTarget) {
15835
- (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_15__/* .consumeFlag */ .PC)(process.argv, 'remote') ||
15836
- (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_15__/* .consumeFlag */ .PC)(process.argv, 'tunnel') ||
15837
- (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_15__/* .readNpmConfigFlag */ .AW)('remote') ||
15838
- (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_15__/* .readNpmConfigFlag */ .AW)('tunnel');
15940
+ (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_17__/* .consumeFlag */ .PC)(process.argv, 'remote') ||
15941
+ (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_17__/* .consumeFlag */ .PC)(process.argv, 'tunnel') ||
15942
+ (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_17__/* .readNpmConfigFlag */ .AW)('remote') ||
15943
+ (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_17__/* .readNpmConfigFlag */ .AW)('tunnel');
15839
15944
  }
15840
15945
  const localFlag =
15841
15946
  accessTarget?.kind === 'local' ||
15842
15947
  (!accessTarget &&
15843
- ((0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_15__/* .consumeFlag */ .PC)(process.argv, 'local') ||
15844
- (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_15__/* .readNpmConfigFlag */ .AW)('local') ||
15948
+ ((0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_17__/* .consumeFlag */ .PC)(process.argv, 'local') ||
15949
+ (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_17__/* .readNpmConfigFlag */ .AW)('local') ||
15845
15950
  isTruthyEnvFlag(process.env.VIBELET_LOCAL_ONLY)));
15846
- const forceFlag = (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_15__/* .consumeFlag */ .PC)(process.argv, 'force') || (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_15__/* .readNpmConfigFlag */ .AW)('force');
15951
+ const forceFlag = (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_17__/* .consumeFlag */ .PC)(process.argv, 'force') || (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_17__/* .readNpmConfigFlag */ .AW)('force');
15952
+ const enableTailcatFlag = (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_17__/* .consumeFlag */ .PC)(process.argv, 'tailcat') || (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_17__/* .readNpmConfigFlag */ .AW)('tailcat');
15953
+ const disableTailcatFlag = (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_17__/* .consumeFlag */ .PC)(process.argv, 'no-tailcat') || (0,_vibelet_cli_args_mjs__WEBPACK_IMPORTED_MODULE_17__/* .readNpmConfigFlag */ .AW)('no-tailcat');
15954
+ if (enableTailcatFlag && disableTailcatFlag) {
15955
+ fail('Do not combine --tailcat with --no-tailcat.');
15956
+ }
15957
+ const explicitTailcatChoice = enableTailcatFlag || disableTailcatFlag;
15958
+ const tailcatEnabled = enableTailcatFlag
15959
+ ? true
15960
+ : disableTailcatFlag
15961
+ ? false
15962
+ : isTruthyEnvFlag(process.env.VIBELET_TAILCAT) || tailcatConfig.load();
15963
+ if (explicitTailcatChoice) tailcatConfig.save(tailcatEnabled);
15964
+ if (tailcatEnabled) process.env.VIBELET_TAILCAT = '1';
15965
+ else delete process.env.VIBELET_TAILCAT;
15847
15966
  const relayArg =
15848
15967
  accessTarget?.kind === 'relay'
15849
15968
  ? accessTarget.relayUrl
@@ -15870,7 +15989,7 @@ async function main() {
15870
15989
  const savedRelayUrl = relayConfig.load();
15871
15990
  // --remote/--tunnel remain accepted for compatibility, but startup commands
15872
15991
  // now default to managed remote access unless another connection target wins.
15873
- const shouldManageTunnel = (0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_11__/* .shouldManageQuickTunnel */ .gm)({
15992
+ const shouldManageTunnel = (0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_12__/* .shouldManageQuickTunnel */ .gm)({
15874
15993
  startCommand,
15875
15994
  localMode: localFlag,
15876
15995
  relayArg,
@@ -15885,7 +16004,7 @@ async function main() {
15885
16004
  }
15886
16005
 
15887
16006
  if (
15888
- (0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_11__/* .shouldRetireManagedQuickTunnel */ .Pg)({
16007
+ (0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_12__/* .shouldRetireManagedQuickTunnel */ .Pg)({
15889
16008
  startCommand,
15890
16009
  manageQuickTunnel: shouldManageTunnel,
15891
16010
  })
@@ -15977,7 +16096,9 @@ async function main() {
15977
16096
  }
15978
16097
  const health = await probeHealth(1_500);
15979
16098
  if (health) {
15980
- process.stdout.write(JSON.stringify(health, null, 2) + '\n');
16099
+ process.stdout.write(
16100
+ JSON.stringify(health, (key, value) => (key === 'serverAddress' ? '[redacted]' : value), 2) + '\n',
16101
+ );
15981
16102
  } else {
15982
16103
  process.stdout.write('Daemon is not responding.\n');
15983
16104
  }
@@ -16020,14 +16141,22 @@ async function main() {
16020
16141
  if (command === 'reset') {
16021
16142
  const healthyDaemon = await probeHealth(1_500);
16022
16143
  const hasExplicitConfigOverrides =
16023
- !(0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_11__/* .doesHealthMatchRequestedConnectionConfig */ .nW)({
16144
+ !(0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_12__/* .doesHealthMatchRequestedConnectionConfig */ .nW)({
16024
16145
  health: healthyDaemon,
16025
16146
  relayUrl,
16026
16147
  canonicalHost: hostArg || '',
16027
16148
  fallbackHosts: fallbackHostsArg || '',
16028
16149
  localMode: localFlag,
16150
+ tailcatEnabled,
16029
16151
  }) &&
16030
- (localFlag || relayArg !== null || Boolean(relayUrl) || Boolean(hostArg) || Boolean(fallbackHostsArg));
16152
+ (localFlag ||
16153
+ relayArg !== null ||
16154
+ Boolean(relayUrl) ||
16155
+ Boolean(hostArg) ||
16156
+ Boolean(fallbackHostsArg) ||
16157
+ explicitTailcatChoice ||
16158
+ tailcatEnabled ||
16159
+ healthyDaemon?.tailcat?.enabled === true);
16031
16160
  const shouldReplaceDetachedDaemon =
16032
16161
  !healthyDaemon && !backend.handlesProcessLifecycle && backend.isServiceInstalled();
16033
16162
  if (shouldReplaceDetachedDaemon || (healthyDaemon && hasExplicitConfigOverrides)) {
@@ -16048,39 +16177,46 @@ async function main() {
16048
16177
  }
16049
16178
 
16050
16179
  let healthyDaemon = await probeHealth(1_500);
16180
+ let tailcatMismatch = (0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_12__/* .isTailcatConfigurationMismatch */ .Zg)({ health: healthyDaemon, tailcatEnabled });
16051
16181
  let hasExplicitConfigOverrides =
16052
- !(0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_11__/* .doesHealthMatchRequestedConnectionConfig */ .nW)({
16182
+ !(0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_12__/* .doesHealthMatchRequestedConnectionConfig */ .nW)({
16053
16183
  health: healthyDaemon,
16054
16184
  relayUrl,
16055
16185
  canonicalHost: hostArg || '',
16056
16186
  fallbackHosts: fallbackHostsArg || '',
16057
16187
  localMode: localFlag,
16188
+ tailcatEnabled,
16058
16189
  }) &&
16059
16190
  (localFlag ||
16060
16191
  shouldManageTunnel ||
16061
16192
  relayArg !== null ||
16062
16193
  Boolean(relayUrl) ||
16063
16194
  Boolean(hostArg) ||
16064
- Boolean(fallbackHostsArg));
16195
+ Boolean(fallbackHostsArg) ||
16196
+ explicitTailcatChoice ||
16197
+ tailcatEnabled ||
16198
+ healthyDaemon?.tailcat?.enabled === true);
16065
16199
  const relayOverrideRequested =
16066
16200
  !localFlag && !hostArg && !fallbackHostsArg && (shouldManageTunnel || relayArg !== null || Boolean(savedRelayUrl));
16067
16201
  const canApplyConnectionConfigWithoutRestart = Boolean(
16068
- healthyDaemon && relayOverrideRequested && hasExplicitConfigOverrides,
16202
+ healthyDaemon && relayOverrideRequested && hasExplicitConfigOverrides && !tailcatMismatch,
16069
16203
  );
16070
16204
  if (healthyDaemon && hasExplicitConfigOverrides && canApplyConnectionConfigWithoutRestart) {
16071
16205
  const refreshedHealth = await tryUpdateRunningDaemonRelay(relayUrl);
16072
16206
  if (refreshedHealth) {
16073
16207
  healthyDaemon = refreshedHealth;
16074
- hasExplicitConfigOverrides = !(0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_11__/* .doesHealthMatchRequestedConnectionConfig */ .nW)({
16208
+ hasExplicitConfigOverrides = !(0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_12__/* .doesHealthMatchRequestedConnectionConfig */ .nW)({
16075
16209
  health: healthyDaemon,
16076
16210
  relayUrl,
16077
16211
  canonicalHost: '',
16078
16212
  fallbackHosts: '',
16079
16213
  localMode: false,
16214
+ tailcatEnabled,
16080
16215
  });
16216
+ tailcatMismatch = (0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_12__/* .isTailcatConfigurationMismatch */ .Zg)({ health: healthyDaemon, tailcatEnabled });
16081
16217
  }
16082
16218
  }
16083
- const existingHealth = (0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_11__/* .shouldReuseHealthyDaemon */ .ZN)({
16219
+ const existingHealth = (0,_vibelet_runtime_policy_mjs__WEBPACK_IMPORTED_MODULE_12__/* .shouldReuseHealthyDaemon */ .ZN)({
16084
16220
  command,
16085
16221
  daemonHealthy: Boolean(healthyDaemon),
16086
16222
  hasExplicitConfigOverrides,