@ekkos/cli 0.2.18 → 0.3.3

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 (42) hide show
  1. package/LICENSE +21 -0
  2. package/dist/capture/eviction-client.d.ts +139 -0
  3. package/dist/capture/eviction-client.js +454 -0
  4. package/dist/capture/index.d.ts +2 -0
  5. package/dist/capture/index.js +2 -0
  6. package/dist/capture/jsonl-rewriter.d.ts +96 -0
  7. package/dist/capture/jsonl-rewriter.js +1369 -0
  8. package/dist/capture/transcript-repair.d.ts +50 -0
  9. package/dist/capture/transcript-repair.js +308 -0
  10. package/dist/commands/doctor.js +23 -1
  11. package/dist/commands/run.d.ts +2 -0
  12. package/dist/commands/run.js +1229 -293
  13. package/dist/commands/usage.d.ts +7 -0
  14. package/dist/commands/usage.js +214 -0
  15. package/dist/cron/index.d.ts +7 -0
  16. package/dist/cron/index.js +13 -0
  17. package/dist/cron/promoter.d.ts +70 -0
  18. package/dist/cron/promoter.js +403 -0
  19. package/dist/index.js +24 -3
  20. package/dist/lib/usage-monitor.d.ts +47 -0
  21. package/dist/lib/usage-monitor.js +124 -0
  22. package/dist/lib/usage-parser.d.ts +72 -0
  23. package/dist/lib/usage-parser.js +238 -0
  24. package/dist/restore/RestoreOrchestrator.d.ts +4 -0
  25. package/dist/restore/RestoreOrchestrator.js +118 -30
  26. package/package.json +12 -12
  27. package/templates/cursor-hooks/after-agent-response.sh +0 -0
  28. package/templates/cursor-hooks/before-submit-prompt.sh +0 -0
  29. package/templates/cursor-hooks/stop.sh +0 -0
  30. package/templates/ekkos-manifest.json +2 -2
  31. package/templates/hooks/assistant-response.sh +0 -0
  32. package/templates/hooks/session-start.sh +0 -0
  33. package/templates/plan-template.md +0 -0
  34. package/templates/spec-template.md +0 -0
  35. package/templates/agents/README.md +0 -182
  36. package/templates/agents/code-reviewer.md +0 -166
  37. package/templates/agents/debug-detective.md +0 -169
  38. package/templates/agents/ekkOS_Vercel.md +0 -99
  39. package/templates/agents/extension-manager.md +0 -229
  40. package/templates/agents/git-companion.md +0 -185
  41. package/templates/agents/github-test-agent.md +0 -321
  42. package/templates/agents/railway-manager.md +0 -215
@@ -0,0 +1,7 @@
1
+ /**
2
+ * ekkos usage [session-id] [--instance instance-id]
3
+ *
4
+ * Track Claude Code session token usage and context percentage
5
+ * Powered by ccusage (https://ccusage.com)
6
+ */
7
+ export declare function usageCommand(args: string[]): Promise<void>;
@@ -0,0 +1,214 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.usageCommand = usageCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const usage_parser_js_1 = require("../lib/usage-parser.js");
9
+ /**
10
+ * ekkos usage [session-id] [--instance instance-id]
11
+ *
12
+ * Track Claude Code session token usage and context percentage
13
+ * Powered by ccusage (https://ccusage.com)
14
+ */
15
+ async function usageCommand(args) {
16
+ const sessionIdArg = args[0];
17
+ const instanceIdFlag = args.indexOf('--instance');
18
+ const listFlag = args.includes('--list');
19
+ // Default instance ID (current project)
20
+ let instanceId = '-Volumes-MacMiniPort-DEV-EKKOS'; // Default to current project
21
+ if (instanceIdFlag !== -1 && args[instanceIdFlag + 1]) {
22
+ instanceId = args[instanceIdFlag + 1];
23
+ }
24
+ // List available sessions
25
+ if (listFlag) {
26
+ await listAvailableSessions(instanceId);
27
+ return;
28
+ }
29
+ // Show usage for specific session
30
+ if (!sessionIdArg) {
31
+ console.log(chalk_1.default.red('❌ Session ID required'));
32
+ console.log(chalk_1.default.gray('\nUsage:'));
33
+ console.log(chalk_1.default.gray(' ekkos usage <session-id> Show usage for session'));
34
+ console.log(chalk_1.default.gray(' ekkos usage --list List available sessions'));
35
+ console.log(chalk_1.default.gray(' ekkos usage <id> --instance <inst> Use specific instance'));
36
+ process.exit(1);
37
+ }
38
+ try {
39
+ console.log(chalk_1.default.gray('Fetching usage data from ccusage...'));
40
+ const usage = await (0, usage_parser_js_1.getSessionUsage)(sessionIdArg, instanceId);
41
+ if (!usage) {
42
+ console.log(chalk_1.default.yellow('⚠️ No usage data found for session'));
43
+ return;
44
+ }
45
+ displaySessionUsage(usage);
46
+ }
47
+ catch (err) {
48
+ console.log(chalk_1.default.red(`❌ Error: ${err.message}`));
49
+ process.exit(1);
50
+ }
51
+ }
52
+ /**
53
+ * Display session usage in formatted table
54
+ */
55
+ function displaySessionUsage(usage) {
56
+ console.log();
57
+ console.log(chalk_1.default.bold.cyan('═'.repeat(80)));
58
+ console.log(chalk_1.default.bold.cyan(` Session Usage: ${usage.session_name}`));
59
+ console.log(chalk_1.default.bold.cyan('═'.repeat(80)));
60
+ console.log();
61
+ // Summary section
62
+ console.log(chalk_1.default.bold('📊 Summary'));
63
+ console.log(chalk_1.default.gray('─'.repeat(80)));
64
+ console.log(` ${chalk_1.default.bold('Session ID:')} ${usage.session_id}`);
65
+ console.log(` ${chalk_1.default.bold('Turn Count:')} ${chalk_1.default.green(usage.turn_count.toString())}`);
66
+ console.log(` ${chalk_1.default.bold('Total Tokens:')} ${formatNumber(usage.total_tokens)}`);
67
+ console.log(` ${chalk_1.default.bold('Avg Context:')} ${formatPercentage(usage.avg_context_percentage)}`);
68
+ console.log(` ${chalk_1.default.bold('Max Context:')} ${formatPercentage(usage.max_context_percentage)}`);
69
+ console.log(` ${chalk_1.default.bold('Started:')} ${formatTimestamp(usage.started_at)}`);
70
+ console.log(` ${chalk_1.default.bold('Last Activity:')} ${formatTimestamp(usage.last_activity)}`);
71
+ console.log();
72
+ // Token breakdown
73
+ console.log(chalk_1.default.bold('🔢 Token Breakdown'));
74
+ console.log(chalk_1.default.gray('─'.repeat(80)));
75
+ console.log(` ${chalk_1.default.bold('Input Tokens:')} ${formatNumber(usage.total_input_tokens)}`);
76
+ console.log(` ${chalk_1.default.bold('Output Tokens:')} ${formatNumber(usage.total_output_tokens)}`);
77
+ console.log(` ${chalk_1.default.bold('Cache Read:')} ${formatNumber(usage.total_cache_read_tokens)} ${chalk_1.default.gray('(90% discount)')}`);
78
+ console.log(` ${chalk_1.default.bold('Cache Creation:')} ${formatNumber(usage.total_cache_creation_tokens)} ${chalk_1.default.gray('(25% premium)')}`);
79
+ console.log();
80
+ // Cost breakdown
81
+ console.log(chalk_1.default.bold('💰 Cost'));
82
+ console.log(chalk_1.default.gray('─'.repeat(80)));
83
+ console.log(` ${chalk_1.default.bold('Total Cost:')} ${chalk_1.default.green('$' + usage.total_cost.toFixed(2))}`);
84
+ console.log(` ${chalk_1.default.bold('Models Used:')} ${chalk_1.default.cyan(usage.models_used.join(', '))}`);
85
+ console.log();
86
+ // ekkOS pattern metrics (if available)
87
+ if (usage.patterns_retrieved !== undefined) {
88
+ console.log(chalk_1.default.bold('🧠 ekkOS Pattern Metrics'));
89
+ console.log(chalk_1.default.gray('─'.repeat(80)));
90
+ console.log(` ${chalk_1.default.bold('Patterns Retrieved:')} ${chalk_1.default.cyan(usage.patterns_retrieved.toString())}`);
91
+ console.log(` ${chalk_1.default.bold('Patterns Applied:')} ${chalk_1.default.green(usage.patterns_applied?.toString() || '0')}`);
92
+ console.log(` ${chalk_1.default.bold('Patterns Learned:')} ${chalk_1.default.yellow(usage.patterns_learned?.toString() || '0')}`);
93
+ console.log(` ${chalk_1.default.bold('Confidence Gain:')} ${chalk_1.default.magenta(`+${((usage.confidence_gain || 0) * 100).toFixed(1)}%`)}`);
94
+ console.log();
95
+ }
96
+ // Turn-by-turn breakdown (if available)
97
+ if (usage.turns.length > 0) {
98
+ console.log(chalk_1.default.bold('📈 Turn-by-Turn Breakdown'));
99
+ console.log(chalk_1.default.gray('─'.repeat(80)));
100
+ console.log(chalk_1.default.gray(' Turn') +
101
+ chalk_1.default.gray(' │ ') +
102
+ chalk_1.default.gray('Context %') +
103
+ chalk_1.default.gray(' │ ') +
104
+ chalk_1.default.gray('Input') +
105
+ chalk_1.default.gray(' │ ') +
106
+ chalk_1.default.gray('Output') +
107
+ chalk_1.default.gray(' │ ') +
108
+ chalk_1.default.gray('Cache Read') +
109
+ chalk_1.default.gray(' │ ') +
110
+ chalk_1.default.gray('Total'));
111
+ console.log(chalk_1.default.gray('─'.repeat(80)));
112
+ for (const turn of usage.turns) {
113
+ const turnStr = turn.turn_number.toString().padStart(4);
114
+ const contextStr = formatPercentage(turn.context_percentage).padStart(10);
115
+ const inputStr = formatNumber(turn.input_tokens).padStart(7);
116
+ const outputStr = formatNumber(turn.output_tokens).padStart(7);
117
+ const cacheStr = formatNumber(turn.cache_read_tokens).padStart(11);
118
+ const totalStr = formatNumber(turn.total_tokens).padStart(8);
119
+ // Color code context percentage
120
+ const contextColor = getContextColor(turn.context_percentage);
121
+ console.log(` ${turnStr} │ ${contextColor(contextStr)} │ ${inputStr} │ ${outputStr} │ ${cacheStr} │ ${totalStr}`);
122
+ }
123
+ console.log();
124
+ }
125
+ // VM validation status
126
+ const isVmWorking = validateVmBehavior(usage);
127
+ if (isVmWorking) {
128
+ console.log(chalk_1.default.green.bold('✅ VM Working: Context staying in constant band (good!)'));
129
+ }
130
+ else {
131
+ console.log(chalk_1.default.yellow.bold('⚠️ VM Warning: Context growing linearly (check proxy eviction)'));
132
+ }
133
+ console.log();
134
+ console.log(chalk_1.default.bold.cyan('═'.repeat(80)));
135
+ console.log();
136
+ }
137
+ /**
138
+ * List available sessions for an instance
139
+ */
140
+ async function listAvailableSessions(instanceId) {
141
+ console.log();
142
+ console.log(chalk_1.default.bold.cyan('📋 Available Sessions (via ccusage)'));
143
+ console.log(chalk_1.default.gray('─'.repeat(80)));
144
+ console.log(chalk_1.default.gray('Fetching sessions...'));
145
+ const sessions = await (0, usage_parser_js_1.getAllSessions)(instanceId);
146
+ if (sessions.length === 0) {
147
+ console.log(chalk_1.default.yellow(' No sessions found'));
148
+ console.log();
149
+ return;
150
+ }
151
+ for (const session of sessions) {
152
+ console.log(` ${chalk_1.default.bold(session.session_id)}`);
153
+ console.log(` ${chalk_1.default.gray('Turns:')} ${chalk_1.default.green(session.turn_count.toString())}, ${chalk_1.default.gray('Cost:')} ${chalk_1.default.green('$' + session.total_cost.toFixed(2))}, ${chalk_1.default.gray('Context:')} ${formatPercentage(session.avg_context_percentage)}`);
154
+ console.log(` ${chalk_1.default.gray('Last:')} ${session.last_activity}, ${chalk_1.default.gray('Models:')} ${chalk_1.default.cyan(session.models_used.join(', '))}`);
155
+ console.log();
156
+ }
157
+ }
158
+ /**
159
+ * Validate VM behavior based on context growth pattern
160
+ */
161
+ function validateVmBehavior(usage) {
162
+ if (usage.turn_count < 5) {
163
+ return true; // Too few turns to judge
164
+ }
165
+ // Check if context is staying in a constant band (±10%)
166
+ const contextValues = usage.turns.map(t => t.context_percentage);
167
+ const min = Math.min(...contextValues);
168
+ const max = Math.max(...contextValues);
169
+ const range = max - min;
170
+ // If range is small (< 15%), VM is working
171
+ return range < 15;
172
+ }
173
+ /**
174
+ * Format numbers with commas
175
+ */
176
+ function formatNumber(num) {
177
+ return num.toLocaleString('en-US');
178
+ }
179
+ /**
180
+ * Format percentage
181
+ */
182
+ function formatPercentage(pct) {
183
+ return `${pct.toFixed(1)}%`;
184
+ }
185
+ /**
186
+ * Format timestamp
187
+ */
188
+ function formatTimestamp(ts) {
189
+ try {
190
+ const date = new Date(ts);
191
+ return date.toLocaleString('en-US', {
192
+ month: 'short',
193
+ day: 'numeric',
194
+ hour: 'numeric',
195
+ minute: '2-digit',
196
+ hour12: true
197
+ });
198
+ }
199
+ catch {
200
+ return ts;
201
+ }
202
+ }
203
+ /**
204
+ * Get color for context percentage
205
+ */
206
+ function getContextColor(pct) {
207
+ if (pct < 30)
208
+ return chalk_1.default.green;
209
+ if (pct < 50)
210
+ return chalk_1.default.yellow;
211
+ if (pct < 70)
212
+ return chalk_1.default.hex('#FFA500'); // Orange
213
+ return chalk_1.default.red;
214
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * ekkOS Cron Jobs
3
+ * ================
4
+ *
5
+ * Background jobs for ekkOS maintenance and evolution.
6
+ */
7
+ export { evaluatePromotions, queryPatternStats, writePatchConfig, type PromoterConfig, type PromotionResult, type PromotedPatchConfig, type PromotedPattern, } from './promoter.js';
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ /**
3
+ * ekkOS Cron Jobs
4
+ * ================
5
+ *
6
+ * Background jobs for ekkOS maintenance and evolution.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.writePatchConfig = exports.queryPatternStats = exports.evaluatePromotions = void 0;
10
+ var promoter_js_1 = require("./promoter.js");
11
+ Object.defineProperty(exports, "evaluatePromotions", { enumerable: true, get: function () { return promoter_js_1.evaluatePromotions; } });
12
+ Object.defineProperty(exports, "queryPatternStats", { enumerable: true, get: function () { return promoter_js_1.queryPatternStats; } });
13
+ Object.defineProperty(exports, "writePatchConfig", { enumerable: true, get: function () { return promoter_js_1.writePatchConfig; } });
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ekkOS PROMETHEUS Pattern Promoter
4
+ * ==================================
5
+ *
6
+ * Daily cron job that evaluates patterns for promotion to constitutional memory.
7
+ *
8
+ * Constitutional patterns are injected into the system prompt via @ekkos/patch,
9
+ * making them "instincts" that don't require retrieval.
10
+ *
11
+ * Promotion Criteria (default):
12
+ * - Success rate ≥ 85%
13
+ * - Applications ≥ 5
14
+ * - Skip rate ≤ 10%
15
+ * - Confidence ≥ 70%
16
+ * - Used within last 30 days
17
+ * - Used in ≥ 2 unique sessions
18
+ *
19
+ * Usage:
20
+ * npx ekkos-promote # Run promotion evaluation
21
+ * npx ekkos-promote --dry-run # Preview without applying changes
22
+ * npx ekkos-promote --user <uuid> # Promote for specific user
23
+ *
24
+ * Schedule via launchd (macOS) or cron:
25
+ * 0 6 * * * /path/to/node /path/to/ekkos-promote
26
+ */
27
+ import { SupabaseClient } from '@supabase/supabase-js';
28
+ import { type PatternStats } from '@ekkos/prometheus';
29
+ interface PromoterConfig {
30
+ supabaseUrl: string;
31
+ supabaseKey: string;
32
+ dryRun: boolean;
33
+ userId?: string;
34
+ patchConfigPath: string;
35
+ verbose: boolean;
36
+ }
37
+ interface PromotionResult {
38
+ evaluated: number;
39
+ promoted: number;
40
+ demoted: number;
41
+ patterns: Array<{
42
+ patternId: string;
43
+ title: string;
44
+ action: 'promoted' | 'demoted' | 'unchanged';
45
+ score: number;
46
+ reason?: string;
47
+ }>;
48
+ patchConfig?: PromotedPatchConfig;
49
+ }
50
+ interface PromotedPattern {
51
+ id: string;
52
+ title: string;
53
+ problem: string;
54
+ solution: string;
55
+ promotedAt: string;
56
+ successRate: number;
57
+ appliedCount: number;
58
+ tags?: string[];
59
+ }
60
+ interface PromotedPatchConfig {
61
+ version: string;
62
+ generatedAt: string;
63
+ promotedPatterns: PromotedPattern[];
64
+ totalPatterns: number;
65
+ }
66
+ declare function queryPatternStats(supabase: SupabaseClient, userId?: string): Promise<PatternStats[]>;
67
+ declare function evaluatePromotions(supabase: SupabaseClient, config: PromoterConfig): Promise<PromotionResult>;
68
+ declare function writePatchConfig(config: PromotedPatchConfig, outputPath: string): void;
69
+ export { evaluatePromotions, queryPatternStats, writePatchConfig };
70
+ export type { PromoterConfig, PromotionResult, PromotedPatchConfig, PromotedPattern };