@ekkos/cli 1.3.1 → 1.3.5

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.
Files changed (131) hide show
  1. package/dist/capture/jsonl-rewriter.d.ts +1 -1
  2. package/dist/capture/jsonl-rewriter.js +3 -3
  3. package/dist/capture/transcript-repair.d.ts +2 -2
  4. package/dist/capture/transcript-repair.js +2 -2
  5. package/dist/commands/claw.d.ts +13 -0
  6. package/dist/commands/claw.js +253 -0
  7. package/dist/commands/dashboard.js +742 -118
  8. package/dist/commands/doctor.d.ts +3 -3
  9. package/dist/commands/doctor.js +6 -79
  10. package/dist/commands/gemini.d.ts +19 -0
  11. package/dist/commands/gemini.js +193 -0
  12. package/dist/commands/init.d.ts +1 -0
  13. package/dist/commands/init.js +56 -41
  14. package/dist/commands/run.d.ts +0 -1
  15. package/dist/commands/run.js +288 -263
  16. package/dist/commands/scan.d.ts +21 -0
  17. package/dist/commands/scan.js +386 -0
  18. package/dist/commands/status.d.ts +4 -1
  19. package/dist/commands/status.js +165 -27
  20. package/dist/commands/swarm-dashboard.js +156 -28
  21. package/dist/commands/swarm.d.ts +1 -1
  22. package/dist/commands/swarm.js +1 -1
  23. package/dist/commands/test-claude.d.ts +2 -2
  24. package/dist/commands/test-claude.js +3 -3
  25. package/dist/deploy/index.d.ts +0 -2
  26. package/dist/deploy/index.js +0 -2
  27. package/dist/deploy/settings.d.ts +6 -5
  28. package/dist/deploy/settings.js +64 -16
  29. package/dist/deploy/skills.js +1 -2
  30. package/dist/index.js +86 -96
  31. package/dist/lib/usage-parser.d.ts +1 -1
  32. package/dist/lib/usage-parser.js +9 -6
  33. package/dist/local/index.d.ts +14 -0
  34. package/dist/local/index.js +28 -0
  35. package/dist/local/local-embeddings.d.ts +49 -0
  36. package/dist/local/local-embeddings.js +232 -0
  37. package/dist/local/offline-fallback.d.ts +44 -0
  38. package/dist/local/offline-fallback.js +159 -0
  39. package/dist/local/sqlite-store.d.ts +126 -0
  40. package/dist/local/sqlite-store.js +393 -0
  41. package/dist/local/sync-engine.d.ts +42 -0
  42. package/dist/local/sync-engine.js +223 -0
  43. package/dist/utils/platform.d.ts +5 -1
  44. package/dist/utils/platform.js +24 -4
  45. package/dist/utils/proxy-url.d.ts +21 -0
  46. package/dist/utils/proxy-url.js +34 -0
  47. package/dist/utils/state.d.ts +1 -1
  48. package/dist/utils/state.js +11 -3
  49. package/dist/utils/templates.js +1 -1
  50. package/package.json +11 -4
  51. package/templates/CLAUDE.md +49 -107
  52. package/dist/agent/daemon.d.ts +0 -130
  53. package/dist/agent/daemon.js +0 -606
  54. package/dist/agent/health-check.d.ts +0 -35
  55. package/dist/agent/health-check.js +0 -243
  56. package/dist/agent/pty-runner.d.ts +0 -53
  57. package/dist/agent/pty-runner.js +0 -190
  58. package/dist/commands/agent.d.ts +0 -50
  59. package/dist/commands/agent.js +0 -544
  60. package/dist/commands/setup-remote.d.ts +0 -20
  61. package/dist/commands/setup-remote.js +0 -582
  62. package/dist/utils/verify-remote-terminal.d.ts +0 -10
  63. package/dist/utils/verify-remote-terminal.js +0 -415
  64. package/templates/README.md +0 -378
  65. package/templates/claude-plugins/PHASE2_COMPLETION.md +0 -346
  66. package/templates/claude-plugins/PLUGIN_PROPOSALS.md +0 -1776
  67. package/templates/claude-plugins/README.md +0 -587
  68. package/templates/claude-plugins/agents/code-reviewer.json +0 -14
  69. package/templates/claude-plugins/agents/debug-detective.json +0 -15
  70. package/templates/claude-plugins/agents/git-companion.json +0 -14
  71. package/templates/claude-plugins/blog-manager/.claude-plugin/plugin.json +0 -8
  72. package/templates/claude-plugins/blog-manager/commands/blog.md +0 -691
  73. package/templates/claude-plugins/golden-loop-monitor/.claude-plugin/plugin.json +0 -8
  74. package/templates/claude-plugins/golden-loop-monitor/commands/loop-status.md +0 -434
  75. package/templates/claude-plugins/learning-tracker/.claude-plugin/plugin.json +0 -8
  76. package/templates/claude-plugins/learning-tracker/commands/my-patterns.md +0 -282
  77. package/templates/claude-plugins/memory-lens/.claude-plugin/plugin.json +0 -8
  78. package/templates/claude-plugins/memory-lens/commands/memory-search.md +0 -181
  79. package/templates/claude-plugins/pattern-coach/.claude-plugin/plugin.json +0 -8
  80. package/templates/claude-plugins/pattern-coach/commands/forge.md +0 -365
  81. package/templates/claude-plugins/project-schema-validator/.claude-plugin/plugin.json +0 -8
  82. package/templates/claude-plugins/project-schema-validator/commands/validate-schema.md +0 -582
  83. package/templates/claude-plugins-admin/AGENT_TEAM_PROPOSALS.md +0 -819
  84. package/templates/claude-plugins-admin/README.md +0 -446
  85. package/templates/claude-plugins-admin/autonomous-admin-agent/.claude-plugin/plugin.json +0 -8
  86. package/templates/claude-plugins-admin/autonomous-admin-agent/commands/agent.md +0 -595
  87. package/templates/claude-plugins-admin/backend-agent/.claude-plugin/plugin.json +0 -8
  88. package/templates/claude-plugins-admin/backend-agent/commands/backend.md +0 -798
  89. package/templates/claude-plugins-admin/deploy-guardian/.claude-plugin/plugin.json +0 -8
  90. package/templates/claude-plugins-admin/deploy-guardian/commands/deploy.md +0 -554
  91. package/templates/claude-plugins-admin/frontend-agent/.claude-plugin/plugin.json +0 -8
  92. package/templates/claude-plugins-admin/frontend-agent/commands/frontend.md +0 -881
  93. package/templates/claude-plugins-admin/mcp-server-manager/.claude-plugin/plugin.json +0 -8
  94. package/templates/claude-plugins-admin/mcp-server-manager/commands/mcp.md +0 -85
  95. package/templates/claude-plugins-admin/memory-system-monitor/.claude-plugin/plugin.json +0 -8
  96. package/templates/claude-plugins-admin/memory-system-monitor/commands/memory-health.md +0 -569
  97. package/templates/claude-plugins-admin/qa-agent/.claude-plugin/plugin.json +0 -8
  98. package/templates/claude-plugins-admin/qa-agent/commands/qa.md +0 -863
  99. package/templates/claude-plugins-admin/tech-lead-agent/.claude-plugin/plugin.json +0 -8
  100. package/templates/claude-plugins-admin/tech-lead-agent/commands/lead.md +0 -732
  101. package/templates/commands/continue.md +0 -47
  102. package/templates/cursor-rules/ekkos-memory.md +0 -127
  103. package/templates/ekkos-manifest.json +0 -223
  104. package/templates/helpers/json-parse.cjs +0 -101
  105. package/templates/hooks-node/lib/state.js +0 -187
  106. package/templates/hooks-node/stop.js +0 -416
  107. package/templates/hooks-node/user-prompt-submit.js +0 -337
  108. package/templates/plan-template.md +0 -306
  109. package/templates/rules/00-hooks-contract.mdc +0 -89
  110. package/templates/rules/30-ekkos-core.mdc +0 -188
  111. package/templates/rules/31-ekkos-messages.mdc +0 -78
  112. package/templates/shared/hooks-enabled.json +0 -22
  113. package/templates/shared/session-words.json +0 -45
  114. package/templates/skills/ekkOS_Deep_Recall/Skill.md +0 -282
  115. package/templates/skills/ekkOS_Learn/Skill.md +0 -265
  116. package/templates/skills/ekkOS_Memory_First/Skill.md +0 -206
  117. package/templates/skills/ekkOS_Plan_Assist/Skill.md +0 -302
  118. package/templates/skills/ekkOS_Preferences/Skill.md +0 -247
  119. package/templates/skills/ekkOS_Reflect/Skill.md +0 -257
  120. package/templates/skills/ekkOS_Safety/Skill.md +0 -265
  121. package/templates/skills/ekkOS_Schema/Skill.md +0 -251
  122. package/templates/skills/ekkOS_Summary/Skill.md +0 -257
  123. package/templates/spec-template.md +0 -159
  124. package/templates/windsurf-rules/ekkos-memory.md +0 -127
  125. package/templates/windsurf-skills/README.md +0 -58
  126. package/templates/windsurf-skills/ekkos-continue/SKILL.md +0 -81
  127. package/templates/windsurf-skills/ekkos-golden-loop/SKILL.md +0 -225
  128. package/templates/windsurf-skills/ekkos-insights/SKILL.md +0 -138
  129. package/templates/windsurf-skills/ekkos-recall/SKILL.md +0 -96
  130. package/templates/windsurf-skills/ekkos-safety/SKILL.md +0 -89
  131. package/templates/windsurf-skills/ekkos-vault/SKILL.md +0 -86
package/dist/index.js CHANGED
@@ -42,19 +42,20 @@ const init_1 = require("./commands/init");
42
42
  const test_1 = require("./commands/test");
43
43
  const status_1 = require("./commands/status");
44
44
  const run_1 = require("./commands/run");
45
+ const gemini_1 = require("./commands/gemini");
45
46
  const test_claude_1 = require("./commands/test-claude");
46
47
  const doctor_1 = require("./commands/doctor");
47
48
  const stream_1 = require("./commands/stream");
49
+ const claw_1 = require("./commands/claw");
48
50
  // DEPRECATED: Hooks removed in hookless architecture migration
49
51
  // hooksInstall, hooksVerify, hooksStatus no longer called — `hooks` command prints a deprecation notice.
50
- const setup_remote_1 = require("./commands/setup-remote");
51
- const agent_1 = require("./commands/agent");
52
52
  const state_1 = require("./utils/state");
53
53
  const index_1 = require("./commands/usage/index");
54
54
  const dashboard_1 = require("./commands/dashboard");
55
55
  const swarm_1 = require("./commands/swarm");
56
56
  const swarm_dashboard_1 = require("./commands/swarm-dashboard");
57
57
  const swarm_setup_1 = require("./commands/swarm-setup");
58
+ const scan_1 = require("./commands/scan");
58
59
  const chalk_1 = __importDefault(require("chalk"));
59
60
  const fs = __importStar(require("fs"));
60
61
  const path = __importStar(require("path"));
@@ -76,10 +77,13 @@ commander_1.program
76
77
  chalk_1.default.cyan.bold('Examples:'),
77
78
  ` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos')} ${chalk_1.default.gray('Start Claude Code with ekkOS memory (default: run)')}`,
78
79
  ` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos init')} ${chalk_1.default.gray('First-time setup — authenticate + configure your IDE')}`,
80
+ ` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos scan')} ${chalk_1.default.gray('Scan repo structure and seed system registry')}`,
81
+ ` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos scan --compile')} ${chalk_1.default.gray('Scan, seed, and trigger compile pass')}`,
79
82
  ` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos run --dashboard')} ${chalk_1.default.gray('Launch with live usage dashboard (tmux split)')}`,
80
83
  ` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos run -b')} ${chalk_1.default.gray('Launch with bypass permissions mode')}`,
81
84
  ` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos doctor --fix')} ${chalk_1.default.gray('Check and auto-fix system prerequisites')}`,
82
85
  ` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos usage daily')} ${chalk_1.default.gray("View today's token usage and costs")}`,
86
+ ` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos gemini')} ${chalk_1.default.gray('Launch Gemini CLI with ekkOS memory proxy')}`,
83
87
  ` ${chalk_1.default.gray('$')} ${chalk_1.default.white('ekkos swarm launch -t "build X"')} ${chalk_1.default.gray('Launch parallel workers on a task')}`,
84
88
  '',
85
89
  chalk_1.default.gray(' Run ') + chalk_1.default.white('ekkos <command> --help') + chalk_1.default.gray(' for detailed options on any command.'),
@@ -149,6 +153,7 @@ commander_1.program
149
153
  icon: '▸',
150
154
  commands: [
151
155
  { name: 'init', desc: 'Authenticate and configure your IDE (Claude, Cursor, Windsurf)' },
156
+ { name: 'scan', desc: 'Scan repo structure and seed ekkOS system registry' },
152
157
  { name: 'status', desc: 'Show memory status and installation info' },
153
158
  { name: 'test', desc: 'Test connection to ekkOS memory API' },
154
159
  { name: 'doctor', desc: 'Check system prerequisites (Node, PTY, Claude, MCP)' },
@@ -158,9 +163,10 @@ commander_1.program
158
163
  title: 'Running',
159
164
  icon: '▸',
160
165
  commands: [
161
- { name: 'run', desc: 'Launch Claude Code with ekkOS memory + auto-continue', note: 'default' },
162
- { name: 'test-claude', desc: 'Launch Claude with proxy only (no ccDNA/PTY) for debugging' },
166
+ { name: 'run', desc: 'Launch Claude Code with ekkOS memory', note: 'default' },
167
+ { name: 'test-claude', desc: 'Launch Claude with proxy only (no PTY) for debugging' },
163
168
  { name: 'sessions', desc: 'List active Claude Code sessions' },
169
+ { name: 'claw', desc: 'OpenClaw integration status and upgrade controls' },
164
170
  ],
165
171
  },
166
172
  {
@@ -173,14 +179,6 @@ commander_1.program
173
179
  { name: 'hooks', desc: '[DEPRECATED] Hooks no longer needed — use `ekkos run`' },
174
180
  ],
175
181
  },
176
- {
177
- title: 'Remote Terminal',
178
- icon: '▸',
179
- commands: [
180
- { name: 'setup-remote', desc: 'Set up remote access (run Claude on your PC from anywhere)' },
181
- { name: 'agent', desc: 'Manage the remote terminal agent (start, stop, status, logs)' },
182
- ],
183
- },
184
182
  {
185
183
  title: 'Swarm (Multi-Agent)',
186
184
  icon: '▸',
@@ -224,30 +222,86 @@ commander_1.program
224
222
  .option('-i, --ide <ide>', 'IDE to setup (claude, cursor, windsurf, all)')
225
223
  .option('-k, --key <key>', 'Use API key instead of device auth')
226
224
  .option('-f, --force', 'Force re-authentication and overwrite existing config')
225
+ .option('-q, --quick', 'Quick setup: auto-detect IDE, use defaults, only prompt for API key if missing')
227
226
  .option('--skip-hooks', '[DEPRECATED] Hooks are no longer deployed; this flag is a no-op')
228
227
  .option('--skip-skills', 'Skip skills deployment')
229
228
  .action(init_1.init);
229
+ // Scan command — discover repo systems and seed registry
230
+ commander_1.program
231
+ .command('scan')
232
+ .description('Scan repo structure, discover systems, and seed ekkOS registry')
233
+ .option('-c, --compile', 'Trigger a compile pass after seeding')
234
+ .option('-n, --dry-run', 'Show discovered systems without seeding')
235
+ .option('-p, --path <path>', 'Path to scan (default: current directory)')
236
+ .action((options) => {
237
+ (0, scan_1.scan)({
238
+ compile: options.compile,
239
+ dryRun: options.dryRun,
240
+ path: options.path,
241
+ });
242
+ });
230
243
  // Status command
231
244
  commander_1.program
232
245
  .command('status')
233
- .description('Show your ekkOS memory status and installation info')
234
- .action(status_1.status);
246
+ .description('Show live session metrics and memory status')
247
+ .option('-w, --watch', 'Watch mode — refresh session panel every 2s')
248
+ .option('--json', 'Output raw metrics JSON (no memory API call)')
249
+ .action((options) => {
250
+ (0, status_1.status)({ watch: options.watch, json: options.json });
251
+ });
252
+ // OpenClaw integration commands
253
+ const clawCmd = commander_1.program
254
+ .command('claw')
255
+ .description('Manage OpenClaw + ekkOS integration');
256
+ clawCmd
257
+ .command('status')
258
+ .description('Show OpenClaw runtime + ekkOS proxy integration status')
259
+ .option('-j, --json', 'Output machine-readable JSON')
260
+ .option('--proxy-url <url>', 'Expected ekkOS proxy URL (default: https://proxy.ekkos.dev)')
261
+ .option('--model <model>', 'Expected primary OpenClaw model (default: ekkos-proxy/claude-sonnet-4-6)')
262
+ .option('--workspace <path>', 'Expected OpenClaw workspace path')
263
+ .action((options) => {
264
+ (0, claw_1.clawStatus)({
265
+ json: options.json,
266
+ proxyUrl: options.proxyUrl,
267
+ model: options.model,
268
+ workspace: options.workspace,
269
+ });
270
+ });
271
+ clawCmd
272
+ .command('upgrade')
273
+ .description('Apply foundation config upgrades for OpenClaw -> ekkOS proxy routing')
274
+ .option('--apply', 'Write changes to ~/.openclaw/openclaw.json (otherwise dry run)')
275
+ .option('--force', 'Reserved for future migration modes')
276
+ .option('-j, --json', 'Output machine-readable JSON')
277
+ .option('--proxy-url <url>', 'Target ekkOS proxy URL')
278
+ .option('--model <model>', 'Target primary OpenClaw model')
279
+ .option('--workspace <path>', 'Expected OpenClaw workspace path for status verification')
280
+ .action((options) => {
281
+ (0, claw_1.clawUpgrade)({
282
+ apply: options.apply,
283
+ force: options.force,
284
+ json: options.json,
285
+ proxyUrl: options.proxyUrl,
286
+ model: options.model,
287
+ workspace: options.workspace,
288
+ });
289
+ });
235
290
  // Test command
236
291
  commander_1.program
237
292
  .command('test')
238
293
  .description('Test connection to ekkOS memory')
239
294
  .action(test_1.test);
240
- // Run command - launches Claude with auto-continue wrapper
295
+ // Run command - launches Claude Code with ekkOS proxy
241
296
  commander_1.program
242
297
  .command('run')
243
- .description('Launch Claude Code with auto-continue (auto /clear + /continue when context is high)')
298
+ .description('Launch Claude Code with ekkOS memory proxy (IPC compression + pattern injection)')
244
299
  .option('-s, --session <name>', 'Session name to restore on clear')
245
300
  .option('-b, --bypass', 'Enable bypass permissions mode (dangerously skip all permission checks)')
246
301
  .option('-v, --verbose', 'Show debug output')
247
302
  .option('-d, --doctor', 'Run diagnostics before starting')
248
303
  .option('-r, --research', 'Auto-run research agent on startup (scans arXiv for new AI papers)')
249
304
  .option('--skip-inject', 'Monitor-only mode (detect context wall but print instructions instead of auto-inject)')
250
- .option('--skip-dna', 'Skip ccDNA injection (bypass Claude Code patching)')
251
305
  .option('--skip-proxy', 'Skip API proxy (use direct Anthropic API, disables seamless context eviction)')
252
306
  .option('--dashboard', 'Launch with live usage dashboard in an isolated 60/40 tmux split (requires tmux)')
253
307
  .option('--add-dir <dirs...>', 'Additional directories Claude Code can access (outside working directory)')
@@ -259,16 +313,29 @@ commander_1.program
259
313
  doctor: options.doctor,
260
314
  noInject: options.skipInject,
261
315
  research: options.research,
262
- noDna: options.skipDna,
263
316
  noProxy: options.skipProxy,
264
317
  dashboard: options.dashboard,
265
318
  addDirs: options.addDir,
266
319
  });
267
320
  });
321
+ // Gemini CLI — launch Gemini with ekkOS proxy
322
+ commander_1.program
323
+ .command('gemini')
324
+ .description('Launch Gemini CLI with ekkOS memory proxy (IPC compression + pattern injection)')
325
+ .option('-s, --session <name>', 'Session name')
326
+ .option('-v, --verbose', 'Show debug output')
327
+ .option('--skip-proxy', 'Skip API proxy (use direct Gemini API)')
328
+ .action((options) => {
329
+ (0, gemini_1.gemini)({
330
+ session: options.session,
331
+ verbose: options.verbose,
332
+ noProxy: options.skipProxy,
333
+ });
334
+ });
268
335
  // Test Claude — bare proxy test (no CLI wrapper)
269
336
  commander_1.program
270
337
  .command('test-claude')
271
- .description('Launch Claude Code with proxy only (no ccDNA, no PTY, no injections) for debugging')
338
+ .description('Launch Claude Code with proxy only (no PTY, no injections) for debugging')
272
339
  .option('--no-proxy', 'Skip proxy too (completely vanilla Claude)')
273
340
  .option('--no-hooks', 'Temporarily disable all hooks during test')
274
341
  .option('-v, --verbose', 'Show debug output')
@@ -381,83 +448,6 @@ commander_1.program
381
448
  key: options.key
382
449
  });
383
450
  });
384
- // ============================================================================
385
- // REMOTE TERMINAL COMMANDS
386
- // ============================================================================
387
- // Setup remote - one-command setup for remote terminal access
388
- commander_1.program
389
- .command('setup-remote')
390
- .description('Set up remote terminal access (run Claude on your PC from anywhere)')
391
- .option('-f, --force', 'Force re-pairing even if already paired')
392
- .option('--skip-service', 'Skip installing background service')
393
- .option('-v, --verbose', 'Show detailed output')
394
- .action((options) => {
395
- (0, setup_remote_1.setupRemote)({
396
- force: options.force,
397
- skipService: options.skipService,
398
- verbose: options.verbose,
399
- });
400
- });
401
- // Agent command - manage the background agent
402
- const agentCmd = commander_1.program
403
- .command('agent')
404
- .description('Manage the remote terminal agent');
405
- agentCmd
406
- .command('daemon')
407
- .description('Run the agent daemon (used by system service)')
408
- .option('-v, --verbose', 'Show verbose output')
409
- .action((options) => {
410
- (0, agent_1.agentDaemon)({ verbose: options.verbose });
411
- });
412
- agentCmd
413
- .command('start')
414
- .description('Start the agent service')
415
- .option('-v, --verbose', 'Show verbose output')
416
- .action((options) => {
417
- (0, agent_1.agentStart)({ verbose: options.verbose });
418
- });
419
- agentCmd
420
- .command('stop')
421
- .description('Stop the agent service')
422
- .option('-v, --verbose', 'Show verbose output')
423
- .action((options) => {
424
- (0, agent_1.agentStop)({ verbose: options.verbose });
425
- });
426
- agentCmd
427
- .command('restart')
428
- .description('Restart the agent service')
429
- .option('-v, --verbose', 'Show verbose output')
430
- .action((options) => {
431
- (0, agent_1.agentRestart)({ verbose: options.verbose });
432
- });
433
- agentCmd
434
- .command('status')
435
- .description('Check agent status and connection')
436
- .option('-v, --verbose', 'Show verbose output')
437
- .action((options) => {
438
- (0, agent_1.agentStatus)({ verbose: options.verbose });
439
- });
440
- agentCmd
441
- .command('uninstall')
442
- .description('Remove the agent service and unpair device')
443
- .option('-v, --verbose', 'Show verbose output')
444
- .action((options) => {
445
- (0, agent_1.agentUninstall)({ verbose: options.verbose });
446
- });
447
- agentCmd
448
- .command('logs')
449
- .description('Show agent logs')
450
- .option('-f, --follow', 'Follow log output (like tail -f)')
451
- .action((options) => {
452
- (0, agent_1.agentLogs)({ follow: options.follow });
453
- });
454
- agentCmd
455
- .command('health')
456
- .description('Check agent daemon health and diagnose connection issues')
457
- .option('-j, --json', 'Output machine-readable JSON')
458
- .action((options) => {
459
- (0, agent_1.agentHealth)({ json: options.json });
460
- });
461
451
  // Swarm command - manage Q-learning routing
462
452
  const swarmCmd = commander_1.program
463
453
  .command('swarm')
@@ -13,7 +13,7 @@ interface SessionNameResolution {
13
13
  encodedProjectPath: string;
14
14
  startedAt?: string;
15
15
  }
16
- /** Detect ekkOS 3-word session names like "lit-lex-zip" */
16
+ /** Detect ekkOS 3-word session names like "lit-lex-zip" or "ink-net-wag-235" */
17
17
  export declare function isEkkosSessionName(name: string): boolean;
18
18
  /** Resolve an ekkOS session name to a JSONL UUID */
19
19
  export declare function resolveSessionName(name: string): SessionNameResolution | null;
@@ -50,11 +50,12 @@ const os = __importStar(require("os"));
50
50
  const path = __importStar(require("path"));
51
51
  // ── Anthropic model pricing per 1M tokens ──────────────────────────────────
52
52
  const MODEL_PRICING = {
53
- 'claude-opus-4-6': { input: 15, output: 75, cacheWrite: 18.75, cacheRead: 1.50 },
54
- 'claude-opus-4-5-20250620': { input: 15, output: 75, cacheWrite: 18.75, cacheRead: 1.50 },
53
+ 'claude-opus-4-6': { input: 5, output: 25, cacheWrite: 6.25, cacheRead: 0.50 },
54
+ 'claude-opus-4-5-20250620': { input: 5, output: 25, cacheWrite: 6.25, cacheRead: 0.50 },
55
+ 'claude-sonnet-4-6': { input: 3, output: 15, cacheWrite: 3.75, cacheRead: 0.30 },
55
56
  'claude-sonnet-4-5-20250929': { input: 3, output: 15, cacheWrite: 3.75, cacheRead: 0.30 },
56
57
  'claude-sonnet-4-5-20250514': { input: 3, output: 15, cacheWrite: 3.75, cacheRead: 0.30 },
57
- 'claude-haiku-4-5-20251001': { input: 0.80, output: 4, cacheWrite: 1.00, cacheRead: 0.08 },
58
+ 'claude-haiku-4-5-20251001': { input: 1, output: 5, cacheWrite: 1.25, cacheRead: 0.10 },
58
59
  };
59
60
  function getModelPricing(modelId) {
60
61
  if (MODEL_PRICING[modelId])
@@ -74,12 +75,14 @@ function calculateTurnCost(model, usage) {
74
75
  (usage.cache_creation_tokens / 1000000) * p.cacheWrite +
75
76
  (usage.cache_read_tokens / 1000000) * p.cacheRead);
76
77
  }
77
- /** Detect ekkOS 3-word session names like "lit-lex-zip" */
78
+ /** Detect ekkOS 3-word session names like "lit-lex-zip" or "ink-net-wag-235" */
78
79
  function isEkkosSessionName(name) {
79
- return /^[a-z]+-[a-z]+-[a-z]+$/.test(name);
80
+ return /^[a-z]+-[a-z]+-[a-z]+(-\d+)?$/.test(name);
80
81
  }
81
82
  function encodeProjectPath(projectPath) {
82
- return projectPath.replace(/\//g, '-');
83
+ // Claude Code replaces all non-alphanumeric chars with '-' in project dir names.
84
+ // This must match Claude's encoding (e.g., /Volumes/ekkOS_Drive → -Volumes-ekkOS-Drive).
85
+ return projectPath.replace(/[^a-zA-Z0-9]/g, '-');
83
86
  }
84
87
  /** Resolve an ekkOS session name to a JSONL UUID */
85
88
  function resolveSessionName(name) {
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Local-First Mode — barrel export
3
+ *
4
+ * Phase 6 of the ekkOS Leadership Plan.
5
+ * Provides offline-capable memory, fallback logic, sync, and local embeddings.
6
+ */
7
+ export { LocalMemoryStore, localStore, } from './sqlite-store';
8
+ export type { Pattern, Directive, EpisodicMemory, SyncQueueItem, StoreStats, } from './sqlite-store';
9
+ export { callWithFallback, isOfflineFallbackReady, OFFLINE_CAPABLE_TOOLS, } from './offline-fallback';
10
+ export type { ToolCallResult, RemoteCallFn, } from './offline-fallback';
11
+ export { SyncEngine, createSyncEngine, } from './sync-engine';
12
+ export type { SyncResult, } from './sync-engine';
13
+ export { generateLocalEmbedding, cosineSimilarity, searchByEmbedding, isEmbeddingAvailable, } from './local-embeddings';
14
+ export type { SimilarityResult, } from './local-embeddings';
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ /**
3
+ * Local-First Mode — barrel export
4
+ *
5
+ * Phase 6 of the ekkOS Leadership Plan.
6
+ * Provides offline-capable memory, fallback logic, sync, and local embeddings.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.isEmbeddingAvailable = exports.searchByEmbedding = exports.cosineSimilarity = exports.generateLocalEmbedding = exports.createSyncEngine = exports.SyncEngine = exports.OFFLINE_CAPABLE_TOOLS = exports.isOfflineFallbackReady = exports.callWithFallback = exports.localStore = exports.LocalMemoryStore = void 0;
10
+ // SQLite memory store (Phase 6A)
11
+ var sqlite_store_1 = require("./sqlite-store");
12
+ Object.defineProperty(exports, "LocalMemoryStore", { enumerable: true, get: function () { return sqlite_store_1.LocalMemoryStore; } });
13
+ Object.defineProperty(exports, "localStore", { enumerable: true, get: function () { return sqlite_store_1.localStore; } });
14
+ // Offline MCP fallback (Phase 6B)
15
+ var offline_fallback_1 = require("./offline-fallback");
16
+ Object.defineProperty(exports, "callWithFallback", { enumerable: true, get: function () { return offline_fallback_1.callWithFallback; } });
17
+ Object.defineProperty(exports, "isOfflineFallbackReady", { enumerable: true, get: function () { return offline_fallback_1.isOfflineFallbackReady; } });
18
+ Object.defineProperty(exports, "OFFLINE_CAPABLE_TOOLS", { enumerable: true, get: function () { return offline_fallback_1.OFFLINE_CAPABLE_TOOLS; } });
19
+ // Sync engine (Phase 6C)
20
+ var sync_engine_1 = require("./sync-engine");
21
+ Object.defineProperty(exports, "SyncEngine", { enumerable: true, get: function () { return sync_engine_1.SyncEngine; } });
22
+ Object.defineProperty(exports, "createSyncEngine", { enumerable: true, get: function () { return sync_engine_1.createSyncEngine; } });
23
+ // Local embeddings (Phase 6D)
24
+ var local_embeddings_1 = require("./local-embeddings");
25
+ Object.defineProperty(exports, "generateLocalEmbedding", { enumerable: true, get: function () { return local_embeddings_1.generateLocalEmbedding; } });
26
+ Object.defineProperty(exports, "cosineSimilarity", { enumerable: true, get: function () { return local_embeddings_1.cosineSimilarity; } });
27
+ Object.defineProperty(exports, "searchByEmbedding", { enumerable: true, get: function () { return local_embeddings_1.searchByEmbedding; } });
28
+ Object.defineProperty(exports, "isEmbeddingAvailable", { enumerable: true, get: function () { return local_embeddings_1.isEmbeddingAvailable; } });
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Local Embeddings using ONNX Runtime
3
+ *
4
+ * Uses bge-small-en-v1.5 (384 dimensions) for offline similarity search.
5
+ * Same model OMEGA uses — lightweight, good quality.
6
+ *
7
+ * Note: Local embeddings are 384-dim (bge-small-en-v1.5)
8
+ * Cloud embeddings are 1536-dim (OpenAI text-embedding-3-small)
9
+ * On sync: re-embed with cloud model for consistency
10
+ *
11
+ * Optional dependency: @xenova/transformers
12
+ * If not installed, falls back to TF-IDF keyword similarity.
13
+ */
14
+ export interface SimilarityResult {
15
+ id: string;
16
+ score: number;
17
+ }
18
+ /**
19
+ * Generate a 384-dimensional embedding vector using bge-small-en-v1.5.
20
+ * Falls back to an empty array if @xenova/transformers is not installed.
21
+ * Callers should check array length before using for similarity.
22
+ */
23
+ export declare function generateLocalEmbedding(text: string): Promise<number[]>;
24
+ /**
25
+ * Cosine similarity between two dense numeric vectors.
26
+ * Returns a value in [-1, 1] (1 = identical direction).
27
+ */
28
+ export declare function cosineSimilarity(a: number[], b: number[]): number;
29
+ /**
30
+ * Rank candidates by semantic similarity to the query.
31
+ *
32
+ * Tries ONNX embedding first; falls back to TF-IDF keyword similarity if
33
+ * @xenova/transformers is not installed or if embedding fails.
34
+ *
35
+ * @param query - Search query string
36
+ * @param candidates - Items to rank (each has an `id` and `text` for embedding)
37
+ * @param topK - How many results to return (default 5)
38
+ *
39
+ * @returns Ranked array of { id, score } sorted by descending similarity
40
+ */
41
+ export declare function searchByEmbedding(query: string, candidates: {
42
+ id: string;
43
+ text: string;
44
+ }[], topK?: number): Promise<SimilarityResult[]>;
45
+ /**
46
+ * Check whether the ONNX embedding pipeline is available.
47
+ * Returns false if @xenova/transformers is not installed.
48
+ */
49
+ export declare function isEmbeddingAvailable(): Promise<boolean>;
@@ -0,0 +1,232 @@
1
+ "use strict";
2
+ /**
3
+ * Local Embeddings using ONNX Runtime
4
+ *
5
+ * Uses bge-small-en-v1.5 (384 dimensions) for offline similarity search.
6
+ * Same model OMEGA uses — lightweight, good quality.
7
+ *
8
+ * Note: Local embeddings are 384-dim (bge-small-en-v1.5)
9
+ * Cloud embeddings are 1536-dim (OpenAI text-embedding-3-small)
10
+ * On sync: re-embed with cloud model for consistency
11
+ *
12
+ * Optional dependency: @xenova/transformers
13
+ * If not installed, falls back to TF-IDF keyword similarity.
14
+ */
15
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ var desc = Object.getOwnPropertyDescriptor(m, k);
18
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
19
+ desc = { enumerable: true, get: function() { return m[k]; } };
20
+ }
21
+ Object.defineProperty(o, k2, desc);
22
+ }) : (function(o, m, k, k2) {
23
+ if (k2 === undefined) k2 = k;
24
+ o[k2] = m[k];
25
+ }));
26
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
27
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
28
+ }) : function(o, v) {
29
+ o["default"] = v;
30
+ });
31
+ var __importStar = (this && this.__importStar) || (function () {
32
+ var ownKeys = function(o) {
33
+ ownKeys = Object.getOwnPropertyNames || function (o) {
34
+ var ar = [];
35
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
36
+ return ar;
37
+ };
38
+ return ownKeys(o);
39
+ };
40
+ return function (mod) {
41
+ if (mod && mod.__esModule) return mod;
42
+ var result = {};
43
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
44
+ __setModuleDefault(result, mod);
45
+ return result;
46
+ };
47
+ })();
48
+ Object.defineProperty(exports, "__esModule", { value: true });
49
+ exports.generateLocalEmbedding = generateLocalEmbedding;
50
+ exports.cosineSimilarity = cosineSimilarity;
51
+ exports.searchByEmbedding = searchByEmbedding;
52
+ exports.isEmbeddingAvailable = isEmbeddingAvailable;
53
+ let _pipeline = null;
54
+ let _pipelineLoading = null;
55
+ let _transformersAvailable = null; // null = not yet checked
56
+ async function getTransformerPipeline() {
57
+ if (_transformersAvailable === false)
58
+ return null;
59
+ if (_pipeline)
60
+ return _pipeline;
61
+ if (_pipelineLoading)
62
+ return _pipelineLoading;
63
+ _pipelineLoading = (async () => {
64
+ try {
65
+ // Dynamic import — fails gracefully if package not installed
66
+ const mod = await Promise.resolve(`${'@xenova/transformers'}`).then(s => __importStar(require(s)));
67
+ const { pipeline } = mod;
68
+ // Load the bge-small-en-v1.5 model (384 dims, ~33MB)
69
+ const featureExtractor = await pipeline('feature-extraction', 'Xenova/bge-small-en-v1.5', {
70
+ quantized: true, // use int8 quantised version for speed
71
+ });
72
+ // Wrap in a normalised shape so callers get consistent output
73
+ const wrapped = async (text) => {
74
+ const output = await featureExtractor(text, { pooling: 'mean', normalize: true });
75
+ return output;
76
+ };
77
+ _pipeline = wrapped;
78
+ _transformersAvailable = true;
79
+ return wrapped;
80
+ }
81
+ catch {
82
+ _transformersAvailable = false;
83
+ return null;
84
+ }
85
+ })();
86
+ return _pipelineLoading;
87
+ }
88
+ // ---------------------------------------------------------------------------
89
+ // TF-IDF fallback
90
+ // ---------------------------------------------------------------------------
91
+ /**
92
+ * Build a simple term-frequency vector from a piece of text.
93
+ * Returns a sparse Map<term, tf> (normalised by document length).
94
+ */
95
+ function buildTfVector(text) {
96
+ const tokens = tokenise(text);
97
+ const tf = new Map();
98
+ for (const token of tokens) {
99
+ tf.set(token, (tf.get(token) ?? 0) + 1);
100
+ }
101
+ // Normalise by document length
102
+ for (const [term, count] of tf) {
103
+ tf.set(term, count / tokens.length);
104
+ }
105
+ return tf;
106
+ }
107
+ function tokenise(text) {
108
+ return text
109
+ .toLowerCase()
110
+ .replace(/[^a-z0-9\s]/g, ' ')
111
+ .split(/\s+/)
112
+ .filter(t => t.length > 1 && !STOP_WORDS.has(t));
113
+ }
114
+ /** Minimal English stop-word list */
115
+ const STOP_WORDS = new Set([
116
+ 'a', 'an', 'the', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for',
117
+ 'of', 'is', 'it', 'its', 'be', 'by', 'as', 'are', 'was', 'were', 'with',
118
+ 'this', 'that', 'from', 'not', 'we', 'i', 'you', 'he', 'she', 'they',
119
+ 'do', 'does', 'did', 'have', 'has', 'had', 'can', 'will', 'would', 'should',
120
+ 'so', 'if', 'up', 'out', 'no', 'my', 'your', 'our', 'all', 'more', 'also',
121
+ ]);
122
+ /**
123
+ * Cosine similarity between two TF sparse vectors.
124
+ */
125
+ function sparseCosine(a, b) {
126
+ let dot = 0;
127
+ let normA = 0;
128
+ let normB = 0;
129
+ for (const [term, va] of a) {
130
+ normA += va * va;
131
+ const vb = b.get(term) ?? 0;
132
+ dot += va * vb;
133
+ }
134
+ for (const [, vb] of b) {
135
+ normB += vb * vb;
136
+ }
137
+ const denom = Math.sqrt(normA) * Math.sqrt(normB);
138
+ return denom === 0 ? 0 : dot / denom;
139
+ }
140
+ // ---------------------------------------------------------------------------
141
+ // Exported functions
142
+ // ---------------------------------------------------------------------------
143
+ /**
144
+ * Generate a 384-dimensional embedding vector using bge-small-en-v1.5.
145
+ * Falls back to an empty array if @xenova/transformers is not installed.
146
+ * Callers should check array length before using for similarity.
147
+ */
148
+ async function generateLocalEmbedding(text) {
149
+ const pipe = await getTransformerPipeline();
150
+ if (!pipe)
151
+ return [];
152
+ try {
153
+ const result = await pipe(text);
154
+ return Array.from(result.data);
155
+ }
156
+ catch (err) {
157
+ console.warn('[LocalEmbeddings] generateLocalEmbedding failed:', err.message);
158
+ return [];
159
+ }
160
+ }
161
+ /**
162
+ * Cosine similarity between two dense numeric vectors.
163
+ * Returns a value in [-1, 1] (1 = identical direction).
164
+ */
165
+ function cosineSimilarity(a, b) {
166
+ if (a.length === 0 || b.length === 0 || a.length !== b.length)
167
+ return 0;
168
+ let dot = 0;
169
+ let normA = 0;
170
+ let normB = 0;
171
+ for (let i = 0; i < a.length; i++) {
172
+ dot += a[i] * b[i];
173
+ normA += a[i] * a[i];
174
+ normB += b[i] * b[i];
175
+ }
176
+ const denom = Math.sqrt(normA) * Math.sqrt(normB);
177
+ return denom === 0 ? 0 : dot / denom;
178
+ }
179
+ /**
180
+ * Rank candidates by semantic similarity to the query.
181
+ *
182
+ * Tries ONNX embedding first; falls back to TF-IDF keyword similarity if
183
+ * @xenova/transformers is not installed or if embedding fails.
184
+ *
185
+ * @param query - Search query string
186
+ * @param candidates - Items to rank (each has an `id` and `text` for embedding)
187
+ * @param topK - How many results to return (default 5)
188
+ *
189
+ * @returns Ranked array of { id, score } sorted by descending similarity
190
+ */
191
+ async function searchByEmbedding(query, candidates, topK = 5) {
192
+ if (candidates.length === 0)
193
+ return [];
194
+ const pipe = await getTransformerPipeline();
195
+ if (pipe) {
196
+ // --- ONNX path ---
197
+ try {
198
+ const queryVec = await generateLocalEmbedding(query);
199
+ if (queryVec.length === 0)
200
+ throw new Error('Empty query embedding');
201
+ const scored = await Promise.all(candidates.map(async (c) => {
202
+ const vec = await generateLocalEmbedding(c.text);
203
+ return { id: c.id, score: cosineSimilarity(queryVec, vec) };
204
+ }));
205
+ return scored
206
+ .sort((a, b) => b.score - a.score)
207
+ .slice(0, topK);
208
+ }
209
+ catch (err) {
210
+ console.warn('[LocalEmbeddings] ONNX search failed, falling back to TF-IDF:', err.message);
211
+ }
212
+ }
213
+ // --- TF-IDF keyword fallback ---
214
+ const queryTf = buildTfVector(query);
215
+ const scored = candidates.map((c) => ({
216
+ id: c.id,
217
+ score: sparseCosine(queryTf, buildTfVector(c.text)),
218
+ }));
219
+ return scored
220
+ .sort((a, b) => b.score - a.score)
221
+ .slice(0, topK);
222
+ }
223
+ /**
224
+ * Check whether the ONNX embedding pipeline is available.
225
+ * Returns false if @xenova/transformers is not installed.
226
+ */
227
+ async function isEmbeddingAvailable() {
228
+ if (_transformersAvailable !== null)
229
+ return _transformersAvailable;
230
+ const pipe = await getTransformerPipeline();
231
+ return pipe !== null;
232
+ }