@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
@@ -1,416 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * ═══════════════════════════════════════════════════════════════════════════
4
- * ekkOS_ Hook: Stop (Claude Code) - CAPTURE + ANALYZE
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 BLUE = '\x1b[0;34m';
27
- const RED = '\x1b[0;31m';
28
- const DIM = '\x1b[2m';
29
- const BOLD = '\x1b[1m';
30
- const RESET = '\x1b[0m';
31
-
32
- // ═══════════════════════════════════════════════════════════════════════════
33
- // HTTP Request Helper
34
- // ═══════════════════════════════════════════════════════════════════════════
35
- function httpRequest(url, options, data) {
36
- return new Promise((resolve, reject) => {
37
- const urlObj = new URL(url);
38
- const lib = urlObj.protocol === 'https:' ? https : http;
39
- const timeout = options.timeout || 10000;
40
-
41
- const req = lib.request({
42
- hostname: urlObj.hostname,
43
- port: urlObj.port || (urlObj.protocol === 'https:' ? 443 : 80),
44
- path: urlObj.pathname + urlObj.search,
45
- method: options.method || 'GET',
46
- headers: options.headers || {},
47
- timeout: timeout
48
- }, (res) => {
49
- let body = '';
50
- res.on('data', chunk => body += chunk);
51
- res.on('end', () => {
52
- try {
53
- resolve(JSON.parse(body));
54
- } catch {
55
- resolve({ raw: body });
56
- }
57
- });
58
- });
59
-
60
- req.on('error', (e) => resolve({ error: e.message }));
61
- req.on('timeout', () => {
62
- req.destroy();
63
- resolve({ error: 'timeout' });
64
- });
65
-
66
- if (data) req.write(typeof data === 'string' ? data : JSON.stringify(data));
67
- req.end();
68
- });
69
- }
70
-
71
- // ═══════════════════════════════════════════════════════════════════════════
72
- // Load Auth Token
73
- // ═══════════════════════════════════════════════════════════════════════════
74
- function loadAuthToken() {
75
- const homeDir = os.homedir();
76
- const ekkosConfig = path.join(homeDir, '.ekkos', 'config.json');
77
- let authToken = '';
78
- let userId = '';
79
-
80
- // 1. First try ~/.ekkos/config.json (set by VS Code extension - most portable)
81
- // Prefer hookApiKey (scoped key for hooks) over apiKey (legacy)
82
- if (fs.existsSync(ekkosConfig)) {
83
- try {
84
- const config = JSON.parse(fs.readFileSync(ekkosConfig, 'utf8'));
85
- authToken = config.hookApiKey || config.apiKey || '';
86
- userId = config.userId || '';
87
- } catch {}
88
- }
89
-
90
- // 2. Then try project .env.local
91
- if (!authToken) {
92
- const envLocal = path.join(state.PROJECT_ROOT, '.env.local');
93
- if (fs.existsSync(envLocal)) {
94
- try {
95
- const content = fs.readFileSync(envLocal, 'utf8');
96
- const match = content.match(/^SUPABASE_SECRET_KEY=(.+)$/m);
97
- if (match) {
98
- authToken = match[1].replace(/["']/g, '').trim();
99
- }
100
- } catch {}
101
- }
102
- }
103
-
104
- // 3. Finally try environment variable
105
- if (!authToken) {
106
- authToken = process.env.SUPABASE_SECRET_KEY || '';
107
- }
108
-
109
- return { authToken, userId };
110
- }
111
-
112
- // ═══════════════════════════════════════════════════════════════════════════
113
- // Main Hook Logic
114
- // ═══════════════════════════════════════════════════════════════════════════
115
- async function main() {
116
- // Read JSON input from stdin
117
- let inputData = '';
118
- for await (const chunk of process.stdin) {
119
- inputData += chunk;
120
- }
121
-
122
- let input;
123
- try {
124
- input = JSON.parse(inputData);
125
- } catch {
126
- process.exit(0);
127
- }
128
-
129
- const sessionId = input.session_id || 'unknown';
130
- const transcriptPath = input.transcript_path || '';
131
- let modelUsed = input.model || 'claude-sonnet-4-5';
132
- const timestamp = new Date().toISOString();
133
-
134
- // Load auth
135
- const { authToken, userId } = loadAuthToken();
136
- if (!authToken) {
137
- process.exit(0);
138
- }
139
-
140
- const MEMORY_API_URL = 'https://mcp.ekkos.dev';
141
-
142
- // Extract conversation from transcript
143
- let lastUser = '';
144
- let lastAssistant = '';
145
-
146
- if (transcriptPath && fs.existsSync(transcriptPath)) {
147
- try {
148
- const transcriptContent = fs.readFileSync(transcriptPath, 'utf8');
149
- const lines = transcriptContent.split('\n').filter(Boolean).map(l => {
150
- try { return JSON.parse(l); } catch { return null; }
151
- }).filter(Boolean);
152
-
153
- // Find last user query (from queue-operation enqueue)
154
- const enqueues = lines.filter(l => l.type === 'queue-operation' && l.operation === 'enqueue');
155
- if (enqueues.length > 0) {
156
- const lastEnqueue = enqueues[enqueues.length - 1];
157
- if (lastEnqueue.content) {
158
- const textContent = lastEnqueue.content.find(c => c.type === 'text');
159
- if (textContent) lastUser = textContent.text;
160
- }
161
- }
162
-
163
- // Find assistant messages after last user query
164
- const assistantMsgs = lines.filter(l => l.type === 'assistant');
165
- if (assistantMsgs.length > 0) {
166
- const lastAssistantMsg = assistantMsgs[assistantMsgs.length - 1];
167
- if (lastAssistantMsg.message?.content) {
168
- if (Array.isArray(lastAssistantMsg.message.content)) {
169
- lastAssistant = lastAssistantMsg.message.content
170
- .filter(c => c.type === 'text')
171
- .map(c => c.text)
172
- .join(' ');
173
- } else {
174
- lastAssistant = lastAssistantMsg.message.content;
175
- }
176
- }
177
- }
178
- } catch {}
179
- }
180
-
181
- // Fallback: use response from input
182
- if (!lastAssistant) {
183
- lastAssistant = input.response || '';
184
- }
185
-
186
- // Load patterns from RETRIEVE step
187
- const storedData = state.loadPatterns(sessionId);
188
- const patterns = storedData.patterns || [];
189
- const patternCount = patterns.length;
190
- const patternIds = patterns.map(p => p.id || p.pattern_id).filter(Boolean);
191
- if (storedData.model_used) modelUsed = storedData.model_used;
192
- const taskId = storedData.task_id || '';
193
-
194
- // ═══════════════════════════════════════════════════════════════════════════
195
- // Pattern Acknowledgment Detection (PatternGuard)
196
- // ═══════════════════════════════════════════════════════════════════════════
197
- let appliedPatternIds = [];
198
- let skippedPatternIds = [];
199
-
200
- if (lastAssistant && patternCount > 0) {
201
- // Check for [ekkOS_SELECT] block
202
- const selectMatch = lastAssistant.match(/\[ekkOS_SELECT\]([\s\S]*?)\[\/ekkOS_SELECT\]/);
203
- if (selectMatch) {
204
- const idMatches = selectMatch[1].matchAll(/id:\s*([a-f0-9-]+)/g);
205
- for (const m of idMatches) {
206
- if (m[1].length >= 8) {
207
- appliedPatternIds.push(m[1]);
208
- console.error(`[ekkOS_SELECT] Applied: ${m[1].substring(0, 8)}...`);
209
- }
210
- }
211
- }
212
-
213
- // Check for [ekkOS_SKIP] block
214
- const skipMatch = lastAssistant.match(/\[ekkOS_SKIP\]([\s\S]*?)\[\/ekkOS_SKIP\]/);
215
- if (skipMatch) {
216
- const idMatches = skipMatch[1].matchAll(/id:\s*([a-f0-9-]+)/g);
217
- for (const m of idMatches) {
218
- if (m[1].length >= 8) {
219
- skippedPatternIds.push(m[1]);
220
- console.error(`[ekkOS_SKIP] Skipped: ${m[1].substring(0, 8)}...`);
221
- }
222
- }
223
- }
224
-
225
- // Calculate coverage
226
- const acknowledged = appliedPatternIds.length + skippedPatternIds.length;
227
- if (patternCount > 0) {
228
- const coverage = Math.round((acknowledged / patternCount) * 100);
229
- if (coverage < 100) {
230
- console.error(`${YELLOW}[PatternGuard] Coverage: ${coverage}% (${acknowledged}/${patternCount} patterns acknowledged)${RESET}`);
231
- } else {
232
- console.error(`${GREEN}[PatternGuard] 100% coverage - all patterns acknowledged${RESET}`);
233
- }
234
- }
235
-
236
- // Legacy: Check for [ekkOS_APPLY] markers
237
- if (appliedPatternIds.length === 0 && skippedPatternIds.length === 0) {
238
- for (const pattern of patterns) {
239
- const title = pattern.title || '';
240
- const pid = pattern.id || pattern.pattern_id || '';
241
- if (lastAssistant.includes('[ekkOS_APPLY]') && lastAssistant.includes(title)) {
242
- appliedPatternIds.push(pid);
243
- console.error(`[ekkOS_APPLY_DETECTED] Pattern: "${title}"`);
244
- }
245
- }
246
- }
247
- }
248
-
249
- console.log('');
250
-
251
- // ═══════════════════════════════════════════════════════════════════════════
252
- // [ekkOS_LEARN_DETECT] Check for manual forge markers
253
- // ═══════════════════════════════════════════════════════════════════════════
254
- let forgeCount = 0;
255
- if (lastAssistant) {
256
- const forgeMatches = lastAssistant.matchAll(/\[ekkOS_LEARN\][^"]*"([^"]+)"/g);
257
- const forgeMarkers = [...forgeMatches];
258
-
259
- if (forgeMarkers.length > 0) {
260
- console.log(`${YELLOW}+${RESET} ${YELLOW}[[[[ekkOS_Learn detect]]]]${RESET} ${DIM}found forge markers${RESET}`);
261
-
262
- for (const marker of forgeMarkers) {
263
- const patternTitle = marker[1];
264
- if (patternTitle) {
265
- console.log(` ${GREEN}+${RESET} forging: "${patternTitle}"`);
266
- forgeCount++;
267
-
268
- // Send to forge endpoint (don't wait)
269
- httpRequest(`${MEMORY_API_URL}/api/v1/patterns`, {
270
- method: 'POST',
271
- headers: {
272
- 'Authorization': `Bearer ${authToken}`,
273
- 'Content-Type': 'application/json'
274
- },
275
- timeout: 10000
276
- }, {
277
- title: patternTitle,
278
- problem: (lastUser || '').substring(0, 500),
279
- solution: (lastAssistant || '').substring(0, 2000),
280
- tags: ['hook-detected', 'golden-loop', 'claude-code-node'],
281
- source: 'claude-code-hook-node',
282
- confidence: 0.85
283
- }).then(res => {
284
- if (res.pattern_id || res.id) {
285
- const pid = res.pattern_id || res.id;
286
- console.error(` ${GREEN}✓${RESET} forged ${DIM}(ID: ${pid.substring(0, 8)}...)${RESET}`);
287
- }
288
- }).catch(() => {});
289
- }
290
- }
291
- }
292
- }
293
-
294
- // ═══════════════════════════════════════════════════════════════════════════
295
- // [ekkOS_CAPTURE] Send data to backend
296
- // ═══════════════════════════════════════════════════════════════════════════
297
- let captured = false;
298
- if (lastUser && lastAssistant) {
299
- console.log(`${CYAN}+${RESET} ${CYAN}[[[[ekkOS_Capture]]]]${RESET} ${DIM}sending to memory substrate${RESET}`);
300
-
301
- const payload = {
302
- user_query: lastUser,
303
- assistant_response: lastAssistant,
304
- session_id: `claude-code-${sessionId}`,
305
- user_id: userId || 'system',
306
- patterns_retrieved: patternIds,
307
- patterns_applied: appliedPatternIds,
308
- metadata: {
309
- source: 'claude-code-node',
310
- model_used: modelUsed,
311
- patterns_retrieved_count: patternCount,
312
- patterns_applied_count: appliedPatternIds.length,
313
- task_id: taskId,
314
- captured_at: timestamp,
315
- auto_apply_detection: true,
316
- user_id: userId || 'system'
317
- }
318
- };
319
-
320
- const captureResponse = await httpRequest(`${MEMORY_API_URL}/api/v1/memory/capture`, {
321
- method: 'POST',
322
- headers: {
323
- 'Authorization': `Bearer ${authToken}`,
324
- 'Content-Type': 'application/json'
325
- },
326
- timeout: 10000
327
- }, payload);
328
-
329
- if (captureResponse.conversation_id) {
330
- const convId = captureResponse.conversation_id;
331
- console.log(` ${GREEN}+${RESET} saved ${DIM}(ID: ${convId.substring(0, 8)}...)${RESET}`);
332
- console.log(`${BLUE}+${RESET} ${BLUE}[[[[ekkOS_Analyze]]]]${RESET} ${DIM}queued for async processing${RESET}`);
333
- captured = true;
334
- } else {
335
- console.log(` ${RED}-${RESET} failed to save`);
336
- }
337
- } else {
338
- console.log(`${DIM}-${RESET} ${DIM}[[[[ekkOS_Capture]]]]${RESET} ${DIM}skipped (no content)${RESET}`);
339
- }
340
-
341
- // Cleanup state file
342
- state.clearPatterns(sessionId);
343
-
344
- // ═══════════════════════════════════════════════════════════════════════════
345
- // [ekkOS_REFLEX] Send turn_end event to trigger 3-Judge evaluation
346
- // ═══════════════════════════════════════════════════════════════════════════
347
- const REFLEX_API_URL = process.env.REFLEX_API_URL || 'https://mcp.ekkos.dev/api/v1/reflex/log';
348
-
349
- if (captured && lastUser && lastAssistant) {
350
- console.log(`${YELLOW}+${RESET} ${YELLOW}[[[[ekkOS_3-Judges]]]]${RESET} ${DIM}triggering consensus evaluation${RESET}`);
351
-
352
- // Send in background (don't wait)
353
- httpRequest(REFLEX_API_URL, {
354
- method: 'POST',
355
- headers: {
356
- 'Authorization': `Bearer ${authToken}`,
357
- 'Content-Type': 'application/json'
358
- },
359
- timeout: 10000
360
- }, {
361
- action: 'turn_end',
362
- summary: `Claude Code session: ${(lastUser || '').substring(0, 100)}...`,
363
- details: {
364
- user_query: lastUser,
365
- assistant_response: (lastAssistant || '').substring(0, 2000),
366
- source: 'claude-code-node',
367
- model_used: modelUsed,
368
- patterns_retrieved: patternCount,
369
- patterns_applied: appliedPatternIds.length,
370
- session_id: `claude-code-${sessionId}`,
371
- timestamp: timestamp
372
- },
373
- learn: {
374
- lookups: patternCount,
375
- reuse: appliedPatternIds.length,
376
- saves: 0,
377
- abstain: 0
378
- },
379
- context: {
380
- source: 'claude-code-node',
381
- task_id: taskId
382
- }
383
- }).then(res => {
384
- if (res.id) {
385
- console.error(` ${GREEN}+${RESET} event queued ${DIM}(ID: ${res.id.substring(0, 8)}...)${RESET}`);
386
- }
387
- }).catch(() => {});
388
- }
389
-
390
- // ═══════════════════════════════════════════════════════════════════════════
391
- // Summary
392
- // ═══════════════════════════════════════════════════════════════════════════
393
- console.log('');
394
- console.log(`${CYAN}${BOLD}[[[[ekkOS_Golden loop]]]]${RESET}`);
395
- console.log('');
396
-
397
- if (captured) {
398
- console.log(` ${GREEN}+${RESET} capture: saved to substrate`);
399
- console.log(` ${GREEN}+${RESET} 3-judge: consensus eval queued`);
400
- } else {
401
- console.log(` ${DIM}-${RESET} capture: skipped (no content)`);
402
- }
403
- console.log(` ${GREEN}+${RESET} patterns: ${patternCount} retrieved`);
404
- if (forgeCount > 0) {
405
- console.log(` ${GREEN}+${RESET} forged: ${forgeCount} new patterns (from [ekkOS_LEARN] markers)`);
406
- }
407
- console.log(` ${GREEN}+${RESET} analyze: async backend processing`);
408
- console.log('');
409
-
410
- // Small delay to let background requests complete
411
- await new Promise(resolve => setTimeout(resolve, 100));
412
-
413
- process.exit(0);
414
- }
415
-
416
- main().catch(() => process.exit(0));