maxsimcli 1.0.5 → 1.0.7

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.
package/dist/install.js CHANGED
@@ -32,19 +32,18 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
35
38
  Object.defineProperty(exports, "__esModule", { value: true });
36
39
  const fs = __importStar(require("node:fs"));
37
40
  const path = __importStar(require("node:path"));
38
41
  const os = __importStar(require("node:os"));
39
- const readline = __importStar(require("node:readline"));
40
42
  const crypto = __importStar(require("node:crypto"));
43
+ const chalk_1 = __importDefault(require("chalk"));
44
+ const ora_1 = __importDefault(require("ora"));
45
+ const prompts_1 = require("@inquirer/prompts");
41
46
  const adapters_1 = require("@maxsim/adapters");
42
- // Colors
43
- const cyan = '\x1b[36m';
44
- const green = '\x1b[32m';
45
- const yellow = '\x1b[33m';
46
- const dim = '\x1b[2m';
47
- const reset = '\x1b[0m';
48
47
  // Get version from package.json
49
48
  // eslint-disable-next-line @typescript-eslint/no-require-imports
50
49
  const pkg = require('../package.json');
@@ -120,21 +119,16 @@ function getOpencodeGlobalDir() {
120
119
  return adapters_1.opencodeAdapter.getGlobalDir();
121
120
  }
122
121
  const banner = '\n' +
123
- cyan +
124
- ' \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\n' +
125
- ' \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u255a\u2588\u2588\u2557\u2588\u2588\u2554\u255d\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255d\u2588\u2588\u2551\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2551\n' +
126
- ' \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551 \u255a\u2588\u2588\u2588\u2554\u255d \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\n' +
127
- ' \u2588\u2588\u2551\u255a\u2588\u2588\u2554\u255d\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551 \u2588\u2588\u2554\u2588\u2588\u2557 \u255a\u2550\u2550\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551\u255a\u2588\u2588\u2554\u255d\u2588\u2588\u2551\n' +
128
- ' \u2588\u2588\u2551 \u255a\u2550\u255d \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u255d \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551 \u255a\u2550\u255d \u2588\u2588\u2551\n' +
129
- ' \u255a\u2550\u255d \u255a\u2550\u255d\u255a\u2550\u255d \u255a\u2550\u255d\u255a\u2550\u255d \u255a\u2550\u255d\u255a\u2550\u2550\u2550\u2550\u2550\u2550\u255d\u255a\u2550\u255d\u255a\u2550\u255d \u255a\u2550\u255d' +
130
- reset +
122
+ chalk_1.default.cyan(' \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\n' +
123
+ ' \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u255a\u2588\u2588\u2557\u2588\u2588\u2554\u255d\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255d\u2588\u2588\u2551\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2551\n' +
124
+ ' \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551 \u255a\u2588\u2588\u2588\u2554\u255d \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\n' +
125
+ ' \u2588\u2588\u2551\u255a\u2588\u2588\u2554\u255d\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551 \u2588\u2588\u2554\u2588\u2588\u2557 \u255a\u2550\u2550\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551\u255a\u2588\u2588\u2554\u255d\u2588\u2588\u2551\n' +
126
+ ' \u2588\u2588\u2551 \u255a\u2550\u255d \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u255d \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551 \u255a\u2550\u255d \u2588\u2588\u2551\n' +
127
+ ' \u255a\u2550\u255d \u255a\u2550\u255d\u255a\u2550\u255d \u255a\u2550\u255d\u255a\u2550\u255d \u255a\u2550\u255d\u255a\u2550\u2550\u2550\u2550\u2550\u2550\u255d\u255a\u2550\u255d\u255a\u2550\u255d \u255a\u2550\u255d') +
131
128
  '\n' +
132
129
  '\n' +
133
130
  ' MAXSIM ' +
134
- dim +
135
- 'v' +
136
- pkg.version +
137
- reset +
131
+ chalk_1.default.dim('v' + pkg.version) +
138
132
  '\n' +
139
133
  ' A meta-prompting, context engineering and spec-driven\n' +
140
134
  ' development system for Claude Code, OpenCode, Gemini, and Codex.\n';
@@ -144,7 +138,7 @@ function parseConfigDirArg() {
144
138
  if (configDirIndex !== -1) {
145
139
  const nextArg = args[configDirIndex + 1];
146
140
  if (!nextArg || nextArg.startsWith('-')) {
147
- console.error(` ${yellow}--config-dir requires a path argument${reset}`);
141
+ console.error(` ${chalk_1.default.yellow('--config-dir requires a path argument')}`);
148
142
  process.exit(1);
149
143
  }
150
144
  return nextArg;
@@ -153,7 +147,7 @@ function parseConfigDirArg() {
153
147
  if (configDirArg) {
154
148
  const value = configDirArg.split('=')[1];
155
149
  if (!value) {
156
- console.error(` ${yellow}--config-dir requires a non-empty path${reset}`);
150
+ console.error(` ${chalk_1.default.yellow('--config-dir requires a non-empty path')}`);
157
151
  process.exit(1);
158
152
  }
159
153
  return value;
@@ -166,7 +160,7 @@ const forceStatusline = args.includes('--force-statusline');
166
160
  console.log(banner);
167
161
  // Show help if requested
168
162
  if (hasHelp) {
169
- console.log(` ${yellow}Usage:${reset} npx maxsimcli [options]\n\n ${yellow}Options:${reset}\n ${cyan}-g, --global${reset} Install globally (to config directory)\n ${cyan}-l, --local${reset} Install locally (to current directory)\n ${cyan}--claude${reset} Install for Claude Code only\n ${cyan}--opencode${reset} Install for OpenCode only\n ${cyan}--gemini${reset} Install for Gemini only\n ${cyan}--codex${reset} Install for Codex only\n ${cyan}--all${reset} Install for all runtimes\n ${cyan}-u, --uninstall${reset} Uninstall MAXSIM (remove all MAXSIM files)\n ${cyan}-c, --config-dir <path>${reset} Specify custom config directory\n ${cyan}-h, --help${reset} Show this help message\n ${cyan}--force-statusline${reset} Replace existing statusline config\n\n ${yellow}Examples:${reset}\n ${dim}# Interactive install (prompts for runtime and location)${reset}\n npx maxsimcli\n\n ${dim}# Install for Claude Code globally${reset}\n npx maxsimcli --claude --global\n\n ${dim}# Install for Gemini globally${reset}\n npx maxsimcli --gemini --global\n\n ${dim}# Install for Codex globally${reset}\n npx maxsimcli --codex --global\n\n ${dim}# Install for all runtimes globally${reset}\n npx maxsimcli --all --global\n\n ${dim}# Install to custom config directory${reset}\n npx maxsimcli --codex --global --config-dir ~/.codex-work\n\n ${dim}# Install to current project only${reset}\n npx maxsimcli --claude --local\n\n ${dim}# Uninstall MAXSIM from Codex globally${reset}\n npx maxsimcli --codex --global --uninstall\n\n ${yellow}Notes:${reset}\n The --config-dir option is useful when you have multiple configurations.\n It takes priority over CLAUDE_CONFIG_DIR / GEMINI_CONFIG_DIR / CODEX_HOME environment variables.\n`);
163
+ console.log(` ${chalk_1.default.yellow('Usage:')} npx maxsimcli [options]\n\n ${chalk_1.default.yellow('Options:')}\n ${chalk_1.default.cyan('-g, --global')} Install globally (to config directory)\n ${chalk_1.default.cyan('-l, --local')} Install locally (to current directory)\n ${chalk_1.default.cyan('--claude')} Install for Claude Code only\n ${chalk_1.default.cyan('--opencode')} Install for OpenCode only\n ${chalk_1.default.cyan('--gemini')} Install for Gemini only\n ${chalk_1.default.cyan('--codex')} Install for Codex only\n ${chalk_1.default.cyan('--all')} Install for all runtimes\n ${chalk_1.default.cyan('-u, --uninstall')} Uninstall MAXSIM (remove all MAXSIM files)\n ${chalk_1.default.cyan('-c, --config-dir <path>')} Specify custom config directory\n ${chalk_1.default.cyan('-h, --help')} Show this help message\n ${chalk_1.default.cyan('--force-statusline')} Replace existing statusline config\n\n ${chalk_1.default.yellow('Examples:')}\n ${chalk_1.default.dim('# Interactive install (prompts for runtime and location)')}\n npx maxsimcli\n\n ${chalk_1.default.dim('# Install for Claude Code globally')}\n npx maxsimcli --claude --global\n\n ${chalk_1.default.dim('# Install for Gemini globally')}\n npx maxsimcli --gemini --global\n\n ${chalk_1.default.dim('# Install for Codex globally')}\n npx maxsimcli --codex --global\n\n ${chalk_1.default.dim('# Install for all runtimes globally')}\n npx maxsimcli --all --global\n\n ${chalk_1.default.dim('# Install to custom config directory')}\n npx maxsimcli --codex --global --config-dir ~/.codex-work\n\n ${chalk_1.default.dim('# Install to current project only')}\n npx maxsimcli --claude --local\n\n ${chalk_1.default.dim('# Uninstall MAXSIM from Codex globally')}\n npx maxsimcli --codex --global --uninstall\n\n ${chalk_1.default.yellow('Notes:')}\n The --config-dir option is useful when you have multiple configurations.\n It takes priority over CLAUDE_CONFIG_DIR / GEMINI_CONFIG_DIR / CODEX_HOME environment variables.\n`);
170
164
  process.exit(0);
171
165
  }
172
166
  // Cache for attribution settings (populated once per runtime during install)
@@ -377,7 +371,7 @@ function cleanupOrphanedFiles(configDir) {
377
371
  const fullPath = path.join(configDir, relPath);
378
372
  if (fs.existsSync(fullPath)) {
379
373
  fs.unlinkSync(fullPath);
380
- console.log(` ${green}\u2713${reset} Removed orphaned ${relPath}`);
374
+ console.log(` ${chalk_1.default.green('\u2713')} Removed orphaned ${relPath}`);
381
375
  }
382
376
  }
383
377
  }
@@ -414,7 +408,7 @@ function cleanupOrphanedHooks(settings) {
414
408
  }
415
409
  }
416
410
  if (cleanedHooks) {
417
- console.log(` ${green}\u2713${reset} Removed orphaned hook registrations`);
411
+ console.log(` ${chalk_1.default.green('\u2713')} Removed orphaned hook registrations`);
418
412
  }
419
413
  const statusLine = settings.statusLine;
420
414
  if (statusLine &&
@@ -422,7 +416,7 @@ function cleanupOrphanedHooks(settings) {
422
416
  statusLine.command.includes('statusline.js') &&
423
417
  !statusLine.command.includes('maxsim-statusline.js')) {
424
418
  statusLine.command = statusLine.command.replace(/statusline\.js/, 'maxsim-statusline.js');
425
- console.log(` ${green}\u2713${reset} Updated statusline path (statusline.js \u2192 maxsim-statusline.js)`);
419
+ console.log(` ${chalk_1.default.green('\u2713')} Updated statusline path (statusline.js \u2192 maxsim-statusline.js)`);
426
420
  }
427
421
  return settings;
428
422
  }
@@ -446,9 +440,9 @@ function uninstall(isGlobal, runtime = 'claude') {
446
440
  runtimeLabel = 'Gemini';
447
441
  if (runtime === 'codex')
448
442
  runtimeLabel = 'Codex';
449
- console.log(` Uninstalling MAXSIM from ${cyan}${runtimeLabel}${reset} at ${cyan}${locationLabel}${reset}\n`);
443
+ console.log(` Uninstalling MAXSIM from ${chalk_1.default.cyan(runtimeLabel)} at ${chalk_1.default.cyan(locationLabel)}\n`);
450
444
  if (!fs.existsSync(targetDir)) {
451
- console.log(` ${yellow}\u26a0${reset} Directory does not exist: ${locationLabel}`);
445
+ console.log(` ${chalk_1.default.yellow('\u26a0')} Directory does not exist: ${locationLabel}`);
452
446
  console.log(` Nothing to uninstall.\n`);
453
447
  return;
454
448
  }
@@ -464,7 +458,7 @@ function uninstall(isGlobal, runtime = 'claude') {
464
458
  removedCount++;
465
459
  }
466
460
  }
467
- console.log(` ${green}\u2713${reset} Removed MAXSIM commands from command/`);
461
+ console.log(` ${chalk_1.default.green('\u2713')} Removed MAXSIM commands from command/`);
468
462
  }
469
463
  }
470
464
  else if (isCodex) {
@@ -480,7 +474,7 @@ function uninstall(isGlobal, runtime = 'claude') {
480
474
  }
481
475
  if (skillCount > 0) {
482
476
  removedCount++;
483
- console.log(` ${green}\u2713${reset} Removed ${skillCount} Codex skills`);
477
+ console.log(` ${chalk_1.default.green('\u2713')} Removed ${skillCount} Codex skills`);
484
478
  }
485
479
  }
486
480
  }
@@ -489,7 +483,7 @@ function uninstall(isGlobal, runtime = 'claude') {
489
483
  if (fs.existsSync(maxsimCommandsDir)) {
490
484
  fs.rmSync(maxsimCommandsDir, { recursive: true });
491
485
  removedCount++;
492
- console.log(` ${green}\u2713${reset} Removed commands/maxsim/`);
486
+ console.log(` ${chalk_1.default.green('\u2713')} Removed commands/maxsim/`);
493
487
  }
494
488
  }
495
489
  // 2. Remove maxsim directory
@@ -497,7 +491,7 @@ function uninstall(isGlobal, runtime = 'claude') {
497
491
  if (fs.existsSync(maxsimDir)) {
498
492
  fs.rmSync(maxsimDir, { recursive: true });
499
493
  removedCount++;
500
- console.log(` ${green}\u2713${reset} Removed maxsim/`);
494
+ console.log(` ${chalk_1.default.green('\u2713')} Removed maxsim/`);
501
495
  }
502
496
  // 3. Remove MAXSIM agents
503
497
  const agentsDir = path.join(targetDir, 'agents');
@@ -512,7 +506,7 @@ function uninstall(isGlobal, runtime = 'claude') {
512
506
  }
513
507
  if (agentCount > 0) {
514
508
  removedCount++;
515
- console.log(` ${green}\u2713${reset} Removed ${agentCount} MAXSIM agents`);
509
+ console.log(` ${chalk_1.default.green('\u2713')} Removed ${agentCount} MAXSIM agents`);
516
510
  }
517
511
  }
518
512
  // 4. Remove MAXSIM hooks
@@ -534,7 +528,7 @@ function uninstall(isGlobal, runtime = 'claude') {
534
528
  }
535
529
  if (hookCount > 0) {
536
530
  removedCount++;
537
- console.log(` ${green}\u2713${reset} Removed ${hookCount} MAXSIM hooks`);
531
+ console.log(` ${chalk_1.default.green('\u2713')} Removed ${hookCount} MAXSIM hooks`);
538
532
  }
539
533
  }
540
534
  // 5. Remove MAXSIM package.json (CommonJS mode marker)
@@ -545,7 +539,7 @@ function uninstall(isGlobal, runtime = 'claude') {
545
539
  if (content === '{"type":"commonjs"}') {
546
540
  fs.unlinkSync(pkgJsonPath);
547
541
  removedCount++;
548
- console.log(` ${green}\u2713${reset} Removed MAXSIM package.json`);
542
+ console.log(` ${chalk_1.default.green('\u2713')} Removed MAXSIM package.json`);
549
543
  }
550
544
  }
551
545
  catch {
@@ -563,7 +557,7 @@ function uninstall(isGlobal, runtime = 'claude') {
563
557
  statusLine.command.includes('maxsim-statusline')) {
564
558
  delete settings.statusLine;
565
559
  settingsModified = true;
566
- console.log(` ${green}\u2713${reset} Removed MAXSIM statusline from settings`);
560
+ console.log(` ${chalk_1.default.green('\u2713')} Removed MAXSIM statusline from settings`);
567
561
  }
568
562
  const settingsHooks = settings.hooks;
569
563
  if (settingsHooks && settingsHooks.SessionStart) {
@@ -579,7 +573,7 @@ function uninstall(isGlobal, runtime = 'claude') {
579
573
  });
580
574
  if (settingsHooks.SessionStart.length < before) {
581
575
  settingsModified = true;
582
- console.log(` ${green}\u2713${reset} Removed MAXSIM hooks from settings`);
576
+ console.log(` ${chalk_1.default.green('\u2713')} Removed MAXSIM hooks from settings`);
583
577
  }
584
578
  if (settingsHooks.SessionStart.length === 0) {
585
579
  delete settingsHooks.SessionStart;
@@ -597,7 +591,7 @@ function uninstall(isGlobal, runtime = 'claude') {
597
591
  });
598
592
  if (settingsHooks.PostToolUse.length < before) {
599
593
  settingsModified = true;
600
- console.log(` ${green}\u2713${reset} Removed context monitor hook from settings`);
594
+ console.log(` ${chalk_1.default.green('\u2713')} Removed context monitor hook from settings`);
601
595
  }
602
596
  if (settingsHooks.PostToolUse.length === 0) {
603
597
  delete settingsHooks.PostToolUse;
@@ -644,7 +638,7 @@ function uninstall(isGlobal, runtime = 'claude') {
644
638
  if (modified) {
645
639
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
646
640
  removedCount++;
647
- console.log(` ${green}\u2713${reset} Removed MAXSIM permissions from opencode.json`);
641
+ console.log(` ${chalk_1.default.green('\u2713')} Removed MAXSIM permissions from opencode.json`);
648
642
  }
649
643
  }
650
644
  catch {
@@ -653,10 +647,10 @@ function uninstall(isGlobal, runtime = 'claude') {
653
647
  }
654
648
  }
655
649
  if (removedCount === 0) {
656
- console.log(` ${yellow}\u26a0${reset} No MAXSIM files found to remove.`);
650
+ console.log(` ${chalk_1.default.yellow('\u26a0')} No MAXSIM files found to remove.`);
657
651
  }
658
652
  console.log(`
659
- ${green}Done!${reset} MAXSIM has been uninstalled from ${runtimeLabel}.
653
+ ${chalk_1.default.green('Done!')} MAXSIM has been uninstalled from ${runtimeLabel}.
660
654
  Your other files and settings have been preserved.
661
655
  `);
662
656
  }
@@ -729,9 +723,9 @@ function configureOpencodePermissions(isGlobal = true) {
729
723
  config = parseJsonc(content);
730
724
  }
731
725
  catch (e) {
732
- console.log(` ${yellow}\u26a0${reset} Could not parse opencode.json - skipping permission config`);
733
- console.log(` ${dim}Reason: ${e.message}${reset}`);
734
- console.log(` ${dim}Your config was NOT modified. Fix the syntax manually if needed.${reset}`);
726
+ console.log(` ${chalk_1.default.yellow('\u26a0')} Could not parse opencode.json - skipping permission config`);
727
+ console.log(` ${chalk_1.default.dim(`Reason: ${e.message}`)}`);
728
+ console.log(` ${chalk_1.default.dim('Your config was NOT modified. Fix the syntax manually if needed.')}`);
735
729
  return;
736
730
  }
737
731
  }
@@ -763,25 +757,25 @@ function configureOpencodePermissions(isGlobal = true) {
763
757
  return;
764
758
  }
765
759
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
766
- console.log(` ${green}\u2713${reset} Configured read permission for MAXSIM docs`);
760
+ console.log(` ${chalk_1.default.green('\u2713')} Configured read permission for MAXSIM docs`);
767
761
  }
768
762
  /**
769
763
  * Verify a directory exists and contains files
770
764
  */
771
765
  function verifyInstalled(dirPath, description) {
772
766
  if (!fs.existsSync(dirPath)) {
773
- console.error(` ${yellow}\u2717${reset} Failed to install ${description}: directory not created`);
767
+ console.error(` ${chalk_1.default.yellow('\u2717')} Failed to install ${description}: directory not created`);
774
768
  return false;
775
769
  }
776
770
  try {
777
771
  const entries = fs.readdirSync(dirPath);
778
772
  if (entries.length === 0) {
779
- console.error(` ${yellow}\u2717${reset} Failed to install ${description}: directory is empty`);
773
+ console.error(` ${chalk_1.default.yellow('\u2717')} Failed to install ${description}: directory is empty`);
780
774
  return false;
781
775
  }
782
776
  }
783
777
  catch (e) {
784
- console.error(` ${yellow}\u2717${reset} Failed to install ${description}: ${e.message}`);
778
+ console.error(` ${chalk_1.default.yellow('\u2717')} Failed to install ${description}: ${e.message}`);
785
779
  return false;
786
780
  }
787
781
  return true;
@@ -791,7 +785,7 @@ function verifyInstalled(dirPath, description) {
791
785
  */
792
786
  function verifyFileInstalled(filePath, description) {
793
787
  if (!fs.existsSync(filePath)) {
794
- console.error(` ${yellow}\u2717${reset} Failed to install ${description}: file not created`);
788
+ console.error(` ${chalk_1.default.yellow('\u2717')} Failed to install ${description}: file not created`);
795
789
  return false;
796
790
  }
797
791
  return true;
@@ -918,16 +912,14 @@ function saveLocalPatches(configDir) {
918
912
  };
919
913
  fs.writeFileSync(path.join(patchesDir, 'backup-meta.json'), JSON.stringify(meta, null, 2));
920
914
  console.log(' ' +
921
- yellow +
922
- 'i' +
923
- reset +
915
+ chalk_1.default.yellow('i') +
924
916
  ' Found ' +
925
917
  modified.length +
926
918
  ' locally modified MAXSIM file(s) \u2014 backed up to ' +
927
919
  PATCHES_DIR_NAME +
928
920
  '/');
929
921
  for (const f of modified) {
930
- console.log(' ' + dim + f + reset);
922
+ console.log(' ' + chalk_1.default.dim(f));
931
923
  }
932
924
  }
933
925
  return modified;
@@ -955,25 +947,18 @@ function reportLocalPatches(configDir, runtime = 'claude') {
955
947
  : '/maxsim:reapply-patches';
956
948
  console.log('');
957
949
  console.log(' ' +
958
- yellow +
959
- 'Local patches detected' +
960
- reset +
950
+ chalk_1.default.yellow('Local patches detected') +
961
951
  ' (from v' +
962
952
  meta.from_version +
963
953
  '):');
964
954
  for (const f of meta.files) {
965
- console.log(' ' + cyan + f + reset);
955
+ console.log(' ' + chalk_1.default.cyan(f));
966
956
  }
967
957
  console.log('');
968
958
  console.log(' Your modifications are saved in ' +
969
- cyan +
970
- PATCHES_DIR_NAME +
971
- '/' +
972
- reset);
959
+ chalk_1.default.cyan(PATCHES_DIR_NAME + '/'));
973
960
  console.log(' Run ' +
974
- cyan +
975
- reapplyCommand +
976
- reset +
961
+ chalk_1.default.cyan(reapplyCommand) +
977
962
  ' to merge them into the new version.');
978
963
  console.log(' Or manually compare and merge the files.');
979
964
  console.log('');
@@ -1002,13 +987,14 @@ function install(isGlobal, runtime = 'claude') {
1002
987
  runtimeLabel = 'Gemini';
1003
988
  if (isCodex)
1004
989
  runtimeLabel = 'Codex';
1005
- console.log(` Installing for ${cyan}${runtimeLabel}${reset} to ${cyan}${locationLabel}${reset}\n`);
990
+ console.log(` Installing for ${chalk_1.default.cyan(runtimeLabel)} to ${chalk_1.default.cyan(locationLabel)}\n`);
1006
991
  const failures = [];
1007
992
  // Save any locally modified MAXSIM files before they get wiped
1008
993
  saveLocalPatches(targetDir);
1009
994
  // Clean up orphaned files from previous versions
1010
995
  cleanupOrphanedFiles(targetDir);
1011
996
  // OpenCode uses command/ (flat), Codex uses skills/, Claude/Gemini use commands/maxsim/
997
+ let spinner = (0, ora_1.default)({ text: 'Installing commands...', color: 'cyan' }).start();
1012
998
  if (isOpencode) {
1013
999
  const commandDir = path.join(targetDir, 'command');
1014
1000
  fs.mkdirSync(commandDir, { recursive: true });
@@ -1018,9 +1004,10 @@ function install(isGlobal, runtime = 'claude') {
1018
1004
  const count = fs
1019
1005
  .readdirSync(commandDir)
1020
1006
  .filter((f) => f.startsWith('maxsim-')).length;
1021
- console.log(` ${green}\u2713${reset} Installed ${count} commands to command/`);
1007
+ spinner.succeed(chalk_1.default.green('✓') + ` Installed ${count} commands to command/`);
1022
1008
  }
1023
1009
  else {
1010
+ spinner.fail('Failed to install commands');
1024
1011
  failures.push('command/maxsim-*');
1025
1012
  }
1026
1013
  }
@@ -1030,9 +1017,10 @@ function install(isGlobal, runtime = 'claude') {
1030
1017
  copyCommandsAsCodexSkills(maxsimSrc, skillsDir, 'maxsim', pathPrefix, runtime);
1031
1018
  const installedSkillNames = listCodexSkillNames(skillsDir);
1032
1019
  if (installedSkillNames.length > 0) {
1033
- console.log(` ${green}\u2713${reset} Installed ${installedSkillNames.length} skills to skills/`);
1020
+ spinner.succeed(chalk_1.default.green('✓') + ` Installed ${installedSkillNames.length} skills to skills/`);
1034
1021
  }
1035
1022
  else {
1023
+ spinner.fail('Failed to install skills');
1036
1024
  failures.push('skills/maxsim-*');
1037
1025
  }
1038
1026
  }
@@ -1043,15 +1031,17 @@ function install(isGlobal, runtime = 'claude') {
1043
1031
  const maxsimDest = path.join(commandsDir, 'maxsim');
1044
1032
  copyWithPathReplacement(maxsimSrc, maxsimDest, pathPrefix, runtime, true);
1045
1033
  if (verifyInstalled(maxsimDest, 'commands/maxsim')) {
1046
- console.log(` ${green}\u2713${reset} Installed commands/maxsim`);
1034
+ spinner.succeed(chalk_1.default.green('✓') + ' Installed commands/maxsim');
1047
1035
  }
1048
1036
  else {
1037
+ spinner.fail('Failed to install commands/maxsim');
1049
1038
  failures.push('commands/maxsim');
1050
1039
  }
1051
1040
  }
1052
1041
  // Copy maxsim directory content (workflows, templates, references) with path replacement
1053
1042
  // Templates package layout: workflows/, templates/, references/ at root
1054
1043
  // Install target: maxsim/workflows/, maxsim/templates/, maxsim/references/
1044
+ spinner = (0, ora_1.default)({ text: 'Installing workflows and templates...', color: 'cyan' }).start();
1055
1045
  const skillDest = path.join(targetDir, 'maxsim');
1056
1046
  const maxsimSubdirs = ['workflows', 'templates', 'references'];
1057
1047
  if (fs.existsSync(skillDest)) {
@@ -1066,14 +1056,16 @@ function install(isGlobal, runtime = 'claude') {
1066
1056
  }
1067
1057
  }
1068
1058
  if (verifyInstalled(skillDest, 'maxsim')) {
1069
- console.log(` ${green}\u2713${reset} Installed maxsim`);
1059
+ spinner.succeed(chalk_1.default.green('✓') + ' Installed maxsim');
1070
1060
  }
1071
1061
  else {
1062
+ spinner.fail('Failed to install maxsim');
1072
1063
  failures.push('maxsim');
1073
1064
  }
1074
1065
  // Copy agents to agents directory
1075
1066
  const agentsSrc = path.join(src, 'agents');
1076
1067
  if (fs.existsSync(agentsSrc)) {
1068
+ spinner = (0, ora_1.default)({ text: 'Installing agents...', color: 'cyan' }).start();
1077
1069
  const agentsDest = path.join(targetDir, 'agents');
1078
1070
  fs.mkdirSync(agentsDest, { recursive: true });
1079
1071
  // Remove old MAXSIM agents before copying new ones
@@ -1104,9 +1096,10 @@ function install(isGlobal, runtime = 'claude') {
1104
1096
  }
1105
1097
  }
1106
1098
  if (verifyInstalled(agentsDest, 'agents')) {
1107
- console.log(` ${green}\u2713${reset} Installed agents`);
1099
+ spinner.succeed(chalk_1.default.green('✓') + ' Installed agents');
1108
1100
  }
1109
1101
  else {
1102
+ spinner.fail('Failed to install agents');
1110
1103
  failures.push('agents');
1111
1104
  }
1112
1105
  }
@@ -1114,11 +1107,13 @@ function install(isGlobal, runtime = 'claude') {
1114
1107
  const changelogSrc = path.join(src, '..', 'CHANGELOG.md');
1115
1108
  const changelogDest = path.join(targetDir, 'maxsim', 'CHANGELOG.md');
1116
1109
  if (fs.existsSync(changelogSrc)) {
1110
+ spinner = (0, ora_1.default)({ text: 'Installing CHANGELOG.md...', color: 'cyan' }).start();
1117
1111
  fs.copyFileSync(changelogSrc, changelogDest);
1118
1112
  if (verifyFileInstalled(changelogDest, 'CHANGELOG.md')) {
1119
- console.log(` ${green}\u2713${reset} Installed CHANGELOG.md`);
1113
+ spinner.succeed(chalk_1.default.green('✓') + ' Installed CHANGELOG.md');
1120
1114
  }
1121
1115
  else {
1116
+ spinner.fail('Failed to install CHANGELOG.md');
1122
1117
  failures.push('CHANGELOG.md');
1123
1118
  }
1124
1119
  }
@@ -1126,11 +1121,13 @@ function install(isGlobal, runtime = 'claude') {
1126
1121
  const claudeMdSrc = path.join(src, 'CLAUDE.md');
1127
1122
  const claudeMdDest = path.join(targetDir, 'CLAUDE.md');
1128
1123
  if (fs.existsSync(claudeMdSrc)) {
1124
+ spinner = (0, ora_1.default)({ text: 'Installing CLAUDE.md...', color: 'cyan' }).start();
1129
1125
  fs.copyFileSync(claudeMdSrc, claudeMdDest);
1130
1126
  if (verifyFileInstalled(claudeMdDest, 'CLAUDE.md')) {
1131
- console.log(` ${green}\u2713${reset} Installed CLAUDE.md`);
1127
+ spinner.succeed(chalk_1.default.green('✓') + ' Installed CLAUDE.md');
1132
1128
  }
1133
1129
  else {
1130
+ spinner.fail('Failed to install CLAUDE.md');
1134
1131
  failures.push('CLAUDE.md');
1135
1132
  }
1136
1133
  }
@@ -1138,7 +1135,7 @@ function install(isGlobal, runtime = 'claude') {
1138
1135
  const versionDest = path.join(targetDir, 'maxsim', 'VERSION');
1139
1136
  fs.writeFileSync(versionDest, pkg.version);
1140
1137
  if (verifyFileInstalled(versionDest, 'VERSION')) {
1141
- console.log(` ${green}\u2713${reset} Wrote VERSION (${pkg.version})`);
1138
+ console.log(` ${chalk_1.default.green('\u2713')} Wrote VERSION (${pkg.version})`);
1142
1139
  }
1143
1140
  else {
1144
1141
  failures.push('VERSION');
@@ -1147,7 +1144,7 @@ function install(isGlobal, runtime = 'claude') {
1147
1144
  // Write package.json to force CommonJS mode for MAXSIM scripts
1148
1145
  const pkgJsonDest = path.join(targetDir, 'package.json');
1149
1146
  fs.writeFileSync(pkgJsonDest, '{"type":"commonjs"}\n');
1150
- console.log(` ${green}\u2713${reset} Wrote package.json (CommonJS mode)`);
1147
+ console.log(` ${chalk_1.default.green('\u2713')} Wrote package.json (CommonJS mode)`);
1151
1148
  // Copy hooks from bundled assets directory (copied from @maxsim/hooks/dist at build time)
1152
1149
  let hooksSrc = null;
1153
1150
  const bundledHooksDir = path.resolve(__dirname, 'assets', 'hooks');
@@ -1155,9 +1152,10 @@ function install(isGlobal, runtime = 'claude') {
1155
1152
  hooksSrc = bundledHooksDir;
1156
1153
  }
1157
1154
  else {
1158
- console.warn(` ${yellow}!${reset} bundled hooks not found - hooks will not be installed`);
1155
+ console.warn(` ${chalk_1.default.yellow('!')} bundled hooks not found - hooks will not be installed`);
1159
1156
  }
1160
1157
  if (hooksSrc) {
1158
+ spinner = (0, ora_1.default)({ text: 'Installing hooks...', color: 'cyan' }).start();
1161
1159
  const hooksDest = path.join(targetDir, 'hooks');
1162
1160
  fs.mkdirSync(hooksDest, { recursive: true });
1163
1161
  const hookEntries = fs.readdirSync(hooksSrc);
@@ -1173,20 +1171,21 @@ function install(isGlobal, runtime = 'claude') {
1173
1171
  }
1174
1172
  }
1175
1173
  if (verifyInstalled(hooksDest, 'hooks')) {
1176
- console.log(` ${green}\u2713${reset} Installed hooks (bundled)`);
1174
+ spinner.succeed(chalk_1.default.green('✓') + ' Installed hooks (bundled)');
1177
1175
  }
1178
1176
  else {
1177
+ spinner.fail('Failed to install hooks');
1179
1178
  failures.push('hooks');
1180
1179
  }
1181
1180
  }
1182
1181
  }
1183
1182
  if (failures.length > 0) {
1184
- console.error(`\n ${yellow}Installation incomplete!${reset} Failed: ${failures.join(', ')}`);
1183
+ console.error(`\n ${chalk_1.default.yellow('Installation incomplete!')} Failed: ${failures.join(', ')}`);
1185
1184
  process.exit(1);
1186
1185
  }
1187
1186
  // Write file manifest for future modification detection
1188
1187
  writeManifest(targetDir, runtime);
1189
- console.log(` ${green}\u2713${reset} Wrote file manifest (${MANIFEST_NAME})`);
1188
+ console.log(` ${chalk_1.default.green('\u2713')} Wrote file manifest (${MANIFEST_NAME})`);
1190
1189
  // Report any backed-up local patches
1191
1190
  reportLocalPatches(targetDir, runtime);
1192
1191
  if (isCodex) {
@@ -1217,7 +1216,7 @@ function install(isGlobal, runtime = 'claude') {
1217
1216
  const experimental = settings.experimental;
1218
1217
  if (!experimental.enableAgents) {
1219
1218
  experimental.enableAgents = true;
1220
- console.log(` ${green}\u2713${reset} Enabled experimental agents`);
1219
+ console.log(` ${chalk_1.default.green('\u2713')} Enabled experimental agents`);
1221
1220
  }
1222
1221
  }
1223
1222
  // Configure SessionStart hook for update checking (skip for opencode)
@@ -1240,7 +1239,7 @@ function install(isGlobal, runtime = 'claude') {
1240
1239
  },
1241
1240
  ],
1242
1241
  });
1243
- console.log(` ${green}\u2713${reset} Configured update check hook`);
1242
+ console.log(` ${chalk_1.default.green('\u2713')} Configured update check hook`);
1244
1243
  }
1245
1244
  // Configure PostToolUse hook for context window monitoring
1246
1245
  if (!installHooks.PostToolUse) {
@@ -1257,7 +1256,7 @@ function install(isGlobal, runtime = 'claude') {
1257
1256
  },
1258
1257
  ],
1259
1258
  });
1260
- console.log(` ${green}\u2713${reset} Configured context window monitor hook`);
1259
+ console.log(` ${chalk_1.default.green('\u2713')} Configured context window monitor hook`);
1261
1260
  }
1262
1261
  }
1263
1262
  return { settingsPath, settings, statuslineCommand, runtime };
@@ -1273,7 +1272,7 @@ function finishInstall(settingsPath, settings, statuslineCommand, shouldInstallS
1273
1272
  type: 'command',
1274
1273
  command: statuslineCommand,
1275
1274
  };
1276
- console.log(` ${green}\u2713${reset} Configured statusline`);
1275
+ console.log(` ${chalk_1.default.green('\u2713')} Configured statusline`);
1277
1276
  }
1278
1277
  if (!isCodex && settingsPath && settings) {
1279
1278
  (0, adapters_1.writeSettings)(settingsPath, settings);
@@ -1294,143 +1293,91 @@ function finishInstall(settingsPath, settings, statuslineCommand, shouldInstallS
1294
1293
  if (runtime === 'codex')
1295
1294
  command = '$maxsim-help';
1296
1295
  console.log(`
1297
- ${green}Done!${reset} Launch ${program} and run ${cyan}${command}${reset}.
1296
+ ${chalk_1.default.green('Done!')} Launch ${program} and run ${chalk_1.default.cyan(command)}.
1298
1297
 
1299
- ${cyan}Join the community:${reset} https://discord.gg/5JJgD5svVS
1298
+ ${chalk_1.default.cyan('Join the community:')} https://discord.gg/5JJgD5svVS
1300
1299
  `);
1301
1300
  }
1302
1301
  /**
1303
- * Handle statusline configuration with optional prompt
1302
+ * Handle statusline configuration returns true if MAXSIM statusline should be installed
1304
1303
  */
1305
- function handleStatusline(settings, isInteractive, callback) {
1304
+ async function handleStatusline(settings, isInteractive) {
1306
1305
  const hasExisting = settings.statusLine != null;
1307
- if (!hasExisting) {
1308
- callback(true);
1309
- return;
1310
- }
1311
- if (forceStatusline) {
1312
- callback(true);
1313
- return;
1314
- }
1306
+ if (!hasExisting)
1307
+ return true;
1308
+ if (forceStatusline)
1309
+ return true;
1315
1310
  if (!isInteractive) {
1316
- console.log(` ${yellow}\u26a0${reset} Skipping statusline (already configured)`);
1317
- console.log(` Use ${cyan}--force-statusline${reset} to replace\n`);
1318
- callback(false);
1319
- return;
1311
+ console.log(chalk_1.default.yellow('⚠') + ' Skipping statusline (already configured)');
1312
+ console.log(' Use ' + chalk_1.default.cyan('--force-statusline') + ' to replace\n');
1313
+ return false;
1320
1314
  }
1321
1315
  const statusLine = settings.statusLine;
1322
1316
  const existingCmd = statusLine.command || statusLine.url || '(custom)';
1323
- const rl = readline.createInterface({
1324
- input: process.stdin,
1325
- output: process.stdout,
1326
- });
1327
- console.log(`
1328
- ${yellow}\u26a0${reset} Existing statusline detected\n
1329
- Your current statusline:
1330
- ${dim}command: ${existingCmd}${reset}
1331
-
1332
- MAXSIM includes a statusline showing:
1333
- \u2022 Model name
1334
- \u2022 Current task (from todo list)
1335
- \u2022 Context window usage (color-coded)
1336
-
1337
- ${cyan}1${reset}) Keep existing
1338
- ${cyan}2${reset}) Replace with MAXSIM statusline
1339
- `);
1340
- rl.question(` Choice ${dim}[1]${reset}: `, (answer) => {
1341
- rl.close();
1342
- const choice = answer.trim() || '1';
1343
- callback(choice === '2');
1317
+ console.log();
1318
+ console.log(chalk_1.default.yellow('⚠ Existing statusline detected'));
1319
+ console.log();
1320
+ console.log(' Your current statusline:');
1321
+ console.log(' ' + chalk_1.default.dim(`command: ${existingCmd}`));
1322
+ console.log();
1323
+ console.log(' MAXSIM includes a statusline showing:');
1324
+ console.log(' • Model name');
1325
+ console.log(' • Current task (from todo list)');
1326
+ console.log(' • Context window usage (color-coded)');
1327
+ console.log();
1328
+ const shouldReplace = await (0, prompts_1.confirm)({
1329
+ message: 'Replace with MAXSIM statusline?',
1330
+ default: false,
1344
1331
  });
1332
+ return shouldReplace;
1345
1333
  }
1346
1334
  /**
1347
- * Prompt for runtime selection
1335
+ * Prompt for runtime selection (multi-select)
1348
1336
  */
1349
- function promptRuntime(callback) {
1350
- const rl = readline.createInterface({
1351
- input: process.stdin,
1352
- output: process.stdout,
1353
- });
1354
- let answered = false;
1355
- rl.on('close', () => {
1356
- if (!answered) {
1357
- answered = true;
1358
- console.log(`\n ${yellow}Installation cancelled${reset}\n`);
1359
- process.exit(0);
1360
- }
1361
- });
1362
- console.log(` ${yellow}Which runtime(s) would you like to install for?${reset}\n\n ${cyan}1${reset}) Claude Code ${dim}(~/.claude)${reset}
1363
- ${cyan}2${reset}) OpenCode ${dim}(~/.config/opencode)${reset} - open source, free models
1364
- ${cyan}3${reset}) Gemini ${dim}(~/.gemini)${reset}
1365
- ${cyan}4${reset}) Codex ${dim}(~/.codex)${reset}
1366
- ${cyan}5${reset}) All
1367
- `);
1368
- rl.question(` Choice ${dim}[1]${reset}: `, (answer) => {
1369
- answered = true;
1370
- rl.close();
1371
- const choice = answer.trim() || '1';
1372
- if (choice === '5') {
1373
- callback(['claude', 'opencode', 'gemini', 'codex']);
1374
- }
1375
- else if (choice === '4') {
1376
- callback(['codex']);
1377
- }
1378
- else if (choice === '3') {
1379
- callback(['gemini']);
1380
- }
1381
- else if (choice === '2') {
1382
- callback(['opencode']);
1383
- }
1384
- else {
1385
- callback(['claude']);
1386
- }
1337
+ async function promptRuntime() {
1338
+ const selected = await (0, prompts_1.checkbox)({
1339
+ message: 'Which runtime(s) would you like to install for?',
1340
+ choices: [
1341
+ { name: 'Claude Code ' + chalk_1.default.dim('(~/.claude)'), value: 'claude', checked: true },
1342
+ { name: 'OpenCode ' + chalk_1.default.dim('(~/.config/opencode)') + ' — open source, free models', value: 'opencode' },
1343
+ { name: 'Gemini ' + chalk_1.default.dim('(~/.gemini)'), value: 'gemini' },
1344
+ { name: 'Codex ' + chalk_1.default.dim('(~/.codex)'), value: 'codex' },
1345
+ ],
1346
+ validate: (choices) => choices.length > 0 || 'Please select at least one runtime',
1387
1347
  });
1348
+ return selected;
1388
1349
  }
1389
1350
  /**
1390
1351
  * Prompt for install location
1391
1352
  */
1392
- function promptLocation(runtimes) {
1353
+ async function promptLocation(runtimes) {
1393
1354
  if (!process.stdin.isTTY) {
1394
- console.log(` ${yellow}Non-interactive terminal detected, defaulting to global install${reset}\n`);
1395
- installAllRuntimes(runtimes, true, false);
1396
- return;
1355
+ console.log(chalk_1.default.yellow('Non-interactive terminal detected, defaulting to global install') + '\n');
1356
+ return true; // isGlobal
1397
1357
  }
1398
- const rl = readline.createInterface({
1399
- input: process.stdin,
1400
- output: process.stdout,
1401
- });
1402
- let answered = false;
1403
- rl.on('close', () => {
1404
- if (!answered) {
1405
- answered = true;
1406
- console.log(`\n ${yellow}Installation cancelled${reset}\n`);
1407
- process.exit(0);
1408
- }
1409
- });
1410
1358
  const pathExamples = runtimes
1411
- .map((r) => {
1412
- const globalPath = getGlobalDir(r, explicitConfigDir);
1413
- return globalPath.replace(os.homedir(), '~');
1414
- })
1415
- .join(', ');
1416
- const localExamples = runtimes
1417
- .map((r) => `./${getDirName(r)}`)
1359
+ .map((r) => getGlobalDir(r, explicitConfigDir).replace(os.homedir(), '~'))
1418
1360
  .join(', ');
1419
- console.log(` ${yellow}Where would you like to install?${reset}\n\n ${cyan}1${reset}) Global ${dim}(${pathExamples})${reset} - available in all projects
1420
- ${cyan}2${reset}) Local ${dim}(${localExamples})${reset} - this project only
1421
- `);
1422
- rl.question(` Choice ${dim}[1]${reset}: `, (answer) => {
1423
- answered = true;
1424
- rl.close();
1425
- const choice = answer.trim() || '1';
1426
- const isGlobal = choice !== '2';
1427
- installAllRuntimes(runtimes, isGlobal, true);
1361
+ const localExamples = runtimes.map((r) => `./${getDirName(r)}`).join(', ');
1362
+ const choice = await (0, prompts_1.select)({
1363
+ message: 'Where would you like to install?',
1364
+ choices: [
1365
+ {
1366
+ name: 'Global ' + chalk_1.default.dim(`(${pathExamples})`) + ' — available in all projects',
1367
+ value: 'global',
1368
+ },
1369
+ {
1370
+ name: 'Local ' + chalk_1.default.dim(`(${localExamples})`) + ' — this project only',
1371
+ value: 'local',
1372
+ },
1373
+ ],
1428
1374
  });
1375
+ return choice === 'global';
1429
1376
  }
1430
1377
  /**
1431
1378
  * Install MAXSIM for all selected runtimes
1432
1379
  */
1433
- function installAllRuntimes(runtimes, isGlobal, isInteractive) {
1380
+ async function installAllRuntimes(runtimes, isGlobal, isInteractive) {
1434
1381
  const results = [];
1435
1382
  for (const runtime of runtimes) {
1436
1383
  const result = install(isGlobal, runtime);
@@ -1438,58 +1385,65 @@ function installAllRuntimes(runtimes, isGlobal, isInteractive) {
1438
1385
  }
1439
1386
  const statuslineRuntimes = ['claude', 'gemini'];
1440
1387
  const primaryStatuslineResult = results.find((r) => statuslineRuntimes.includes(r.runtime));
1441
- const finalize = (shouldInstallStatusline) => {
1442
- for (const result of results) {
1443
- const useStatusline = statuslineRuntimes.includes(result.runtime) && shouldInstallStatusline;
1444
- finishInstall(result.settingsPath, result.settings, result.statuslineCommand, useStatusline, result.runtime, isGlobal);
1445
- }
1446
- };
1388
+ let shouldInstallStatusline = false;
1447
1389
  if (primaryStatuslineResult && primaryStatuslineResult.settings) {
1448
- handleStatusline(primaryStatuslineResult.settings, isInteractive, finalize);
1390
+ shouldInstallStatusline = await handleStatusline(primaryStatuslineResult.settings, isInteractive);
1449
1391
  }
1450
- else {
1451
- finalize(false);
1392
+ for (const result of results) {
1393
+ const useStatusline = statuslineRuntimes.includes(result.runtime) && shouldInstallStatusline;
1394
+ finishInstall(result.settingsPath, result.settings, result.statuslineCommand, useStatusline, result.runtime, isGlobal);
1452
1395
  }
1453
1396
  }
1454
1397
  // Main logic
1455
- if (hasGlobal && hasLocal) {
1456
- console.error(` ${yellow}Cannot specify both --global and --local${reset}`);
1457
- process.exit(1);
1458
- }
1459
- else if (explicitConfigDir && hasLocal) {
1460
- console.error(` ${yellow}Cannot use --config-dir with --local${reset}`);
1461
- process.exit(1);
1462
- }
1463
- else if (hasUninstall) {
1464
- if (!hasGlobal && !hasLocal) {
1465
- console.error(` ${yellow}--uninstall requires --global or --local${reset}`);
1398
+ (async () => {
1399
+ if (hasGlobal && hasLocal) {
1400
+ console.error(chalk_1.default.yellow('Cannot specify both --global and --local'));
1466
1401
  process.exit(1);
1467
1402
  }
1468
- const runtimes = selectedRuntimes.length > 0 ? selectedRuntimes : ['claude'];
1469
- for (const runtime of runtimes) {
1470
- uninstall(hasGlobal, runtime);
1403
+ else if (explicitConfigDir && hasLocal) {
1404
+ console.error(chalk_1.default.yellow('Cannot use --config-dir with --local'));
1405
+ process.exit(1);
1471
1406
  }
1472
- }
1473
- else if (selectedRuntimes.length > 0) {
1474
- if (!hasGlobal && !hasLocal) {
1475
- promptLocation(selectedRuntimes);
1407
+ else if (hasUninstall) {
1408
+ if (!hasGlobal && !hasLocal) {
1409
+ console.error(chalk_1.default.yellow('--uninstall requires --global or --local'));
1410
+ process.exit(1);
1411
+ }
1412
+ const runtimes = selectedRuntimes.length > 0 ? selectedRuntimes : ['claude'];
1413
+ for (const runtime of runtimes) {
1414
+ uninstall(hasGlobal, runtime);
1415
+ }
1476
1416
  }
1477
- else {
1478
- installAllRuntimes(selectedRuntimes, hasGlobal, false);
1417
+ else if (selectedRuntimes.length > 0) {
1418
+ if (!hasGlobal && !hasLocal) {
1419
+ const isGlobal = await promptLocation(selectedRuntimes);
1420
+ await installAllRuntimes(selectedRuntimes, isGlobal, true);
1421
+ }
1422
+ else {
1423
+ await installAllRuntimes(selectedRuntimes, hasGlobal, false);
1424
+ }
1479
1425
  }
1480
- }
1481
- else if (hasGlobal || hasLocal) {
1482
- installAllRuntimes(['claude'], hasGlobal, false);
1483
- }
1484
- else {
1485
- if (!process.stdin.isTTY) {
1486
- console.log(` ${yellow}Non-interactive terminal detected, defaulting to Claude Code global install${reset}\n`);
1487
- installAllRuntimes(['claude'], true, false);
1426
+ else if (hasGlobal || hasLocal) {
1427
+ await installAllRuntimes(['claude'], hasGlobal, false);
1488
1428
  }
1489
1429
  else {
1490
- promptRuntime((runtimes) => {
1491
- promptLocation(runtimes);
1492
- });
1430
+ if (!process.stdin.isTTY) {
1431
+ console.log(chalk_1.default.yellow('Non-interactive terminal detected, defaulting to Claude Code global install') + '\n');
1432
+ await installAllRuntimes(['claude'], true, false);
1433
+ }
1434
+ else {
1435
+ const runtimes = await promptRuntime();
1436
+ const isGlobal = await promptLocation(runtimes);
1437
+ await installAllRuntimes(runtimes, isGlobal, true);
1438
+ }
1493
1439
  }
1494
- }
1440
+ })().catch((err) => {
1441
+ if (err instanceof Error && err.message.includes('User force closed')) {
1442
+ // User pressed Ctrl+C during an @inquirer/prompts prompt — exit cleanly
1443
+ console.log('\n' + chalk_1.default.yellow('Installation cancelled') + '\n');
1444
+ process.exit(0);
1445
+ }
1446
+ console.error(chalk_1.default.red('Unexpected error:'), err);
1447
+ process.exit(1);
1448
+ });
1495
1449
  //# sourceMappingURL=install.js.map