@ekkos/cli 1.3.9 → 1.4.1
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 +520 -42
- package/dist/commands/gemini.d.ts +1 -0
- package/dist/commands/gemini.js +170 -10
- package/dist/commands/init-living-docs.d.ts +6 -0
- package/dist/commands/init-living-docs.js +57 -0
- package/dist/commands/living-docs.js +3 -3
- package/dist/commands/run.js +85 -21
- package/dist/commands/setup-ci.d.ts +3 -0
- package/dist/commands/setup-ci.js +107 -0
- package/dist/commands/validate-living-docs.d.ts +27 -0
- package/dist/commands/validate-living-docs.js +489 -0
- package/dist/index.js +109 -82
- package/dist/utils/state.d.ts +16 -3
- package/dist/utils/state.js +10 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -38,15 +38,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
38
38
|
};
|
|
39
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
40
|
const commander_1 = require("commander");
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
const run_1 = require("./commands/run");
|
|
45
|
-
const dashboard_1 = require("./commands/dashboard");
|
|
41
|
+
// Command modules loaded lazily inside .action() callbacks to avoid
|
|
42
|
+
// importing most heavy modules (node-pty, swarm, etc.) on every launch.
|
|
43
|
+
// Commands that must work in subprocess mode (usage/dashboard) are registered eagerly.
|
|
46
44
|
const chalk_1 = __importDefault(require("chalk"));
|
|
47
45
|
const fs = __importStar(require("fs"));
|
|
48
46
|
const path = __importStar(require("path"));
|
|
49
47
|
const child_process_1 = require("child_process");
|
|
48
|
+
const index_1 = require("./commands/usage/index");
|
|
49
|
+
const dashboard_1 = require("./commands/dashboard");
|
|
50
50
|
// Get version from package.json (CommonJS compatible)
|
|
51
51
|
const pkgPath = path.resolve(__dirname, '../package.json');
|
|
52
52
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
@@ -63,16 +63,13 @@ commander_1.program
|
|
|
63
63
|
.addHelpText('after', [
|
|
64
64
|
'',
|
|
65
65
|
chalk_1.default.cyan.bold('Examples:'),
|
|
66
|
-
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos')} ${chalk_1.default.gray('
|
|
67
|
-
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos
|
|
68
|
-
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos
|
|
69
|
-
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos
|
|
70
|
-
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos
|
|
71
|
-
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos
|
|
72
|
-
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos
|
|
73
|
-
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos connect gemini')} ${chalk_1.default.gray('Store your Gemini API key in the cloud')}`,
|
|
74
|
-
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos swarm launch -t "task"')} ${chalk_1.default.gray('Parallel workers on a decomposed task')}`,
|
|
75
|
-
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos agent create --path ./repo')} ${chalk_1.default.gray('Spawn a headless remote agent')}`,
|
|
66
|
+
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos')} ${chalk_1.default.gray('Start Claude Code with ekkOS memory (default)')}`,
|
|
67
|
+
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos codex')} ${chalk_1.default.gray('Start Codex (OpenAI) mode')}`,
|
|
68
|
+
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos daemon start')} ${chalk_1.default.gray('Start the background mobile sync service')}`,
|
|
69
|
+
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos docs watch')} ${chalk_1.default.gray('Keep local ekkOS_CONTEXT.md files updated on disk')}`,
|
|
70
|
+
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos connect gemini')} ${chalk_1.default.gray('Securely store your Gemini API key in the cloud')}`,
|
|
71
|
+
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos agent create --path ./repo')} ${chalk_1.default.gray('Spawn a headless remote agent in a directory')}`,
|
|
72
|
+
` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos run --dashboard')} ${chalk_1.default.gray('Launch Claude with live usage dashboard')}`,
|
|
76
73
|
'',
|
|
77
74
|
chalk_1.default.gray(' Run ') + chalk_1.default.white('ekkos <command> --help') + chalk_1.default.gray(' for detailed options on any command.'),
|
|
78
75
|
'',
|
|
@@ -137,53 +134,52 @@ commander_1.program
|
|
|
137
134
|
}
|
|
138
135
|
const groups = [
|
|
139
136
|
{
|
|
140
|
-
title: '
|
|
141
|
-
icon: '
|
|
137
|
+
title: 'Getting Started',
|
|
138
|
+
icon: '▸',
|
|
142
139
|
commands: [
|
|
143
|
-
{ name: '
|
|
144
|
-
{ name: '
|
|
145
|
-
{ name: '
|
|
146
|
-
{ name: '
|
|
147
|
-
{ name: '
|
|
140
|
+
{ name: 'init', desc: 'First-time setup — authenticate and configure IDEs' },
|
|
141
|
+
{ name: 'scan', desc: 'Scan repo structure and seed ekkOS system registry' },
|
|
142
|
+
{ name: 'docs', desc: 'Cortex: Watch and regenerate local ekkOS_CONTEXT.md files' },
|
|
143
|
+
{ name: 'status', desc: 'Show overall system status (Memory, Sync Daemon, Auth)' },
|
|
144
|
+
{ name: 'doctor', desc: 'Check system prerequisites and fix runaway processes' },
|
|
148
145
|
],
|
|
149
146
|
},
|
|
150
147
|
{
|
|
151
|
-
title: '
|
|
152
|
-
icon: '
|
|
148
|
+
title: 'Launch Agents (Local + Mobile Synced)',
|
|
149
|
+
icon: '▸',
|
|
153
150
|
commands: [
|
|
154
|
-
{ name: '
|
|
155
|
-
{ name: '
|
|
156
|
-
{ name: '
|
|
157
|
-
{ name: '
|
|
151
|
+
{ name: 'run', desc: 'Launch Claude Code with memory and mobile control', note: 'default' },
|
|
152
|
+
{ name: 'codex', desc: 'Launch Codex (OpenAI) with mobile control' },
|
|
153
|
+
{ name: 'gemini', desc: 'Launch Gemini mode (ACP) with mobile control' },
|
|
154
|
+
{ name: 'acp', desc: 'Launch a generic ACP-compatible agent' },
|
|
158
155
|
],
|
|
159
156
|
},
|
|
160
157
|
{
|
|
161
|
-
title: '
|
|
162
|
-
icon: '
|
|
158
|
+
title: 'Mobile Sync & Cloud (Synk)',
|
|
159
|
+
icon: '▸',
|
|
163
160
|
commands: [
|
|
164
|
-
{ name: '
|
|
165
|
-
{ name: '
|
|
166
|
-
{ name: 'sandbox', desc: 'OS-level sandboxing for agent execution' },
|
|
161
|
+
{ name: 'daemon', desc: 'Manage background mobile sync service (start, stop, status)' },
|
|
162
|
+
{ name: 'connect', desc: 'Securely store AI vendor API keys in the cloud' },
|
|
163
|
+
{ name: 'sandbox', desc: 'Configure OS-level sandboxing for agent execution' },
|
|
164
|
+
{ name: 'notify', desc: 'Send push notifications to your Synk mobile app' },
|
|
167
165
|
],
|
|
168
166
|
},
|
|
169
167
|
{
|
|
170
|
-
title: '
|
|
171
|
-
icon: '
|
|
168
|
+
title: 'Headless Agents (Remote Control)',
|
|
169
|
+
icon: '▸',
|
|
172
170
|
commands: [
|
|
173
|
-
{ name: '
|
|
174
|
-
{ name: '
|
|
175
|
-
{ name: 'usage', desc: 'Token usage and cost tracking' },
|
|
176
|
-
{ name: 'sessions', desc: 'List active local CLI sessions' },
|
|
171
|
+
{ name: 'agent', desc: 'Manage remote headless agents (create, list, stop)' },
|
|
172
|
+
{ name: 'swarm', desc: 'Parallel workers, Q-learning routing, and swarm dashboard' },
|
|
177
173
|
],
|
|
178
174
|
},
|
|
179
175
|
{
|
|
180
|
-
title: '
|
|
181
|
-
icon: '
|
|
176
|
+
title: 'Monitoring & Usage',
|
|
177
|
+
icon: '▸',
|
|
182
178
|
commands: [
|
|
183
|
-
{ name: 'auth', desc: 'Manage authentication
|
|
184
|
-
{ name: '
|
|
185
|
-
{ name: '
|
|
186
|
-
{ name: '
|
|
179
|
+
{ name: 'auth', desc: 'Manage authentication for Memory, Agents, and Mobile App' },
|
|
180
|
+
{ name: 'usage', desc: 'Token usage and cost tracking (daily, weekly, monthly, session)' },
|
|
181
|
+
{ name: 'dashboard', desc: 'Live TUI dashboard for session monitoring' },
|
|
182
|
+
{ name: 'sessions', desc: 'List active local CLI sessions' },
|
|
187
183
|
],
|
|
188
184
|
},
|
|
189
185
|
];
|
|
@@ -241,13 +237,28 @@ commander_1.program
|
|
|
241
237
|
path: options.path,
|
|
242
238
|
});
|
|
243
239
|
});
|
|
244
|
-
//
|
|
240
|
+
// ekkOS Cortex command group
|
|
245
241
|
const docsCmd = commander_1.program
|
|
246
242
|
.command('docs')
|
|
247
|
-
.
|
|
243
|
+
.alias('cortex')
|
|
244
|
+
.description('ekkOS Cortex: Manage local living docs (ekkOS_CONTEXT.md)');
|
|
245
|
+
docsCmd
|
|
246
|
+
.command('init')
|
|
247
|
+
.description('Initialize Cortex: Discover systems and perform a one-shot generation of all ekkOS_CONTEXT.md files')
|
|
248
|
+
.option('-p, --path <path>', 'Path to repository root (default: current directory)')
|
|
249
|
+
.option('--timezone <iana-tz>', 'IANA timezone for timestamps (default: local machine timezone)')
|
|
250
|
+
.option('--no-seed', 'Do not seed the platform registry')
|
|
251
|
+
.action(async (options) => {
|
|
252
|
+
const { initLivingDocs } = await Promise.resolve().then(() => __importStar(require('./commands/init-living-docs')));
|
|
253
|
+
await initLivingDocs({
|
|
254
|
+
path: options.path,
|
|
255
|
+
timeZone: options.timezone,
|
|
256
|
+
noSeed: options.seed === false,
|
|
257
|
+
});
|
|
258
|
+
});
|
|
248
259
|
docsCmd
|
|
249
260
|
.command('watch')
|
|
250
|
-
.description('Watch the local workspace and keep
|
|
261
|
+
.description('Watch the local workspace and keep Cortex docs current on disk')
|
|
251
262
|
.option('-p, --path <path>', 'Path to watch (default: current directory)')
|
|
252
263
|
.option('--timezone <iana-tz>', 'IANA timezone for timestamps (default: local machine timezone)')
|
|
253
264
|
.option('--poll-interval-ms <ms>', 'Polling interval fallback in milliseconds', (value) => parseInt(value, 10))
|
|
@@ -263,6 +274,30 @@ docsCmd
|
|
|
263
274
|
noSeed: options.seed === false,
|
|
264
275
|
});
|
|
265
276
|
});
|
|
277
|
+
docsCmd
|
|
278
|
+
.command('setup-ci')
|
|
279
|
+
.description('Generate a GitHub Actions workflow to automatically validate Cortex docs on PRs')
|
|
280
|
+
.option('-p, --path <path>', 'Path to repository root (default: current directory)')
|
|
281
|
+
.action(async (options) => {
|
|
282
|
+
const { setupCiCommand } = await Promise.resolve().then(() => __importStar(require('./commands/setup-ci')));
|
|
283
|
+
const exitCode = await setupCiCommand({ repoRoot: options.path || process.cwd() });
|
|
284
|
+
process.exit(exitCode);
|
|
285
|
+
});
|
|
286
|
+
docsCmd
|
|
287
|
+
.command('validate')
|
|
288
|
+
.description('Validate Cortex docs (ekkOS_CONTEXT.md) in a repository (CI/CD friendly)')
|
|
289
|
+
.option('-p, --path <path>', 'Path to repository root (default: current directory)')
|
|
290
|
+
.option('--fix', 'Attempt to automatically fix content hash mismatches')
|
|
291
|
+
.option('--system <system_id>', 'Filter validation to a specific system_id')
|
|
292
|
+
.action(async (options) => {
|
|
293
|
+
const { validateLivingDocsCommand } = await Promise.resolve().then(() => __importStar(require('./commands/validate-living-docs')));
|
|
294
|
+
const exitCode = await validateLivingDocsCommand({
|
|
295
|
+
repoRoot: options.path || process.cwd(),
|
|
296
|
+
fix: options.fix,
|
|
297
|
+
systemFilter: options.system,
|
|
298
|
+
});
|
|
299
|
+
process.exit(exitCode);
|
|
300
|
+
});
|
|
266
301
|
// Status command
|
|
267
302
|
commander_1.program
|
|
268
303
|
.command('status')
|
|
@@ -324,6 +359,10 @@ commander_1.program
|
|
|
324
359
|
.description('Launch Claude Code with ekkOS memory proxy (IPC compression + pattern injection)')
|
|
325
360
|
.option('-s, --session <name>', 'Session name to restore on clear')
|
|
326
361
|
.option('-b, --bypass', 'Enable bypass permissions mode (dangerously skip all permission checks)')
|
|
362
|
+
.option('--model [model]', 'Launch model: pass a model ID, or omit value to open the interactive selector')
|
|
363
|
+
.option('--context-window <window>', 'Context lane override: auto, 200k, or 1m')
|
|
364
|
+
.option('--continue-last', 'Continue most recent Claude conversation')
|
|
365
|
+
.option('--resume-session <id>', 'Resume Claude conversation by ID')
|
|
327
366
|
.option('-v, --verbose', 'Show debug output')
|
|
328
367
|
.option('-d, --doctor', 'Run diagnostics before starting')
|
|
329
368
|
.option('-r, --research', 'Auto-run research agent on startup (scans arXiv for new AI papers)')
|
|
@@ -331,12 +370,9 @@ commander_1.program
|
|
|
331
370
|
.option('--skip-proxy', 'Skip API proxy (use direct Anthropic API, disables seamless context eviction)')
|
|
332
371
|
.option('--dashboard', 'Launch with live usage dashboard in an isolated 60/40 tmux split (requires tmux)')
|
|
333
372
|
.option('--add-dir <dirs...>', 'Additional directories Claude Code can access (outside working directory)')
|
|
334
|
-
.
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
.option('--resume-session <id>', 'Resume a Claude conversation by session ID')
|
|
338
|
-
.action((options) => {
|
|
339
|
-
(0, run_1.run)({
|
|
373
|
+
.action(async (options) => {
|
|
374
|
+
const { run } = await Promise.resolve().then(() => __importStar(require('./commands/run')));
|
|
375
|
+
run({
|
|
340
376
|
session: options.session,
|
|
341
377
|
bypass: options.bypass,
|
|
342
378
|
verbose: options.verbose,
|
|
@@ -354,32 +390,27 @@ commander_1.program
|
|
|
354
390
|
});
|
|
355
391
|
commander_1.program
|
|
356
392
|
.command('pulse')
|
|
357
|
-
.description('Launch
|
|
393
|
+
.description('Launch PULSE mode (equivalent to `ekkos -b --model --dashboard`)')
|
|
358
394
|
.option('-s, --session <name>', 'Session name to restore on clear')
|
|
359
|
-
.option('--
|
|
395
|
+
.option('--context-window <window>', 'Context lane override: auto, 200k, or 1m')
|
|
396
|
+
.option('--continue-last', 'Continue most recent Claude conversation')
|
|
397
|
+
.option('--resume-session <id>', 'Resume Claude conversation by ID')
|
|
360
398
|
.option('-v, --verbose', 'Show debug output')
|
|
361
|
-
.option('-d, --doctor', 'Run diagnostics before starting')
|
|
362
|
-
.option('-r, --research', 'Auto-run research agent on startup (scans arXiv for new AI papers)')
|
|
363
399
|
.option('--skip-inject', 'Monitor-only mode (detect context wall but print instructions instead of auto-inject)')
|
|
364
400
|
.option('--skip-proxy', 'Skip API proxy (use direct Anthropic API, disables seamless context eviction)')
|
|
365
401
|
.option('--add-dir <dirs...>', 'Additional directories Claude Code can access (outside working directory)')
|
|
366
|
-
.
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
.option('--resume-session <id>', 'Resume a Claude conversation by session ID')
|
|
370
|
-
.action((options) => {
|
|
371
|
-
(0, run_1.run)({
|
|
402
|
+
.action(async (options) => {
|
|
403
|
+
const { run } = await Promise.resolve().then(() => __importStar(require('./commands/run')));
|
|
404
|
+
run({
|
|
372
405
|
session: options.session,
|
|
373
|
-
bypass:
|
|
406
|
+
bypass: true,
|
|
374
407
|
pulse: true,
|
|
375
408
|
verbose: options.verbose,
|
|
376
|
-
doctor: options.doctor,
|
|
377
409
|
noInject: options.skipInject,
|
|
378
|
-
research: options.research,
|
|
379
410
|
noProxy: options.skipProxy,
|
|
380
411
|
dashboard: true,
|
|
381
412
|
addDirs: options.addDir,
|
|
382
|
-
model:
|
|
413
|
+
model: true,
|
|
383
414
|
contextWindow: options.contextWindow,
|
|
384
415
|
continueLast: options.continueLast,
|
|
385
416
|
resumeSession: options.resumeSession,
|
|
@@ -392,12 +423,14 @@ commander_1.program
|
|
|
392
423
|
.option('-s, --session <name>', 'Session name')
|
|
393
424
|
.option('-v, --verbose', 'Show debug output')
|
|
394
425
|
.option('--skip-proxy', 'Skip API proxy (use direct Gemini API)')
|
|
426
|
+
.option('--dashboard', 'Launch Gemini with a dedicated live dashboard split (requires tmux)')
|
|
395
427
|
.action(async (options) => {
|
|
396
428
|
const { gemini } = await Promise.resolve().then(() => __importStar(require('./commands/gemini')));
|
|
397
429
|
gemini({
|
|
398
430
|
session: options.session,
|
|
399
431
|
verbose: options.verbose,
|
|
400
432
|
noProxy: options.skipProxy,
|
|
433
|
+
dashboard: options.dashboard,
|
|
401
434
|
});
|
|
402
435
|
});
|
|
403
436
|
// Test Claude — bare proxy test (no CLI wrapper)
|
|
@@ -465,19 +498,9 @@ commander_1.program
|
|
|
465
498
|
console.log(chalk_1.default.gray(' the ekkOS proxy — no shell hooks required.'));
|
|
466
499
|
console.log('');
|
|
467
500
|
});
|
|
468
|
-
// Usage
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
.description('Token usage and cost tracking (daily, weekly, monthly, session)')
|
|
472
|
-
.allowUnknownOption()
|
|
473
|
-
.action(async () => {
|
|
474
|
-
const { registerUsageCommand } = await Promise.resolve().then(() => __importStar(require('./commands/usage/index')));
|
|
475
|
-
const { Command } = await Promise.resolve().then(() => __importStar(require('commander')));
|
|
476
|
-
const usageProgram = new Command('ekkos');
|
|
477
|
-
registerUsageCommand(usageProgram);
|
|
478
|
-
usageProgram.parse(['node', 'ekkos', 'usage', ...process.argv.slice(3)]);
|
|
479
|
-
});
|
|
480
|
-
// Dashboard command — eager because `run --dashboard` spawns `ekkos dashboard` in tmux
|
|
501
|
+
// Usage and dashboard are registered synchronously so command parsing is reliable
|
|
502
|
+
// when launched as subprocesses (for example tmux split-pane dashboard mode).
|
|
503
|
+
(0, index_1.registerUsageCommand)(commander_1.program);
|
|
481
504
|
commander_1.program.addCommand(dashboard_1.dashboardCommand);
|
|
482
505
|
// Sessions command - list active Claude Code sessions (swarm support)
|
|
483
506
|
commander_1.program
|
|
@@ -563,6 +586,7 @@ swarmCmd
|
|
|
563
586
|
.option('--queen-strategy <strategy>', 'Queen strategy (adaptive-default, hierarchical-cascade, mesh-consensus)')
|
|
564
587
|
.option('-v, --verbose', 'Show debug output')
|
|
565
588
|
.action(async (options) => {
|
|
589
|
+
// Auto-open wizard when --task is missing
|
|
566
590
|
if (!options.task) {
|
|
567
591
|
const { swarmSetup } = await Promise.resolve().then(() => __importStar(require('./commands/swarm-setup')));
|
|
568
592
|
swarmSetup();
|
|
@@ -582,7 +606,10 @@ swarmCmd
|
|
|
582
606
|
swarmCmd
|
|
583
607
|
.command('setup')
|
|
584
608
|
.description('Interactive TUI wizard for configuring and launching a swarm')
|
|
585
|
-
.action(async () => {
|
|
609
|
+
.action(async () => {
|
|
610
|
+
const { swarmSetup } = await Promise.resolve().then(() => __importStar(require('./commands/swarm-setup')));
|
|
611
|
+
swarmSetup();
|
|
612
|
+
});
|
|
586
613
|
swarmCmd
|
|
587
614
|
.command('swarm-dashboard')
|
|
588
615
|
.description('Live swarm dashboard')
|
package/dist/utils/state.d.ts
CHANGED
|
@@ -3,7 +3,20 @@ export declare const STATE_FILE: string;
|
|
|
3
3
|
export declare const ACTIVE_SESSIONS_FILE: string;
|
|
4
4
|
export declare const AUTO_CLEAR_FLAG: string;
|
|
5
5
|
export declare const CONFIG_FILE: string;
|
|
6
|
-
export interface
|
|
6
|
+
export interface ClaudeSessionMetadata {
|
|
7
|
+
provider?: 'claude' | 'gemini';
|
|
8
|
+
claudeModel?: string;
|
|
9
|
+
claudeLaunchModel?: string;
|
|
10
|
+
claudeProfile?: string;
|
|
11
|
+
claudeContextWindow?: 'auto' | '200k' | '1m';
|
|
12
|
+
claudeContextSize?: number;
|
|
13
|
+
claudeMaxOutputTokens?: number;
|
|
14
|
+
claudeCodeVersion?: string;
|
|
15
|
+
geminiProjectId?: string;
|
|
16
|
+
dashboardEnabled?: boolean;
|
|
17
|
+
bypassEnabled?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface ActiveSession extends ClaudeSessionMetadata {
|
|
7
20
|
sessionId: string;
|
|
8
21
|
sessionName: string;
|
|
9
22
|
pid: number;
|
|
@@ -82,7 +95,7 @@ export declare function getActiveSessions(): ActiveSession[];
|
|
|
82
95
|
/**
|
|
83
96
|
* Register a new active session (for swarm tracking)
|
|
84
97
|
*/
|
|
85
|
-
export declare function registerActiveSession(sessionId: string, sessionName: string, projectPath: string): ActiveSession;
|
|
98
|
+
export declare function registerActiveSession(sessionId: string, sessionName: string, projectPath: string, metadata?: ClaudeSessionMetadata): ActiveSession;
|
|
86
99
|
/**
|
|
87
100
|
* Update heartbeat for current process's session
|
|
88
101
|
*/
|
|
@@ -103,4 +116,4 @@ export declare function getActiveSessionByName(sessionName: string): ActiveSessi
|
|
|
103
116
|
* Update the session for the current PID (when session name is detected)
|
|
104
117
|
* This does NOT write to the global state.json - only to active-sessions.json
|
|
105
118
|
*/
|
|
106
|
-
export declare function updateCurrentProcessSession(sessionId: string, sessionName: string): void;
|
|
119
|
+
export declare function updateCurrentProcessSession(sessionId: string, sessionName: string, metadata?: Partial<ClaudeSessionMetadata>): void;
|
package/dist/utils/state.js
CHANGED
|
@@ -286,7 +286,7 @@ function getActiveSessions() {
|
|
|
286
286
|
/**
|
|
287
287
|
* Register a new active session (for swarm tracking)
|
|
288
288
|
*/
|
|
289
|
-
function registerActiveSession(sessionId, sessionName, projectPath) {
|
|
289
|
+
function registerActiveSession(sessionId, sessionName, projectPath, metadata) {
|
|
290
290
|
ensureEkkosDir();
|
|
291
291
|
const sessions = getActiveSessions();
|
|
292
292
|
const now = new Date().toISOString();
|
|
@@ -299,7 +299,8 @@ function registerActiveSession(sessionId, sessionName, projectPath) {
|
|
|
299
299
|
pid,
|
|
300
300
|
startedAt: now,
|
|
301
301
|
projectPath,
|
|
302
|
-
lastHeartbeat: now
|
|
302
|
+
lastHeartbeat: now,
|
|
303
|
+
...metadata,
|
|
303
304
|
};
|
|
304
305
|
filtered.push(newSession);
|
|
305
306
|
fs.writeFileSync(exports.ACTIVE_SESSIONS_FILE, JSON.stringify(filtered, null, 2));
|
|
@@ -371,7 +372,7 @@ function isProcessAlive(pid) {
|
|
|
371
372
|
* Update the session for the current PID (when session name is detected)
|
|
372
373
|
* This does NOT write to the global state.json - only to active-sessions.json
|
|
373
374
|
*/
|
|
374
|
-
function updateCurrentProcessSession(sessionId, sessionName) {
|
|
375
|
+
function updateCurrentProcessSession(sessionId, sessionName, metadata) {
|
|
375
376
|
try {
|
|
376
377
|
const sessions = getActiveSessions();
|
|
377
378
|
const pid = process.pid;
|
|
@@ -379,6 +380,12 @@ function updateCurrentProcessSession(sessionId, sessionName) {
|
|
|
379
380
|
if (idx !== -1) {
|
|
380
381
|
sessions[idx].sessionId = sessionId;
|
|
381
382
|
sessions[idx].sessionName = sessionName;
|
|
383
|
+
if (metadata) {
|
|
384
|
+
sessions[idx] = {
|
|
385
|
+
...sessions[idx],
|
|
386
|
+
...metadata,
|
|
387
|
+
};
|
|
388
|
+
}
|
|
382
389
|
sessions[idx].lastHeartbeat = new Date().toISOString();
|
|
383
390
|
fs.writeFileSync(exports.ACTIVE_SESSIONS_FILE, JSON.stringify(sessions, null, 2));
|
|
384
391
|
}
|
package/package.json
CHANGED