@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
@@ -63,11 +63,12 @@ const commander_1 = require("commander");
63
63
  const state_js_1 = require("../utils/state.js");
64
64
  // ── Pricing (per MTok) ──
65
65
  const MODEL_PRICING = {
66
- 'claude-opus-4-6': { input: 15, output: 75, cacheWrite: 18.75, cacheRead: 1.50 },
67
- 'claude-opus-4-5-20250620': { input: 15, output: 75, cacheWrite: 18.75, cacheRead: 1.50 },
66
+ 'claude-opus-4-6': { input: 5, output: 25, cacheWrite: 6.25, cacheRead: 0.50 },
67
+ 'claude-opus-4-5-20250620': { input: 5, output: 25, cacheWrite: 6.25, cacheRead: 0.50 },
68
+ 'claude-sonnet-4-6': { input: 3, output: 15, cacheWrite: 3.75, cacheRead: 0.30 },
68
69
  'claude-sonnet-4-5-20250929': { input: 3, output: 15, cacheWrite: 3.75, cacheRead: 0.30 },
69
70
  'claude-sonnet-4-5-20250514': { input: 3, output: 15, cacheWrite: 3.75, cacheRead: 0.30 },
70
- 'claude-haiku-4-5-20251001': { input: 0.80, output: 4, cacheWrite: 1.00, cacheRead: 0.08 },
71
+ 'claude-haiku-4-5-20251001': { input: 1, output: 5, cacheWrite: 1.25, cacheRead: 0.10 },
71
72
  };
72
73
  function getModelPricing(modelId) {
73
74
  if (MODEL_PRICING[modelId])
@@ -332,11 +333,20 @@ async function launchSwarmDashboard(launchTs, refreshMs) {
332
333
  const USAGE_H = 4;
333
334
  const FOOTER_H = 3;
334
335
  const FIXED_H = HEADER_H + WORKERS_H + USAGE_H + FOOTER_H;
336
+ function resolveChartRatio(height) {
337
+ if (height >= 62)
338
+ return 0.22;
339
+ if (height >= 48)
340
+ return 0.25;
341
+ if (height >= 36)
342
+ return 0.28;
343
+ return 0.32;
344
+ }
335
345
  function calcLayout() {
336
- const H = Math.max(30, screen.height);
346
+ const H = Math.max(30, screen.height || 30);
337
347
  const remaining = Math.max(10, H - FIXED_H);
338
- const chartH = Math.max(CHART_H_MIN, Math.floor(remaining * 0.30));
339
- const tableH = Math.max(4, remaining - chartH);
348
+ const chartH = Math.max(CHART_H_MIN, Math.floor(remaining * resolveChartRatio(H)));
349
+ const tableH = Math.max(5, remaining - chartH);
340
350
  return {
341
351
  header: { top: 0, height: HEADER_H },
342
352
  workers: { top: HEADER_H, height: WORKERS_H },
@@ -368,15 +378,20 @@ async function launchSwarmDashboard(launchTs, refreshMs) {
368
378
  border: { type: 'line' },
369
379
  label: ' Workers ',
370
380
  });
371
- const tokenChart = contrib.line({
372
- top: layout.chart.top, left: 0, width: W, height: layout.chart.height,
373
- label: ' Tokens/Turn (K) ',
374
- showLegend: true,
375
- legend: { width: 12 },
376
- style: { line: 'green', text: 'white', baseline: 'white', border: { fg: 'yellow' } },
377
- border: { type: 'line', fg: 'yellow' },
378
- xLabelPadding: 0, xPadding: 1, wholeNumbersOnly: false,
379
- });
381
+ function createTokenChart(top, left, width, height) {
382
+ return contrib.line({
383
+ top, left, width, height,
384
+ label: ' Tokens/Turn (K) ',
385
+ showLegend: true,
386
+ legend: { width: 12 },
387
+ style: { line: 'green', text: 'white', baseline: 'white', border: { fg: 'yellow' } },
388
+ border: { type: 'line', fg: 'yellow' },
389
+ xLabelPadding: 0, xPadding: 1, wholeNumbersOnly: false,
390
+ });
391
+ }
392
+ let tokenChart = createTokenChart(layout.chart.top, 0, W, layout.chart.height);
393
+ let chartLayoutW = 0;
394
+ let chartLayoutH = 0;
380
395
  const turnBox = blessed.box({
381
396
  top: layout.table.top, left: 0, width: W, height: layout.table.height,
382
397
  content: '',
@@ -413,22 +428,77 @@ async function launchSwarmDashboard(launchTs, refreshMs) {
413
428
  screen.append(footerBox);
414
429
  function applyLayout() {
415
430
  layout = calcLayout();
431
+ const fullWidth = Math.max(24, screen.width || 80);
432
+ const H_PAD = 1;
433
+ const contentWidth = Math.max(20, fullWidth - (H_PAD * 2));
416
434
  headerBox.top = layout.header.top;
435
+ headerBox.left = H_PAD;
436
+ headerBox.width = contentWidth;
417
437
  headerBox.height = layout.header.height;
418
438
  workersBox.top = layout.workers.top;
439
+ workersBox.left = H_PAD;
440
+ workersBox.width = contentWidth;
419
441
  workersBox.height = layout.workers.height;
420
- tokenChart.top = layout.chart.top;
421
- tokenChart.height = layout.chart.height;
442
+ if (chartLayoutW !== contentWidth || chartLayoutH !== layout.chart.height) {
443
+ try {
444
+ screen.remove(tokenChart);
445
+ }
446
+ catch { }
447
+ try {
448
+ tokenChart.destroy?.();
449
+ }
450
+ catch { }
451
+ tokenChart = createTokenChart(layout.chart.top, H_PAD, contentWidth, layout.chart.height);
452
+ chartLayoutW = contentWidth;
453
+ chartLayoutH = layout.chart.height;
454
+ screen.append(tokenChart);
455
+ }
456
+ else {
457
+ tokenChart.top = layout.chart.top;
458
+ tokenChart.left = H_PAD;
459
+ tokenChart.width = contentWidth;
460
+ tokenChart.height = layout.chart.height;
461
+ }
422
462
  turnBox.top = layout.table.top;
463
+ turnBox.left = H_PAD;
464
+ turnBox.width = contentWidth;
423
465
  turnBox.height = layout.table.height;
424
466
  windowBox.top = layout.usage.top;
467
+ windowBox.left = H_PAD;
468
+ windowBox.width = contentWidth;
425
469
  windowBox.height = layout.usage.height;
426
470
  footerBox.top = layout.footer.top;
471
+ footerBox.left = H_PAD;
472
+ footerBox.width = contentWidth;
427
473
  footerBox.height = layout.footer.height;
474
+ if (lastChartSeries) {
475
+ try {
476
+ tokenChart.setData(lastChartSeries);
477
+ }
478
+ catch { }
479
+ }
428
480
  }
429
481
  // ── State ──
430
482
  let lastWorkers = [];
483
+ let lastChartSeries = null;
431
484
  let sparkleTimer;
485
+ let lastLayoutW = screen.width || 0;
486
+ let lastLayoutH = screen.height || 0;
487
+ function ensureLayoutSynced() {
488
+ const w = screen.width || 0;
489
+ const h = screen.height || 0;
490
+ if (w === lastLayoutW && h === lastLayoutH)
491
+ return;
492
+ lastLayoutW = w;
493
+ lastLayoutH = h;
494
+ try {
495
+ screen.realloc?.();
496
+ }
497
+ catch { }
498
+ applyLayout();
499
+ }
500
+ // Apply once so initial render uses the final, padded geometry.
501
+ applyLayout();
432
502
  // ── Logo animation ──
433
503
  function renderLogoWave() {
434
504
  try {
@@ -446,11 +516,11 @@ async function launchSwarmDashboard(launchTs, refreshMs) {
446
516
  const rawLogoLen = 14; // " ekkOS_ Swarm " roughly
447
517
  const infoStr = ` ${lastWorkers.length}W ${totalTurns}t $${totalCost.toFixed(2)} ${durStr} `;
448
518
  const rawInfoLen = infoStr.length + 1;
449
- const boxW = screen.width - 2;
519
+ const boxW = Math.max(10, headerBox.width - 2);
450
520
  const pad = Math.max(1, boxW - rawLogoLen - rawInfoLen);
451
521
  headerBox.setLabel(logoStr + '\u2500'.repeat(pad) + infoStr);
452
522
  // Header content: task description
453
- const maxW = screen.width - 6;
523
+ const maxW = Math.max(8, headerBox.width - 6);
454
524
  const truncTask = taskStr.length > maxW ? taskStr.slice(0, maxW - 3) + '...' : taskStr;
455
525
  headerBox.setContent(` {gray-fg}Task:{/gray-fg} ${truncTask}`);
456
526
  waveOffset = (waveOffset + 1) % WAVE_COLORS.length;
@@ -471,7 +541,7 @@ async function launchSwarmDashboard(launchTs, refreshMs) {
471
541
  workersBox.setContent(' {gray-fg}No workers detected yet...{/gray-fg}');
472
542
  return;
473
543
  }
474
- const boxW = Math.max(20, screen.width - 4);
544
+ const boxW = Math.max(20, workersBox.width - 2);
475
545
  const WORKER_COLORS = ['magenta', 'blue', 'green', 'yellow', 'cyan', 'red', 'white', 'gray'];
476
546
  const lines = [];
477
547
  // Row 1: Worker names + context bars
@@ -510,8 +580,9 @@ async function launchSwarmDashboard(launchTs, refreshMs) {
510
580
  // ── Combined turn table ──
511
581
  function renderTurnTable(workers) {
512
582
  const WORKER_COLORS = ['magenta', 'blue', 'green', 'yellow', 'cyan', 'red', 'white', 'gray'];
513
- const w = Math.max(20, screen.width - 4);
583
+ const w = Math.max(18, turnBox.width - 4);
514
584
  const div = '{gray-fg}|{/gray-fg}';
585
+ const lastScrollPerc = turnBox.getScrollPerc();
515
586
  // Columns: W(2) Turn(4) Model(7) Context(7) CacheRd(flex) CacheWr(flex) Out(flex) Cost(7)
516
587
  const colW = 2;
517
588
  const colNum = 4;
@@ -540,8 +611,7 @@ async function launchSwarmDashboard(launchTs, refreshMs) {
540
611
  }
541
612
  // Sort by timestamp descending (newest first)
542
613
  allTurns.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
543
- const visibleRows = Math.max(1, layout.table.height - 4);
544
- const rows = allTurns.slice(0, visibleRows).map(t => {
614
+ const rows = allTurns.map(t => {
545
615
  const wColor = WORKER_COLORS[(t.workerIndex - 1) % WORKER_COLORS.length];
546
616
  const mTag = modelTag(t.routedModel);
547
617
  const mColor = t.routedModel.includes('haiku') ? 'green' : t.routedModel.includes('sonnet') ? 'blue' : 'magenta';
@@ -557,6 +627,9 @@ async function launchSwarmDashboard(launchTs, refreshMs) {
557
627
  costFlag + rpad(`$${t.cost.toFixed(2)}`, colCost) + costEnd);
558
628
  });
559
629
  turnBox.setContent([header, separator, ...rows].join('\n'));
630
+ if (lastScrollPerc > 0) {
631
+ turnBox.setScrollPerc(lastScrollPerc);
632
+ }
560
633
  }
561
634
  // ── Combined chart ──
562
635
  function renderChart(workers) {
@@ -576,16 +649,68 @@ async function launchSwarmDashboard(launchTs, refreshMs) {
576
649
  });
577
650
  }
578
651
  if (series.length > 0) {
652
+ lastChartSeries = series;
579
653
  tokenChart.setData(series);
580
654
  }
581
655
  }
582
656
  // ── Usage window (Anthropic OAuth) ──
657
+ function extractClaudeOauthAccessToken(rawBlob) {
658
+ const raw = (rawBlob || '').trim();
659
+ if (!raw)
660
+ return null;
661
+ const candidates = new Set([raw]);
662
+ if (/^[0-9a-fA-F]+$/.test(raw) && raw.length % 2 === 0) {
663
+ const decoded = Buffer.from(raw, 'hex').toString('utf8');
664
+ candidates.add(decoded);
665
+ candidates.add(decoded.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '').trim());
666
+ }
667
+ for (const candidate of candidates) {
668
+ if (!candidate)
669
+ continue;
670
+ try {
671
+ const parsed = JSON.parse(candidate);
672
+ const token = parsed?.claudeAiOauth?.accessToken;
673
+ if (typeof token === 'string' && token.length > 0)
674
+ return token;
675
+ }
676
+ catch { }
677
+ try {
678
+ const parsed = JSON.parse(`{${candidate}}`);
679
+ const token = parsed?.claudeAiOauth?.accessToken;
680
+ if (typeof token === 'string' && token.length > 0)
681
+ return token;
682
+ }
683
+ catch { }
684
+ const oauthMatch = candidate.match(/"claudeAiOauth"\s*:\s*(\{[\s\S]*?\})/);
685
+ if (oauthMatch) {
686
+ try {
687
+ const oauth = JSON.parse(oauthMatch[1]);
688
+ const token = oauth?.accessToken;
689
+ if (typeof token === 'string' && token.length > 0)
690
+ return token;
691
+ }
692
+ catch { }
693
+ const tokenMatch = oauthMatch[1].match(/"accessToken"\s*:\s*"([^"]+)"/);
694
+ if (tokenMatch?.[1])
695
+ return tokenMatch[1];
696
+ }
697
+ }
698
+ return null;
699
+ }
583
700
  async function fetchAnthropicUsage() {
584
701
  try {
585
- const { execSync } = require('child_process');
586
- const credsJson = execSync('security find-generic-password -s "Claude Code-credentials" -w', { encoding: 'utf-8', timeout: 5000 }).trim();
587
- const creds = JSON.parse(credsJson);
588
- const token = creds?.claudeAiOauth?.accessToken;
702
+ let token = null;
703
+ if (process.platform === 'darwin') {
704
+ const { execSync } = require('child_process');
705
+ const credsBlob = execSync('security find-generic-password -s "Claude Code-credentials" -w', { encoding: 'utf-8', timeout: 5000 }).trim();
706
+ token = extractClaudeOauthAccessToken(credsBlob);
707
+ }
708
+ if (!token) {
709
+ const credsPath = path.join(os.homedir(), '.claude', '.credentials.json');
710
+ if (fs.existsSync(credsPath)) {
711
+ token = extractClaudeOauthAccessToken(fs.readFileSync(credsPath, 'utf-8'));
712
+ }
713
+ }
589
714
  if (!token)
590
715
  return null;
591
716
  const resp = await fetch('https://api.anthropic.com/api/oauth/usage', {
@@ -664,6 +789,7 @@ async function launchSwarmDashboard(launchTs, refreshMs) {
664
789
  // ── Main update loop ──
665
790
  function updateDashboard() {
666
791
  try {
792
+ ensureLayoutSynced();
667
793
  const workers = discoverWorkers(launchTs);
668
794
  lastWorkers = workers;
669
795
  renderWorkerCards(workers);
@@ -691,7 +817,9 @@ async function launchSwarmDashboard(launchTs, refreshMs) {
691
817
  screen.on('resize', () => {
692
818
  try {
693
819
  screen.realloc?.();
694
- applyLayout();
820
+ lastLayoutW = 0;
821
+ lastLayoutH = 0;
822
+ ensureLayoutSynced();
695
823
  updateDashboard();
696
824
  }
697
825
  catch { }
@@ -32,7 +32,7 @@ export interface SwarmLaunchOptions {
32
32
  * - Uses tmux WINDOWS (not panes) — compatible with Python Queen discovery
33
33
  * - Window 0: Swarm Dashboard (blessed TUI showing all workers)
34
34
  * - Windows 1-N: Workers running `ekkos run -b` (proxy + infinite context)
35
- * - Each worker gets full ekkOS stack: proxy, hooks, ccDNA, context eviction
35
+ * - Each worker gets full ekkOS stack: proxy, hooks, context eviction
36
36
  *
37
37
  * Flow:
38
38
  * 1. Decompose task via Gemini Flash (free, fast)
@@ -194,7 +194,7 @@ function findPythonPath(swarmDir) {
194
194
  * - Uses tmux WINDOWS (not panes) — compatible with Python Queen discovery
195
195
  * - Window 0: Swarm Dashboard (blessed TUI showing all workers)
196
196
  * - Windows 1-N: Workers running `ekkos run -b` (proxy + infinite context)
197
- * - Each worker gets full ekkOS stack: proxy, hooks, ccDNA, context eviction
197
+ * - Each worker gets full ekkOS stack: proxy, hooks, context eviction
198
198
  *
199
199
  * Flow:
200
200
  * 1. Decompose task via Gemini Flash (free, fast)
@@ -2,11 +2,11 @@
2
2
  * ekkos test-claude — Bare proxy test (no CLI wrapper)
3
3
  *
4
4
  * Launches vanilla Claude Code with ONLY the proxy URL set.
5
- * No ccDNA, no PTY wrapper, no injection, no context management.
5
+ * No PTY wrapper, no injection, no context management.
6
6
  *
7
7
  * Purpose: Isolate whether fast context growth is caused by:
8
8
  * A) The proxy (IPC, injections, tool compression)
9
- * B) The ekkos CLI wrapper (ccDNA, PTY, run.ts logic)
9
+ * B) The ekkos CLI wrapper (PTY, run.ts logic)
10
10
  */
11
11
  export interface TestClaudeOptions {
12
12
  noProxy?: boolean;
@@ -3,11 +3,11 @@
3
3
  * ekkos test-claude — Bare proxy test (no CLI wrapper)
4
4
  *
5
5
  * Launches vanilla Claude Code with ONLY the proxy URL set.
6
- * No ccDNA, no PTY wrapper, no injection, no context management.
6
+ * No PTY wrapper, no injection, no context management.
7
7
  *
8
8
  * Purpose: Isolate whether fast context growth is caused by:
9
9
  * A) The proxy (IPC, injections, tool compression)
10
- * B) The ekkos CLI wrapper (ccDNA, PTY, run.ts logic)
10
+ * B) The ekkos CLI wrapper (PTY, run.ts logic)
11
11
  */
12
12
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
13
  if (k2 === undefined) k2 = k;
@@ -59,7 +59,7 @@ async function testClaude(options) {
59
59
  console.log(chalk_1.default.cyan('\n ekkOS test-claude — Bare Proxy Test'));
60
60
  console.log(chalk_1.default.gray(' ══════════════════════════════════'));
61
61
  console.log(chalk_1.default.green(' Proxy: ') + (options.noProxy ? chalk_1.default.yellow('NO') : chalk_1.default.green('YES')));
62
- console.log(chalk_1.default.green(' CLI: ') + chalk_1.default.yellow('NO (no ccDNA, no PTY, no inject)'));
62
+ console.log(chalk_1.default.green(' CLI: ') + chalk_1.default.yellow('NO (no PTY, no inject)'));
63
63
  console.log(chalk_1.default.green(' Hooks: ') + (options.noHooks ? chalk_1.default.yellow('NO (disabled)') : chalk_1.default.gray('YES (same .claude/hooks/)')));
64
64
  console.log('');
65
65
  // Resolve Claude path
@@ -2,6 +2,4 @@ export * from './mcp';
2
2
  export * from './settings';
3
3
  export * from './hooks';
4
4
  export * from './skills';
5
- export * from './agents';
6
- export * from './plugins';
7
5
  export * from './instructions';
@@ -19,6 +19,4 @@ __exportStar(require("./mcp"), exports);
19
19
  __exportStar(require("./settings"), exports);
20
20
  __exportStar(require("./hooks"), exports);
21
21
  __exportStar(require("./skills"), exports);
22
- __exportStar(require("./agents"), exports);
23
- __exportStar(require("./plugins"), exports);
24
22
  __exportStar(require("./instructions"), exports);
@@ -1,11 +1,12 @@
1
1
  /**
2
- * DEPRECATED: Hook configuration removed in hookless architecture migration.
3
- * Claude Code settings.json will NOT have any hooks entries written by ekkOS.
4
- * The CLI + proxy handle everything hooks are no longer needed.
2
+ * Claude Code settings.json management for ekkOS.
3
+ * - Disables Claude's built-in auto-memory (ekkOS replaces it with 11-layer memory)
4
+ * - Registers ekkOS hooks in correct Claude Code format (PascalCase events, { type, command } objects)
5
5
  */
6
6
  /**
7
- * Deploy Claude Code settings.json — no-op for hooks.
8
- * Preserves any existing settings but does NOT write any hooks configuration.
7
+ * Deploy Claude Code settings.json — disables auto-memory and configures hooks.
8
+ * ekkOS provides its own memory system via MCP, so Claude's built-in auto-memory
9
+ * is redundant and wastes ~1K tokens/turn on duplicate context.
9
10
  */
10
11
  export declare function deployClaudeSettings(): void;
11
12
  /**
@@ -1,37 +1,85 @@
1
1
  "use strict";
2
2
  /**
3
- * DEPRECATED: Hook configuration removed in hookless architecture migration.
4
- * Claude Code settings.json will NOT have any hooks entries written by ekkOS.
5
- * The CLI + proxy handle everything hooks are no longer needed.
3
+ * Claude Code settings.json management for ekkOS.
4
+ * - Disables Claude's built-in auto-memory (ekkOS replaces it with 11-layer memory)
5
+ * - Registers ekkOS hooks in correct Claude Code format (PascalCase events, { type, command } objects)
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
8
  exports.deployClaudeSettings = deployClaudeSettings;
9
9
  exports.areHooksConfigured = areHooksConfigured;
10
10
  const fs_1 = require("fs");
11
+ const path_1 = require("path");
12
+ const os_1 = require("os");
11
13
  const platform_1 = require("../utils/platform");
12
14
  /**
13
- * Deploy Claude Code settings.json — no-op for hooks.
14
- * Preserves any existing settings but does NOT write any hooks configuration.
15
+ * Deploy Claude Code settings.json — disables auto-memory and configures hooks.
16
+ * ekkOS provides its own memory system via MCP, so Claude's built-in auto-memory
17
+ * is redundant and wastes ~1K tokens/turn on duplicate context.
15
18
  */
16
19
  function deployClaudeSettings() {
17
20
  // Ensure .claude directory exists
18
21
  if (!(0, fs_1.existsSync)(platform_1.CLAUDE_DIR)) {
19
22
  (0, fs_1.mkdirSync)(platform_1.CLAUDE_DIR, { recursive: true });
20
23
  }
21
- // Read existing settings (if any) but do NOT add or modify hooks
22
- if (!(0, fs_1.existsSync)(platform_1.CLAUDE_SETTINGS)) {
23
- return; // Nothing to do — don't create an empty file
24
+ let settings = {};
25
+ if ((0, fs_1.existsSync)(platform_1.CLAUDE_SETTINGS)) {
26
+ try {
27
+ settings = JSON.parse((0, fs_1.readFileSync)(platform_1.CLAUDE_SETTINGS, 'utf-8'));
28
+ }
29
+ catch {
30
+ // Invalid JSON — start fresh
31
+ settings = {};
32
+ }
33
+ }
34
+ let changed = false;
35
+ // Disable Claude's built-in auto-memory — ekkOS replaces it
36
+ if (settings.autoMemoryEnabled !== false) {
37
+ settings.autoMemoryEnabled = false;
38
+ changed = true;
24
39
  }
25
- try {
26
- const settings = JSON.parse((0, fs_1.readFileSync)(platform_1.CLAUDE_SETTINGS, 'utf-8'));
27
- // Remove any previously-installed ekkOS hooks entries
28
- if ('hooks' in settings) {
29
- delete settings.hooks;
30
- (0, fs_1.writeFileSync)(platform_1.CLAUDE_SETTINGS, JSON.stringify(settings, null, 2));
40
+ // Build correct hooks config pointing to ~/.claude/hooks/ scripts.
41
+ // Claude Code requires PascalCase event names and { type, command } objects.
42
+ const hooksDir = (0, path_1.join)((0, os_1.homedir)(), '.claude', 'hooks');
43
+ const isWindows = process.platform === 'win32';
44
+ const ext = isWindows ? '.ps1' : '.sh';
45
+ const hookMapping = [
46
+ { event: 'SessionStart', script: `session-start${ext}` },
47
+ { event: 'UserPromptSubmit', script: `user-prompt-submit${ext}` },
48
+ { event: 'Stop', script: `stop${ext}` },
49
+ ];
50
+ // Only register hooks for scripts that actually exist on disk
51
+ const newHooks = {};
52
+ for (const { event, script } of hookMapping) {
53
+ const scriptPath = (0, path_1.join)(hooksDir, script);
54
+ if ((0, fs_1.existsSync)(scriptPath)) {
55
+ newHooks[event] = [
56
+ {
57
+ matcher: '',
58
+ hooks: [
59
+ {
60
+ type: 'command',
61
+ command: scriptPath,
62
+ },
63
+ ],
64
+ },
65
+ ];
31
66
  }
32
67
  }
33
- catch {
34
- // Invalid JSON or read error — leave the file alone
68
+ // Replace hooks if they differ from expected (fixes wrong format + adds missing)
69
+ const existingHooks = settings.hooks;
70
+ if (Object.keys(newHooks).length > 0) {
71
+ if (JSON.stringify(existingHooks) !== JSON.stringify(newHooks)) {
72
+ settings.hooks = newHooks;
73
+ changed = true;
74
+ }
75
+ }
76
+ else if (existingHooks) {
77
+ // No hook scripts on disk — remove stale hooks entry
78
+ delete settings.hooks;
79
+ changed = true;
80
+ }
81
+ if (changed) {
82
+ (0, fs_1.writeFileSync)(platform_1.CLAUDE_SETTINGS, JSON.stringify(settings, null, 2));
35
83
  }
36
84
  }
37
85
  /**
@@ -39,8 +39,7 @@ function areSkillsDeployed() {
39
39
  if (!(0, fs_1.existsSync)(platform_1.CLAUDE_SKILLS_DIR))
40
40
  return false;
41
41
  const deployed = (0, fs_1.readdirSync)(platform_1.CLAUDE_SKILLS_DIR);
42
- // Check for at least some core skills
43
- return deployed.length >= 5;
42
+ return deployed.length >= 1;
44
43
  }
45
44
  /**
46
45
  * Count deployed skills