@ekkos/cli 1.3.1 → 1.3.2
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/dist/commands/dashboard.js +147 -57
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +54 -16
- package/dist/commands/run.js +163 -44
- package/dist/commands/status.d.ts +4 -1
- package/dist/commands/status.js +165 -27
- package/dist/commands/synk.d.ts +7 -0
- package/dist/commands/synk.js +339 -0
- package/dist/deploy/settings.d.ts +6 -5
- package/dist/deploy/settings.js +27 -17
- package/dist/index.js +12 -82
- package/dist/lib/usage-parser.d.ts +1 -1
- package/dist/lib/usage-parser.js +5 -3
- package/dist/local/index.d.ts +14 -0
- package/dist/local/index.js +28 -0
- package/dist/local/local-embeddings.d.ts +49 -0
- package/dist/local/local-embeddings.js +232 -0
- package/dist/local/offline-fallback.d.ts +44 -0
- package/dist/local/offline-fallback.js +159 -0
- package/dist/local/sqlite-store.d.ts +126 -0
- package/dist/local/sqlite-store.js +393 -0
- package/dist/local/sync-engine.d.ts +42 -0
- package/dist/local/sync-engine.js +223 -0
- package/dist/synk/api.d.ts +22 -0
- package/dist/synk/api.js +133 -0
- package/dist/synk/auth.d.ts +7 -0
- package/dist/synk/auth.js +30 -0
- package/dist/synk/config.d.ts +18 -0
- package/dist/synk/config.js +37 -0
- package/dist/synk/daemon/control-client.d.ts +11 -0
- package/dist/synk/daemon/control-client.js +101 -0
- package/dist/synk/daemon/control-server.d.ts +24 -0
- package/dist/synk/daemon/control-server.js +91 -0
- package/dist/synk/daemon/run.d.ts +14 -0
- package/dist/synk/daemon/run.js +338 -0
- package/dist/synk/encryption.d.ts +17 -0
- package/dist/synk/encryption.js +133 -0
- package/dist/synk/index.d.ts +13 -0
- package/dist/synk/index.js +36 -0
- package/dist/synk/machine-client.d.ts +42 -0
- package/dist/synk/machine-client.js +218 -0
- package/dist/synk/persistence.d.ts +51 -0
- package/dist/synk/persistence.js +211 -0
- package/dist/synk/qr.d.ts +5 -0
- package/dist/synk/qr.js +33 -0
- package/dist/synk/session-bridge.d.ts +58 -0
- package/dist/synk/session-bridge.js +171 -0
- package/dist/synk/session-client.d.ts +46 -0
- package/dist/synk/session-client.js +240 -0
- package/dist/synk/types.d.ts +574 -0
- package/dist/synk/types.js +74 -0
- package/dist/utils/platform.d.ts +5 -1
- package/dist/utils/platform.js +24 -4
- package/dist/utils/proxy-url.d.ts +10 -0
- package/dist/utils/proxy-url.js +19 -0
- package/dist/utils/state.d.ts +1 -1
- package/dist/utils/state.js +11 -3
- package/package.json +13 -4
- package/templates/claude-plugins-admin/AGENT_TEAM_PROPOSALS.md +0 -819
- package/templates/claude-plugins-admin/README.md +0 -446
- package/templates/claude-plugins-admin/autonomous-admin-agent/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins-admin/autonomous-admin-agent/commands/agent.md +0 -595
- package/templates/claude-plugins-admin/backend-agent/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins-admin/backend-agent/commands/backend.md +0 -798
- package/templates/claude-plugins-admin/deploy-guardian/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins-admin/deploy-guardian/commands/deploy.md +0 -554
- package/templates/claude-plugins-admin/frontend-agent/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins-admin/frontend-agent/commands/frontend.md +0 -881
- package/templates/claude-plugins-admin/mcp-server-manager/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins-admin/mcp-server-manager/commands/mcp.md +0 -85
- package/templates/claude-plugins-admin/memory-system-monitor/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins-admin/memory-system-monitor/commands/memory-health.md +0 -569
- package/templates/claude-plugins-admin/qa-agent/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins-admin/qa-agent/commands/qa.md +0 -863
- package/templates/claude-plugins-admin/tech-lead-agent/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins-admin/tech-lead-agent/commands/lead.md +0 -732
- package/templates/hooks-node/lib/state.js +0 -187
- package/templates/hooks-node/stop.js +0 -416
- package/templates/hooks-node/user-prompt-submit.js +0 -337
- package/templates/rules/00-hooks-contract.mdc +0 -89
- package/templates/rules/30-ekkos-core.mdc +0 -188
- package/templates/rules/31-ekkos-messages.mdc +0 -78
|
@@ -1,337 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* ═══════════════════════════════════════════════════════════════════════════
|
|
4
|
-
* ekkOS_ Hook: UserPromptSubmit (Claude Code) - CAPTURE + RETRIEVE + INJECT
|
|
5
|
-
* Node.js version - Works on Windows, macOS, Linux without bash dependencies
|
|
6
|
-
*
|
|
7
|
-
* ARCHITECTURE: Dumb Hook, Smart Backend
|
|
8
|
-
* ═══════════════════════════════════════════════════════════════════════════
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
const https = require('https');
|
|
12
|
-
const http = require('http');
|
|
13
|
-
const fs = require('fs');
|
|
14
|
-
const path = require('path');
|
|
15
|
-
const os = require('os');
|
|
16
|
-
|
|
17
|
-
// Load state management
|
|
18
|
-
const state = require('./lib/state');
|
|
19
|
-
|
|
20
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
21
|
-
// ANSI Color Codes
|
|
22
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
23
|
-
const CYAN = '\x1b[0;36m';
|
|
24
|
-
const GREEN = '\x1b[0;32m';
|
|
25
|
-
const YELLOW = '\x1b[1;33m';
|
|
26
|
-
const MAGENTA = '\x1b[0;35m';
|
|
27
|
-
const DIM = '\x1b[2m';
|
|
28
|
-
const BOLD = '\x1b[1m';
|
|
29
|
-
const RESET = '\x1b[0m';
|
|
30
|
-
|
|
31
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
32
|
-
// HTTP Request Helper (uses built-in https module)
|
|
33
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
34
|
-
function httpRequest(url, options, data) {
|
|
35
|
-
return new Promise((resolve, reject) => {
|
|
36
|
-
const urlObj = new URL(url);
|
|
37
|
-
const lib = urlObj.protocol === 'https:' ? https : http;
|
|
38
|
-
const timeout = options.timeout || 2000;
|
|
39
|
-
|
|
40
|
-
const req = lib.request({
|
|
41
|
-
hostname: urlObj.hostname,
|
|
42
|
-
port: urlObj.port || (urlObj.protocol === 'https:' ? 443 : 80),
|
|
43
|
-
path: urlObj.pathname + urlObj.search,
|
|
44
|
-
method: options.method || 'GET',
|
|
45
|
-
headers: options.headers || {},
|
|
46
|
-
timeout: timeout
|
|
47
|
-
}, (res) => {
|
|
48
|
-
let body = '';
|
|
49
|
-
res.on('data', chunk => body += chunk);
|
|
50
|
-
res.on('end', () => {
|
|
51
|
-
try {
|
|
52
|
-
resolve(JSON.parse(body));
|
|
53
|
-
} catch {
|
|
54
|
-
resolve({ raw: body });
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
req.on('error', (e) => resolve({ error: e.message }));
|
|
60
|
-
req.on('timeout', () => {
|
|
61
|
-
req.destroy();
|
|
62
|
-
resolve({ error: 'timeout' });
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
if (data) req.write(typeof data === 'string' ? data : JSON.stringify(data));
|
|
66
|
-
req.end();
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
71
|
-
// Load Auth Token - PORTABLE: Check 3 sources in priority order
|
|
72
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
73
|
-
function loadAuthToken() {
|
|
74
|
-
const homeDir = os.homedir();
|
|
75
|
-
const ekkosConfig = path.join(homeDir, '.ekkos', 'config.json');
|
|
76
|
-
let authToken = '';
|
|
77
|
-
let userId = '';
|
|
78
|
-
|
|
79
|
-
// 1. First try ~/.ekkos/config.json (set by VS Code extension - most portable)
|
|
80
|
-
// Prefer hookApiKey (scoped key for hooks) over apiKey (legacy)
|
|
81
|
-
if (fs.existsSync(ekkosConfig)) {
|
|
82
|
-
try {
|
|
83
|
-
const config = JSON.parse(fs.readFileSync(ekkosConfig, 'utf8'));
|
|
84
|
-
authToken = config.hookApiKey || config.apiKey || '';
|
|
85
|
-
userId = config.userId || '';
|
|
86
|
-
} catch {}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// 2. Then try project .env.local (for developers with service role key)
|
|
90
|
-
if (!authToken) {
|
|
91
|
-
const envLocal = path.join(state.PROJECT_ROOT, '.env.local');
|
|
92
|
-
if (fs.existsSync(envLocal)) {
|
|
93
|
-
try {
|
|
94
|
-
const content = fs.readFileSync(envLocal, 'utf8');
|
|
95
|
-
const match = content.match(/^SUPABASE_SECRET_KEY=(.+)$/m);
|
|
96
|
-
if (match) {
|
|
97
|
-
authToken = match[1].replace(/["']/g, '').trim();
|
|
98
|
-
}
|
|
99
|
-
} catch {}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// 3. Finally try environment variable
|
|
104
|
-
if (!authToken) {
|
|
105
|
-
authToken = process.env.SUPABASE_SECRET_KEY || '';
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return { authToken, userId };
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
112
|
-
// Main Hook Logic
|
|
113
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
114
|
-
async function main() {
|
|
115
|
-
// Read JSON input from stdin
|
|
116
|
-
let inputData = '';
|
|
117
|
-
for await (const chunk of process.stdin) {
|
|
118
|
-
inputData += chunk;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
let input;
|
|
122
|
-
try {
|
|
123
|
-
input = JSON.parse(inputData);
|
|
124
|
-
} catch {
|
|
125
|
-
process.exit(0);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const userQuery = input.query || input.message || input.prompt || '';
|
|
129
|
-
const sessionId = input.session_id || 'unknown';
|
|
130
|
-
const modelInfo = input.model || 'claude-sonnet-4-5';
|
|
131
|
-
const transcriptPath = input.transcript_path || '';
|
|
132
|
-
|
|
133
|
-
// Skip if empty
|
|
134
|
-
if (!userQuery) {
|
|
135
|
-
process.exit(0);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Load auth
|
|
139
|
-
const { authToken, userId } = loadAuthToken();
|
|
140
|
-
const MEMORY_API_URL = 'https://mcp.ekkos.dev';
|
|
141
|
-
|
|
142
|
-
// Get current timestamp
|
|
143
|
-
const now = new Date();
|
|
144
|
-
const currentTime = now.toLocaleString('en-US', {
|
|
145
|
-
year: 'numeric',
|
|
146
|
-
month: '2-digit',
|
|
147
|
-
day: '2-digit',
|
|
148
|
-
hour: '2-digit',
|
|
149
|
-
minute: '2-digit',
|
|
150
|
-
hour12: true,
|
|
151
|
-
timeZoneName: 'short'
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
// Visual header
|
|
155
|
-
console.log('');
|
|
156
|
-
console.log(`${CYAN}${BOLD}🧠 ekkOS Memory${RESET} ${DIM}| Claude Code (${modelInfo}) | ${currentTime}${RESET}`);
|
|
157
|
-
|
|
158
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
159
|
-
// [ekkOS_CAPTURE] Capture the PREVIOUS exchange before processing new one
|
|
160
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
161
|
-
if (state.acquireLock(sessionId)) {
|
|
162
|
-
if (transcriptPath && fs.existsSync(transcriptPath)) {
|
|
163
|
-
try {
|
|
164
|
-
const transcriptContent = fs.readFileSync(transcriptPath, 'utf8');
|
|
165
|
-
const lines = transcriptContent.split('\n').filter(Boolean).map(l => {
|
|
166
|
-
try { return JSON.parse(l); } catch { return null; }
|
|
167
|
-
}).filter(Boolean);
|
|
168
|
-
|
|
169
|
-
// Get human messages
|
|
170
|
-
const humanMsgs = lines.filter(l => l.type === 'human');
|
|
171
|
-
const assistantMsgs = lines.filter(l => l.type === 'assistant');
|
|
172
|
-
|
|
173
|
-
// Get second-to-last human message (the previous query, not current)
|
|
174
|
-
const prevUser = humanMsgs.length > 1 ? humanMsgs[humanMsgs.length - 2]?.message : null;
|
|
175
|
-
|
|
176
|
-
// Get last assistant response
|
|
177
|
-
const lastAssistant = assistantMsgs[assistantMsgs.length - 1];
|
|
178
|
-
let prevAssistant = '';
|
|
179
|
-
if (lastAssistant?.message?.content) {
|
|
180
|
-
if (Array.isArray(lastAssistant.message.content)) {
|
|
181
|
-
prevAssistant = lastAssistant.message.content
|
|
182
|
-
.filter(c => c.type === 'text')
|
|
183
|
-
.map(c => c.text)
|
|
184
|
-
.join(' ');
|
|
185
|
-
} else {
|
|
186
|
-
prevAssistant = lastAssistant.message.content;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Capture if we have both
|
|
191
|
-
if (prevUser && prevAssistant) {
|
|
192
|
-
const prevHash = state.generateTurnHash(prevUser, prevAssistant);
|
|
193
|
-
|
|
194
|
-
if (!state.wasTurnCaptured(sessionId, prevHash)) {
|
|
195
|
-
// Capture in background (don't wait)
|
|
196
|
-
httpRequest(`${MEMORY_API_URL}/api/v1/memory/capture`, {
|
|
197
|
-
method: 'POST',
|
|
198
|
-
headers: {
|
|
199
|
-
'Authorization': `Bearer ${authToken}`,
|
|
200
|
-
'Content-Type': 'application/json'
|
|
201
|
-
},
|
|
202
|
-
timeout: 5000
|
|
203
|
-
}, {
|
|
204
|
-
user_query: prevUser,
|
|
205
|
-
assistant_response: prevAssistant,
|
|
206
|
-
session_id: `claude-code-${sessionId}`,
|
|
207
|
-
metadata: {
|
|
208
|
-
source: 'claude-code-hook-node',
|
|
209
|
-
model_used: modelInfo,
|
|
210
|
-
captured_at: new Date().toISOString()
|
|
211
|
-
}
|
|
212
|
-
}).catch(() => {});
|
|
213
|
-
|
|
214
|
-
state.markTurnCaptured(sessionId, prevHash);
|
|
215
|
-
console.log(`${CYAN} 💾 Capture${RESET} ${DIM}saving previous turn${RESET}`);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
} catch {}
|
|
219
|
-
}
|
|
220
|
-
state.releaseLock(sessionId);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
224
|
-
// [ekkOS_RETRIEVE] Single API call - backend handles ALL the work
|
|
225
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
226
|
-
console.log(`${MAGENTA} 🔍 Retrieve${RESET} ${DIM}searching memory substrate...${RESET}`);
|
|
227
|
-
|
|
228
|
-
let apiResponse;
|
|
229
|
-
if (!authToken) {
|
|
230
|
-
console.log(`${DIM} ⚠️ Retrieve${RESET} ${DIM}skipped (no auth)${RESET}`);
|
|
231
|
-
apiResponse = { error: 'no_auth', formatted_context: '', layers: { patterns: [], directives: [] } };
|
|
232
|
-
} else {
|
|
233
|
-
apiResponse = await httpRequest(`${MEMORY_API_URL}/api/v1/context/retrieve`, {
|
|
234
|
-
method: 'POST',
|
|
235
|
-
headers: {
|
|
236
|
-
'Authorization': `Bearer ${authToken}`,
|
|
237
|
-
'Content-Type': 'application/json'
|
|
238
|
-
},
|
|
239
|
-
timeout: 1500
|
|
240
|
-
}, {
|
|
241
|
-
query: userQuery,
|
|
242
|
-
user_id: userId || 'system',
|
|
243
|
-
session_id: `claude-code-${sessionId}`,
|
|
244
|
-
max_per_layer: 5,
|
|
245
|
-
include_layers: ['working', 'episodic', 'semantic', 'patterns', 'procedural', 'collective', 'codebase', 'directives'],
|
|
246
|
-
metadata: {
|
|
247
|
-
source: 'claude-code-node',
|
|
248
|
-
model_used: modelInfo
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
if (!apiResponse.layers) {
|
|
253
|
-
apiResponse = { error: 'timeout', formatted_context: '', layers: { patterns: [], directives: [] } };
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// Extract counts
|
|
258
|
-
const layers = apiResponse.layers || {};
|
|
259
|
-
const patternCount = (layers.patterns || []).length;
|
|
260
|
-
const directiveCount = (layers.directives || []).length;
|
|
261
|
-
const episodicCount = (layers.episodic || []).length;
|
|
262
|
-
const proceduralCount = (layers.procedural || []).length;
|
|
263
|
-
const codebaseCount = (layers.codebase || []).length;
|
|
264
|
-
const totalCount = patternCount + directiveCount + episodicCount + proceduralCount + codebaseCount;
|
|
265
|
-
|
|
266
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
267
|
-
// [ekkOS_INJECT] Output the formatted context
|
|
268
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
269
|
-
if (totalCount > 0) {
|
|
270
|
-
console.log(`${GREEN} ✨ Inject${RESET} ${GREEN}${totalCount}${RESET} ${DIM}memories loaded (${patternCount} patterns, ${directiveCount} directives)${RESET}`);
|
|
271
|
-
console.log('');
|
|
272
|
-
|
|
273
|
-
const formatted = apiResponse.formatted_context;
|
|
274
|
-
if (formatted) {
|
|
275
|
-
console.log(formatted);
|
|
276
|
-
} else {
|
|
277
|
-
// Fallback: structured output
|
|
278
|
-
if (patternCount > 0) {
|
|
279
|
-
console.log('## Pattern Memory (Layer 4) - Directive Compliant');
|
|
280
|
-
console.log('Proven solutions:');
|
|
281
|
-
for (const p of layers.patterns.slice(0, 5)) {
|
|
282
|
-
console.log(`${p.title || 'Untitled'}`);
|
|
283
|
-
console.log(` Problem: ${(p.problem || 'N/A').substring(0, 200)}`);
|
|
284
|
-
console.log(` Solution: ${(p.solution || 'N/A').substring(0, 300)}`);
|
|
285
|
-
console.log(` Success Rate: ${p.success_rate || 0}%`);
|
|
286
|
-
console.log('');
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
if (directiveCount > 0) {
|
|
291
|
-
console.log('## Directive Memory (Layer 9) - HIGHEST PRIORITY');
|
|
292
|
-
console.log('User rules that MUST be followed:');
|
|
293
|
-
for (const d of layers.directives.slice(0, 5)) {
|
|
294
|
-
console.log(` [${d.type || 'PREFER'}] ${d.rule || d.content || 'No rule'}`);
|
|
295
|
-
}
|
|
296
|
-
console.log('');
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (proceduralCount > 0) {
|
|
300
|
-
console.log('## Procedural Memory (Layer 5)');
|
|
301
|
-
console.log('Multi-step workflows:');
|
|
302
|
-
for (const p of layers.procedural.slice(0, 3)) {
|
|
303
|
-
console.log(` • ${p.title || p.name || 'Workflow'}`);
|
|
304
|
-
}
|
|
305
|
-
console.log('');
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if (episodicCount > 0) {
|
|
309
|
-
console.log('## Episodic Memory (Layer 2)');
|
|
310
|
-
console.log('Similar past conversations:');
|
|
311
|
-
for (const e of layers.episodic.slice(0, 3)) {
|
|
312
|
-
console.log(` • ${(e.query_preview || e.problem || 'Previous session').substring(0, 100)}...`);
|
|
313
|
-
}
|
|
314
|
-
console.log('');
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
if (codebaseCount > 0) {
|
|
318
|
-
console.log('## Codebase Memory (Layer 8)');
|
|
319
|
-
console.log('Project-specific knowledge:');
|
|
320
|
-
for (const c of layers.codebase.slice(0, 3)) {
|
|
321
|
-
console.log(` • ${c.file_path || c.title || 'Code pattern'}`);
|
|
322
|
-
}
|
|
323
|
-
console.log('');
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
} else {
|
|
327
|
-
console.log(`${DIM} 📭 Inject${RESET} ${DIM}no matching patterns found${RESET}`);
|
|
328
|
-
console.log('');
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// Save patterns for stop.js
|
|
332
|
-
state.savePatterns(sessionId, layers.patterns || [], modelInfo);
|
|
333
|
-
|
|
334
|
-
process.exit(0);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
main().catch(() => process.exit(0));
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
priority: 100
|
|
3
|
-
globs: ["**/*"]
|
|
4
|
-
alwaysApply: true
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# 🔒 Cursor Hooks Contract
|
|
8
|
-
|
|
9
|
-
⚠️ **MANDATORY**: Hooks run automatically - you don't call them manually
|
|
10
|
-
|
|
11
|
-
## Hook Architecture
|
|
12
|
-
|
|
13
|
-
**Dumb Hooks, Smart Backend** - Hooks just capture data, backend does analysis
|
|
14
|
-
|
|
15
|
-
### user-prompt-submit.sh (Runs BEFORE Response)
|
|
16
|
-
|
|
17
|
-
**Triggers**: When user sends a message
|
|
18
|
-
**Does**:
|
|
19
|
-
|
|
20
|
-
- Captures start time
|
|
21
|
-
- Retrieves patterns from MCP gateway (automatic)
|
|
22
|
-
- Displays patterns to user
|
|
23
|
-
- Saves patterns to `.cursor/state/` for badge
|
|
24
|
-
|
|
25
|
-
**You see**:
|
|
26
|
-
|
|
27
|
-
```
|
|
28
|
-
🧠 ekkOS™_Retrieving [18ms]
|
|
29
|
-
✓ 3 patterns loaded from memory
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
### stop.sh (Runs AFTER Response)
|
|
33
|
-
|
|
34
|
-
**Triggers**: When your response completes
|
|
35
|
-
**Does**:
|
|
36
|
-
|
|
37
|
-
- Captures conversation to memory API
|
|
38
|
-
- Generates badge with metrics
|
|
39
|
-
- Triggers async analysis (pattern detection, success judgment)
|
|
40
|
-
- Displays badge at end
|
|
41
|
-
|
|
42
|
-
**You see**:
|
|
43
|
-
|
|
44
|
-
```
|
|
45
|
-
[ekkOS_CAPTURE] ✓ Saved (ID: abc123...)
|
|
46
|
-
[reflex:uuid] badge
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## What You Do
|
|
50
|
-
|
|
51
|
-
**✅ DO**:
|
|
52
|
-
|
|
53
|
-
- Display `_ekkos_stream_message` when present in tool responses
|
|
54
|
-
- Call `forge_insight` when solving problems
|
|
55
|
-
- Show ekkOS branded messages
|
|
56
|
-
|
|
57
|
-
**❌ DON'T**:
|
|
58
|
-
|
|
59
|
-
- Manually call capture scripts (hooks do this)
|
|
60
|
-
- Generate badges yourself (hooks do this)
|
|
61
|
-
- Worry about pattern retrieval (MCP gateway does this)
|
|
62
|
-
|
|
63
|
-
## Hook Flow
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
User sends message
|
|
67
|
-
↓
|
|
68
|
-
user-prompt-submit.sh runs
|
|
69
|
-
↓
|
|
70
|
-
Patterns retrieved and displayed
|
|
71
|
-
↓
|
|
72
|
-
You respond (using patterns)
|
|
73
|
-
↓
|
|
74
|
-
stop.sh runs
|
|
75
|
-
↓
|
|
76
|
-
Conversation captured + badge generated
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Trust the Hooks
|
|
80
|
-
|
|
81
|
-
Hooks are:
|
|
82
|
-
|
|
83
|
-
- ✅ Fully portable (POSIX-compliant)
|
|
84
|
-
- ✅ Bulletproof (fallbacks for missing tools)
|
|
85
|
-
- ✅ Fast (non-blocking, cloud-first)
|
|
86
|
-
- ✅ Automatic (you never call them)
|
|
87
|
-
|
|
88
|
-
**Your job**: Use the patterns hooks provide, forge insights when you solve problems
|
|
89
|
-
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
priority: 100
|
|
3
|
-
globs: ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"]
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# 🧠 ekkOS™ Memory Integration [CRITICAL]
|
|
7
|
-
|
|
8
|
-
## Golden Loop Enforcement
|
|
9
|
-
|
|
10
|
-
⚠️ MANDATORY WORKFLOW - NO EXCEPTIONS
|
|
11
|
-
|
|
12
|
-
### Phase 1: RETRIEVE (⚠️ CURSOR: YOU MUST DO THIS)
|
|
13
|
-
|
|
14
|
-
🔴 **FIRST THING EVERY RESPONSE**: Call `ekkOS_Search` with the user's query!
|
|
15
|
-
|
|
16
|
-
```typescript
|
|
17
|
-
// ALWAYS call this BEFORE doing anything else
|
|
18
|
-
mcp__ekkos-memory__ekkOS_Search({
|
|
19
|
-
query: "<user's question or task>",
|
|
20
|
-
limit: 5
|
|
21
|
-
})
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
Then check response for: `_ekkos_patterns`, `_ekkos_stream_message`
|
|
25
|
-
|
|
26
|
-
**Why?** Cursor has no hooks. Claude Code auto-retrieves via hooks - you don't.
|
|
27
|
-
You MUST manually retrieve or the Golden Loop breaks.
|
|
28
|
-
|
|
29
|
-
### Phase 2: APPLY (Use Retrieved Patterns)
|
|
30
|
-
|
|
31
|
-
When patterns found → Apply them (PROVEN solutions, not suggestions)
|
|
32
|
-
Output: `[ekkOS_APPLY] Using pattern: "Pattern Name"`
|
|
33
|
-
|
|
34
|
-
### Phase 3: MEASURE (Track Outcomes)
|
|
35
|
-
|
|
36
|
-
Pattern worked? → success | Pattern failed? → failure
|
|
37
|
-
Output: `[ekkOS_MEASURE] Pattern "X" outcome: success/failure`
|
|
38
|
-
|
|
39
|
-
### Phase 4: LEARN (Forge New Patterns)
|
|
40
|
-
|
|
41
|
-
🔴 MANDATORY: Call `forge_insight` when you solve ANY problem
|
|
42
|
-
|
|
43
|
-
**When to forge**:
|
|
44
|
-
|
|
45
|
-
- Fixed bug (non-obvious) → forge
|
|
46
|
-
- Found better approach → forge
|
|
47
|
-
- Discovered gotcha/pitfall → forge
|
|
48
|
-
- User corrected you → forge
|
|
49
|
-
- Solved problem (>1 attempt) → forge
|
|
50
|
-
|
|
51
|
-
**Tool call**:
|
|
52
|
-
|
|
53
|
-
```typescript
|
|
54
|
-
mcp__ekkos-memory__forge_insight({
|
|
55
|
-
title: "Clear Title",
|
|
56
|
-
problem: "What failed?",
|
|
57
|
-
solution: "How you fixed it",
|
|
58
|
-
tags: ["tech", "tags"],
|
|
59
|
-
});
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
Output: `[ekkOS_LEARN] Forged: "Pattern Title"`
|
|
63
|
-
|
|
64
|
-
### Phase 5: CAPTURE (Cursor: Limited)
|
|
65
|
-
|
|
66
|
-
⚠️ **Cursor limitation**: No automatic capture like Claude Code hooks.
|
|
67
|
-
Conversations are captured when MCP tools are called (search_memory, forge_insight).
|
|
68
|
-
For full capture, use Claude Code or the ekkOS dashboard.
|
|
69
|
-
|
|
70
|
-
## MCP Tools (31 Total - YOU call these)
|
|
71
|
-
|
|
72
|
-
### 🔴 MANDATORY - Use Proactively
|
|
73
|
-
|
|
74
|
-
| Tool | Trigger | Description |
|
|
75
|
-
|------|---------|-------------|
|
|
76
|
-
| `ekkOS_Search` | Before ANY technical question | Search all 11 memory layers |
|
|
77
|
-
| `ekkOS_Forge` | When you fix bug, learn, get corrected | Create pattern from solution |
|
|
78
|
-
| `ekkOS_Directive` | User says "always/never/prefer/avoid" | Create MUST/NEVER/PREFER/AVOID rules |
|
|
79
|
-
| `ekkOS_Outcome` | Pattern worked or failed | Track success/failure |
|
|
80
|
-
| `ekkOS_Detect` | After responding | Auto-detect patterns used |
|
|
81
|
-
| `ekkOS_Summary` | Show MCP activity | Get activity summary |
|
|
82
|
-
| `ekkOS_Conflict` | Before destructive action | Check for conflicts |
|
|
83
|
-
| `ekkOS_Reflect` | Analyze response quality | Find improvement opportunities |
|
|
84
|
-
|
|
85
|
-
### 📚 Recall & Context
|
|
86
|
-
|
|
87
|
-
| Tool | Description |
|
|
88
|
-
|------|-------------|
|
|
89
|
-
| `ekkOS_Recall` | "What did we discuss yesterday?" |
|
|
90
|
-
| `ekkOS_Context` | Get task-specific context |
|
|
91
|
-
| `ekkOS_Codebase` | Find code patterns in project |
|
|
92
|
-
| `ekkOS_Capture` | Manual event capture |
|
|
93
|
-
| `ekkOS_Track` | Track pattern application |
|
|
94
|
-
| `ekkOS_Stats` | Memory layer statistics |
|
|
95
|
-
|
|
96
|
-
### 📊 Schema Awareness
|
|
97
|
-
|
|
98
|
-
| Tool | Description |
|
|
99
|
-
|------|-------------|
|
|
100
|
-
| `ekkOS_IndexSchema` | Index database schemas (Supabase/Prisma/TS) |
|
|
101
|
-
| `ekkOS_GetSchema` | Get schema for a specific table/type |
|
|
102
|
-
|
|
103
|
-
### 📋 Plan Management
|
|
104
|
-
|
|
105
|
-
| Tool | Description |
|
|
106
|
-
|------|-------------|
|
|
107
|
-
| `ekkOS_Plan` | Create structured plan |
|
|
108
|
-
| `ekkOS_Plans` | List user's plans |
|
|
109
|
-
| `ekkOS_PlanStatus` | Change plan state |
|
|
110
|
-
| `ekkOS_PlanStep` | Mark step complete |
|
|
111
|
-
| `ekkOS_Generate` | AI-generate plan |
|
|
112
|
-
| `ekkOS_SaveTemplate` | Save as reusable template |
|
|
113
|
-
| `ekkOS_Templates` | List templates |
|
|
114
|
-
| `ekkOS_FromTemplate` | Create from template |
|
|
115
|
-
|
|
116
|
-
### 🔐 Secrets Management
|
|
117
|
-
|
|
118
|
-
| Tool | Description |
|
|
119
|
-
|------|-------------|
|
|
120
|
-
| `ekkOS_StoreSecret` | Encrypt and store credentials |
|
|
121
|
-
| `ekkOS_GetSecret` | Retrieve and decrypt |
|
|
122
|
-
| `ekkOS_ListSecrets` | List metadata (no values) |
|
|
123
|
-
| `ekkOS_DeleteSecret` | Permanently delete |
|
|
124
|
-
| `ekkOS_RotateSecret` | Update with new value |
|
|
125
|
-
|
|
126
|
-
### 💾 Portability
|
|
127
|
-
|
|
128
|
-
| Tool | Description |
|
|
129
|
-
|------|-------------|
|
|
130
|
-
| `ekkOS_Export` | Backup patterns, directives, plans |
|
|
131
|
-
| `ekkOS_Import` | Restore from backup |
|
|
132
|
-
|
|
133
|
-
## Proactive Tool Triggers
|
|
134
|
-
|
|
135
|
-
### Always Use `ekkOS_Search` When:
|
|
136
|
-
- User asks technical question
|
|
137
|
-
- User mentions past discussion
|
|
138
|
-
- Topic involves architecture, config, debugging
|
|
139
|
-
- You're about to make a decision
|
|
140
|
-
|
|
141
|
-
### Always Use `ekkOS_Forge` When:
|
|
142
|
-
- Fixed bug (especially non-obvious)
|
|
143
|
-
- Discovered better approach
|
|
144
|
-
- Found pitfall or gotcha
|
|
145
|
-
- User corrected you
|
|
146
|
-
- Made architectural decision
|
|
147
|
-
- Something DIDN'T work (anti-pattern)
|
|
148
|
-
|
|
149
|
-
### Always Use `ekkOS_Directive` When:
|
|
150
|
-
- User says "always..." → MUST
|
|
151
|
-
- User says "never..." → NEVER
|
|
152
|
-
- User says "I prefer..." → PREFER
|
|
153
|
-
- User says "don't..." → AVOID
|
|
154
|
-
|
|
155
|
-
### Always Use `ekkOS_Conflict` When:
|
|
156
|
-
- About to delete files/data
|
|
157
|
-
- About to deploy to production
|
|
158
|
-
- About to modify config files
|
|
159
|
-
|
|
160
|
-
## Enforcement
|
|
161
|
-
|
|
162
|
-
⚠️ Violating Golden Loop = System failure
|
|
163
|
-
Every conversation MUST follow: RETRIEVE → APPLY → MEASURE → LEARN → CAPTURE
|
|
164
|
-
|
|
165
|
-
---
|
|
166
|
-
|
|
167
|
-
## 🔴 MANDATORY RESPONSE FORMAT (NO EXCEPTIONS)
|
|
168
|
-
|
|
169
|
-
**Every response MUST end with a timestamp footer:**
|
|
170
|
-
|
|
171
|
-
```
|
|
172
|
-
---
|
|
173
|
-
🧠 **ekkOS_™** · 📅 YYYY-MM-DD H:MM AM/PM TZ
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
**Example:**
|
|
177
|
-
```
|
|
178
|
-
---
|
|
179
|
-
🧠 **ekkOS_™** · 📅 2025-12-08 2:30 PM PST
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
**Why this matters:**
|
|
183
|
-
- Timestamps track when patterns were applied
|
|
184
|
-
- 3-Judge evaluations need temporal context
|
|
185
|
-
- Future agents can trace learning timeline
|
|
186
|
-
- Golden Loop metrics require time-based correlation
|
|
187
|
-
|
|
188
|
-
**⚠️ MISSING TIMESTAMP = INCOMPLETE LOOP = SYSTEM DEGRADATION**
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
priority: 100
|
|
3
|
-
globs: ["**/*"]
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# ekkOS™ Branded Message Templates
|
|
7
|
-
|
|
8
|
-
## Stream Message Fields (Display All Present)
|
|
9
|
-
|
|
10
|
-
```
|
|
11
|
-
_ekkos_stream_message → Display FIRST (🧠 Retrieving/🔄 Applying/✅ Learned)
|
|
12
|
-
_ekkos_learning_message → Display AFTER solution (🔥 Learning - pattern detected)
|
|
13
|
-
_ekkos_session_summary → Display AT END (📊 Summary at turns 5/10/20/50)
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
## Message Examples
|
|
17
|
-
|
|
18
|
-
### Before Response:
|
|
19
|
-
|
|
20
|
-
```
|
|
21
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
22
|
-
🧠 ekkOS™_Retrieving [18ms]
|
|
23
|
-
✓ 3 patterns loaded from memory
|
|
24
|
-
• "Pattern Name" (94% success, 12 uses)
|
|
25
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
### When Learning:
|
|
29
|
-
|
|
30
|
-
```
|
|
31
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
32
|
-
🔥 ekkOS™_Learning
|
|
33
|
-
New pattern detected: "Title"
|
|
34
|
-
Confidence: 60% (forming)
|
|
35
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### When Pattern Saved:
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
42
|
-
✅ ekkOS™_Learned
|
|
43
|
-
Pattern saved: "Title"
|
|
44
|
-
Confidence: 85% | Success: 100%
|
|
45
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### When Reusing:
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
52
|
-
🔄 ekkOS™_Applying
|
|
53
|
-
Using pattern from 2 messages ago
|
|
54
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### Session Summary:
|
|
58
|
-
|
|
59
|
-
```
|
|
60
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
61
|
-
📊 ekkOS™_Session_Summary
|
|
62
|
-
Memory Activity:
|
|
63
|
-
Retrieved: 5 patterns
|
|
64
|
-
Applied: 3 patterns
|
|
65
|
-
Learned: 2 new patterns
|
|
66
|
-
Confidence: +8% overall
|
|
67
|
-
|
|
68
|
-
Your AI is getting smarter.
|
|
69
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Requirements
|
|
73
|
-
|
|
74
|
-
- ALWAYS use ekkOS™ branding (with ™)
|
|
75
|
-
- ALWAYS show retrieval before response
|
|
76
|
-
- ALWAYS show learning when it happens
|
|
77
|
-
- Keep messages concise but visible
|
|
78
|
-
|