@ekkos/cli 0.3.3 → 1.0.1

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 (81) hide show
  1. package/README.md +57 -0
  2. package/dist/agent/daemon.d.ts +27 -0
  3. package/dist/agent/daemon.js +254 -29
  4. package/dist/agent/health-check.d.ts +35 -0
  5. package/dist/agent/health-check.js +243 -0
  6. package/dist/agent/pty-runner.d.ts +1 -0
  7. package/dist/agent/pty-runner.js +6 -1
  8. package/dist/capture/transcript-repair.d.ts +1 -0
  9. package/dist/capture/transcript-repair.js +12 -1
  10. package/dist/commands/agent.d.ts +6 -0
  11. package/dist/commands/agent.js +244 -0
  12. package/dist/commands/dashboard.d.ts +25 -0
  13. package/dist/commands/dashboard.js +1175 -0
  14. package/dist/commands/run.d.ts +3 -0
  15. package/dist/commands/run.js +503 -350
  16. package/dist/commands/setup-remote.js +146 -37
  17. package/dist/commands/swarm-dashboard.d.ts +20 -0
  18. package/dist/commands/swarm-dashboard.js +735 -0
  19. package/dist/commands/swarm-setup.d.ts +10 -0
  20. package/dist/commands/swarm-setup.js +956 -0
  21. package/dist/commands/swarm.d.ts +46 -0
  22. package/dist/commands/swarm.js +441 -0
  23. package/dist/commands/test-claude.d.ts +16 -0
  24. package/dist/commands/test-claude.js +156 -0
  25. package/dist/commands/usage/blocks.d.ts +8 -0
  26. package/dist/commands/usage/blocks.js +60 -0
  27. package/dist/commands/usage/daily.d.ts +9 -0
  28. package/dist/commands/usage/daily.js +96 -0
  29. package/dist/commands/usage/dashboard.d.ts +8 -0
  30. package/dist/commands/usage/dashboard.js +104 -0
  31. package/dist/commands/usage/formatters.d.ts +41 -0
  32. package/dist/commands/usage/formatters.js +147 -0
  33. package/dist/commands/usage/index.d.ts +13 -0
  34. package/dist/commands/usage/index.js +87 -0
  35. package/dist/commands/usage/monthly.d.ts +8 -0
  36. package/dist/commands/usage/monthly.js +66 -0
  37. package/dist/commands/usage/session.d.ts +11 -0
  38. package/dist/commands/usage/session.js +193 -0
  39. package/dist/commands/usage/weekly.d.ts +9 -0
  40. package/dist/commands/usage/weekly.js +61 -0
  41. package/dist/deploy/instructions.d.ts +5 -2
  42. package/dist/deploy/instructions.js +11 -8
  43. package/dist/index.js +256 -20
  44. package/dist/lib/tmux-scrollbar.d.ts +14 -0
  45. package/dist/lib/tmux-scrollbar.js +296 -0
  46. package/dist/lib/usage-parser.d.ts +95 -5
  47. package/dist/lib/usage-parser.js +416 -71
  48. package/dist/utils/log-rotate.d.ts +18 -0
  49. package/dist/utils/log-rotate.js +74 -0
  50. package/dist/utils/platform.d.ts +2 -0
  51. package/dist/utils/platform.js +3 -1
  52. package/dist/utils/session-binding.d.ts +5 -0
  53. package/dist/utils/session-binding.js +46 -0
  54. package/dist/utils/state.js +4 -0
  55. package/dist/utils/verify-remote-terminal.d.ts +10 -0
  56. package/dist/utils/verify-remote-terminal.js +415 -0
  57. package/package.json +16 -11
  58. package/templates/CLAUDE.md +135 -23
  59. package/templates/cursor-hooks/after-agent-response.sh +0 -0
  60. package/templates/cursor-hooks/before-submit-prompt.sh +0 -0
  61. package/templates/cursor-hooks/stop.sh +0 -0
  62. package/templates/ekkos-manifest.json +5 -5
  63. package/templates/hooks/assistant-response.sh +0 -0
  64. package/templates/hooks/lib/contract.sh +43 -31
  65. package/templates/hooks/lib/count-tokens.cjs +86 -0
  66. package/templates/hooks/lib/ekkos-reminders.sh +98 -0
  67. package/templates/hooks/lib/state.sh +53 -1
  68. package/templates/hooks/session-start.sh +0 -0
  69. package/templates/hooks/stop.sh +150 -388
  70. package/templates/hooks/user-prompt-submit.sh +353 -443
  71. package/templates/plan-template.md +0 -0
  72. package/templates/spec-template.md +0 -0
  73. package/templates/windsurf-hooks/README.md +212 -0
  74. package/templates/windsurf-hooks/hooks.json +9 -2
  75. package/templates/windsurf-hooks/install.sh +148 -0
  76. package/templates/windsurf-hooks/lib/contract.sh +2 -0
  77. package/templates/windsurf-hooks/post-cascade-response.sh +251 -0
  78. package/templates/windsurf-hooks/pre-user-prompt.sh +435 -0
  79. package/templates/windsurf-skills/ekkos-memory/SKILL.md +219 -0
  80. package/LICENSE +0 -21
  81. package/templates/windsurf-hooks/before-submit-prompt.sh +0 -238
@@ -53,6 +53,28 @@ After `/clear`, when you see restored turns in `<system-reminder>` (pattern: `**
53
53
  ```
54
54
  This is the ONLY way users see that restoration worked. Hook output is invisible to them.
55
55
 
56
+ ### RULE 6: AUTO-RESTORE AFTER COMPACTION (CONTEXT GUARDIAN)
57
+ When you see `<ekkos-context-preserved>` in the conversation (appears after auto-compaction):
58
+ 1. **IMMEDIATELY** call `ekkOS_RestoreContext` with the `restoration_token` from the tag
59
+ 2. This restores your working memory that was preserved before compaction
60
+ 3. Start your response with:
61
+ ```
62
+ ✓ **Context restored** - ekkOS preserved X turns before compaction
63
+ ```
64
+
65
+ **This is how seamless context continuity works:**
66
+ - PreCompact hook fires → ekkOS_PreserveContext saves your state
67
+ - Claude Code compacts → Summary includes the preservation tag
68
+ - You see the tag → Call ekkOS_RestoreContext → Full context restored
69
+ - User experiences zero knowledge loss despite compaction
70
+
71
+ **Example restoration call:**
72
+ ```
73
+ ekkOS_RestoreContext({
74
+ restoration_token: "<token from tag>"
75
+ })
76
+ ```
77
+
56
78
  ---
57
79
 
58
80
  ## SKILL TRIGGERS (MANDATORY)
@@ -79,8 +101,7 @@ Call skills using `Skill(skill: "name")` when you detect these triggers:
79
101
  | Trigger Keywords | Agent | When to Use |
80
102
  |------------------|-------|-------------|
81
103
  | extension, vsix, publish, marketplace, ekkos-connect | `extension-manager` | Version bumps, VSIX builds, publishing |
82
- | vercel, deploy to vercel, platform.ekkos.dev, apps/web | `devops` | Vercel deployments (link + archive mode) |
83
- | deploy, railway, workers, pm2, restart, logs, queue | `railway-manager` | Railway deployments, service management |
104
+ | vercel, deploy, apps/*, ekkos.dev, api.ekkos.dev | `devops` | Vercel deployments ALL apps/ deploy to Vercel |
84
105
  | commit, push, branch, merge, git, pull request, rebase | `git-companion` | All git operations |
85
106
  | error, bug, broken, not working, failing, crash | `debug-detective` | Systematic debugging |
86
107
  | review, PR, check this code, code quality | `code-reviewer` | Code reviews |
@@ -89,6 +110,25 @@ Call skills using `Skill(skill: "name")` when you detect these triggers:
89
110
  | backend, API, database, Supabase, RLS | `backend` | API and database work |
90
111
  | test, QA, quality, coverage | `qa` | Testing and quality assurance |
91
112
  | plan, architect, design, implement feature | `tech-lead` | Complex planning and coordination |
113
+ | research, papers, arXiv, cutting edge, latest AI | `research-scout` | Monitor AI research, update roadmap |
114
+
115
+ **Vercel Project Mapping** (apps/ folder → Vercel project → URL):
116
+
117
+ | apps/ folder | Vercel project | Production URL |
118
+ |-------------|----------------|----------------|
119
+ | `apps/web` | **platform** | platform.ekkos.dev |
120
+ | `apps/memory` | memory | api.ekkos.dev |
121
+ | `apps/proxy` | proxy | proxy.ekkos.dev |
122
+ | `apps/docs` | docs | docs.ekkos.dev |
123
+ | `apps/marketing` | marketing | ekkos.dev |
124
+ | `apps/ekkosca` | ekkosca | ekkos.ca |
125
+ | `apps/blog` | blog | blog.ekkos.dev |
126
+ | `apps/support` | support | support.ekkos.dev |
127
+ | `apps/labs` | labs | ekkoslabs.com |
128
+ | `apps/admin` | admin | admin.ekkos.ca |
129
+ | `apps/sdk` | sdk | sdk-ekkos.vercel.app |
130
+
131
+ **NOTE:** `apps/web` → Vercel project name is `platform`, NOT `web`.
92
132
 
93
133
  **How it works:**
94
134
  1. Detect trigger keywords in user request
@@ -109,39 +149,55 @@ You: Task(subagent_type="extension-manager", prompt="Bump version...")
109
149
 
110
150
  ---
111
151
 
112
- ## MCP Tools (31 Total)
152
+ ## MCP Tools (68 Total)
113
153
 
114
- ### Core Memory Tools
154
+ ### Core Memory Tools (7)
115
155
  | Tool | Description |
116
156
  |------|-------------|
117
157
  | `ekkOS_Search` | 🔴 REQUIRED: Search all 11 layers before answering |
118
- | `ekkOS_Context` | Get relevant context for a task |
158
+ | `ekkOS_ExpandPattern` | Get full details of a pattern from compact search results |
119
159
  | `ekkOS_Capture` | Capture memory events |
120
160
  | `ekkOS_Forge` | 🔴 REQUIRED: Create pattern from solution |
121
- | `ekkOS_Directive` | 🔴 REQUIRED: Create MUST/NEVER/PREFER/AVOID rules |
161
+ | `ekkOS_Track` | Track when pattern is applied |
122
162
  | `ekkOS_Outcome` | Track if pattern worked or failed |
123
- | `ekkOS_Detect` | 🔴 REQUIRED: Auto-detect which patterns were used |
124
- | `ekkOS_Summary` | 🔴 REQUIRED: Get summary of MCP activity |
125
- | `ekkOS_Conflict` | 🔴 REQUIRED: Check for conflicts before destructive actions |
126
- | `ekkOS_Recall` | Recall past conversations by time |
127
- | `ekkOS_Codebase` | Search project code embeddings |
128
163
  | `ekkOS_Stats` | Get statistics for all layers |
129
- | `ekkOS_Track` | Track when pattern is applied |
130
- | `ekkOS_Reflect` | Analyze response for improvement opportunities |
131
164
 
132
- ### Schema Awareness Tools
165
+ ### Context & Retrieval Tools (5)
133
166
  | Tool | Description |
134
167
  |------|-------------|
135
- | `ekkOS_IndexSchema` | Index database schemas (Supabase, Prisma, TypeScript) |
136
- | `ekkOS_GetSchema` | Get schema for a specific table/type |
168
+ | `ekkOS_Context` | Get relevant context for a task |
169
+ | `ekkOS_Codebase` | Search project code embeddings |
170
+ | `ekkOS_Recall` | Recall past conversations by time |
171
+ | `ekkOS_PreserveContext` | 🔴 REQUIRED: Preserve working memory before compaction |
172
+ | `ekkOS_RestoreContext` | 🔴 REQUIRED: Restore context after compaction (RULE 6) |
137
173
 
138
- ### Portability Tools
174
+ ### Utility Tools (8)
139
175
  | Tool | Description |
140
176
  |------|-------------|
177
+ | `ekkOS_Summary` | 🔴 REQUIRED: Get summary of MCP activity |
178
+ | `ekkOS_Conflict` | 🔴 REQUIRED: Check for conflicts before destructive actions |
179
+ | `ekkOS_Reflect` | Analyze response for improvement opportunities |
180
+ | `ekkOS_Detect` | 🔴 REQUIRED: Auto-detect which patterns were used |
141
181
  | `ekkOS_Export` | Export your patterns, directives, plans as portable JSON backup |
142
182
  | `ekkOS_Import` | Import memory from backup (auto-deduplication) |
183
+ | `ekkOS_Why` | Explain why a pattern or decision was made |
184
+ | `ekkOS_Health` | System health check for ekkOS infrastructure |
185
+
186
+ ### Directive Tools (4)
187
+ | Tool | Description |
188
+ |------|-------------|
189
+ | `ekkOS_Directive` | 🔴 REQUIRED: Create MUST/NEVER/PREFER/AVOID rules |
190
+ | `ekkOS_UpdateDirective` | Update existing directive |
191
+ | `ekkOS_DeleteDirective` | Remove a directive |
192
+ | `ekkOS_UniversalDirectives` | Get directives that apply to all users (constitutional) |
193
+
194
+ ### Schema Awareness Tools (2)
195
+ | Tool | Description |
196
+ |------|-------------|
197
+ | `ekkOS_IndexSchema` | Index database schemas (Supabase, Prisma, TypeScript) |
198
+ | `ekkOS_GetSchema` | Get schema for a specific table/type |
143
199
 
144
- ### Plan Management
200
+ ### Plan Management (8)
145
201
  | Tool | Description |
146
202
  |------|-------------|
147
203
  | `ekkOS_Plan` | Create structured task plan |
@@ -153,7 +209,7 @@ You: Task(subagent_type="extension-manager", prompt="Bump version...")
153
209
  | `ekkOS_Templates` | List available templates |
154
210
  | `ekkOS_FromTemplate` | Create plan from template |
155
211
 
156
- ### Secrets Management (Layer 11)
212
+ ### Secrets Management (5)
157
213
  | Tool | Description |
158
214
  |------|-------------|
159
215
  | `ekkOS_StoreSecret` | Encrypt and store sensitive data (AES-256-GCM) |
@@ -162,6 +218,39 @@ You: Task(subagent_type="extension-manager", prompt="Bump version...")
162
218
  | `ekkOS_DeleteSecret` | Permanently delete a secret |
163
219
  | `ekkOS_RotateSecret` | Update secret with new value |
164
220
 
221
+ ### Project/Sync Tools (4)
222
+ | Tool | Description |
223
+ |------|-------------|
224
+ | `ekkOS_ProjectInit` | Initialize ekkOS for a new project |
225
+ | `ekkOS_Ingest` | Bulk ingest data into memory layers |
226
+ | `ekkOS_Snapshot` | Create point-in-time snapshot of memory state |
227
+ | `ekkOS_Sync` | Sync local and cloud memory state |
228
+
229
+ ### Session Management (1)
230
+ | Tool | Description |
231
+ |------|-------------|
232
+ | `ekkOS_Session` | Manage L1 Working Memory sessions (start/resume/end) |
233
+
234
+ ### Learning Tools (2)
235
+ | Tool | Description |
236
+ |------|-------------|
237
+ | `ekkOS_Learn` | Auto-learning from corrections, successes, observations |
238
+ | `ekkOS_ReviewLearning` | Review pending learning candidates, approve/reject patterns |
239
+
240
+ ### Relationship Tools (2)
241
+ | Tool | Description |
242
+ |------|-------------|
243
+ | `ekkOS_Link` | Create relationships between patterns |
244
+ | `ekkOS_Playbook` | Manage ordered sequences of patterns (workflows) |
245
+
246
+ ### PROMETHEUS Tools (4)
247
+ | Tool | Description |
248
+ |------|-------------|
249
+ | `ekkOS_Delta` | Compute improvement score using Δ_prometheus formula |
250
+ | `ekkOS_MetaState` | System introspection ("I know what I know") |
251
+ | `ekkOS_Goal` | Manage persistent objectives and success criteria |
252
+ | `ekkOS_Strategy` | Context-aware strategy selection for tasks |
253
+
165
254
  ---
166
255
 
167
256
  ## Proactive Tool Triggers (MEMORIZE THESE)
@@ -204,6 +293,28 @@ You: Task(subagent_type="extension-manager", prompt="Bump version...")
204
293
  - Need to retrieve stored credentials
205
294
  - User asks "do you have my X key?"
206
295
 
296
+ ### Always Use Context Preservation When:
297
+ - PreCompact hook fires (auto-triggered)
298
+ - See `<ekkos-context-preserved>` tag (auto-restore)
299
+ - RULE 6 activation
300
+
301
+ ### Always Use Learning Tools When:
302
+ - User corrects you (ekkOS_Learn mode: correction)
303
+ - Solution succeeds (ekkOS_Learn mode: success)
304
+ - Discover insight (ekkOS_Learn mode: observe)
305
+ - Review pending patterns (ekkOS_ReviewLearning)
306
+
307
+ ### Always Use Relationship Tools When:
308
+ - Patterns are sequential (ekkOS_Link type: leads_to)
309
+ - Creating workflows (ekkOS_Playbook)
310
+ - Patterns are alternatives (ekkOS_Link type: alternative)
311
+
312
+ ### Always Use PROMETHEUS Tools When:
313
+ - Evaluating system improvement (ekkOS_Delta)
314
+ - Self-assessment needed (ekkOS_MetaState)
315
+ - Setting objectives (ekkOS_Goal)
316
+ - Choosing approach (ekkOS_Strategy)
317
+
207
318
  ---
208
319
 
209
320
  ## 11-Layer Memory Architecture
@@ -253,20 +364,21 @@ Call `ekkOS_Directive` when user says:
253
364
  **EVERY response MUST end with this footer:**
254
365
  ```
255
366
  ---
256
- {IDE} ({Model}) · 🧠 **ekkOS_™** · Turn {N} · 📅 {Timestamp}
367
+ {IDE} ({Model}) · 🧠 **ekkOS_™** · Turn {N} · {SessionName} · 📅 {Timestamp}
257
368
  ```
258
369
 
259
370
  **How to detect values:**
260
371
  - **IDE**: Claude Code, Cursor, Windsurf, etc. (from environment)
261
372
  - **Model**: Sonnet 4.5, Opus 4.5, etc. (from your model name)
262
373
  - **Turn Number**: From hook header (e.g., "Turn 47") - starts at 0 for each new session
374
+ - **Session Name**: From hook header (e.g., "sol-gem-dig") - human-readable session identifier
263
375
  - **Timestamp**: From hook header (accurate local time in EST)
264
376
 
265
377
  **Examples:**
266
- - `Claude Code (Sonnet 4.5) · 🧠 **ekkOS_™** · Turn 12 · 📅 2026-01-09 4:50 PM EST`
267
- - `Cursor (Claude Sonnet 4) · 🧠 **ekkOS_™** · Turn 5 · 📅 2026-01-09 10:15 AM EST`
378
+ - `Claude Code (Sonnet 4.5) · 🧠 **ekkOS_™** · Turn 12 · cosmic-penguin-runs · 📅 2026-01-09 4:50 PM EST`
379
+ - `Cursor (Claude Sonnet 4) · 🧠 **ekkOS_™** · Turn 5 · bright-falcon-soars · 📅 2026-01-09 10:15 AM EST`
268
380
 
269
- **The hook header shows:** `🧠 ekkOS Memory | Turn {N} | Session: {ID} | {timestamp}`
381
+ **The hook header shows:** `🧠 ekkOS Memory | Turn {N} | {Context%} | {SessionName} | {timestamp}`
270
382
 
271
383
  ---
272
384
 
File without changes
File without changes
File without changes
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://ekkos.dev/schemas/manifest-v1.json",
3
3
  "manifestVersion": "1.0.0",
4
- "generatedAt": "2026-02-04T04:30:49.260Z",
4
+ "generatedAt": "2026-02-18T04:29:25.535Z",
5
5
  "platforms": {
6
6
  "darwin": {
7
7
  "configDir": "~/.ekkos",
@@ -68,14 +68,14 @@
68
68
  "source": "hooks/user-prompt-submit.sh",
69
69
  "destination": "user-prompt-submit.sh",
70
70
  "description": "User prompt submit hook (Unix)",
71
- "checksum": "38aa190d08e2c24129e7f653732a860693fbd2a7015e59226aec57e8b3659114",
71
+ "checksum": "ef294d0088a94c6588a91fc91e6cc06a14dd46bc83ca09d73c64abfb11984f40",
72
72
  "executable": true
73
73
  },
74
74
  {
75
75
  "source": "hooks/stop.sh",
76
76
  "destination": "stop.sh",
77
77
  "description": "Session stop hook (Unix)",
78
- "checksum": "fd436ea847bf6fbe367f8aa61ddf6d97e8605837badc3af8d433b59599ef6615",
78
+ "checksum": "f3b4495c0c2bbdf5bfef762568faec7b70b41b463dad4c88b37cf7ee32b5257d",
79
79
  "executable": true
80
80
  },
81
81
  {
@@ -124,14 +124,14 @@
124
124
  "source": "hooks/lib/contract.sh",
125
125
  "destination": "lib/contract.sh",
126
126
  "description": "Hook contract library",
127
- "checksum": "1d86128a2a4a25e653a02c4eb08dbfd28db53063c618cd43b85f0603a135e8b2",
127
+ "checksum": "3ef16930ba10cd37a1c5fa8469ec13a6a84cadb882d3f9a96c72da875ba07fc7",
128
128
  "executable": true
129
129
  },
130
130
  {
131
131
  "source": "hooks/lib/state.sh",
132
132
  "destination": "lib/state.sh",
133
133
  "description": "Hook state management library",
134
- "checksum": "ba72c00a1fb0f6768e37aff754ad6ac0e8e20aa0b9b393193e2d92357cac5a71",
134
+ "checksum": "99223ce9b869d78762084ff184327fa2814af7a16e5f2ac9619af43b5e551d7c",
135
135
  "executable": true
136
136
  }
137
137
  ]
File without changes
@@ -78,7 +78,7 @@ write_turn_contract() {
78
78
  "retrieved_directive_ids": $directive_array,
79
79
  "timestamp": "$timestamp",
80
80
  "query_hash": "$query_hash",
81
- "ekkos_strict": ${EKKOS_STRICT:-0}
81
+ "ekkos_strict": ${EKKOS_STRICT:-1}
82
82
  }
83
83
  EOF
84
84
 
@@ -134,7 +134,7 @@ cleanup_turn_contract() {
134
134
 
135
135
  # Check if strict mode is enabled
136
136
  is_strict_mode() {
137
- [ "${EKKOS_STRICT:-0}" = "1" ]
137
+ [ "${EKKOS_STRICT:-1}" = "1" ] # DEFAULT: ON
138
138
  }
139
139
 
140
140
  # Generate strict mode blocker message for Claude Code
@@ -157,50 +157,57 @@ EOF
157
157
  }
158
158
 
159
159
  # Validate PatternGuard coverage (returns 0-100)
160
+ # PORTABLE: Works on macOS without Perl regex (grep -P)
160
161
  calculate_pattern_guard_coverage() {
161
162
  local assistant_response="$1"
162
163
  local pattern_ids="$2" # Comma-separated
163
164
 
164
- # Count total patterns
165
- local total_count
166
- total_count=$(echo "$pattern_ids" | tr ',' '\n' | grep -c '.' || echo 0)
165
+ # Count total patterns - more robust counting
166
+ local total_count=0
167
+ if [ -n "$pattern_ids" ]; then
168
+ total_count=$(echo "$pattern_ids" | tr ',' '\n' | grep -v '^$' | wc -l | tr -d ' ')
169
+ fi
167
170
 
168
171
  if [ "$total_count" -eq 0 ]; then
169
172
  echo "100" # No patterns = 100% coverage by definition
170
173
  return 0
171
174
  fi
172
175
 
173
- # Extract acknowledged IDs from [ekkOS_SELECT] and [ekkOS_SKIP] blocks
176
+ # Extract acknowledged IDs using portable awk (works on macOS and Linux)
174
177
  local acknowledged_count=0
175
178
 
176
- # Check SELECT block
177
- local select_block
178
- select_block=$(echo "$assistant_response" | grep -ozP '\[ekkOS_SELECT\][\s\S]*?\[/ekkOS_SELECT\]' 2>/dev/null | tr '\0' '\n' || true)
179
- if [ -n "$select_block" ]; then
180
- local select_count
181
- select_count=$(echo "$select_block" | grep -oE 'id:\s*[a-f0-9-]+' | wc -l | tr -d ' ')
182
- acknowledged_count=$((acknowledged_count + select_count))
183
- fi
184
-
185
- # Check SKIP block
186
- local skip_block
187
- skip_block=$(echo "$assistant_response" | grep -ozP '\[ekkOS_SKIP\][\s\S]*?\[/ekkOS_SKIP\]' 2>/dev/null | tr '\0' '\n' || true)
188
- if [ -n "$skip_block" ]; then
189
- local skip_count
190
- skip_count=$(echo "$skip_block" | grep -oE 'id:\s*[a-f0-9-]+' | wc -l | tr -d ' ')
191
- acknowledged_count=$((acknowledged_count + skip_count))
192
- fi
179
+ # Use awk to extract SELECT block and count IDs - PORTABLE approach
180
+ local select_count=0
181
+ select_count=$(echo "$assistant_response" | awk '
182
+ /\[ekkOS_SELECT\]/{in_block=1; next}
183
+ /\[\/ekkOS_SELECT\]/{in_block=0}
184
+ in_block && /id:/{count++}
185
+ END{print count+0}
186
+ ')
187
+ acknowledged_count=$((acknowledged_count + select_count))
188
+
189
+ # Use awk to extract SKIP block and count IDs
190
+ local skip_count=0
191
+ skip_count=$(echo "$assistant_response" | awk '
192
+ /\[ekkOS_SKIP\]/{in_block=1; next}
193
+ /\[\/ekkOS_SKIP\]/{in_block=0}
194
+ in_block && /id:/{count++}
195
+ END{print count+0}
196
+ ')
197
+ acknowledged_count=$((acknowledged_count + skip_count))
193
198
 
194
199
  # Legacy: Check for [ekkOS_APPLY] markers (fallback)
195
200
  if [ "$acknowledged_count" -eq 0 ]; then
196
201
  local apply_count
197
- apply_count=$(echo "$assistant_response" | grep -c '\[ekkOS_APPLY\]' || echo 0)
198
- acknowledged_count=$apply_count
202
+ apply_count=$(echo "$assistant_response" | grep -c '\[ekkOS_APPLY\]' 2>/dev/null || echo 0)
203
+ acknowledged_count=$((acknowledged_count + apply_count))
199
204
  fi
200
205
 
201
206
  # Calculate coverage percentage
202
- local coverage
203
- coverage=$((acknowledged_count * 100 / total_count))
207
+ local coverage=0
208
+ if [ "$total_count" -gt 0 ]; then
209
+ coverage=$((acknowledged_count * 100 / total_count))
210
+ fi
204
211
 
205
212
  # Cap at 100%
206
213
  if [ "$coverage" -gt 100 ]; then
@@ -255,11 +262,16 @@ EOF
255
262
  }
256
263
 
257
264
  # Determine if turn is compliant
265
+ # ROBUST: Handles edge cases with non-numeric or empty values
258
266
  is_turn_compliant() {
259
- local retrieval_ok="$1"
260
- local pattern_guard_coverage="$2"
261
- local footer_present="$3"
262
- local pattern_count="$4"
267
+ local retrieval_ok="${1:-true}"
268
+ local pattern_guard_coverage="${2:-100}"
269
+ local footer_present="${3:-true}"
270
+ local pattern_count="${4:-0}"
271
+
272
+ # Sanitize numeric values (default to safe values)
273
+ pattern_guard_coverage=$(echo "$pattern_guard_coverage" | grep -oE '^[0-9]+$' || echo "100")
274
+ pattern_count=$(echo "$pattern_count" | grep -oE '^[0-9]+$' || echo "0")
263
275
 
264
276
  # Retrieval must have succeeded
265
277
  if [ "$retrieval_ok" != "true" ]; then
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Token counter for Claude Code hooks
4
+ * Extracts ACTUAL token data from Anthropic API usage field
5
+ *
6
+ * The transcript contains the real usage data from each API response:
7
+ * - input_tokens: new tokens in this request
8
+ * - cache_read_input_tokens: cached tokens from previous turns
9
+ * - cache_creation_input_tokens: tokens added to cache
10
+ *
11
+ * Usage:
12
+ * node count-tokens.cjs <transcript.jsonl> -> outputs total token count
13
+ * node count-tokens.cjs <transcript.jsonl> --json -> outputs full breakdown as JSON
14
+ */
15
+
16
+ const fs = require('fs');
17
+
18
+ const filePath = process.argv[2];
19
+ const outputJson = process.argv.includes('--json');
20
+
21
+ if (!filePath) {
22
+ console.error('Usage: count-tokens.cjs <transcript.jsonl> [--json]');
23
+ process.exit(1);
24
+ }
25
+
26
+ if (!fs.existsSync(filePath)) {
27
+ console.error(`[count-tokens] ERROR: File not found: ${filePath}`);
28
+ process.exit(1);
29
+ }
30
+
31
+ /**
32
+ * Extract token breakdown from the most recent assistant message's usage field
33
+ * This is the authoritative data from Anthropic's API
34
+ */
35
+ function getTokenBreakdown(filePath) {
36
+ const content = fs.readFileSync(filePath, 'utf-8');
37
+ const lines = content.trim().split('\n').filter(Boolean);
38
+
39
+ // Find the most recent assistant message with usage data
40
+ let latestUsage = null;
41
+
42
+ for (const line of lines) {
43
+ try {
44
+ const entry = JSON.parse(line);
45
+
46
+ if (entry.type === 'assistant' && entry.message?.usage) {
47
+ latestUsage = entry.message.usage;
48
+ }
49
+ } catch (e) {
50
+ continue;
51
+ }
52
+ }
53
+
54
+ if (!latestUsage) {
55
+ return {
56
+ input_tokens: 0,
57
+ cache_read_tokens: 0,
58
+ cache_creation_tokens: 0,
59
+ total_tokens: 0,
60
+ output_tokens: 0
61
+ };
62
+ }
63
+
64
+ const inputTokens = latestUsage.input_tokens || 0;
65
+ const cacheRead = latestUsage.cache_read_input_tokens || 0;
66
+ const cacheCreation = latestUsage.cache_creation_input_tokens || 0;
67
+ const outputTokens = latestUsage.output_tokens || 0;
68
+
69
+ return {
70
+ input_tokens: inputTokens,
71
+ cache_read_tokens: cacheRead,
72
+ cache_creation_tokens: cacheCreation,
73
+ total_tokens: inputTokens + cacheRead + cacheCreation,
74
+ output_tokens: outputTokens
75
+ };
76
+ }
77
+
78
+ const breakdown = getTokenBreakdown(filePath);
79
+
80
+ if (outputJson) {
81
+ // Output full breakdown as JSON (for API)
82
+ console.log(JSON.stringify(breakdown));
83
+ } else {
84
+ // Output just the total (backward compatible)
85
+ console.log(breakdown.total_tokens);
86
+ }
@@ -0,0 +1,98 @@
1
+ #!/bin/bash
2
+ # ═══════════════════════════════════════════════════════════════════════════
3
+ # ekkOS Tool Usage Reminders - Inject proactive tool usage hints
4
+ # ═══════════════════════════════════════════════════════════════════════════
5
+
6
+ # Detect if user query suggests using specific ekkOS tools
7
+ # Returns markdown reminders to inject into Claude's context
8
+
9
+ get_ekkos_reminders() {
10
+ local query="$1"
11
+ local prev_response="$2"
12
+ local reminders=""
13
+
14
+ # Convert to lowercase for matching
15
+ query_lower=$(echo "$query" | tr '[:upper:]' '[:lower:]')
16
+ response_lower=$(echo "$prev_response" | tr '[:upper:]' '[:lower:]')
17
+
18
+ # ═══════════════════════════════════════════════════════════════════════════
19
+ # ekkOS_Search - Before answering technical questions
20
+ # ═══════════════════════════════════════════════════════════════════════════
21
+ if echo "$query_lower" | grep -qE "(how do|how to|what is|why|explain|security|authentication|database|rls|deployment|error|bug|fix)"; then
22
+ reminders+="🧠 **ekkOS_Search Required**: Search memory before answering technical questions\n"
23
+ fi
24
+
25
+ # ═══════════════════════════════════════════════════════════════════════════
26
+ # ekkOS_Forge - When fixing bugs or learning
27
+ # ═══════════════════════════════════════════════════════════════════════════
28
+ if echo "$response_lower" | grep -qE "(fixed|solved|resolved|bug|issue|error|migration|implemented|created|updated)"; then
29
+ reminders+="🔨 **ekkOS_Forge Recommended**: Forge pattern after fixing bugs or implementing solutions\n"
30
+ fi
31
+
32
+ # ═══════════════════════════════════════════════════════════════════════════
33
+ # ekkOS_Directive - User preferences
34
+ # ═══════════════════════════════════════════════════════════════════════════
35
+ if echo "$query_lower" | grep -qE "(always|never|dont|don't|prefer|avoid|should not|shouldn't)"; then
36
+ directive_type="PREFER"
37
+ if echo "$query_lower" | grep -qE "(always|must)"; then
38
+ directive_type="MUST"
39
+ elif echo "$query_lower" | grep -qE "(never|dont|don't|avoid|should not)"; then
40
+ directive_type="NEVER"
41
+ fi
42
+ reminders+="📋 **ekkOS_Directive Required**: User stated a preference - save as ${directive_type} directive\n"
43
+ fi
44
+
45
+ # ═══════════════════════════════════════════════════════════════════════════
46
+ # ekkOS_Conflict - Destructive operations
47
+ # ═══════════════════════════════════════════════════════════════════════════
48
+ if echo "$query_lower" | grep -qE "(delete|remove|drop|truncate|destroy|wipe)"; then
49
+ reminders+="⚠️ **ekkOS_Conflict Required**: Check for conflicts before destructive operations\n"
50
+ fi
51
+
52
+ # ═══════════════════════════════════════════════════════════════════════════
53
+ # ekkOS_Plan - Complex multi-step tasks
54
+ # ═══════════════════════════════════════════════════════════════════════════
55
+ if echo "$query_lower" | grep -qE "(implement|build|create.*feature|add.*functionality|refactor|migrate)"; then
56
+ reminders+="📝 **ekkOS_Plan Recommended**: Create structured plan for multi-step implementation\n"
57
+ fi
58
+
59
+ # ═══════════════════════════════════════════════════════════════════════════
60
+ # ekkOS_StoreSecret - Credentials shared
61
+ # ═══════════════════════════════════════════════════════════════════════════
62
+ if echo "$query_lower" | grep -qE "(api.?key|token|password|secret|credential|github.*key|openai.*key)"; then
63
+ reminders+="🔐 **ekkOS_StoreSecret Available**: Use to securely store credentials (AES-256-GCM)\n"
64
+ fi
65
+
66
+ # ═══════════════════════════════════════════════════════════════════════════
67
+ # ekkOS_Recall - Past conversations
68
+ # ═══════════════════════════════════════════════════════════════════════════
69
+ if echo "$query_lower" | grep -qE "(yesterday|last week|previously|we discussed|earlier|before)"; then
70
+ reminders+="🕐 **ekkOS_Recall Available**: Retrieve past conversations by time\n"
71
+ fi
72
+
73
+ # ═══════════════════════════════════════════════════════════════════════════
74
+ # ekkOS_Codebase - Project-specific search
75
+ # ═══════════════════════════════════════════════════════════════════════════
76
+ if echo "$query_lower" | grep -qE "(in this project|in our codebase|where is.*defined|find.*file)"; then
77
+ reminders+="📂 **ekkOS_Codebase Available**: Search project-specific memory\n"
78
+ fi
79
+
80
+ # ═══════════════════════════════════════════════════════════════════════════
81
+ # ekkOS_Export - Backup request
82
+ # ═══════════════════════════════════════════════════════════════════════════
83
+ if echo "$query_lower" | grep -qE "(export|backup|download|save.*memory|portable)"; then
84
+ reminders+="💾 **ekkOS_Export Available**: Export all patterns/directives as portable JSON\n"
85
+ fi
86
+
87
+ # ═══════════════════════════════════════════════════════════════════════════
88
+ # ekkOS_Summary - Show activity
89
+ # ═══════════════════════════════════════════════════════════════════════════
90
+ if echo "$query_lower" | grep -qE "(what did.*do|ekkos.*activity|memory.*stats|show.*patterns)"; then
91
+ reminders+="📊 **ekkOS_Summary Available**: Show recent ekkOS activity\n"
92
+ fi
93
+
94
+ echo "$reminders"
95
+ }
96
+
97
+ # Export function
98
+ export -f get_ekkos_reminders