@ekkos/cli 1.3.8 → 1.3.9

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.
@@ -94,9 +94,18 @@ async function showPulseLoadedBanner() {
94
94
  }
95
95
  /**
96
96
  * Resolve Gemini CLI binary path.
97
- * Checks common locations then falls back to PATH lookup.
97
+ * Checks PATH first (which/where), then falls back to common locations.
98
98
  */
99
99
  function resolveGeminiPath() {
100
+ // 1. PATH lookup first to respect nvm/volta/npm-global settings
101
+ const whichCmd = isWindows ? 'where gemini' : 'which gemini';
102
+ try {
103
+ const result = (0, child_process_1.execSync)(whichCmd, { encoding: 'utf-8', stdio: 'pipe' }).trim();
104
+ if (result)
105
+ return result.split('\n')[0];
106
+ }
107
+ catch { /* not found in PATH */ }
108
+ // 2. Fallback to common global install locations
100
109
  if (!isWindows) {
101
110
  const pathsToCheck = [
102
111
  '/opt/homebrew/bin/gemini',
@@ -109,15 +118,7 @@ function resolveGeminiPath() {
109
118
  return p;
110
119
  }
111
120
  }
112
- // PATH lookup
113
- const whichCmd = isWindows ? 'where gemini' : 'which gemini';
114
- try {
115
- const result = (0, child_process_1.execSync)(whichCmd, { encoding: 'utf-8', stdio: 'pipe' }).trim();
116
- if (result)
117
- return result.split('\n')[0];
118
- }
119
- catch { /* not found */ }
120
- // Fallback — let spawn resolve it (will error with helpful message)
121
+ // 3. Ultimate fallback — let spawn resolve it (will error with helpful message)
121
122
  return 'gemini';
122
123
  }
123
124
  /**
@@ -2,12 +2,17 @@ interface RunOptions {
2
2
  session?: string;
3
3
  verbose?: boolean;
4
4
  bypass?: boolean;
5
+ pulse?: boolean;
5
6
  doctor?: boolean;
6
7
  noInject?: boolean;
7
8
  research?: boolean;
8
9
  noProxy?: boolean;
9
10
  dashboard?: boolean;
10
11
  addDirs?: string[];
12
+ model?: string | boolean;
13
+ contextWindow?: string;
14
+ continueLast?: boolean;
15
+ resumeSession?: string;
11
16
  slashOpenDelayMs?: number;
12
17
  charDelayMs?: number;
13
18
  postEnterDelayMs?: number;
@@ -86,6 +86,244 @@ function getConfig(options) {
86
86
  };
87
87
  /* eslint-enable no-restricted-syntax */
88
88
  }
89
+ const MAX_OUTPUT_1M_MODELS = '128000';
90
+ const MAX_OUTPUT_200K_OPUS_SONNET = '32768';
91
+ let runtimeClaudeCodeVersion = null;
92
+ let runtimeClaudeContextWindow = 'auto';
93
+ let runtimeClaudeLaunchModel;
94
+ function normalizeContextWindowOption(value) {
95
+ const normalized = (value || '').trim().toLowerCase();
96
+ if (normalized === '200k' || normalized === '200000')
97
+ return '200k';
98
+ if (normalized === '1m' || normalized === '1000000')
99
+ return '1m';
100
+ return 'auto';
101
+ }
102
+ function normalizeRequestedLaunchModel(value) {
103
+ if (typeof value !== 'string')
104
+ return {};
105
+ const raw = (value || '').trim();
106
+ if (!raw)
107
+ return {};
108
+ if (raw.toLowerCase() === 'default') {
109
+ return {};
110
+ }
111
+ const oneMillionMatch = raw.match(/^(.*)\[1m\]$/i);
112
+ if (oneMillionMatch) {
113
+ return {
114
+ model: oneMillionMatch[1].trim(),
115
+ syntheticContextWindow: '1m',
116
+ };
117
+ }
118
+ const lower = raw.toLowerCase();
119
+ if (lower.endsWith('-200k')) {
120
+ return {
121
+ model: raw.slice(0, -5).trim(),
122
+ syntheticContextWindow: '200k',
123
+ };
124
+ }
125
+ if (lower.endsWith('-1m')) {
126
+ return {
127
+ model: raw.slice(0, -3).trim(),
128
+ syntheticContextWindow: '1m',
129
+ };
130
+ }
131
+ return { model: raw };
132
+ }
133
+ function modelSupportsOneMillionContext(model) {
134
+ const normalized = (model || 'default').trim().toLowerCase();
135
+ if (!normalized || normalized === 'default')
136
+ return true;
137
+ if (normalized === 'opus' || normalized === 'sonnet')
138
+ return true;
139
+ return normalized.includes('claude-opus-4-6') || normalized.includes('claude-sonnet-4-6');
140
+ }
141
+ function buildClaudeLaunchModelArg(model, contextWindow) {
142
+ if (!model)
143
+ return undefined;
144
+ const normalized = normalizeRequestedLaunchModel(model).model;
145
+ if (!normalized)
146
+ return undefined;
147
+ if (contextWindow === '1m' && modelSupportsOneMillionContext(normalized)) {
148
+ return `${normalized}[1m]`;
149
+ }
150
+ return normalized;
151
+ }
152
+ function isTwoHundredKFixedOutputModel(model) {
153
+ const normalized = (model || '').trim().toLowerCase();
154
+ if (!normalized)
155
+ return false;
156
+ if (normalized === 'opus' || normalized === 'sonnet')
157
+ return true;
158
+ return /^claude-(?:opus|sonnet)-4-(?:5|6)(?:$|-)/.test(normalized);
159
+ }
160
+ function resolveClaudeMaxOutputTokens(model, contextWindow) {
161
+ if (process.env.EKKOS_MAX_OUTPUT_TOKENS) {
162
+ return process.env.EKKOS_MAX_OUTPUT_TOKENS;
163
+ }
164
+ if (contextWindow === '200k' && isTwoHundredKFixedOutputModel(model)) {
165
+ return MAX_OUTPUT_200K_OPUS_SONNET;
166
+ }
167
+ return MAX_OUTPUT_1M_MODELS;
168
+ }
169
+ function shouldOpenLaunchSelector(options) {
170
+ return options.model === true;
171
+ }
172
+ function renderClaudeLaunchSelectorIntro() {
173
+ const neonCyan = chalk_1.default.hex('#00f5ff');
174
+ const acidGreen = chalk_1.default.hex('#9dff00');
175
+ const signalAmber = chalk_1.default.hex('#ffb300');
176
+ const steel = chalk_1.default.hex('#8a92a6');
177
+ const width = 68;
178
+ const line = (text) => {
179
+ const pad = Math.max(0, width - stripAnsi(text).length);
180
+ return `${neonCyan('║')} ${text}${' '.repeat(pad)}${neonCyan('║')}`;
181
+ };
182
+ console.log('');
183
+ console.log(neonCyan('╔══════════════════════════════════════════════════════════════════════╗'));
184
+ console.log(line(chalk_1.default.white.bold('ekkOS.dev // PULSE')));
185
+ console.log(neonCyan('╠══════════════════════════════════════════════════════════════════════╣'));
186
+ console.log(line(`${acidGreen('200K')} ${steel('compat lane')} ${chalk_1.default.white('// Opus/Sonnet 4.5/4.6 => 32,768 output')}`));
187
+ console.log(line(`${signalAmber(' 1M')} ${steel('wide lane')} ${chalk_1.default.white('// Opus/Sonnet 4.6 => 128,000 output')}`));
188
+ console.log(line(steel('Pick a launch vector, then a fixed runtime profile. No hidden context prompt.')));
189
+ console.log(neonCyan('╚══════════════════════════════════════════════════════════════════════╝'));
190
+ console.log('');
191
+ }
192
+ function buildLaunchModeChoices() {
193
+ return [
194
+ {
195
+ name: `${chalk_1.default.hex('#00f5ff').bold('Fresh boot')} ${chalk_1.default.gray('// new shell')}`,
196
+ value: 'fresh',
197
+ },
198
+ {
199
+ name: `${chalk_1.default.hex('#9dff00').bold('Resume recent')} ${chalk_1.default.gray('// latest thread')}`,
200
+ value: 'continue',
201
+ },
202
+ {
203
+ name: `${chalk_1.default.hex('#ffb300').bold('Resume by ID')} ${chalk_1.default.gray('// targeted reconnect')}`,
204
+ value: 'resume',
205
+ },
206
+ ];
207
+ }
208
+ function buildLaunchModelChoices() {
209
+ const cyan = chalk_1.default.hex('#00f5ff');
210
+ const amber = chalk_1.default.hex('#ffb300');
211
+ const green = chalk_1.default.hex('#00ff88');
212
+ return [
213
+ {
214
+ name: `${cyan.bold('Auto route')} ${chalk_1.default.gray('// Claude decides profile')}`,
215
+ value: 'default',
216
+ },
217
+ {
218
+ name: `${cyan.bold('Claude Opus 4.5')} ${green('[200K]')} ${chalk_1.default.gray('// out 32,768')}`,
219
+ value: 'claude-opus-4-5',
220
+ },
221
+ {
222
+ name: `${cyan.bold('Claude Opus 4.6')} ${green('[200K]')} ${chalk_1.default.gray('// out 32,768')}`,
223
+ value: 'claude-opus-4-6-200k',
224
+ },
225
+ {
226
+ name: `${cyan.bold('Claude Opus 4.6')} ${amber('[1M]')} ${chalk_1.default.gray('// out 128,000')}`,
227
+ value: 'claude-opus-4-6-1m',
228
+ },
229
+ {
230
+ name: `${cyan.bold('Claude Sonnet 4.5')} ${green('[200K]')} ${chalk_1.default.gray('// out 32,768')}`,
231
+ value: 'claude-sonnet-4-5',
232
+ },
233
+ {
234
+ name: `${cyan.bold('Claude Sonnet 4.6')} ${green('[200K]')} ${chalk_1.default.gray('// out 32,768')}`,
235
+ value: 'claude-sonnet-4-6-200k',
236
+ },
237
+ {
238
+ name: `${cyan.bold('Claude Sonnet 4.6')} ${amber('[1M]')} ${chalk_1.default.gray('// out 128,000')}`,
239
+ value: 'claude-sonnet-4-6-1m',
240
+ },
241
+ {
242
+ name: `${cyan.bold('Claude Haiku 4.5')} ${green('[200K]')} ${chalk_1.default.gray('// fast lane')}`,
243
+ value: 'claude-haiku-4-5',
244
+ },
245
+ ];
246
+ }
247
+ async function resolveClaudeLaunchSelection(options) {
248
+ const requestedModel = normalizeRequestedLaunchModel(typeof options.model === 'string' ? options.model : process.env.EKKOS_CLAUDE_MODEL);
249
+ let model = requestedModel.model;
250
+ let contextWindow = requestedModel.syntheticContextWindow
251
+ || normalizeContextWindowOption(options.contextWindow || process.env.EKKOS_CLAUDE_CONTEXT_WINDOW);
252
+ let continueLast = options.continueLast || false;
253
+ let resumeSession = (options.resumeSession || '').trim();
254
+ const shouldShowLaunchWindow = shouldOpenLaunchSelector(options)
255
+ && process.stdin.isTTY === true
256
+ && process.stdout.isTTY === true
257
+ && process.env.EKKOS_DISABLE_LAUNCH_WINDOW !== '1';
258
+ if (!shouldShowLaunchWindow) {
259
+ if (!modelSupportsOneMillionContext(model)) {
260
+ contextWindow = '200k';
261
+ }
262
+ return {
263
+ model,
264
+ contextWindow,
265
+ continueLast: !!continueLast && !resumeSession,
266
+ resumeSession: resumeSession || undefined,
267
+ };
268
+ }
269
+ const { default: inquirer } = await Promise.resolve().then(() => __importStar(require('inquirer')));
270
+ renderClaudeLaunchSelectorIntro();
271
+ const defaultLaunchMode = resumeSession ? 'resume' : continueLast ? 'continue' : 'fresh';
272
+ const firstPrompt = await inquirer.prompt([
273
+ {
274
+ type: 'list',
275
+ name: 'launchMode',
276
+ message: chalk_1.default.hex('#00f5ff').bold('>> Boot vector'),
277
+ default: defaultLaunchMode,
278
+ pageSize: 3,
279
+ loop: false,
280
+ choices: buildLaunchModeChoices(),
281
+ },
282
+ {
283
+ type: 'list',
284
+ name: 'model',
285
+ message: chalk_1.default.hex('#00f5ff').bold('>> Model lane'),
286
+ default: model || 'default',
287
+ pageSize: 8,
288
+ loop: false,
289
+ choices: buildLaunchModelChoices(),
290
+ },
291
+ ]);
292
+ const selectedProfile = normalizeRequestedLaunchModel(firstPrompt.model);
293
+ model = firstPrompt.model === 'default' ? undefined : selectedProfile.model;
294
+ continueLast = firstPrompt.launchMode === 'continue';
295
+ resumeSession = firstPrompt.launchMode === 'resume' ? resumeSession : '';
296
+ if (firstPrompt.launchMode === 'resume') {
297
+ const resumePrompt = await inquirer.prompt([
298
+ {
299
+ type: 'input',
300
+ name: 'resumeSession',
301
+ message: 'Claude session ID',
302
+ default: resumeSession,
303
+ validate: (value) => value.trim().length > 0 || 'Session ID is required',
304
+ },
305
+ ]);
306
+ resumeSession = resumePrompt.resumeSession.trim();
307
+ }
308
+ if (firstPrompt.model === 'default') {
309
+ contextWindow = 'auto';
310
+ }
311
+ else if (selectedProfile.syntheticContextWindow) {
312
+ contextWindow = selectedProfile.syntheticContextWindow;
313
+ }
314
+ else if (!modelSupportsOneMillionContext(model)) {
315
+ contextWindow = '200k';
316
+ }
317
+ else {
318
+ contextWindow = 'auto';
319
+ }
320
+ return {
321
+ model,
322
+ contextWindow,
323
+ continueLast,
324
+ resumeSession: resumeSession || undefined,
325
+ };
326
+ }
89
327
  // ═══════════════════════════════════════════════════════════════════════════
90
328
  // PATTERN MATCHING
91
329
  // ═══════════════════════════════════════════════════════════════════════════
@@ -291,13 +529,6 @@ const isWindows = os.platform() === 'win32';
291
529
  // Core ekkOS patches (eviction, context management) work with all recent versions
292
530
  // Cosmetic patches may fail on newer versions but don't affect functionality
293
531
  const PINNED_CLAUDE_VERSION = 'latest';
294
- // Max output tokens for Claude responses
295
- // Default: 128000 (Opus 4.6 / Sonnet 4.6 max output)
296
- // Override via EKKOS_MAX_OUTPUT_TOKENS env var if needed
297
- // Note: Claude Code has a known bug where CLAUDE_CODE_MAX_OUTPUT_TOKENS is ignored on Opus 4.6
298
- // (see github.com/anthropics/claude-code/issues/24159). We set it anyway + the proxy also
299
- // enforces this via max_tokens override on the API request.
300
- const EKKOS_MAX_OUTPUT_TOKENS = process.env.EKKOS_MAX_OUTPUT_TOKENS || '128000';
301
532
  const proxy_url_1 = require("../utils/proxy-url");
302
533
  // Track proxy mode for getEkkosEnv (set by run() based on options)
303
534
  let proxyModeEnabled = true;
@@ -318,12 +549,13 @@ let cliSessionName = null;
318
549
  let cliSessionId = null;
319
550
  /**
320
551
  * Get environment with ekkOS enhancements
321
- * - Sets CLAUDE_CODE_MAX_OUTPUT_TOKENS to 128K (API max for Opus/Sonnet 4.6)
552
+ * - Sets CLAUDE_CODE_MAX_OUTPUT_TOKENS dynamically for the selected Claude profile
322
553
  * - Routes API through ekkOS proxy for seamless context eviction (when enabled)
323
554
  * - Sets EKKOS_PROXY_MODE to signal JSONL rewriter to disable eviction
324
555
  * - Passes session headers for eviction/retrieval context tracking
325
556
  */
326
557
  function getEkkosEnv() {
558
+ const maxOutputTokens = resolveClaudeMaxOutputTokens(runtimeClaudeLaunchModel, runtimeClaudeContextWindow);
327
559
  /* eslint-disable no-restricted-syntax -- System env spreading, not API key access */
328
560
  const env = {
329
561
  ...process.env,
@@ -335,13 +567,18 @@ function getEkkosEnv() {
335
567
  // Native autocompact would compact without ekkOS saving state first, causing knowledge loss.
336
568
  // Only ekkOS-wrapped sessions get this; vanilla `claude` keeps autocompact on.
337
569
  DISABLE_AUTO_COMPACT: 'true',
338
- // Set max output tokens to 128K (Opus 4.6 / Sonnet 4.6 API max).
339
- // Note: Claude Code has a known bug where this env var is ignored on Opus 4.6
340
- // (github.com/anthropics/claude-code/issues/24159). The proxy also enforces
341
- // this by overriding max_tokens on the API request as a fallback.
342
- CLAUDE_CODE_MAX_OUTPUT_TOKENS: EKKOS_MAX_OUTPUT_TOKENS,
570
+ // Align Claude's advertised output ceiling with the chosen model/context profile.
571
+ // 1M Opus/Sonnet gets 128K; 200K Opus/Sonnet 4.5/4.6 is forced to 32,768.
572
+ // The proxy also enforces this server-side in case Claude Code ignores the env var.
573
+ CLAUDE_CODE_MAX_OUTPUT_TOKENS: maxOutputTokens,
343
574
  };
344
575
  /* eslint-enable no-restricted-syntax */
576
+ if (runtimeClaudeContextWindow === '200k') {
577
+ env.CLAUDE_CODE_DISABLE_1M_CONTEXT = '1';
578
+ }
579
+ else {
580
+ delete env.CLAUDE_CODE_DISABLE_1M_CONTEXT;
581
+ }
345
582
  // Check if proxy is disabled via env var or options
346
583
  // eslint-disable-next-line no-restricted-syntax -- Feature flag, not API key
347
584
  const proxyDisabled = process.env.EKKOS_DISABLE_PROXY === '1' || !proxyModeEnabled;
@@ -354,7 +591,9 @@ function getEkkosEnv() {
354
591
  if (!cliSessionName) {
355
592
  cliSessionId = crypto.randomUUID();
356
593
  cliSessionName = (0, state_1.uuidToWords)(cliSessionId);
357
- console.log(chalk_1.default.gray(` 📂 Session: ${cliSessionName}`));
594
+ if (process.env.EKKOS_NO_SPLASH !== '1') {
595
+ console.log(chalk_1.default.gray(` 📂 Session: ${cliSessionName}`));
596
+ }
358
597
  }
359
598
  // Get full userId from config (NOT the truncated version from auth token)
360
599
  // Config has full UUID like "d4532ba0-0a86-42ce-bab4-22aa62b55ce6"
@@ -374,7 +613,10 @@ function getEkkosEnv() {
374
613
  // CRITICAL: Embed user/session in URL path since ANTHROPIC_HEADERS doesn't work
375
614
  // Claude Code SDK doesn't forward custom headers, but it DOES use ANTHROPIC_BASE_URL
376
615
  // Gateway extracts from URL: /proxy/{userId}/{sessionName}/v1/messages
377
- const proxyUrl = (0, proxy_url_1.buildProxyUrl)(userId, cliSessionName, process.cwd(), cliSessionId);
616
+ const proxyUrl = (0, proxy_url_1.buildProxyUrl)(userId, cliSessionName, process.cwd(), cliSessionId, {
617
+ claudeCodeVersion: runtimeClaudeCodeVersion || undefined,
618
+ claudeContextWindow: runtimeClaudeContextWindow,
619
+ });
378
620
  env.ANTHROPIC_BASE_URL = proxyUrl;
379
621
  // Proxy URL contains userId + project path — don't leak to terminal
380
622
  }
@@ -585,6 +827,105 @@ function resolveGlobalClaudePath() {
585
827
  function sleep(ms) {
586
828
  return new Promise(resolve => setTimeout(resolve, ms));
587
829
  }
830
+ function formatPulseLaunchMode(options) {
831
+ if (options.resumeSession)
832
+ return `RESUME // ${options.resumeSession}`;
833
+ if (options.continueLast)
834
+ return 'CONTINUE // most recent Claude thread';
835
+ return 'FRESH // new interactive shell';
836
+ }
837
+ function formatPulseModel(model) {
838
+ const normalized = (model || '').trim().toLowerCase();
839
+ if (!normalized)
840
+ return 'Claude default';
841
+ if (normalized === 'opus')
842
+ return 'Opus alias';
843
+ if (normalized === 'sonnet')
844
+ return 'Sonnet alias';
845
+ if (normalized === 'claude-opus-4-5')
846
+ return 'Claude Opus 4.5';
847
+ if (normalized === 'claude-opus-4-6')
848
+ return 'Claude Opus 4.6';
849
+ if (normalized === 'claude-sonnet-4-5')
850
+ return 'Claude Sonnet 4.5';
851
+ if (normalized === 'claude-sonnet-4-6')
852
+ return 'Claude Sonnet 4.6';
853
+ if (normalized === 'claude-haiku-4-5')
854
+ return 'Claude Haiku 4.5';
855
+ return model || 'Claude default';
856
+ }
857
+ function formatPulseContextLine(contextWindow) {
858
+ if (contextWindow === '200k') {
859
+ return '200K // 200,000 token window // forced 32,768 output';
860
+ }
861
+ if (contextWindow === '1m') {
862
+ return '1M // 1,000,000 token window // unlocked 128,000 output';
863
+ }
864
+ return 'AUTO // ekkOS resolves 200K vs 1M from the selected profile';
865
+ }
866
+ async function showPulseLaunchLoader(options) {
867
+ const cyan = chalk_1.default.hex('#00f0ff');
868
+ const amber = chalk_1.default.hex('#ffb800');
869
+ const green = chalk_1.default.hex('#00ff88');
870
+ const steel = chalk_1.default.hex('#7a7a8e');
871
+ const panel = chalk_1.default.hex('#111118');
872
+ const wordmark = [
873
+ '██████╗ ██╗ ██╗██╗ ███████╗███████╗',
874
+ '██╔══██╗██║ ██║██║ ██╔════╝██╔════╝',
875
+ '██████╔╝██║ ██║██║ ███████╗█████╗ ',
876
+ '██╔═══╝ ██║ ██║██║ ╚════██║██╔══╝ ',
877
+ '██║ ╚██████╔╝███████╗███████║███████╗',
878
+ '╚═╝ ╚═════╝ ╚══════╝╚══════╝╚══════╝',
879
+ ];
880
+ const stages = [
881
+ 'arming pulse launcher',
882
+ 'syncing dashboard split',
883
+ 'routing claude session',
884
+ ];
885
+ const barWidth = 26;
886
+ const panelInnerWidth = 76;
887
+ const buildPanelLine = (labelColor, label, value) => {
888
+ const content = ` ${label.padEnd(7)} ${value}`;
889
+ const pad = Math.max(0, panelInnerWidth - stripAnsi(content).length);
890
+ return ` ${cyan('║')} ${labelColor(label.padEnd(7))} ${chalk_1.default.white(value)}${' '.repeat(pad)}${cyan('║')}`;
891
+ };
892
+ const headerContent = ' ekkOS.dev // PULSE BOOTSTRAP live launch matrix for Claude + dashboard';
893
+ const headerPad = Math.max(0, panelInnerWidth - headerContent.length);
894
+ console.log('');
895
+ for (const [idx, line] of wordmark.entries()) {
896
+ const color = idx % 2 === 0 ? cyan.bold : chalk_1.default.white.bold;
897
+ console.log(' ' + color(line));
898
+ await sleep(22);
899
+ }
900
+ console.log(' ' + amber('▔').repeat(54));
901
+ console.log(cyan(' ╔══════════════════════════════════════════════════════════════════════════════╗'));
902
+ console.log(` ${cyan('║')}${chalk_1.default.white.bold(' ekkOS.dev // PULSE BOOTSTRAP')}${steel(' live launch matrix for Claude + dashboard')}${' '.repeat(headerPad)}${cyan('║')}`);
903
+ console.log(buildPanelLine(green, 'MODE', formatPulseLaunchMode(options)));
904
+ console.log(buildPanelLine(green, 'MODEL', formatPulseModel(typeof options.model === 'string' ? options.model : undefined)));
905
+ console.log(buildPanelLine(amber, 'WINDOW', formatPulseContextLine(normalizeContextWindowOption(options.contextWindow))));
906
+ console.log(buildPanelLine(steel, 'PATH', 'selector -> dashboard -> claude -> proxy'));
907
+ console.log(cyan(' ╚══════════════════════════════════════════════════════════════════════════════╝'));
908
+ console.log(` ${green('200K')} ${steel('// Opus/Sonnet 4.5/4.6 => 32,768 output')}`);
909
+ console.log(` ${amber('1M ')} ${steel('// Opus/Sonnet 4.6 => 128,000 output')}`);
910
+ console.log('');
911
+ for (const stage of stages) {
912
+ for (let filled = 0; filled <= barWidth; filled += 1) {
913
+ const complete = '█'.repeat(filled);
914
+ const pending = '░'.repeat(barWidth - filled);
915
+ process.stdout.write(`\r ${amber('[')}${cyan(complete)}${steel(pending)}${amber(']')} ${chalk_1.default.white(stage)}`);
916
+ await sleep(16);
917
+ }
918
+ process.stdout.write('\n');
919
+ }
920
+ console.log(` ${green('READY')} ${panel('dashboard split armed')} ${steel('// selector handoff imminent')}`);
921
+ if (options.bypass) {
922
+ console.log(` ${amber('BYPASS')} ${chalk_1.default.white('permission prompts disabled for this launch')}`);
923
+ }
924
+ if (options.verbose) {
925
+ console.log(` ${steel('TRACE')} ${steel('verbose telemetry enabled')}`);
926
+ }
927
+ console.log('');
928
+ }
588
929
  /**
589
930
  * Show morning dreams with WOW factor right after sparkle animation.
590
931
  * Colorful, lively, readable — real magic moment. Then pause for Enter.
@@ -844,6 +1185,15 @@ function launchWithDashboard(options) {
844
1185
  runArgs.push('--skip-inject');
845
1186
  if (options.noProxy)
846
1187
  runArgs.push('--skip-proxy');
1188
+ if (options.continueLast)
1189
+ runArgs.push('--continue-last');
1190
+ if (options.resumeSession)
1191
+ runArgs.push('--resume-session', options.resumeSession);
1192
+ if (typeof options.model === 'string')
1193
+ runArgs.push('--model', options.model);
1194
+ if (options.contextWindow && options.contextWindow !== 'auto') {
1195
+ runArgs.push('--context-window', options.contextWindow);
1196
+ }
847
1197
  const ekkosCmd = process.argv[1]; // Path to ekkos CLI
848
1198
  const cwd = process.cwd();
849
1199
  const termCols = process.stdout.columns ?? 160;
@@ -929,6 +1279,15 @@ function launchWithWindowsTerminal(options) {
929
1279
  runArgs.push('--skip-inject');
930
1280
  if (options.noProxy)
931
1281
  runArgs.push('--skip-proxy');
1282
+ if (options.continueLast)
1283
+ runArgs.push('--continue-last');
1284
+ if (options.resumeSession)
1285
+ runArgs.push('--resume-session', options.resumeSession);
1286
+ if (typeof options.model === 'string')
1287
+ runArgs.push('--model', options.model);
1288
+ if (options.contextWindow && options.contextWindow !== 'auto') {
1289
+ runArgs.push('--context-window', options.contextWindow);
1290
+ }
932
1291
  // Write a temp batch file to avoid all quoting issues
933
1292
  // wt.exe doesn't resolve PATH for npm global bins — must use `cmd /c`
934
1293
  const batPath = path.join(os.tmpdir(), `ekkos-wt-${Date.now()}.cmd`);
@@ -976,6 +1335,14 @@ async function run(options) {
976
1335
  const verbose = options.verbose || false;
977
1336
  const bypass = options.bypass || false;
978
1337
  const noInject = options.noInject || false;
1338
+ const suppressPreClaudeOutput = process.env.EKKOS_NO_SPLASH === '1';
1339
+ const launchSelection = await resolveClaudeLaunchSelection(options);
1340
+ options.model = launchSelection.model;
1341
+ options.contextWindow = launchSelection.contextWindow;
1342
+ options.continueLast = launchSelection.continueLast;
1343
+ options.resumeSession = launchSelection.resumeSession;
1344
+ runtimeClaudeLaunchModel = launchSelection.model;
1345
+ runtimeClaudeContextWindow = launchSelection.contextWindow;
979
1346
  // Honour -s flag: lock the session name before getEkkosEnv() can mint a new one.
980
1347
  // This is critical for --dashboard mode where launchWithDashboard() pre-generates
981
1348
  // a session name and passes it via -s so the dashboard and run command agree.
@@ -986,11 +1353,28 @@ async function run(options) {
986
1353
  // Set proxy mode based on options (used by getEkkosEnv)
987
1354
  proxyModeEnabled = !(options.noProxy || false);
988
1355
  if (proxyModeEnabled) {
989
- console.log(chalk_1.default.cyan(' 🧠 ekkOS_Continuum Loaded!'));
1356
+ if (!suppressPreClaudeOutput && !options.pulse) {
1357
+ console.log(chalk_1.default.cyan(' 🧠 ekkOS_Continuum Loaded!'));
1358
+ }
990
1359
  }
991
- else if (verbose) {
1360
+ else if (verbose && !suppressPreClaudeOutput) {
992
1361
  console.log(chalk_1.default.yellow(' ⏭️ API proxy disabled (--no-proxy)'));
993
1362
  }
1363
+ let pulseIntroShown = false;
1364
+ if (options.pulse
1365
+ && process.env.EKKOS_REMOTE_SESSION !== '1'
1366
+ && process.env.EKKOS_NO_SPLASH !== '1'
1367
+ && process.stdout.isTTY === true) {
1368
+ await showPulseLaunchLoader({
1369
+ model: options.model,
1370
+ contextWindow: options.contextWindow,
1371
+ continueLast: options.continueLast,
1372
+ resumeSession: options.resumeSession,
1373
+ bypass: options.bypass,
1374
+ verbose: options.verbose,
1375
+ });
1376
+ pulseIntroShown = true;
1377
+ }
994
1378
  // ══════════════════════════════════════════════════════════════════════════
995
1379
  // DASHBOARD MODE: Launch via tmux (Unix) or Windows Terminal split pane
996
1380
  // ══════════════════════════════════════════════════════════════════════════
@@ -1079,11 +1463,22 @@ async function run(options) {
1079
1463
  const isNpxMode = rawClaudePath.startsWith('npx:');
1080
1464
  const pinnedVersion = isNpxMode ? rawClaudePath.split(':')[1] : null;
1081
1465
  const claudePath = isNpxMode ? 'npx' : rawClaudePath;
1466
+ runtimeClaudeCodeVersion = pinnedVersion || getClaudeVersion(claudePath);
1082
1467
  // Build args early
1083
1468
  const earlyArgs = [];
1084
1469
  if (isNpxMode) {
1085
1470
  earlyArgs.push(`@anthropic-ai/claude-code@${pinnedVersion}`);
1086
1471
  }
1472
+ if (options.resumeSession) {
1473
+ earlyArgs.push('--resume', options.resumeSession);
1474
+ }
1475
+ else if (options.continueLast) {
1476
+ earlyArgs.push('--continue');
1477
+ }
1478
+ const launchModelArg = buildClaudeLaunchModelArg(options.model, options.contextWindow);
1479
+ if (launchModelArg) {
1480
+ earlyArgs.push('--model', launchModelArg);
1481
+ }
1087
1482
  if (bypass) {
1088
1483
  earlyArgs.push('--dangerously-skip-permissions');
1089
1484
  }
@@ -1146,7 +1541,7 @@ async function run(options) {
1146
1541
  // ══════════════════════════════════════════════════════════════════════════
1147
1542
  // STARTUP BANNER WITH COLOR PULSE ANIMATION
1148
1543
  // ══════════════════════════════════════════════════════════════════════════
1149
- const skipFancyIntro = process.env.EKKOS_REMOTE_SESSION === '1' || process.env.EKKOS_NO_SPLASH === '1' || !!process.env.TMUX;
1544
+ const skipFancyIntro = pulseIntroShown || process.env.EKKOS_REMOTE_SESSION === '1' || suppressPreClaudeOutput || !!process.env.TMUX;
1150
1545
  if (!skipFancyIntro) {
1151
1546
  const logoLines = [
1152
1547
  ' ▄▄▄▄▄ ▄▄▄▄▄▄▄ ▄▄▄ ▄▄ ▄▄',
@@ -1328,7 +1723,7 @@ async function run(options) {
1328
1723
  }
1329
1724
  console.log('');
1330
1725
  }
1331
- else {
1726
+ else if (!suppressPreClaudeOutput) {
1332
1727
  // Static banner for Windows / remote / no-splash — no cursor manipulation
1333
1728
  console.log('');
1334
1729
  console.log(chalk_1.default.hex('#FF6B35').bold(' ekkOS_Pulse') + chalk_1.default.gray(' — Context is finite. Intelligence isn\'t.'));
@@ -1344,7 +1739,9 @@ async function run(options) {
1344
1739
  // ══════════════════════════════════════════════════════════════════════════
1345
1740
  // MAGIC MOMENT: Morning dreams right after sparkle, before Claude appears
1346
1741
  // ══════════════════════════════════════════════════════════════════════════
1347
- await showMorningDreamsIfNeeded();
1742
+ if (!suppressPreClaudeOutput && !options.pulse) {
1743
+ await showMorningDreamsIfNeeded();
1744
+ }
1348
1745
  // ══════════════════════════════════════════════════════════════════════════
1349
1746
  // ANIMATION COMPLETE: Mark ready and flush buffered Claude output
1350
1747
  // ══════════════════════════════════════════════════════════════════════════
@@ -1835,9 +2232,21 @@ async function run(options) {
1835
2232
  }
1836
2233
  if (verbose) {
1837
2234
  // Show Claude version
1838
- const ccVersion = pinnedVersion || PINNED_CLAUDE_VERSION;
2235
+ const ccVersion = runtimeClaudeCodeVersion || pinnedVersion || PINNED_CLAUDE_VERSION;
1839
2236
  const versionStr = `Claude Code v${ccVersion}`;
1840
2237
  console.log(chalk_1.default.gray(` 🤖 ${versionStr}`));
2238
+ if (options.model) {
2239
+ console.log(chalk_1.default.gray(` 🧩 Model: ${buildClaudeLaunchModelArg(options.model, options.contextWindow)}`));
2240
+ }
2241
+ if (options.contextWindow && options.contextWindow !== 'auto') {
2242
+ console.log(chalk_1.default.gray(` 🪟 Context: ${options.contextWindow}`));
2243
+ }
2244
+ if (options.continueLast) {
2245
+ console.log(chalk_1.default.gray(' ↩ Continue: most recent Claude conversation'));
2246
+ }
2247
+ if (options.resumeSession) {
2248
+ console.log(chalk_1.default.gray(` ↪ Resume: ${options.resumeSession}`));
2249
+ }
1841
2250
  if (currentSession) {
1842
2251
  console.log(chalk_1.default.green(` 📍 Session: ${currentSession}`));
1843
2252
  }