@ekkos/cli 1.0.26 → 1.0.28
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/dashboard.js +60 -2
- package/dist/commands/run.js +1 -3
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -67,6 +67,7 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
67
67
|
const commander_1 = require("commander");
|
|
68
68
|
const usage_parser_js_1 = require("../lib/usage-parser.js");
|
|
69
69
|
const state_js_1 = require("../utils/state.js");
|
|
70
|
+
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
70
71
|
// ── Pricing ──
|
|
71
72
|
// Pricing per MTok from https://platform.claude.com/docs/en/about-claude/pricing
|
|
72
73
|
const MODEL_PRICING = {
|
|
@@ -272,6 +273,55 @@ function parseJsonlFile(jsonlPath, sessionName) {
|
|
|
272
273
|
turns,
|
|
273
274
|
};
|
|
274
275
|
}
|
|
276
|
+
function readJsonFile(filePath) {
|
|
277
|
+
try {
|
|
278
|
+
if (!fs.existsSync(filePath))
|
|
279
|
+
return null;
|
|
280
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
function resolveSessionAlias(sessionId) {
|
|
287
|
+
const normalized = sessionId.toLowerCase();
|
|
288
|
+
// Project-local hook state (most reliable for the active session)
|
|
289
|
+
const projectState = readJsonFile(path.join(process.cwd(), '.claude', 'state', 'current-session.json'));
|
|
290
|
+
if (projectState?.session_id?.toLowerCase() === normalized &&
|
|
291
|
+
projectState.session_name &&
|
|
292
|
+
!UUID_REGEX.test(projectState.session_name)) {
|
|
293
|
+
return projectState.session_name;
|
|
294
|
+
}
|
|
295
|
+
// Global Claude hook state
|
|
296
|
+
const claudeState = readJsonFile(path.join(os.homedir(), '.claude', 'state', 'current-session.json'));
|
|
297
|
+
if (claudeState?.session_id?.toLowerCase() === normalized &&
|
|
298
|
+
claudeState.session_name &&
|
|
299
|
+
!UUID_REGEX.test(claudeState.session_name)) {
|
|
300
|
+
return claudeState.session_name;
|
|
301
|
+
}
|
|
302
|
+
// ekkOS global state
|
|
303
|
+
const ekkosState = readJsonFile(path.join(os.homedir(), '.ekkos', 'current-session.json'));
|
|
304
|
+
if (ekkosState?.session_id?.toLowerCase() === normalized &&
|
|
305
|
+
ekkosState.session_name &&
|
|
306
|
+
!UUID_REGEX.test(ekkosState.session_name)) {
|
|
307
|
+
return ekkosState.session_name;
|
|
308
|
+
}
|
|
309
|
+
// Multi-session index fallback
|
|
310
|
+
const activeSessions = readJsonFile(path.join(os.homedir(), '.ekkos', 'active-sessions.json')) || [];
|
|
311
|
+
const bySessionId = activeSessions
|
|
312
|
+
.filter(s => s.sessionId?.toLowerCase() === normalized && s.sessionName && !UUID_REGEX.test(s.sessionName))
|
|
313
|
+
.sort((a, b) => (b.lastHeartbeat || '').localeCompare(a.lastHeartbeat || ''));
|
|
314
|
+
if (bySessionId.length > 0)
|
|
315
|
+
return bySessionId[0].sessionName || null;
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
function displaySessionName(rawName) {
|
|
319
|
+
if (!rawName)
|
|
320
|
+
return 'session';
|
|
321
|
+
if (!UUID_REGEX.test(rawName))
|
|
322
|
+
return rawName;
|
|
323
|
+
return resolveSessionAlias(rawName) || (0, state_js_1.uuidToWords)(rawName);
|
|
324
|
+
}
|
|
275
325
|
// ── Resolve session to JSONL path ──
|
|
276
326
|
function resolveJsonlPath(sessionName, createdAfterMs) {
|
|
277
327
|
// 1) Try standard resolution (works when sessionId is a real UUID)
|
|
@@ -499,7 +549,7 @@ function sleep(ms) {
|
|
|
499
549
|
}
|
|
500
550
|
// ── TUI Dashboard ──
|
|
501
551
|
async function launchDashboard(initialSessionName, jsonlPath, refreshMs) {
|
|
502
|
-
let sessionName = initialSessionName;
|
|
552
|
+
let sessionName = displaySessionName(initialSessionName);
|
|
503
553
|
const blessed = require('blessed');
|
|
504
554
|
const contrib = require('blessed-contrib');
|
|
505
555
|
const inTmux = process.env.TMUX !== undefined;
|
|
@@ -836,12 +886,20 @@ async function launchDashboard(initialSessionName, jsonlPath, refreshMs) {
|
|
|
836
886
|
const basename = path.basename(jsonlPath, '.jsonl');
|
|
837
887
|
// JSONL filename is the session UUID (e.g., 607bd8e4-0a04-4db2-acf5-3f794be0f956.jsonl)
|
|
838
888
|
if (/^[0-9a-f]{8}-/.test(basename)) {
|
|
839
|
-
sessionName = (
|
|
889
|
+
sessionName = displaySessionName(basename);
|
|
840
890
|
screen.title = `ekkOS - ${sessionName}`;
|
|
841
891
|
}
|
|
842
892
|
}
|
|
843
893
|
catch { }
|
|
844
894
|
}
|
|
895
|
+
// If we started with a UUID fallback, keep trying to resolve to the bound word session.
|
|
896
|
+
if (UUID_REGEX.test(sessionName)) {
|
|
897
|
+
const resolvedName = displaySessionName(sessionName);
|
|
898
|
+
if (resolvedName !== sessionName) {
|
|
899
|
+
sessionName = resolvedName;
|
|
900
|
+
screen.title = `ekkOS - ${sessionName}`;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
845
903
|
let data;
|
|
846
904
|
try {
|
|
847
905
|
const stat = fs.statSync(jsonlPath);
|
package/dist/commands/run.js
CHANGED
|
@@ -748,7 +748,6 @@ function launchWithDashboardWindows(options) {
|
|
|
748
748
|
runArgs.push('--skip-dna');
|
|
749
749
|
if (options.noProxy)
|
|
750
750
|
runArgs.push('--skip-proxy');
|
|
751
|
-
runArgs.push('--kickstart');
|
|
752
751
|
const ekkosCmd = process.argv[1];
|
|
753
752
|
const cwd = process.cwd();
|
|
754
753
|
// Write dashboard launch marker
|
|
@@ -766,7 +765,7 @@ function launchWithDashboardWindows(options) {
|
|
|
766
765
|
// PowerShell -EncodedCommand expects UTF-16LE Base64
|
|
767
766
|
return Buffer.from(script, 'utf16le').toString('base64');
|
|
768
767
|
}
|
|
769
|
-
// cd to original CWD first so ekkos run
|
|
768
|
+
// cd to original CWD first so ekkos run registers the correct projectPath
|
|
770
769
|
const runScript = `Set-Location '${cwdEscaped}'; & node '${ekkosCmdEscaped}' ${runArgs.join(' ')}`;
|
|
771
770
|
const dashScript = `& node '${ekkosCmdEscaped}' dashboard --wait-for-new --refresh 2000`;
|
|
772
771
|
const runEncoded = toPsEncoded(runScript);
|
|
@@ -816,7 +815,6 @@ function launchWithDashboard(options) {
|
|
|
816
815
|
runArgs.push('--skip-dna');
|
|
817
816
|
if (options.noProxy)
|
|
818
817
|
runArgs.push('--skip-proxy');
|
|
819
|
-
runArgs.push('--kickstart'); // Auto-send "test" to create session immediately for dashboard
|
|
820
818
|
const ekkosCmd = process.argv[1]; // Path to ekkos CLI
|
|
821
819
|
const cwd = process.cwd();
|
|
822
820
|
const termCols = process.stdout.columns ?? 160;
|
package/dist/index.js
CHANGED
|
@@ -249,7 +249,7 @@ commander_1.program
|
|
|
249
249
|
.option('--skip-dna', 'Deprecated no-op (legacy ccDNA patching has been removed)')
|
|
250
250
|
.option('--skip-proxy', 'Skip API proxy (use direct Anthropic API, disables seamless context eviction)')
|
|
251
251
|
.option('--dashboard', 'Launch with live usage dashboard in an isolated 60/40 tmux split (requires tmux)')
|
|
252
|
-
.option('--kickstart', 'Auto-send "test" on load to create session immediately (
|
|
252
|
+
.option('--kickstart', 'Auto-send "test" on load to create session immediately (manual/debug use)')
|
|
253
253
|
.option('--add-dir <dirs...>', 'Additional directories Claude Code can access (outside working directory)')
|
|
254
254
|
.action((options) => {
|
|
255
255
|
(0, run_1.run)({
|