@ekkos/cli 1.2.0 → 1.2.2
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/commands/init.js +9 -19
- package/dist/commands/run.js +76 -34
- package/dist/index.js +3 -66
- package/dist/utils/state.d.ts +1 -1
- package/dist/utils/state.js +2 -2
- package/package.json +1 -1
package/dist/commands/init.js
CHANGED
|
@@ -251,28 +251,18 @@ async function deployForClaude(apiKey, userId, options) {
|
|
|
251
251
|
catch (error) {
|
|
252
252
|
spinner.fail('MCP server configuration failed');
|
|
253
253
|
}
|
|
254
|
-
// Settings.json (hook registration)
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
254
|
+
// Settings.json (hook registration)
|
|
255
|
+
spinner = (0, ora_1.default)('Deploying hooks configuration...').start();
|
|
256
|
+
try {
|
|
257
|
+
(0, settings_1.deployClaudeSettings)();
|
|
258
258
|
result.settings = true;
|
|
259
|
+
spinner.succeed('Hooks configuration');
|
|
259
260
|
}
|
|
260
|
-
|
|
261
|
-
spinner
|
|
262
|
-
try {
|
|
263
|
-
(0, settings_1.deployClaudeSettings)();
|
|
264
|
-
result.settings = true;
|
|
265
|
-
spinner.succeed('Hooks configuration');
|
|
266
|
-
}
|
|
267
|
-
catch (error) {
|
|
268
|
-
spinner.fail('Hooks configuration failed');
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
// Hook scripts — skipped on Windows
|
|
272
|
-
if (platform_1.isWindows) {
|
|
273
|
-
// Skip hook scripts on Windows
|
|
261
|
+
catch (error) {
|
|
262
|
+
spinner.fail('Hooks configuration failed');
|
|
274
263
|
}
|
|
275
|
-
|
|
264
|
+
// Hook scripts
|
|
265
|
+
if (!options.skipHooks) {
|
|
276
266
|
spinner = (0, ora_1.default)('Deploying hook scripts...').start();
|
|
277
267
|
try {
|
|
278
268
|
result.hooks = (0, hooks_1.deployHooks)(apiKey);
|
package/dist/commands/run.js
CHANGED
|
@@ -876,6 +876,57 @@ function launchWithDashboard(options) {
|
|
|
876
876
|
console.log(chalk_1.default.gray('Falling back to normal mode. Run "ekkos dashboard --latest" in another terminal.'));
|
|
877
877
|
}
|
|
878
878
|
}
|
|
879
|
+
/**
|
|
880
|
+
* Launch Claude Code in a new Windows Terminal pane, dashboard stays in current terminal.
|
|
881
|
+
* Dashboard runs where the user typed the command; Claude opens alongside it.
|
|
882
|
+
*/
|
|
883
|
+
function launchWithWindowsTerminal(options) {
|
|
884
|
+
const ekkosCmd = process.argv[1];
|
|
885
|
+
const cwd = process.cwd();
|
|
886
|
+
const launchTime = Date.now();
|
|
887
|
+
// Write marker file so dashboard knows to wait for a NEW session
|
|
888
|
+
const markerPath = path.join(state_1.EKKOS_DIR, '.dashboard-launch-ts');
|
|
889
|
+
try {
|
|
890
|
+
fs.writeFileSync(markerPath, `${launchTime}\n${cwd}`);
|
|
891
|
+
}
|
|
892
|
+
catch { }
|
|
893
|
+
// Build the ekkos run command WITHOUT --dashboard (prevent recursion)
|
|
894
|
+
const runArgs = ['run'];
|
|
895
|
+
if (options.session)
|
|
896
|
+
runArgs.push('-s', options.session);
|
|
897
|
+
if (options.bypass)
|
|
898
|
+
runArgs.push('-b');
|
|
899
|
+
if (options.verbose)
|
|
900
|
+
runArgs.push('-v');
|
|
901
|
+
if (options.doctor)
|
|
902
|
+
runArgs.push('-d');
|
|
903
|
+
if (options.research)
|
|
904
|
+
runArgs.push('-r');
|
|
905
|
+
if (options.noInject)
|
|
906
|
+
runArgs.push('--skip-inject');
|
|
907
|
+
if (options.noDna)
|
|
908
|
+
runArgs.push('--skip-dna');
|
|
909
|
+
if (options.noProxy)
|
|
910
|
+
runArgs.push('--skip-proxy');
|
|
911
|
+
const runCommand = `node "${ekkosCmd}" ${runArgs.join(' ')}`;
|
|
912
|
+
try {
|
|
913
|
+
// Launch Claude Code in a new pane (60% width), dashboard stays in current pane
|
|
914
|
+
// -V = vertical split, -s 0.6 = 60% width for Claude
|
|
915
|
+
(0, child_process_1.execSync)(`wt.exe -w 0 split-pane -V -s 0.6 -d "${cwd}" cmd /c "${runCommand}"`, { stdio: 'pipe' });
|
|
916
|
+
console.log(chalk_1.default.cyan('\n Claude Code launched in right pane (60%)'));
|
|
917
|
+
console.log(chalk_1.default.gray(' Switch panes: Alt+Arrow keys\n'));
|
|
918
|
+
}
|
|
919
|
+
catch (err) {
|
|
920
|
+
console.log(chalk_1.default.yellow(` Windows Terminal split failed: ${err.message}`));
|
|
921
|
+
console.log(chalk_1.default.gray(' Run "ekkos dashboard --latest" in a separate terminal'));
|
|
922
|
+
return;
|
|
923
|
+
}
|
|
924
|
+
// Dashboard runs in THIS terminal (the pane user launched from)
|
|
925
|
+
// Use dynamic import to avoid circular dependency
|
|
926
|
+
Promise.resolve().then(() => __importStar(require('./dashboard'))).then(({ dashboardCommand }) => {
|
|
927
|
+
dashboardCommand.parseAsync(['--wait-for-new', '--refresh', '2000'], { from: 'user' });
|
|
928
|
+
});
|
|
929
|
+
}
|
|
879
930
|
async function run(options) {
|
|
880
931
|
// ══════════════════════════════════════════════════════════════════════════
|
|
881
932
|
// FIRST-RUN CHECK: If no config exists, run init first
|
|
@@ -906,43 +957,34 @@ async function run(options) {
|
|
|
906
957
|
console.log(chalk_1.default.yellow(' ⏭️ API proxy disabled (--no-proxy)'));
|
|
907
958
|
}
|
|
908
959
|
// ══════════════════════════════════════════════════════════════════════════
|
|
909
|
-
//
|
|
910
|
-
// Hooks can cause PowerShell execution policy issues and hangs on Windows.
|
|
911
|
-
// The proxy handles context management; hooks aren't strictly required.
|
|
912
|
-
// ══════════════════════════════════════════════════════════════════════════
|
|
913
|
-
if (isWindows) {
|
|
914
|
-
try {
|
|
915
|
-
const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
|
|
916
|
-
if (fs.existsSync(settingsPath)) {
|
|
917
|
-
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
918
|
-
if (settings.hooks) {
|
|
919
|
-
delete settings.hooks;
|
|
920
|
-
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
921
|
-
console.log(chalk_1.default.gray(' ⏭️ Hooks disabled (Windows proxy-only mode)'));
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
catch {
|
|
926
|
-
// Non-fatal — continue without hook cleanup
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
// ══════════════════════════════════════════════════════════════════════════
|
|
930
|
-
// DASHBOARD MODE: Launch via tmux with isolated dashboard pane (60/40)
|
|
960
|
+
// DASHBOARD MODE: Launch via tmux (Unix) or Windows Terminal split pane
|
|
931
961
|
// ══════════════════════════════════════════════════════════════════════════
|
|
932
962
|
if (options.dashboard) {
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
963
|
+
if (isWindows) {
|
|
964
|
+
// Windows: Claude opens in new pane, dashboard stays in this terminal
|
|
965
|
+
try {
|
|
966
|
+
(0, child_process_1.execSync)('where wt.exe', { encoding: 'utf-8', stdio: 'pipe' });
|
|
967
|
+
launchWithWindowsTerminal(options);
|
|
968
|
+
return; // Dashboard runs in this terminal, Claude is in the new pane
|
|
969
|
+
}
|
|
970
|
+
catch {
|
|
971
|
+
console.log(chalk_1.default.yellow(' Windows Terminal (wt.exe) not found.'));
|
|
972
|
+
console.log(chalk_1.default.gray(' Alternative: run "ekkos dashboard --latest" in a separate terminal'));
|
|
973
|
+
console.log(chalk_1.default.gray(' Continuing without dashboard...\n'));
|
|
974
|
+
}
|
|
938
975
|
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
976
|
+
else {
|
|
977
|
+
// Unix: launch via tmux split pane
|
|
978
|
+
try {
|
|
979
|
+
(0, child_process_1.execSync)('command -v tmux', { encoding: 'utf-8', stdio: 'pipe' });
|
|
980
|
+
launchWithDashboard(options);
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
983
|
+
catch {
|
|
984
|
+
console.log(chalk_1.default.yellow(' tmux not found. Install: brew install tmux'));
|
|
985
|
+
console.log(chalk_1.default.gray(' Alternative: run "ekkos dashboard --latest" in a separate terminal'));
|
|
986
|
+
console.log(chalk_1.default.gray(' Continuing without dashboard...\n'));
|
|
987
|
+
}
|
|
946
988
|
}
|
|
947
989
|
}
|
|
948
990
|
// Generate instance ID for this run
|
package/dist/index.js
CHANGED
|
@@ -51,9 +51,6 @@ const agent_1 = require("./commands/agent");
|
|
|
51
51
|
const state_1 = require("./utils/state");
|
|
52
52
|
const index_1 = require("./commands/usage/index");
|
|
53
53
|
const dashboard_1 = require("./commands/dashboard");
|
|
54
|
-
const swarm_1 = require("./commands/swarm");
|
|
55
|
-
const swarm_dashboard_1 = require("./commands/swarm-dashboard");
|
|
56
|
-
const swarm_setup_1 = require("./commands/swarm-setup");
|
|
57
54
|
const chalk_1 = __importDefault(require("chalk"));
|
|
58
55
|
const fs = __importStar(require("fs"));
|
|
59
56
|
const path = __importStar(require("path"));
|
|
@@ -79,7 +76,7 @@ commander_1.program
|
|
|
79
76
|
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos run -b')} ${chalk_1.default.gray('Launch with bypass permissions mode')}`,
|
|
80
77
|
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos doctor --fix')} ${chalk_1.default.gray('Check and auto-fix system prerequisites')}`,
|
|
81
78
|
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos usage daily')} ${chalk_1.default.gray("View today's token usage and costs")}`,
|
|
82
|
-
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos
|
|
79
|
+
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos sessions')} ${chalk_1.default.gray('List active Claude Code sessions')}`,
|
|
83
80
|
'',
|
|
84
81
|
chalk_1.default.gray(' Run ') + chalk_1.default.white('ekkos <command> --help') + chalk_1.default.gray(' for detailed options on any command.'),
|
|
85
82
|
'',
|
|
@@ -180,13 +177,6 @@ commander_1.program
|
|
|
180
177
|
{ name: 'agent', desc: 'Manage the remote terminal agent (start, stop, status, logs)' },
|
|
181
178
|
],
|
|
182
179
|
},
|
|
183
|
-
{
|
|
184
|
-
title: 'Swarm (Multi-Agent)',
|
|
185
|
-
icon: '▸',
|
|
186
|
-
commands: [
|
|
187
|
-
{ name: 'swarm', desc: 'Parallel workers, Q-learning routing, swarm dashboard' },
|
|
188
|
-
],
|
|
189
|
-
},
|
|
190
180
|
];
|
|
191
181
|
const padCmd = 18;
|
|
192
182
|
let output = '';
|
|
@@ -352,10 +342,10 @@ hooksCmd
|
|
|
352
342
|
(0, index_1.registerUsageCommand)(commander_1.program);
|
|
353
343
|
// Dashboard command - live TUI for monitoring session usage
|
|
354
344
|
commander_1.program.addCommand(dashboard_1.dashboardCommand);
|
|
355
|
-
// Sessions command - list active Claude Code sessions
|
|
345
|
+
// Sessions command - list active Claude Code sessions
|
|
356
346
|
commander_1.program
|
|
357
347
|
.command('sessions')
|
|
358
|
-
.description('List active Claude Code sessions
|
|
348
|
+
.description('List active Claude Code sessions')
|
|
359
349
|
.option('-j, --json', 'Output machine-readable JSON')
|
|
360
350
|
.action((options) => {
|
|
361
351
|
const sessions = (0, state_1.getActiveSessions)();
|
|
@@ -480,59 +470,6 @@ agentCmd
|
|
|
480
470
|
.action((options) => {
|
|
481
471
|
(0, agent_1.agentHealth)({ json: options.json });
|
|
482
472
|
});
|
|
483
|
-
// Swarm command - manage Q-learning routing
|
|
484
|
-
const swarmCmd = commander_1.program
|
|
485
|
-
.command('swarm')
|
|
486
|
-
.description('Manage Swarm Q-learning model routing');
|
|
487
|
-
swarmCmd
|
|
488
|
-
.command('status')
|
|
489
|
-
.description('Show Q-table stats (states, visits, epsilon, top actions)')
|
|
490
|
-
.action(swarm_1.swarmStatus);
|
|
491
|
-
swarmCmd
|
|
492
|
-
.command('reset')
|
|
493
|
-
.description('Clear Q-table from Redis (routing reverts to static rules)')
|
|
494
|
-
.action(swarm_1.swarmReset);
|
|
495
|
-
swarmCmd
|
|
496
|
-
.command('export')
|
|
497
|
-
.description('Export Q-table to .swarm/q-learning-model.json')
|
|
498
|
-
.action(swarm_1.swarmExport);
|
|
499
|
-
swarmCmd
|
|
500
|
-
.command('import')
|
|
501
|
-
.description('Import Q-table from .swarm/q-learning-model.json into Redis')
|
|
502
|
-
.action(swarm_1.swarmImport);
|
|
503
|
-
swarmCmd
|
|
504
|
-
.command('launch')
|
|
505
|
-
.description('Launch parallel workers on a decomposed task (opens wizard if --task is omitted)')
|
|
506
|
-
.option('-w, --workers <count>', 'Number of parallel workers (2-8)', parseInt)
|
|
507
|
-
.option('-t, --task <task>', 'Task description to decompose and execute')
|
|
508
|
-
.option('--no-bypass', 'Disable bypass permissions mode')
|
|
509
|
-
.option('--no-decompose', 'Skip AI decomposition (send same task to all workers)')
|
|
510
|
-
.option('--no-queen', 'Skip launching the Python Queen coordinator')
|
|
511
|
-
.option('--queen-strategy <strategy>', 'Queen strategy (adaptive-default, hierarchical-cascade, mesh-consensus)')
|
|
512
|
-
.option('-v, --verbose', 'Show debug output')
|
|
513
|
-
.action((options) => {
|
|
514
|
-
// Auto-open wizard when --task is missing
|
|
515
|
-
if (!options.task) {
|
|
516
|
-
(0, swarm_setup_1.swarmSetup)();
|
|
517
|
-
return;
|
|
518
|
-
}
|
|
519
|
-
(0, swarm_1.swarmLaunch)({
|
|
520
|
-
workers: options.workers || 4,
|
|
521
|
-
task: options.task,
|
|
522
|
-
bypass: options.bypass !== false,
|
|
523
|
-
noDecompose: options.decompose === false,
|
|
524
|
-
noQueen: options.queen === false,
|
|
525
|
-
queenStrategy: options.queenStrategy,
|
|
526
|
-
verbose: options.verbose,
|
|
527
|
-
});
|
|
528
|
-
});
|
|
529
|
-
swarmCmd
|
|
530
|
-
.command('setup')
|
|
531
|
-
.description('Interactive TUI wizard for configuring and launching a swarm')
|
|
532
|
-
.action(() => {
|
|
533
|
-
(0, swarm_setup_1.swarmSetup)();
|
|
534
|
-
});
|
|
535
|
-
swarmCmd.addCommand(swarm_dashboard_1.swarmDashboardCommand);
|
|
536
473
|
// Handle `-help` (single dash) — rewrite to `--help` for Commander compatibility
|
|
537
474
|
const helpIdx = process.argv.indexOf('-help');
|
|
538
475
|
if (helpIdx !== -1) {
|
package/dist/utils/state.d.ts
CHANGED
|
@@ -80,7 +80,7 @@ export declare function getMostRecentSession(): {
|
|
|
80
80
|
*/
|
|
81
81
|
export declare function getActiveSessions(): ActiveSession[];
|
|
82
82
|
/**
|
|
83
|
-
* Register a new active session
|
|
83
|
+
* Register a new active session
|
|
84
84
|
*/
|
|
85
85
|
export declare function registerActiveSession(sessionId: string, sessionName: string, projectPath: string): ActiveSession;
|
|
86
86
|
/**
|
package/dist/utils/state.js
CHANGED
|
@@ -244,7 +244,7 @@ function getMostRecentSession() {
|
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
246
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
247
|
-
// MULTI-SESSION
|
|
247
|
+
// MULTI-SESSION SUPPORT
|
|
248
248
|
// Track multiple concurrent Claude Code sessions without state collision
|
|
249
249
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
250
250
|
/**
|
|
@@ -271,7 +271,7 @@ function getActiveSessions() {
|
|
|
271
271
|
}
|
|
272
272
|
}
|
|
273
273
|
/**
|
|
274
|
-
* Register a new active session
|
|
274
|
+
* Register a new active session
|
|
275
275
|
*/
|
|
276
276
|
function registerActiveSession(sessionId, sessionName, projectPath) {
|
|
277
277
|
ensureEkkosDir();
|