@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.
- package/LICENSE +21 -0
- package/dist/capture/eviction-client.d.ts +139 -0
- package/dist/capture/eviction-client.js +454 -0
- package/dist/capture/index.d.ts +2 -0
- package/dist/capture/index.js +2 -0
- package/dist/capture/jsonl-rewriter.d.ts +96 -0
- package/dist/capture/jsonl-rewriter.js +1369 -0
- package/dist/capture/transcript-repair.d.ts +50 -0
- package/dist/capture/transcript-repair.js +308 -0
- package/dist/commands/doctor.js +23 -1
- package/dist/commands/run.d.ts +2 -0
- package/dist/commands/run.js +1229 -293
- package/dist/commands/usage.d.ts +7 -0
- package/dist/commands/usage.js +214 -0
- package/dist/cron/index.d.ts +7 -0
- package/dist/cron/index.js +13 -0
- package/dist/cron/promoter.d.ts +70 -0
- package/dist/cron/promoter.js +403 -0
- package/dist/index.js +24 -3
- package/dist/lib/usage-monitor.d.ts +47 -0
- package/dist/lib/usage-monitor.js +124 -0
- package/dist/lib/usage-parser.d.ts +72 -0
- package/dist/lib/usage-parser.js +238 -0
- package/dist/restore/RestoreOrchestrator.d.ts +4 -0
- package/dist/restore/RestoreOrchestrator.js +118 -30
- package/package.json +12 -12
- package/templates/cursor-hooks/after-agent-response.sh +0 -0
- package/templates/cursor-hooks/before-submit-prompt.sh +0 -0
- package/templates/cursor-hooks/stop.sh +0 -0
- package/templates/ekkos-manifest.json +2 -2
- package/templates/hooks/assistant-response.sh +0 -0
- package/templates/hooks/session-start.sh +0 -0
- package/templates/plan-template.md +0 -0
- package/templates/spec-template.md +0 -0
- package/templates/agents/README.md +0 -182
- package/templates/agents/code-reviewer.md +0 -166
- package/templates/agents/debug-detective.md +0 -169
- package/templates/agents/ekkOS_Vercel.md +0 -99
- package/templates/agents/extension-manager.md +0 -229
- package/templates/agents/git-companion.md +0 -185
- package/templates/agents/github-test-agent.md +0 -321
- package/templates/agents/railway-manager.md +0 -215
|
@@ -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 };
|