@ekkos/cli 0.2.18 → 1.0.0
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/README.md +57 -0
- package/dist/agent/daemon.d.ts +27 -0
- package/dist/agent/daemon.js +254 -29
- package/dist/agent/health-check.d.ts +35 -0
- package/dist/agent/health-check.js +243 -0
- package/dist/agent/pty-runner.d.ts +1 -0
- package/dist/agent/pty-runner.js +6 -1
- 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 +51 -0
- package/dist/capture/transcript-repair.js +319 -0
- package/dist/commands/agent.d.ts +6 -0
- package/dist/commands/agent.js +244 -0
- package/dist/commands/dashboard.d.ts +25 -0
- package/dist/commands/dashboard.js +1175 -0
- package/dist/commands/doctor.js +23 -1
- package/dist/commands/run.d.ts +5 -0
- package/dist/commands/run.js +1605 -516
- package/dist/commands/setup-remote.js +146 -37
- package/dist/commands/swarm-dashboard.d.ts +20 -0
- package/dist/commands/swarm-dashboard.js +735 -0
- package/dist/commands/swarm-setup.d.ts +10 -0
- package/dist/commands/swarm-setup.js +956 -0
- package/dist/commands/swarm.d.ts +46 -0
- package/dist/commands/swarm.js +441 -0
- package/dist/commands/test-claude.d.ts +16 -0
- package/dist/commands/test-claude.js +156 -0
- package/dist/commands/usage/blocks.d.ts +8 -0
- package/dist/commands/usage/blocks.js +60 -0
- package/dist/commands/usage/daily.d.ts +9 -0
- package/dist/commands/usage/daily.js +96 -0
- package/dist/commands/usage/dashboard.d.ts +8 -0
- package/dist/commands/usage/dashboard.js +104 -0
- package/dist/commands/usage/formatters.d.ts +41 -0
- package/dist/commands/usage/formatters.js +147 -0
- package/dist/commands/usage/index.d.ts +13 -0
- package/dist/commands/usage/index.js +87 -0
- package/dist/commands/usage/monthly.d.ts +8 -0
- package/dist/commands/usage/monthly.js +66 -0
- package/dist/commands/usage/session.d.ts +11 -0
- package/dist/commands/usage/session.js +193 -0
- package/dist/commands/usage/weekly.d.ts +9 -0
- package/dist/commands/usage/weekly.js +61 -0
- 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/deploy/instructions.d.ts +5 -2
- package/dist/deploy/instructions.js +11 -8
- package/dist/index.js +262 -5
- package/dist/lib/tmux-scrollbar.d.ts +14 -0
- package/dist/lib/tmux-scrollbar.js +296 -0
- package/dist/lib/usage-monitor.d.ts +47 -0
- package/dist/lib/usage-monitor.js +124 -0
- package/dist/lib/usage-parser.d.ts +162 -0
- package/dist/lib/usage-parser.js +583 -0
- package/dist/restore/RestoreOrchestrator.d.ts +4 -0
- package/dist/restore/RestoreOrchestrator.js +118 -30
- package/dist/utils/log-rotate.d.ts +18 -0
- package/dist/utils/log-rotate.js +74 -0
- package/dist/utils/platform.d.ts +2 -0
- package/dist/utils/platform.js +3 -1
- package/dist/utils/session-binding.d.ts +5 -0
- package/dist/utils/session-binding.js +46 -0
- package/dist/utils/state.js +4 -0
- package/dist/utils/verify-remote-terminal.d.ts +10 -0
- package/dist/utils/verify-remote-terminal.js +415 -0
- package/package.json +9 -2
- package/templates/CLAUDE.md +135 -23
- package/templates/ekkos-manifest.json +5 -5
- package/templates/hooks/lib/contract.sh +43 -31
- package/templates/hooks/lib/count-tokens.cjs +86 -0
- package/templates/hooks/lib/ekkos-reminders.sh +98 -0
- package/templates/hooks/lib/state.sh +53 -1
- package/templates/hooks/stop.sh +150 -388
- package/templates/hooks/user-prompt-submit.sh +353 -443
- package/templates/windsurf-hooks/README.md +212 -0
- package/templates/windsurf-hooks/hooks.json +9 -2
- package/templates/windsurf-hooks/install.sh +148 -0
- package/templates/windsurf-hooks/lib/contract.sh +2 -0
- package/templates/windsurf-hooks/post-cascade-response.sh +251 -0
- package/templates/windsurf-hooks/pre-user-prompt.sh +435 -0
- package/templates/windsurf-skills/ekkos-memory/SKILL.md +219 -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
- package/templates/windsurf-hooks/before-submit-prompt.sh +0 -238
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Simple usage monitoring for ekkOS embedding costs
|
|
4
|
+
* Tracks daily usage to prevent runaway costs
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.loadUsage = loadUsage;
|
|
11
|
+
exports.recordEmbedding = recordEmbedding;
|
|
12
|
+
exports.getUsageForDate = getUsageForDate;
|
|
13
|
+
exports.getUsageForDays = getUsageForDays;
|
|
14
|
+
exports.checkThreshold = checkThreshold;
|
|
15
|
+
exports.pruneOldUsage = pruneOldUsage;
|
|
16
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
17
|
+
const path_1 = __importDefault(require("path"));
|
|
18
|
+
const os_1 = require("os");
|
|
19
|
+
const USAGE_FILE = path_1.default.join((0, os_1.homedir)(), '.ekkos', 'usage.json');
|
|
20
|
+
const COST_PER_1M_TOKENS = 0.02; // OpenAI text-embedding-3-small
|
|
21
|
+
const AVG_TOKENS_PER_EMBEDDING = 100; // Conservative estimate
|
|
22
|
+
/**
|
|
23
|
+
* Ensure usage file exists
|
|
24
|
+
*/
|
|
25
|
+
async function ensureUsageFile() {
|
|
26
|
+
const dir = path_1.default.dirname(USAGE_FILE);
|
|
27
|
+
await promises_1.default.mkdir(dir, { recursive: true });
|
|
28
|
+
try {
|
|
29
|
+
await promises_1.default.access(USAGE_FILE);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
await promises_1.default.writeFile(USAGE_FILE, JSON.stringify([], null, 2));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Load usage records
|
|
37
|
+
*/
|
|
38
|
+
async function loadUsage() {
|
|
39
|
+
await ensureUsageFile();
|
|
40
|
+
const data = await promises_1.default.readFile(USAGE_FILE, 'utf-8');
|
|
41
|
+
return JSON.parse(data);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Save usage records
|
|
45
|
+
*/
|
|
46
|
+
async function saveUsage(records) {
|
|
47
|
+
await ensureUsageFile();
|
|
48
|
+
await promises_1.default.writeFile(USAGE_FILE, JSON.stringify(records, null, 2));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Record an embedding generation
|
|
52
|
+
*/
|
|
53
|
+
async function recordEmbedding(model = 'text-embedding-3-small', tokens = AVG_TOKENS_PER_EMBEDDING) {
|
|
54
|
+
const cost = (tokens / 1000000) * COST_PER_1M_TOKENS;
|
|
55
|
+
const today = new Date().toISOString().split('T')[0];
|
|
56
|
+
const records = await loadUsage();
|
|
57
|
+
records.push({
|
|
58
|
+
date: today,
|
|
59
|
+
embeddings: 1,
|
|
60
|
+
cost,
|
|
61
|
+
model,
|
|
62
|
+
});
|
|
63
|
+
await saveUsage(records);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get usage for a specific date
|
|
67
|
+
*/
|
|
68
|
+
async function getUsageForDate(date) {
|
|
69
|
+
const records = await loadUsage();
|
|
70
|
+
const dayRecords = records.filter(r => r.date === date);
|
|
71
|
+
const byModel = {};
|
|
72
|
+
let totalEmbeddings = 0;
|
|
73
|
+
let totalCost = 0;
|
|
74
|
+
for (const record of dayRecords) {
|
|
75
|
+
totalEmbeddings += record.embeddings;
|
|
76
|
+
totalCost += record.cost;
|
|
77
|
+
if (!byModel[record.model]) {
|
|
78
|
+
byModel[record.model] = { count: 0, cost: 0 };
|
|
79
|
+
}
|
|
80
|
+
byModel[record.model].count += record.embeddings;
|
|
81
|
+
byModel[record.model].cost += record.cost;
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
date,
|
|
85
|
+
totalEmbeddings,
|
|
86
|
+
totalCost,
|
|
87
|
+
byModel,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Get usage for the last N days
|
|
92
|
+
*/
|
|
93
|
+
async function getUsageForDays(days) {
|
|
94
|
+
const results = [];
|
|
95
|
+
const today = new Date();
|
|
96
|
+
for (let i = 0; i < days; i++) {
|
|
97
|
+
const date = new Date(today);
|
|
98
|
+
date.setDate(date.getDate() - i);
|
|
99
|
+
const dateStr = date.toISOString().split('T')[0];
|
|
100
|
+
const usage = await getUsageForDate(dateStr);
|
|
101
|
+
results.push(usage);
|
|
102
|
+
}
|
|
103
|
+
return results;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Check if usage exceeds threshold
|
|
107
|
+
*/
|
|
108
|
+
async function checkThreshold(dailyLimit = 10000, costLimit = 10.0) {
|
|
109
|
+
const today = new Date().toISOString().split('T')[0];
|
|
110
|
+
const usage = await getUsageForDate(today);
|
|
111
|
+
const exceeded = usage.totalEmbeddings > dailyLimit || usage.totalCost > costLimit;
|
|
112
|
+
return { exceeded, usage };
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Clear old usage data (keep last 90 days)
|
|
116
|
+
*/
|
|
117
|
+
async function pruneOldUsage() {
|
|
118
|
+
const records = await loadUsage();
|
|
119
|
+
const cutoff = new Date();
|
|
120
|
+
cutoff.setDate(cutoff.getDate() - 90);
|
|
121
|
+
const cutoffStr = cutoff.toISOString().split('T')[0];
|
|
122
|
+
const pruned = records.filter(r => r.date >= cutoffStr);
|
|
123
|
+
await saveUsage(pruned);
|
|
124
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
export interface ActiveSession {
|
|
2
|
+
sessionId: string;
|
|
3
|
+
sessionName: string;
|
|
4
|
+
pid: number;
|
|
5
|
+
startedAt: string;
|
|
6
|
+
projectPath: string;
|
|
7
|
+
lastHeartbeat: string;
|
|
8
|
+
}
|
|
9
|
+
interface SessionNameResolution {
|
|
10
|
+
uuid: string;
|
|
11
|
+
sessionName: string;
|
|
12
|
+
projectPath: string;
|
|
13
|
+
encodedProjectPath: string;
|
|
14
|
+
startedAt?: string;
|
|
15
|
+
}
|
|
16
|
+
/** Detect ekkOS 3-word session names like "lit-lex-zip" */
|
|
17
|
+
export declare function isEkkosSessionName(name: string): boolean;
|
|
18
|
+
/** Resolve an ekkOS session name to a JSONL UUID */
|
|
19
|
+
export declare function resolveSessionName(name: string): SessionNameResolution | null;
|
|
20
|
+
/** Parse a single JSONL file and return SessionUsage for an ekkOS-named session */
|
|
21
|
+
export declare function getSessionUsageByName(name: string): Promise<SessionUsage | null>;
|
|
22
|
+
/** List ekkOS sessions with lightweight cost data (for session list view) */
|
|
23
|
+
export declare function listEkkosSessions(limit?: number): Promise<{
|
|
24
|
+
name: string;
|
|
25
|
+
uuid: string;
|
|
26
|
+
projectPath: string;
|
|
27
|
+
startedAt: string;
|
|
28
|
+
lastHeartbeat: string;
|
|
29
|
+
cost: number;
|
|
30
|
+
tokens: number;
|
|
31
|
+
models: string[];
|
|
32
|
+
turnCount: number;
|
|
33
|
+
}[]>;
|
|
34
|
+
export interface TurnMetrics {
|
|
35
|
+
turn_number: number;
|
|
36
|
+
timestamp: string;
|
|
37
|
+
input_tokens: number;
|
|
38
|
+
output_tokens: number;
|
|
39
|
+
cache_read_tokens: number;
|
|
40
|
+
cache_creation_tokens: number;
|
|
41
|
+
total_tokens: number;
|
|
42
|
+
context_percentage: number;
|
|
43
|
+
model: string;
|
|
44
|
+
}
|
|
45
|
+
export interface SessionUsage {
|
|
46
|
+
session_id: string;
|
|
47
|
+
instance_id: string;
|
|
48
|
+
session_name: string;
|
|
49
|
+
turn_count: number;
|
|
50
|
+
total_input_tokens: number;
|
|
51
|
+
total_output_tokens: number;
|
|
52
|
+
total_cache_read_tokens: number;
|
|
53
|
+
total_cache_creation_tokens: number;
|
|
54
|
+
total_tokens: number;
|
|
55
|
+
total_cost: number;
|
|
56
|
+
avg_context_percentage: number;
|
|
57
|
+
max_context_percentage: number;
|
|
58
|
+
started_at: string;
|
|
59
|
+
last_activity: string;
|
|
60
|
+
models_used: string[];
|
|
61
|
+
turns: TurnMetrics[];
|
|
62
|
+
patterns_retrieved?: number;
|
|
63
|
+
patterns_applied?: number;
|
|
64
|
+
patterns_learned?: number;
|
|
65
|
+
confidence_gain?: number;
|
|
66
|
+
}
|
|
67
|
+
export interface CcusageSession {
|
|
68
|
+
sessionId: string;
|
|
69
|
+
inputTokens: number;
|
|
70
|
+
outputTokens: number;
|
|
71
|
+
cacheCreationTokens: number;
|
|
72
|
+
cacheReadTokens: number;
|
|
73
|
+
cost: number;
|
|
74
|
+
totalCost: number;
|
|
75
|
+
lastActivity: string;
|
|
76
|
+
versions?: string[];
|
|
77
|
+
modelsUsed: string[];
|
|
78
|
+
modelBreakdowns: {
|
|
79
|
+
modelName: string;
|
|
80
|
+
inputTokens: number;
|
|
81
|
+
outputTokens: number;
|
|
82
|
+
cacheCreationTokens: number;
|
|
83
|
+
cacheReadTokens: number;
|
|
84
|
+
cost: number;
|
|
85
|
+
}[];
|
|
86
|
+
projectPath: string;
|
|
87
|
+
}
|
|
88
|
+
/** Daily usage entry from ccusage */
|
|
89
|
+
export interface CcusageDailyUsage {
|
|
90
|
+
date: string;
|
|
91
|
+
inputTokens: number;
|
|
92
|
+
outputTokens: number;
|
|
93
|
+
cacheCreationTokens: number;
|
|
94
|
+
cacheReadTokens: number;
|
|
95
|
+
cost: number;
|
|
96
|
+
totalCost: number;
|
|
97
|
+
modelsUsed: string[];
|
|
98
|
+
modelBreakdowns: {
|
|
99
|
+
modelName: string;
|
|
100
|
+
inputTokens: number;
|
|
101
|
+
outputTokens: number;
|
|
102
|
+
cacheCreationTokens: number;
|
|
103
|
+
cacheReadTokens: number;
|
|
104
|
+
cost: number;
|
|
105
|
+
}[];
|
|
106
|
+
}
|
|
107
|
+
/** Weekly usage entry from ccusage */
|
|
108
|
+
export interface CcusageWeeklyUsage {
|
|
109
|
+
week: string;
|
|
110
|
+
inputTokens: number;
|
|
111
|
+
outputTokens: number;
|
|
112
|
+
cacheCreationTokens: number;
|
|
113
|
+
cacheReadTokens: number;
|
|
114
|
+
totalCost: number;
|
|
115
|
+
modelsUsed: string[];
|
|
116
|
+
modelBreakdowns: CcusageDailyUsage['modelBreakdowns'];
|
|
117
|
+
}
|
|
118
|
+
/** Monthly usage entry from ccusage */
|
|
119
|
+
export interface CcusageMonthlyUsage {
|
|
120
|
+
month: string;
|
|
121
|
+
inputTokens: number;
|
|
122
|
+
outputTokens: number;
|
|
123
|
+
cacheCreationTokens: number;
|
|
124
|
+
cacheReadTokens: number;
|
|
125
|
+
cost: number;
|
|
126
|
+
totalCost: number;
|
|
127
|
+
modelsUsed: string[];
|
|
128
|
+
modelBreakdowns: CcusageDailyUsage['modelBreakdowns'];
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get all sessions using ccusage library
|
|
132
|
+
*/
|
|
133
|
+
export declare function getAllSessions(instanceId?: string): Promise<SessionUsage[]>;
|
|
134
|
+
/**
|
|
135
|
+
* Get specific session usage using ccusage library
|
|
136
|
+
*/
|
|
137
|
+
export declare function getSessionUsage(sessionId: string, instanceId?: string): Promise<SessionUsage | null>;
|
|
138
|
+
/**
|
|
139
|
+
* Get human-readable session name
|
|
140
|
+
*/
|
|
141
|
+
export declare function getSessionName(sessionId: string): string;
|
|
142
|
+
/**
|
|
143
|
+
* Get current session ID from active Claude Code process
|
|
144
|
+
*/
|
|
145
|
+
export declare function getCurrentSessionId(): string | null;
|
|
146
|
+
/**
|
|
147
|
+
* Load daily usage data via ccusage library
|
|
148
|
+
*/
|
|
149
|
+
export declare function getDailyUsage(): Promise<CcusageDailyUsage[]>;
|
|
150
|
+
/**
|
|
151
|
+
* Load weekly usage data via ccusage library
|
|
152
|
+
*/
|
|
153
|
+
export declare function getWeeklyUsage(): Promise<CcusageWeeklyUsage[]>;
|
|
154
|
+
/**
|
|
155
|
+
* Load monthly usage data via ccusage library
|
|
156
|
+
*/
|
|
157
|
+
export declare function getMonthlyUsage(): Promise<CcusageMonthlyUsage[]>;
|
|
158
|
+
/**
|
|
159
|
+
* Load bucket (5-hour block) usage data via ccusage library
|
|
160
|
+
*/
|
|
161
|
+
export declare function getBucketUsage(): Promise<any[]>;
|
|
162
|
+
export {};
|