sliccy 5.16.0 → 5.18.0

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 (100) hide show
  1. package/dist/node-server/electron-controller.d.ts +0 -1
  2. package/dist/node-server/electron-controller.js +4 -10
  3. package/dist/node-server/electron-main.js +5 -13
  4. package/dist/node-server/electron-runtime.d.ts +0 -4
  5. package/dist/node-server/electron-runtime.js +4 -21
  6. package/dist/node-server/index.js +28 -178
  7. package/dist/node-server/runtime-flags.d.ts +0 -1
  8. package/dist/node-server/runtime-flags.js +184 -170
  9. package/dist/ui/assets/{account-store-BVzBgQ-v.js → account-store-BlJxZ8bA.js} +2 -2
  10. package/dist/ui/assets/{account-store-CVlnJB81.js → account-store-CXTiaOBF.js} +2 -2
  11. package/dist/ui/assets/{adobe-SkYkxgg4.js → adobe-4-CD_R9o.js} +1 -1
  12. package/dist/ui/assets/{adobe-BFJRWiBP.js → adobe-E2DIgnz1.js} +1 -1
  13. package/dist/ui/assets/{adobe-oauth-state-BlTiu0EW.js → adobe-oauth-state-B9YxNQJp.js} +1 -1
  14. package/dist/ui/assets/{agent-message-to-chat-IZJU7XsF.js → agent-message-to-chat-DZEPoDrl.js} +1 -1
  15. package/dist/ui/assets/{apps-CGs6f4_D.js → apps-Fb83z-vc.js} +1 -1
  16. package/dist/ui/assets/{azure-openai-BPKSSyhH.js → azure-openai-D7rHwq_y.js} +1 -1
  17. package/dist/ui/assets/{azure-openai-CGgQnr10.js → azure-openai-Dsscn7WN.js} +1 -1
  18. package/dist/ui/assets/{composer-speech-HQRRG5ym.js → composer-speech-DJ-Mw0M5.js} +1 -1
  19. package/dist/ui/assets/{connect-surface-CK4b42-9.js → connect-surface-C-4d0ls3.js} +1 -1
  20. package/dist/ui/assets/dip-BINZ1ICD.js +1 -0
  21. package/dist/ui/assets/{dist-x2GYqOXm.js → dist-CseAKSVh.js} +1 -1
  22. package/dist/ui/assets/{dist-DtpnSVfI.js → dist-V73PvJP5.js} +1 -1
  23. package/dist/ui/assets/{ensure-speech-assets-Dn8D8dRb.js → ensure-speech-assets-CpXHTB8K.js} +1 -1
  24. package/dist/ui/assets/esp8266-CiVYkcWu.js +1 -0
  25. package/dist/ui/assets/{esptool-operations-D9gFmxN7.js → esptool-operations-BrkzeaKN.js} +2 -2
  26. package/dist/ui/assets/{fs-BdfVEExy.js → fs-DR-xqM-9.js} +1 -1
  27. package/dist/ui/assets/{fs-Bd593l61.js → fs-e_JED6o9.js} +2 -2
  28. package/dist/ui/assets/{github-B8weBp2j.js → github-D1teU7MS.js} +1 -1
  29. package/dist/ui/assets/{github-8kxwir4q.js → github-Db5GCKq4.js} +2 -2
  30. package/dist/ui/assets/{github-copilot-CPYs96aw.js → github-copilot-BhDan7GW.js} +1 -1
  31. package/dist/ui/assets/{github-copilot-DdE_r53L.js → github-copilot-DC5kS9aJ.js} +1 -1
  32. package/dist/ui/assets/{hear-Dk1gIguU.js → hear-CISOdKc7.js} +1 -1
  33. package/dist/ui/assets/{hear-J30GxNJC.js → hear-ST2A8Ojf.js} +1 -1
  34. package/dist/ui/assets/{kernel-worker-CHH5Mx3j.js → kernel-worker-DElXqFYz.js} +18 -18
  35. package/dist/ui/assets/{kokoro-engine-DXi-4Lk1.js → kokoro-engine-pjPKeKE-.js} +1 -1
  36. package/dist/ui/assets/{lick-ws-bridge-Di_eIPel.js → lick-ws-bridge-CgLt3-md.js} +1 -1
  37. package/dist/ui/assets/{lick-ws-bridge-BErTRf2C.js → lick-ws-bridge-uMf3lFqX.js} +1 -1
  38. package/dist/ui/assets/{local-llm-Bhn3zPzV.js → local-llm-CYNOX_zH.js} +1 -1
  39. package/dist/ui/assets/{main-CBEoDTj_.js → main-99mCaNK1.js} +4 -4
  40. package/dist/ui/assets/{mime-types-CIg5nqjf.js → mime-types-ugOWOUZ9.js} +1 -1
  41. package/dist/ui/assets/{mount-D0PTVzqd.js → mount-CIoB0cu-.js} +2 -2
  42. package/dist/ui/assets/{mount-C4pLRV8G.js → mount-DDFp4uJK.js} +1 -1
  43. package/dist/ui/assets/{new-session-D3cDkirv.js → new-session-yO9a-skO.js} +2 -2
  44. package/dist/ui/assets/{oauth-bootstrap-CW0Iq4DJ.js → oauth-bootstrap-BjE1yxq_.js} +2 -2
  45. package/dist/ui/assets/{openai-codex-BhKQGaPl.js → openai-codex-CxQ8e4UF.js} +1 -1
  46. package/dist/ui/assets/{openai-codex-jRbHGzPJ.js → openai-codex-D9qpuznd.js} +1 -1
  47. package/dist/ui/assets/{page-follower-tray-B7V5Hdk3.js → page-follower-tray-DWGutKN6.js} +1 -1
  48. package/dist/ui/assets/{panel-rpc-handlers-HGirMMc_.js → panel-rpc-handlers-Bh3kNYD4.js} +2 -2
  49. package/dist/ui/assets/{provider-fwp5doUF.js → provider-BHsa0Rrz.js} +1 -1
  50. package/dist/ui/assets/{provider-T0IaN12Z.js → provider-BWRxgi1b.js} +2 -2
  51. package/dist/ui/assets/provider-store-access-Ct7bph7W.js +1 -0
  52. package/dist/ui/assets/provider-store-access-Dxm0WwoL.js +1 -0
  53. package/dist/ui/assets/{providers-BJpLjsbl.js → providers-D3nv5fF8.js} +1 -1
  54. package/dist/ui/assets/{quick-llm-DmM8V850.js → quick-llm-nkhmm4Rf.js} +1 -1
  55. package/dist/ui/assets/session-freezer-BoHtcQZ7.js +1 -0
  56. package/dist/ui/assets/{shared-Cddyus7m.js → shared-mxZcIrza.js} +1 -1
  57. package/dist/ui/assets/speak-DoCdEEhw.js +3 -0
  58. package/dist/ui/assets/speak-zyz6ag-g.js +1 -0
  59. package/dist/ui/assets/{sprinkle-bridge-Cd-pvRLY.js → sprinkle-bridge-BB1Ge79t.js} +1 -1
  60. package/dist/ui/assets/{sprinkle-manager-Cu6u-z69.js → sprinkle-manager-BqIyFmnb.js} +1 -1
  61. package/dist/ui/assets/{store-BaMl32ka.js → store-CYnFF7yg.js} +1 -1
  62. package/dist/ui/assets/{sudo-DBuMJPLn.js → sudo-Bs4eVV8G.js} +1 -1
  63. package/dist/ui/assets/{transformers-env-CEn9s_Z3.js → transformers-env-B2qCXqw-.js} +1 -1
  64. package/dist/ui/assets/{transformers-env-BNvU2_5X.js → transformers-env-t6_cAHU1.js} +1 -1
  65. package/dist/ui/assets/{tray-leader-BufiJcof.js → tray-leader-BjtMXiMR.js} +1 -1
  66. package/dist/ui/assets/{tray-leave-runtime-CPPXBBg9.js → tray-leave-runtime-BoCD9arc.js} +1 -1
  67. package/dist/ui/assets/{upgrade-detection-D19M3hIS.js → upgrade-detection-CLuyCKRm.js} +1 -1
  68. package/dist/ui/assets/voice-reply-BLN1aJMo.js +1 -0
  69. package/dist/ui/assets/{wc-attach-jjQplnwa.js → wc-attach-BoWNytPR.js} +2 -2
  70. package/dist/ui/assets/{wc-detached-Dz2uBF5T.js → wc-detached-Cyqt2rB-.js} +1 -1
  71. package/dist/ui/assets/{wc-extension-BmxoVHlX.js → wc-extension-TU20M11H.js} +2 -2
  72. package/dist/ui/assets/{wc-follower-Cr4dFgMb.js → wc-follower-J9dIOTtr.js} +2 -2
  73. package/dist/ui/assets/wc-live-C00evhz8.js +253 -0
  74. package/dist/ui/assets/{wc-nav-CXbbv1oy.js → wc-nav-CDGop7zp.js} +2 -2
  75. package/dist/ui/assets/{wc-onboarding-n0z_itcq.js → wc-onboarding-BJdN1JOs.js} +2 -2
  76. package/dist/ui/assets/{wc-placeholder-D5zdaLbn.js → wc-placeholder-CX_bmbWN.js} +3 -3
  77. package/dist/ui/assets/{wc-settings-qtsuiHg1.js → wc-settings-pnqs-c98.js} +2 -2
  78. package/dist/ui/assets/{wc-shell-B2jkbIzt.js → wc-shell-DoOezClu.js} +963 -786
  79. package/dist/ui/assets/{wc-sprinkles-BAKT9WrK.js → wc-sprinkles-B3Di9lOW.js} +2 -2
  80. package/dist/ui/assets/{wc-tray-cnJoLvS2.js → wc-tray-D-6xnB2i.js} +2 -2
  81. package/dist/ui/assets/{whisper-engine-BSOAcb8a.js → whisper-engine-C_zUz3xO.js} +1 -1
  82. package/dist/ui/assets/{whisper-session-CW3OA9V7.js → whisper-session-7nSKj94g.js} +2 -2
  83. package/dist/ui/assets/{xai-grok---YndVHa.js → xai-grok-C3lfFdpm.js} +1 -1
  84. package/dist/ui/assets/{xai-grok-Da_y6R6g.js → xai-grok-Di62sFOW.js} +1 -1
  85. package/dist/ui/electron-overlay-entry.js +299 -6180
  86. package/dist/ui/index.html +2 -2
  87. package/dist/ui/packages/webapp/index.html +2 -2
  88. package/package.json +8 -6
  89. package/dist/node-server/ui-serving.d.ts +0 -18
  90. package/dist/node-server/ui-serving.js +0 -91
  91. package/dist/ui/assets/dip-NVUHjmhc.js +0 -1
  92. package/dist/ui/assets/esp8266-DL6QxCn7.js +0 -1
  93. package/dist/ui/assets/provider-store-access-BVRQIXtM.js +0 -1
  94. package/dist/ui/assets/provider-store-access-DTw81yRr.js +0 -1
  95. package/dist/ui/assets/session-freezer-D6XPq9Ct.js +0 -1
  96. package/dist/ui/assets/speak-BLaMFnqh.js +0 -3
  97. package/dist/ui/assets/speak-BM_ACI3J.js +0 -1
  98. package/dist/ui/assets/voice-reply--p0t9Lgo.js +0 -1
  99. package/dist/ui/assets/wc-live-DbLgOajX.js +0 -253
  100. package/dist/ui/electron-overlay-entry.css +0 -37
@@ -149,7 +149,6 @@ export declare class ElectronOverlayInjector {
149
149
  static create(options: {
150
150
  cdpPort: number;
151
151
  servePort: number;
152
- dev: boolean;
153
152
  projectRoot: string;
154
153
  /**
155
154
  * Thin-bridge coordinates: the overlay loads from the hosted launcher
@@ -7,7 +7,7 @@ import { promisify } from 'util';
7
7
  import { WebSocket } from 'ws';
8
8
  import { inflateSync } from 'zlib';
9
9
  import { BRIDGE_TOKEN_QUERY_PARAM, BRIDGE_WS_QUERY_PARAM } from './bridge-security.js';
10
- import { buildElectronAppLaunchSpec, buildElectronOverlayBootstrapScript, buildElectronOverlayEntryUrl, ELECTRON_OVERLAY_APP_PATH, getElectronOverlayEntryDistPath, getElectronServeOrigin, selectBestOverlayTargets, } from './electron-runtime.js';
10
+ import { buildElectronAppLaunchSpec, buildElectronOverlayBootstrapScript, ELECTRON_OVERLAY_APP_PATH, getElectronOverlayEntryDistPath, selectBestOverlayTargets, } from './electron-runtime.js';
11
11
  const execFile = promisify(nodeExecFile);
12
12
  const ELECTRON_OVERLAY_SYNC_INTERVAL_MS = 1500;
13
13
  /**
@@ -420,14 +420,6 @@ function detectAppThemeFromScreenshot(ws, send) {
420
420
  });
421
421
  }
422
422
  async function loadElectronOverlayBundleSource(options) {
423
- const serveOrigin = getElectronServeOrigin(options.servePort);
424
- if (options.dev) {
425
- const response = await fetch(buildElectronOverlayEntryUrl(serveOrigin));
426
- if (!response.ok) {
427
- throw new Error(`Failed to fetch electron overlay entry: ${response.status} ${response.statusText}`);
428
- }
429
- return await response.text();
430
- }
431
423
  return await readFile(getElectronOverlayEntryDistPath(options.projectRoot), 'utf8');
432
424
  }
433
425
  /**
@@ -567,7 +559,9 @@ export class ElectronOverlayInjector {
567
559
  this.presenceCheckIntervalMs = presenceCheckIntervalMs;
568
560
  }
569
561
  static async create(options) {
570
- const bundleSource = await loadElectronOverlayBundleSource(options);
562
+ const bundleSource = await loadElectronOverlayBundleSource({
563
+ projectRoot: options.projectRoot,
564
+ });
571
565
  const thinBootstraps = {
572
566
  leader: buildElectronOverlayBootstrapScript({
573
567
  bundleSource,
@@ -5,7 +5,7 @@ import { resolve } from 'path';
5
5
  import { fileURLToPath } from 'url';
6
6
  import { mintBridgeToken } from './bridge-security.js';
7
7
  import { BRIDGE_ROLE_LEADER, buildThinOverlayAppUrl, resolveHostedLeaderOrigin, } from './electron-controller.js';
8
- import { buildElectronOverlayEntryUrl, buildElectronOverlayInjectionCall, buildElectronServerSpawnConfig, getElectronOverlayEntryDistPath, getElectronServeOrigin, parseElectronFloatFlags, } from './electron-runtime.js';
8
+ import { buildElectronOverlayInjectionCall, buildElectronServerSpawnConfig, getElectronOverlayEntryDistPath, getElectronServeOrigin, parseElectronFloatFlags, } from './electron-runtime.js';
9
9
  const Dirname = fileURLToPath(new URL('.', import.meta.url));
10
10
  const PROJECT_ROOT = resolve(Dirname, '..', '..');
11
11
  const FLAGS = parseElectronFloatFlags(process.argv.slice(2));
@@ -61,13 +61,6 @@ async function waitForServerReady(origin, retries = 60, delayMs = 500) {
61
61
  throw new Error(`Electron float server did not become ready at ${origin}`);
62
62
  }
63
63
  async function loadOverlayBundleSource() {
64
- if (FLAGS.dev) {
65
- const response = await fetch(buildElectronOverlayEntryUrl(SERVE_ORIGIN));
66
- if (!response.ok) {
67
- throw new Error(`Failed to fetch electron overlay entry: ${response.status} ${response.statusText}`);
68
- }
69
- return await response.text();
70
- }
71
64
  return await readFile(getElectronOverlayEntryDistPath(PROJECT_ROOT), 'utf8');
72
65
  }
73
66
  async function injectOverlay(window) {
@@ -132,7 +125,6 @@ async function createFloatWindow(targetUrl) {
132
125
  }
133
126
  function startCliServer() {
134
127
  const spawnConfig = buildElectronServerSpawnConfig(PROJECT_ROOT, {
135
- dev: FLAGS.dev,
136
128
  cdpPort: FLAGS.cdpPort,
137
129
  nodePath: process.env['npm_node_execpath'] ?? 'node',
138
130
  });
@@ -141,10 +133,10 @@ function startCliServer() {
141
133
  env: {
142
134
  ...process.env,
143
135
  PORT: String(FLAGS.servePort),
144
- // Forward the per-process bridge token to the child server. The
145
- // current --serve-only mode doesn't gate /cdp on it (THIN_BRIDGE_MODE
146
- // is false), but the env var is in place so a follow-up index.ts
147
- // change can flip the gate on without retouching this file.
136
+ // Forward the per-process bridge token to the child server. The child
137
+ // runs as a thin /cdp bridge and gates its `/cdp` upgrade on this
138
+ // token (via `resolveServerBridgeToken`), so it matches the token
139
+ // carried by the float's overlay BrowserWindow.
148
140
  SLICC_BRIDGE_TOKEN: BRIDGE_TOKEN,
149
141
  SLICC_HOSTED_LEADER_ORIGIN: HOSTED_LEADER_ORIGIN,
150
142
  },
@@ -1,5 +1,4 @@
1
1
  export interface ElectronFloatFlags {
2
- dev: boolean;
3
2
  cdpPort: number;
4
3
  servePort: number;
5
4
  targetUrl: string;
@@ -54,13 +53,10 @@ export declare function buildElectronAppLaunchSpec(appPath: string, options: {
54
53
  }): ElectronAppLaunchSpec;
55
54
  export declare function parseElectronFloatFlags(argv: string[], env?: Record<string, string | undefined>): ElectronFloatFlags;
56
55
  export declare function buildElectronServerSpawnConfig(projectRoot: string, options: {
57
- dev: boolean;
58
56
  cdpPort: number;
59
- platform?: NodeJS.Platform;
60
57
  nodePath?: string;
61
58
  }): ElectronServerSpawnConfig;
62
59
  export declare function getElectronServeOrigin(servePort: number): string;
63
- export declare function buildElectronOverlayEntryUrl(serveOrigin: string): string;
64
60
  export declare function getElectronOverlayEntryDistPath(projectRoot: string): string;
65
61
  export declare function buildElectronOverlayInjectionCall(options: {
66
62
  appUrl: string;
@@ -196,14 +196,9 @@ function parsePositiveInt(value, fallback) {
196
196
  return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
197
197
  }
198
198
  export function parseElectronFloatFlags(argv, env = process.env) {
199
- let dev = false;
200
199
  let cdpPort = DEFAULT_ELECTRON_CDP_PORT;
201
200
  let targetUrl = DEFAULT_ELECTRON_TARGET_URL;
202
201
  for (const arg of argv) {
203
- if (arg === '--dev') {
204
- dev = true;
205
- continue;
206
- }
207
202
  if (arg.startsWith('--cdp-port=')) {
208
203
  cdpPort = parsePositiveInt(arg.slice('--cdp-port='.length), DEFAULT_ELECTRON_CDP_PORT);
209
204
  continue;
@@ -218,25 +213,12 @@ export function parseElectronFloatFlags(argv, env = process.env) {
218
213
  }
219
214
  }
220
215
  return {
221
- dev,
222
216
  cdpPort,
223
217
  servePort: parsePositiveInt(env['PORT'], DEFAULT_ELECTRON_SERVE_PORT),
224
218
  targetUrl,
225
219
  };
226
220
  }
227
221
  export function buildElectronServerSpawnConfig(projectRoot, options) {
228
- if (options.dev) {
229
- return {
230
- command: (options.platform ?? process.platform) === 'win32' ? 'npx.cmd' : 'npx',
231
- args: [
232
- 'tsx',
233
- 'packages/node-server/src/index.ts',
234
- '--dev',
235
- '--serve-only',
236
- `--cdp-port=${options.cdpPort}`,
237
- ],
238
- };
239
- }
240
222
  return {
241
223
  command: options.nodePath ?? process.env['npm_node_execpath'] ?? 'node',
242
224
  args: [
@@ -249,9 +231,10 @@ export function buildElectronServerSpawnConfig(projectRoot, options) {
249
231
  export function getElectronServeOrigin(servePort) {
250
232
  return `http://${DEFAULT_ELECTRON_SERVE_HOST}:${servePort}`;
251
233
  }
252
- export function buildElectronOverlayEntryUrl(serveOrigin) {
253
- return new URL('/electron-overlay-entry.js', serveOrigin).toString();
254
- }
234
+ // The overlay bootstrap IIFE is produced by `@ai-ecoverse/spoon`'s build
235
+ // (`node packages/spoon/build.mjs`), which emits to this canonical `dist/ui`
236
+ // path — the same location the webapp build mirrors it to and swift-launcher
237
+ // copies from. node-server reads it from disk at runtime; the path is stable.
255
238
  export function getElectronOverlayEntryDistPath(projectRoot) {
256
239
  return resolve(projectRoot, 'dist/ui/electron-overlay-entry.js');
257
240
  }
@@ -43,7 +43,6 @@ import { SecretProxyManager } from './secrets/proxy-manager.js';
43
43
  import { readOrCreateSessionId } from './secrets/session-id-file.js';
44
44
  import { registerSecretsReloadEndpoint } from './secrets-reload-endpoint.js';
45
45
  import { registerSudoApproveEndpoint } from './sudo/endpoint.js';
46
- import { attachUiServing } from './ui-serving.js';
47
46
  const Dirname = fileURLToPath(new URL('.', import.meta.url));
48
47
  const PROJECT_ROOT = resolve(Dirname, '..', '..');
49
48
  // ---------------------------------------------------------------------------
@@ -61,25 +60,28 @@ if (RUNTIME_FLAGS.version) {
61
60
  console.log(pkg.version);
62
61
  process.exit(0);
63
62
  }
64
- const DEV_MODE = RUNTIME_FLAGS.dev;
65
63
  const SERVE_ONLY = RUNTIME_FLAGS.serveOnly;
66
64
  const ELECTRON_MODE = RUNTIME_FLAGS.electron;
67
65
  const ELECTRON_APP = RUNTIME_FLAGS.electronApp;
68
66
  const KILL_EXISTING_ELECTRON_APP = RUNTIME_FLAGS.kill;
69
67
  /**
70
- * Standalone thin-bridge mode: production CLI with no bundled UI. The
71
- * launched Chrome opens a sliccy.ai-hosted leader; node-server is a thin
72
- * /cdp bridge + /api surface. Dev / electron / serve-only / hosted all
73
- * keep the bundled UI path (a separate path B / hosted task covers those).
68
+ * Whether to default-mint a `/cdp` bridge token (and mount thin-bridge
69
+ * CORS) for this process. Active in every mode EXCEPT a direct
70
+ * `--serve-only` run with no forwarded token: serve-only reuses an
71
+ * external CDP target and never launches a browser or prints a hosted
72
+ * launch URL carrying a freshly minted token, so minting one would gate
73
+ * `/cdp` (and `/api/*` CORS) on a secret the already-open page can never
74
+ * present. A `--serve-only` reattach from Sliccstart still works because
75
+ * it forwards `SLICC_BRIDGE_TOKEN`, which `resolveServerBridgeToken` and
76
+ * `shouldMountThinBridgeCors` honor regardless of this flag.
74
77
  */
75
- const THIN_BRIDGE_MODE = !DEV_MODE && !SERVE_ONLY && !ELECTRON_MODE && !RUNTIME_FLAGS.hosted;
78
+ const THIN_BRIDGE_MODE = !SERVE_ONLY;
76
79
  // ---------------------------------------------------------------------------
77
80
  // File logger — persistent log file in ~/.slicc/logs/
78
81
  // ---------------------------------------------------------------------------
79
82
  const fileLogger = new FileLogger({
80
83
  logDir: RUNTIME_FLAGS.logDir ?? undefined,
81
84
  logLevel: RUNTIME_FLAGS.logLevel,
82
- devMode: DEV_MODE,
83
85
  });
84
86
  if (fileLogger.logFile) {
85
87
  console.log(`Log file: ${fileLogger.logFile}`);
@@ -115,13 +117,6 @@ async function waitForCDP(port, retries = 30, delayMs = 500) {
115
117
  }
116
118
  throw new Error(`CDP did not become available on port ${port}`);
117
119
  }
118
- // ---------------------------------------------------------------------------
119
- // ANSI color helpers
120
- // ---------------------------------------------------------------------------
121
- const ANSI_RED = '\x1b[31m';
122
- const ANSI_YELLOW = '\x1b[33m';
123
- const ANSI_CYAN = '\x1b[36m';
124
- const ANSI_RESET = '\x1b[0m';
125
120
  function pipeChildOutput(child, label) {
126
121
  child.stdout?.on('data', (data) => {
127
122
  process.stdout.write(`[${label}:out] ${data}`);
@@ -175,123 +170,6 @@ async function findAvailablePort(preferred) {
175
170
  throw err;
176
171
  }
177
172
  }
178
- function formatPreviewProperties(properties) {
179
- return properties
180
- .map((p) => {
181
- let val;
182
- if (p.type === 'object')
183
- val = p.subtype === 'array' ? '[...]' : '{...}';
184
- else if (p.type === 'string')
185
- val = `"${p.value}"`;
186
- else
187
- val = p.value;
188
- return `${p.name}: ${val}`;
189
- })
190
- .join(', ');
191
- }
192
- function formatRemoteObject(obj) {
193
- if (obj.type === 'undefined')
194
- return 'undefined';
195
- if (obj.type === 'object' && obj.subtype === 'null')
196
- return 'null';
197
- // Format objects/arrays using preview properties when available
198
- if (obj.type === 'object' && obj.preview?.properties && obj.preview.properties.length > 0) {
199
- const inner = formatPreviewProperties(obj.preview.properties);
200
- const suffix = obj.preview.overflow ? ', ...' : '';
201
- if (obj.subtype === 'array')
202
- return `[${inner}${suffix}]`;
203
- return `{ ${inner}${suffix} }`;
204
- }
205
- if (obj.preview?.description)
206
- return obj.preview.description;
207
- if (obj.description !== undefined)
208
- return obj.description;
209
- if (obj.value !== undefined)
210
- return String(obj.value);
211
- return `[${obj.type}]`;
212
- }
213
- function colorForType(type) {
214
- switch (type) {
215
- case 'error':
216
- return ANSI_RED;
217
- case 'warning':
218
- return ANSI_YELLOW;
219
- default:
220
- return ANSI_CYAN;
221
- }
222
- }
223
- async function findPageTarget(cdpPort, pageUrl) {
224
- try {
225
- const res = await fetch(`http://127.0.0.1:${cdpPort}/json`);
226
- const targets = (await res.json());
227
- const match = targets.find((t) => t.type === 'page' && t.url.includes(`localhost:${pageUrl}`) && t.webSocketDebuggerUrl);
228
- return match ? { webSocketDebuggerUrl: match.webSocketDebuggerUrl } : null;
229
- }
230
- catch {
231
- return null;
232
- }
233
- }
234
- async function attachConsoleForwarder(cdpPort, pageUrl) {
235
- const pageDedup = new CliLogDedup('[page]');
236
- const connect = async () => {
237
- // Poll for the page target
238
- let target = null;
239
- for (let i = 0; i < 20; i++) {
240
- target = await findPageTarget(cdpPort, pageUrl);
241
- if (target)
242
- break;
243
- await new Promise((r) => setTimeout(r, 500));
244
- }
245
- if (!target) {
246
- console.log('[page] Could not find page target — console forwarding disabled');
247
- return;
248
- }
249
- const ws = new WebSocket(target.webSocketDebuggerUrl);
250
- ws.on('open', () => {
251
- ws.send(JSON.stringify({ id: 1, method: 'Runtime.enable' }));
252
- });
253
- ws.on('message', (raw) => {
254
- try {
255
- const msg = JSON.parse(String(raw));
256
- if (msg.method === 'Runtime.consoleAPICalled') {
257
- const params = msg.params;
258
- const type = params.type;
259
- const color = colorForType(type);
260
- const argsStr = params.args.map(formatRemoteObject).join(' ');
261
- const line = `[page:${type}] ${argsStr}`;
262
- if (pageDedup.shouldLog(line)) {
263
- console.log(`${color}[page:${type}]${ANSI_RESET} ${argsStr}`);
264
- }
265
- }
266
- if (msg.method === 'Runtime.exceptionThrown') {
267
- const params = msg.params;
268
- const details = params.exceptionDetails;
269
- const desc = details.exception?.description ?? details.text;
270
- console.log(`${ANSI_RED}[page:exception]${ANSI_RESET} ${desc}`);
271
- if (details.stackTrace) {
272
- for (const frame of details.stackTrace.callFrames) {
273
- const fn = frame.functionName || '<anonymous>';
274
- console.log(`${ANSI_RED} at ${fn} (${frame.url}:${frame.lineNumber}:${frame.columnNumber})${ANSI_RESET}`);
275
- }
276
- }
277
- }
278
- }
279
- catch {
280
- // Ignore malformed messages
281
- }
282
- });
283
- ws.on('close', () => {
284
- // Reconnect after a short delay (page may have reloaded)
285
- setTimeout(() => {
286
- connect();
287
- }, 1000);
288
- });
289
- ws.on('error', () => {
290
- // Error will trigger close, which handles reconnection
291
- });
292
- };
293
- await connect();
294
- }
295
173
  // ---------------------------------------------------------------------------
296
174
  // Main
297
175
  // ---------------------------------------------------------------------------
@@ -349,8 +227,6 @@ async function resolvePorts(state) {
349
227
  else if (state.servePort !== PREFERRED_SERVE_PORT) {
350
228
  console.log(`Port ${PREFERRED_SERVE_PORT} in use, serving on port ${state.servePort}`);
351
229
  }
352
- if (DEV_MODE)
353
- console.log('Starting in dev mode (Vite HMR enabled)');
354
230
  if (SERVE_ONLY) {
355
231
  console.log(`Starting in serve-only mode (reusing external CDP on port ${state.cdpPort})`);
356
232
  }
@@ -491,7 +367,7 @@ function buildBrowserLaunchUrl(state) {
491
367
  // Thin-bridge standalone: Chrome opens the hosted leader directly; the
492
368
  // local node-server serves no UI at all. Bridge coordinates ride as
493
369
  // query params so the leader can discover + authenticate /cdp.
494
- const serveOriginForLaunch = THIN_BRIDGE_MODE && state.bridgeToken ? resolveThinLeaderOrigin() : state.serveOrigin;
370
+ const serveOriginForLaunch = state.bridgeToken ? resolveThinLeaderOrigin() : state.serveOrigin;
495
371
  let url = resolveCliBrowserLaunchUrl({
496
372
  serveOrigin: serveOriginForLaunch,
497
373
  lead: RUNTIME_FLAGS.lead,
@@ -499,7 +375,7 @@ function buildBrowserLaunchUrl(state) {
499
375
  envWorkerBaseUrl: process.env['WORKER_BASE_URL'] ?? null,
500
376
  join: RUNTIME_FLAGS.join,
501
377
  joinUrl: RUNTIME_FLAGS.joinUrl,
502
- bridgeWsUrl: THIN_BRIDGE_MODE && state.bridgeToken ? `ws://localhost:${state.servePort}/cdp` : null,
378
+ bridgeWsUrl: state.bridgeToken ? `ws://localhost:${state.servePort}/cdp` : null,
503
379
  bridgeToken: state.bridgeToken,
504
380
  });
505
381
  if (RUNTIME_FLAGS.hosted) {
@@ -514,7 +390,7 @@ function buildBrowserLaunchUrl(state) {
514
390
  else if (RUNTIME_FLAGS.lead) {
515
391
  console.log(`Lead launch URL: ${url}`);
516
392
  }
517
- else if (THIN_BRIDGE_MODE) {
393
+ else {
518
394
  // Print WITHOUT the bridgeToken — it's a session capability.
519
395
  const sanitized = url.replace(/([?&])bridgeToken=[^&]+/, '$1bridgeToken=<redacted>');
520
396
  console.log(`Thin-bridge launch URL: ${sanitized}`);
@@ -543,7 +419,7 @@ async function launchChromeTarget(state) {
543
419
  const browserLaunchUrl = buildBrowserLaunchUrl(state);
544
420
  const chromeProfile = resolveChromeProfileOrExit(state);
545
421
  const chromePath = findChromeExecutable({
546
- executablePreference: !DEV_MODE && !chromeProfile.id ? 'installed' : 'chrome-for-testing',
422
+ executablePreference: !chromeProfile.id ? 'installed' : 'chrome-for-testing',
547
423
  });
548
424
  if (!chromePath) {
549
425
  console.error('Could not find Chrome/Chromium. Please install Chrome or set CHROME_PATH.');
@@ -996,7 +872,6 @@ async function startOverlayInjector(state, cdpPort, servePort) {
996
872
  state.overlayInjector = await ElectronOverlayInjector.create({
997
873
  cdpPort,
998
874
  servePort,
999
- dev: DEV_MODE,
1000
875
  projectRoot: PROJECT_ROOT,
1001
876
  thinBridge,
1002
877
  });
@@ -1023,17 +898,11 @@ function startListening(deps) {
1023
898
  const { server, fileLogger, servePort, serveOrigin, cdpPort } = deps;
1024
899
  return new Promise((resolve) => {
1025
900
  server.listen(servePort, '127.0.0.1', () => {
1026
- if (THIN_BRIDGE_MODE) {
1027
- console.log(`Thin /cdp bridge + /api at ${serveOrigin}`);
1028
- }
1029
- else {
1030
- console.log(`Serving UI at ${serveOrigin}`);
1031
- }
901
+ console.log(`Thin /cdp bridge + /api at ${serveOrigin}`);
1032
902
  console.log(`CDP proxy at ws://localhost:${servePort}/cdp`);
1033
903
  fileLogger.log('info', 'CLI server started', {
1034
904
  port: servePort,
1035
905
  cdpPort,
1036
- devMode: DEV_MODE,
1037
906
  electronMode: ELECTRON_MODE,
1038
907
  });
1039
908
  resolve();
@@ -1042,10 +911,10 @@ function startListening(deps) {
1042
911
  }
1043
912
  /**
1044
913
  * Post-listen warmup: pre-connects to Chrome's CDP (so the proxy is warm
1045
- * before the first client), starts the Electron overlay injector, and
1046
- * attaches the console forwarder. Reads `state.cdpPort` dynamically so
1047
- * the value populated by `launchChromeTarget` is used regardless of when
1048
- * this runs relative to the listen callback.
914
+ * before the first client) and, in Electron mode, starts the overlay
915
+ * injector. Reads `state.cdpPort` dynamically so the value populated by
916
+ * `launchChromeTarget` is used regardless of when this runs relative to
917
+ * the listen callback.
1049
918
  */
1050
919
  function runCdpProxyWarmup(state, deps) {
1051
920
  const { app, ctx, servePort } = deps;
@@ -1053,15 +922,6 @@ function runCdpProxyWarmup(state, deps) {
1053
922
  if (ELECTRON_MODE) {
1054
923
  void startOverlayInjector(state, state.cdpPort, servePort);
1055
924
  }
1056
- else if (!THIN_BRIDGE_MODE) {
1057
- // Thin-bridge mode has no local UI page to forward console output from.
1058
- const cdpPort = state.cdpPort;
1059
- setTimeout(() => {
1060
- attachConsoleForwarder(cdpPort, String(servePort)).catch((err) => {
1061
- console.error('[page] Console forwarder error:', err);
1062
- });
1063
- }, 2500);
1064
- }
1065
925
  }
1066
926
  /**
1067
927
  * Build the secret stores + masking pipeline shared by the fetch-proxy, the
@@ -1171,7 +1031,7 @@ async function main() {
1171
1031
  // shutdown handler) read it dynamically from `state`.
1172
1032
  const state = createServerState();
1173
1033
  await resolvePorts(state);
1174
- const { servePort: SERVE_PORT, serveOrigin: SERVE_ORIGIN } = state;
1034
+ const { servePort: SERVE_PORT } = state;
1175
1035
  // 3. Set up express app with request logging
1176
1036
  const { secretStore, secretProxy, oauthStore } = await bootstrapSecrets();
1177
1037
  const app = express();
@@ -1206,9 +1066,7 @@ async function main() {
1206
1066
  (process.env['SLICC_TRAY_WORKER_BASE_URL']?.trim() || null) ??
1207
1067
  RUNTIME_FLAGS.leadWorkerBaseUrl ??
1208
1068
  (process.env['WORKER_BASE_URL']?.trim() || null) ??
1209
- (DEV_MODE
1210
- ? 'https://slicc-tray-hub-staging.minivelos.workers.dev'
1211
- : 'https://www.sliccy.ai'),
1069
+ 'https://www.sliccy.ai',
1212
1070
  // Read dynamically from state — populated by `launchElectronTarget`
1213
1071
  // when an existing leader is discovered. `launchBrowser` now runs
1214
1072
  // after `server.listen()`, so this endpoint must NOT close over a
@@ -1242,7 +1100,7 @@ async function main() {
1242
1100
  registerHandoffRoute(app, { broadcastLickEvent });
1243
1101
  // Secret management API — direct .env file access (no browser needed),
1244
1102
  // plus the S3 / DA sign-and-forward and masked-secret endpoints.
1245
- registerSecretRoutes(app, { secretStore, secretProxy, oauthStore, devMode: DEV_MODE });
1103
+ registerSecretRoutes(app, { secretStore, secretProxy, oauthStore, devMode: false });
1246
1104
  // Cloud status endpoint (hosted-only) — writes join info to /tmp/slicc-join.json
1247
1105
  // Register BEFORE Chromium launches. The webapp's first action after
1248
1106
  // ?runtime=hosted-leader boot is to mint a tray and POST /api/cloud-status.
@@ -1259,21 +1117,13 @@ async function main() {
1259
1117
  // Fetch proxy — forwards cross-origin requests from the browser to bypass CORS,
1260
1118
  // injecting/unmasking secrets and streaming the response with a UTF-8-safe scrub.
1261
1119
  registerFetchProxyRoute(app, { secretProxy });
1262
- // Create the HTTP server BEFORE Vite so we can register our upgrade handler first
1120
+ // node-server serves no UI in any mode: it is a pure /cdp bridge + /api
1121
+ // surface. Chrome opens the sliccy.ai-hosted leader which talks to /cdp +
1122
+ // /api cross-origin. Create the HTTP server so we can attach the /cdp WS
1123
+ // upgrade handler to it.
1263
1124
  const server = createServer(app);
1264
- // Thin-bridge mode: skip UI serving entirely. node-server becomes a
1265
- // pure /cdp bridge + /api surface; Chrome opens the sliccy.ai-hosted
1266
- // leader which talks to /cdp + /api cross-origin.
1267
- if (!THIN_BRIDGE_MODE) {
1268
- await attachUiServing(app, server, {
1269
- devMode: DEV_MODE,
1270
- hosted: RUNTIME_FLAGS.hosted,
1271
- serveOrigin: SERVE_ORIGIN,
1272
- uiDir: resolve(Dirname, '..', 'ui'),
1273
- });
1274
- }
1275
- // 4. CDP WebSocket proxy at /cdp — noServer mode so Vite's dev middleware
1276
- // doesn't intercept the upgrade.
1125
+ // 4. CDP WebSocket proxy at /cdp noServer mode so we own the upgrade
1126
+ // handler routing for /cdp and /licks-ws.
1277
1127
  const wss = createCdpWebSocketServer(state.bridgeToken);
1278
1128
  attachCdpUpgradeRouting(server, wss, lickWss, state.bridgeToken);
1279
1129
  const cdpCtx = {
@@ -1,6 +1,5 @@
1
1
  export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
2
2
  export interface CliRuntimeFlags {
3
- dev: boolean;
4
3
  serveOnly: boolean;
5
4
  cdpPort: number;
6
5
  /** Whether --cdp-port was explicitly specified */