@ekkos/cli 0.2.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.
Files changed (135) hide show
  1. package/dist/cache/LocalSessionStore.d.ts +129 -0
  2. package/dist/cache/LocalSessionStore.js +688 -0
  3. package/dist/cache/capture.d.ts +26 -0
  4. package/dist/cache/capture.js +461 -0
  5. package/dist/cache/index.d.ts +7 -0
  6. package/dist/cache/index.js +23 -0
  7. package/dist/cache/types.d.ts +147 -0
  8. package/dist/cache/types.js +40 -0
  9. package/dist/commands/init.d.ts +9 -0
  10. package/dist/commands/init.js +478 -0
  11. package/dist/commands/run.d.ts +12 -0
  12. package/dist/commands/run.js +829 -0
  13. package/dist/commands/setup.d.ts +6 -0
  14. package/dist/commands/setup.js +658 -0
  15. package/dist/commands/status.d.ts +1 -0
  16. package/dist/commands/status.js +109 -0
  17. package/dist/commands/test.d.ts +1 -0
  18. package/dist/commands/test.js +157 -0
  19. package/dist/deploy/agents.d.ts +15 -0
  20. package/dist/deploy/agents.js +72 -0
  21. package/dist/deploy/hooks.d.ts +16 -0
  22. package/dist/deploy/hooks.js +121 -0
  23. package/dist/deploy/index.d.ts +7 -0
  24. package/dist/deploy/index.js +24 -0
  25. package/dist/deploy/instructions.d.ts +12 -0
  26. package/dist/deploy/instructions.js +36 -0
  27. package/dist/deploy/mcp.d.ts +19 -0
  28. package/dist/deploy/mcp.js +109 -0
  29. package/dist/deploy/plugins.d.ts +19 -0
  30. package/dist/deploy/plugins.js +62 -0
  31. package/dist/deploy/settings.d.ts +8 -0
  32. package/dist/deploy/settings.js +84 -0
  33. package/dist/deploy/skills.d.ts +19 -0
  34. package/dist/deploy/skills.js +60 -0
  35. package/dist/index.d.ts +2 -0
  36. package/dist/index.js +71 -0
  37. package/dist/restore/RestoreOrchestrator.d.ts +48 -0
  38. package/dist/restore/RestoreOrchestrator.js +481 -0
  39. package/dist/restore/index.d.ts +4 -0
  40. package/dist/restore/index.js +20 -0
  41. package/dist/utils/platform.d.ts +29 -0
  42. package/dist/utils/platform.js +65 -0
  43. package/dist/utils/session-words.json +119 -0
  44. package/dist/utils/state.d.ts +57 -0
  45. package/dist/utils/state.js +186 -0
  46. package/dist/utils/templates.d.ts +24 -0
  47. package/dist/utils/templates.js +118 -0
  48. package/package.json +48 -0
  49. package/templates/CLAUDE.md +287 -0
  50. package/templates/README.md +378 -0
  51. package/templates/agents/README.md +182 -0
  52. package/templates/agents/code-reviewer.md +166 -0
  53. package/templates/agents/debug-detective.md +169 -0
  54. package/templates/agents/ekkOS_Vercel.md +99 -0
  55. package/templates/agents/extension-manager.md +229 -0
  56. package/templates/agents/git-companion.md +185 -0
  57. package/templates/agents/github-test-agent.md +321 -0
  58. package/templates/agents/railway-manager.md +179 -0
  59. package/templates/claude-plugins/PHASE2_COMPLETION.md +346 -0
  60. package/templates/claude-plugins/PLUGIN_PROPOSALS.md +1776 -0
  61. package/templates/claude-plugins/README.md +587 -0
  62. package/templates/claude-plugins/agents/code-reviewer.json +14 -0
  63. package/templates/claude-plugins/agents/debug-detective.json +15 -0
  64. package/templates/claude-plugins/agents/git-companion.json +14 -0
  65. package/templates/claude-plugins/blog-manager/.claude-plugin/plugin.json +8 -0
  66. package/templates/claude-plugins/blog-manager/commands/blog.md +691 -0
  67. package/templates/claude-plugins/golden-loop-monitor/.claude-plugin/plugin.json +8 -0
  68. package/templates/claude-plugins/golden-loop-monitor/commands/loop-status.md +434 -0
  69. package/templates/claude-plugins/learning-tracker/.claude-plugin/plugin.json +8 -0
  70. package/templates/claude-plugins/learning-tracker/commands/my-patterns.md +282 -0
  71. package/templates/claude-plugins/memory-lens/.claude-plugin/plugin.json +8 -0
  72. package/templates/claude-plugins/memory-lens/commands/memory-search.md +181 -0
  73. package/templates/claude-plugins/pattern-coach/.claude-plugin/plugin.json +8 -0
  74. package/templates/claude-plugins/pattern-coach/commands/forge.md +365 -0
  75. package/templates/claude-plugins/project-schema-validator/.claude-plugin/plugin.json +8 -0
  76. package/templates/claude-plugins/project-schema-validator/commands/validate-schema.md +582 -0
  77. package/templates/claude-plugins-admin/AGENT_TEAM_PROPOSALS.md +819 -0
  78. package/templates/claude-plugins-admin/README.md +446 -0
  79. package/templates/claude-plugins-admin/autonomous-admin-agent/.claude-plugin/plugin.json +8 -0
  80. package/templates/claude-plugins-admin/autonomous-admin-agent/commands/agent.md +595 -0
  81. package/templates/claude-plugins-admin/backend-agent/.claude-plugin/plugin.json +8 -0
  82. package/templates/claude-plugins-admin/backend-agent/commands/backend.md +798 -0
  83. package/templates/claude-plugins-admin/deploy-guardian/.claude-plugin/plugin.json +8 -0
  84. package/templates/claude-plugins-admin/deploy-guardian/commands/deploy.md +554 -0
  85. package/templates/claude-plugins-admin/frontend-agent/.claude-plugin/plugin.json +8 -0
  86. package/templates/claude-plugins-admin/frontend-agent/commands/frontend.md +881 -0
  87. package/templates/claude-plugins-admin/mcp-server-manager/.claude-plugin/plugin.json +8 -0
  88. package/templates/claude-plugins-admin/mcp-server-manager/commands/mcp.md +85 -0
  89. package/templates/claude-plugins-admin/memory-system-monitor/.claude-plugin/plugin.json +8 -0
  90. package/templates/claude-plugins-admin/memory-system-monitor/commands/memory-health.md +569 -0
  91. package/templates/claude-plugins-admin/qa-agent/.claude-plugin/plugin.json +8 -0
  92. package/templates/claude-plugins-admin/qa-agent/commands/qa.md +863 -0
  93. package/templates/claude-plugins-admin/tech-lead-agent/.claude-plugin/plugin.json +8 -0
  94. package/templates/claude-plugins-admin/tech-lead-agent/commands/lead.md +732 -0
  95. package/templates/commands/continue.md +47 -0
  96. package/templates/cursor-hooks/after-agent-response.sh +117 -0
  97. package/templates/cursor-hooks/before-submit-prompt.sh +419 -0
  98. package/templates/cursor-hooks/hooks.json +20 -0
  99. package/templates/cursor-hooks/lib/contract.sh +320 -0
  100. package/templates/cursor-hooks/stop.sh +75 -0
  101. package/templates/cursor-rules/ekkos-memory.md +187 -0
  102. package/templates/hooks/assistant-response.sh +96 -0
  103. package/templates/hooks/hooks.json +28 -0
  104. package/templates/hooks/lib/contract.sh +320 -0
  105. package/templates/hooks/lib/state.sh +158 -0
  106. package/templates/hooks/session-start.ps1 +41 -0
  107. package/templates/hooks/session-start.sh +318 -0
  108. package/templates/hooks/stop.ps1 +16 -0
  109. package/templates/hooks/stop.sh +989 -0
  110. package/templates/hooks/user-prompt-submit.ps1 +174 -0
  111. package/templates/hooks/user-prompt-submit.sh +587 -0
  112. package/templates/hooks-node/lib/state.js +187 -0
  113. package/templates/hooks-node/stop.js +416 -0
  114. package/templates/hooks-node/user-prompt-submit.js +337 -0
  115. package/templates/plan-template.md +306 -0
  116. package/templates/rules/00-hooks-contract.mdc +89 -0
  117. package/templates/rules/30-ekkos-core.mdc +188 -0
  118. package/templates/rules/31-ekkos-messages.mdc +78 -0
  119. package/templates/skills/continue/SKILL.md +169 -0
  120. package/templates/skills/ekkOS_Deep_Recall/Skill.md +282 -0
  121. package/templates/skills/ekkOS_Learn/Skill.md +265 -0
  122. package/templates/skills/ekkOS_Memory_First/Skill.md +206 -0
  123. package/templates/skills/ekkOS_Plan_Assist/Skill.md +302 -0
  124. package/templates/skills/ekkOS_Preferences/Skill.md +247 -0
  125. package/templates/skills/ekkOS_Reflect/Skill.md +257 -0
  126. package/templates/skills/ekkOS_Safety/Skill.md +265 -0
  127. package/templates/skills/ekkOS_Schema/Skill.md +251 -0
  128. package/templates/skills/ekkOS_Summary/Skill.md +257 -0
  129. package/templates/skills/ekkOS_Vault/Skill.md +287 -0
  130. package/templates/skills/permissions/Skill.md +322 -0
  131. package/templates/spec-template.md +159 -0
  132. package/templates/windsurf-hooks/before-submit-prompt.sh +238 -0
  133. package/templates/windsurf-hooks/hooks.json +10 -0
  134. package/templates/windsurf-hooks/lib/contract.sh +320 -0
  135. package/templates/windsurf-rules/ekkos-memory.md +129 -0
@@ -0,0 +1,587 @@
1
+ #!/bin/bash
2
+ # ═══════════════════════════════════════════════════════════════════════════
3
+ # ekkOS_ Hook: UserPromptSubmit - SEAMLESS CONTEXT CONTINUITY
4
+ # ═══════════════════════════════════════════════════════════════════════════
5
+ # ZERO USER ACTION NEEDED:
6
+ # 1. Tracks turn number and context size
7
+ # 2. Detects when compaction happened (context dropped from high to low)
8
+ # 3. AUTO-INJECTS restored context - user just keeps working
9
+ # ═══════════════════════════════════════════════════════════════════════════
10
+
11
+ set +e
12
+
13
+ # ═══════════════════════════════════════════════════════════════════════════
14
+ # SESSION NAME GENERATION (must be defined early - used by ekkos-capture)
15
+ # Format: adj-noun-verb (e.g., "cosmic-penguin-runs")
16
+ # 100 × 100 × 100 = 1,000,000 combinations
17
+ # ═══════════════════════════════════════════════════════════════════════════
18
+ ADJECTIVES=(
19
+ "cosmic" "turbo" "mega" "hyper" "quantum" "atomic" "stellar" "epic"
20
+ "mighty" "groovy" "zippy" "snappy" "jazzy" "funky" "zesty" "peppy"
21
+ "spicy" "crispy" "fluffy" "sparkly" "chunky" "bouncy" "bubbly" "sassy"
22
+ "slick" "sleek" "bold" "nifty" "perky" "plucky" "witty" "nimble"
23
+ "dapper" "fancy" "quirky" "punchy" "swift" "brave" "clever" "dandy"
24
+ "eager" "fiery" "golden" "hasty" "icy" "jolly" "keen" "lively"
25
+ "merry" "noble" "odd" "plush" "quick" "royal" "silly" "tidy"
26
+ "ultra" "vivid" "wacky" "zany" "alpha" "beta" "cyber" "delta"
27
+ "electric" "foggy" "giga" "hazy" "ionic" "jumpy" "kinky" "lunar"
28
+ "magic" "nerdy" "omega" "pixel" "quaint" "retro" "solar" "techno"
29
+ "unified" "viral" "wonky" "xerox" "yappy" "zen" "agile" "binary"
30
+ "chrome" "disco" "elastic" "fizzy" "glossy" "humble" "itchy" "jiffy"
31
+ "kooky" "loopy" "moody" "noisy"
32
+ )
33
+ NOUNS=(
34
+ "penguin" "panda" "otter" "narwhal" "alpaca" "llama" "badger" "walrus"
35
+ "waffle" "pickle" "noodle" "pretzel" "muffin" "taco" "nugget" "biscuit"
36
+ "rocket" "comet" "nebula" "quasar" "meteor" "photon" "pulsar" "nova"
37
+ "ninja" "pirate" "wizard" "robot" "yeti" "phoenix" "sphinx" "kraken"
38
+ "thunder" "blizzard" "tornado" "avalanche" "mango" "kiwi" "banana" "coconut"
39
+ "donut" "espresso" "falafel" "gyro" "hummus" "icecream" "jambon" "kebab"
40
+ "latte" "mocha" "nachos" "olive" "pasta" "quinoa" "ramen" "sushi"
41
+ "tamale" "udon" "velvet" "wasabi" "xmas" "yogurt" "ziti" "anchor"
42
+ "beacon" "canyon" "drifter" "echo" "falcon" "glacier" "harbor" "island"
43
+ "jetpack" "kayak" "lagoon" "meadow" "nebula" "orbit" "parrot" "quest"
44
+ "rapids" "summit" "tunnel" "umbrella" "volcano" "whisper" "xylophone" "yacht"
45
+ "zephyr" "acorn" "bobcat" "cactus" "dolphin" "eagle" "ferret" "gopher"
46
+ "hedgehog" "iguana" "jackal" "koala"
47
+ )
48
+ VERBS=(
49
+ "runs" "jumps" "flies" "swims" "dives" "soars" "glides" "dashes"
50
+ "zooms" "zips" "spins" "twirls" "bounces" "floats" "drifts" "sails"
51
+ "climbs" "leaps" "hops" "skips" "rolls" "slides" "surfs" "rides"
52
+ "builds" "creates" "forges" "shapes" "crafts" "designs" "codes" "types"
53
+ "thinks" "dreams" "learns" "grows" "blooms" "shines" "glows" "sparks"
54
+ "sings" "hums" "calls" "beeps" "clicks" "taps" "pings" "chimes"
55
+ "wins" "leads" "helps" "saves" "guards" "shields" "heals" "fixes"
56
+ "starts" "begins" "launches" "ignites" "blazes" "flares" "bursts" "pops"
57
+ "waves" "nods" "winks" "grins" "smiles" "laughs" "cheers" "claps"
58
+ "seeks" "finds" "spots" "tracks" "hunts" "chases" "catches" "grabs"
59
+ "pushes" "pulls" "lifts" "throws" "kicks" "punts" "bats" "swings"
60
+ "reads" "writes" "draws" "paints" "sculpts" "carves" "molds" "weaves"
61
+ "cooks" "bakes" "grills" "fries"
62
+ )
63
+
64
+ uuid_to_words() {
65
+ local uuid="$1"
66
+ local hex="${uuid//-/}"
67
+ hex="${hex:0:12}"
68
+ if [[ ! "$hex" =~ ^[0-9a-fA-F]+$ ]]; then
69
+ echo "unknown-session-starts"
70
+ return
71
+ fi
72
+ local adj_seed=$((16#${hex:0:4}))
73
+ local noun_seed=$((16#${hex:4:4}))
74
+ local verb_seed=$((16#${hex:8:4}))
75
+ local adj_idx=$((adj_seed % ${#ADJECTIVES[@]}))
76
+ local noun_idx=$((noun_seed % ${#NOUNS[@]}))
77
+ local verb_idx=$((verb_seed % ${#VERBS[@]}))
78
+ echo "${ADJECTIVES[$adj_idx]}-${NOUNS[$noun_idx]}-${VERBS[$verb_idx]}"
79
+ }
80
+
81
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
82
+ PROJECT_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
83
+
84
+ INPUT=$(cat)
85
+ USER_QUERY=$(echo "$INPUT" | jq -r '.query // .message // .prompt // ""')
86
+ RAW_SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
87
+ TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // ""')
88
+
89
+ [ -z "$USER_QUERY" ] || [ "$USER_QUERY" = "null" ] && exit 0
90
+
91
+ # Fallback: read session_id from saved state if not in INPUT
92
+ if [ "$RAW_SESSION_ID" = "unknown" ] || [ "$RAW_SESSION_ID" = "null" ] || [ -z "$RAW_SESSION_ID" ]; then
93
+ STATE_FILE="$HOME/.claude/state/current-session.json"
94
+ if [ -f "$STATE_FILE" ]; then
95
+ RAW_SESSION_ID=$(jq -r '.session_id // "unknown"' "$STATE_FILE" 2>/dev/null || echo "unknown")
96
+ fi
97
+ fi
98
+
99
+ # ═══════════════════════════════════════════════════════════════════════════
100
+ # INTELLIGENT TOOL ROUTER: Multi-trigger skill detection
101
+ # Detects ALL applicable skills/tools and injects as system reminder
102
+ # ═══════════════════════════════════════════════════════════════════════════
103
+ SKILL_REMINDERS=()
104
+ QUERY_LOWER=$(echo "$USER_QUERY" | tr '[:upper:]' '[:lower:]')
105
+
106
+ # ─────────────────────────────────────────────────────────────────────────────
107
+ # MANDATORY TRIGGERS (Always check ekkOS first)
108
+ # ─────────────────────────────────────────────────────────────────────────────
109
+
110
+ # Memory First - Debug/Error/Problem solving
111
+ if echo "$QUERY_LOWER" | grep -qE '(how do i|debug|error|bug|fix|not working|broken|fails|issue|problem|wrong|crash)'; then
112
+ SKILL_REMINDERS+=("🔧 SKILL REQUIRED: Call Skill(skill: \"ekkOS_Memory_First\") FIRST before debugging")
113
+ fi
114
+
115
+ # ─────────────────────────────────────────────────────────────────────────────
116
+ # RECALL TRIGGERS (Time-based memory)
117
+ # ─────────────────────────────────────────────────────────────────────────────
118
+ if echo "$QUERY_LOWER" | grep -qE '(yesterday|last week|last month|remember when|what did we|where did we leave|before|earlier|previous|ago)'; then
119
+ SKILL_REMINDERS+=("📅 SKILL REQUIRED: Call Skill(skill: \"ekkOS_Deep_Recall\") for time-based memory")
120
+ fi
121
+
122
+ # ─────────────────────────────────────────────────────────────────────────────
123
+ # DIRECTIVE TRIGGERS (User preferences)
124
+ # ─────────────────────────────────────────────────────────────────────────────
125
+ if echo "$QUERY_LOWER" | grep -qE '(always |never |i prefer|i like |dont |don.t |avoid |remember that |from now on)'; then
126
+ SKILL_REMINDERS+=("⚙️ SKILL REQUIRED: Call Skill(skill: \"ekkOS_Preferences\") to capture directive")
127
+ fi
128
+
129
+ # ─────────────────────────────────────────────────────────────────────────────
130
+ # SAFETY TRIGGERS (Destructive actions)
131
+ # ─────────────────────────────────────────────────────────────────────────────
132
+ if echo "$QUERY_LOWER" | grep -qE '(delete|drop |rm -rf|deploy|push.*main|push.*master|production|migrate|rollback)'; then
133
+ SKILL_REMINDERS+=("⚠️ SAFETY REQUIRED: Call ekkOS_Conflict before this destructive action")
134
+ fi
135
+
136
+ # ─────────────────────────────────────────────────────────────────────────────
137
+ # SCHEMA TRIGGERS (Database operations)
138
+ # ─────────────────────────────────────────────────────────────────────────────
139
+ if echo "$QUERY_LOWER" | grep -qE '(sql|query|supabase|prisma|database|table|column|select |insert |update |where )'; then
140
+ SKILL_REMINDERS+=("🗄️ SCHEMA REQUIRED: Call ekkOS_GetSchema for correct field names")
141
+ fi
142
+
143
+ # ─────────────────────────────────────────────────────────────────────────────
144
+ # SECRET TRIGGERS (API keys, credentials)
145
+ # ─────────────────────────────────────────────────────────────────────────────
146
+ if echo "$QUERY_LOWER" | grep -qE '(api key|token|password|credential|secret|my.*key|store.*key)'; then
147
+ SKILL_REMINDERS+=("🔐 SECRETS: Use ekkOS_StoreSecret to securely save credentials")
148
+ fi
149
+
150
+ # ─────────────────────────────────────────────────────────────────────────────
151
+ # PLAN TRIGGERS (Complex multi-step tasks)
152
+ # ─────────────────────────────────────────────────────────────────────────────
153
+ if echo "$QUERY_LOWER" | grep -qE '(implement|build|create.*feature|refactor|migrate|set up|architecture)'; then
154
+ SKILL_REMINDERS+=("📋 PLAN REQUIRED: Call ekkOS_Plan for complex multi-step tasks")
155
+ fi
156
+
157
+ # ─────────────────────────────────────────────────────────────────────────────
158
+ # LEARN TRIGGERS (User expressing success/failure)
159
+ # ─────────────────────────────────────────────────────────────────────────────
160
+ if echo "$QUERY_LOWER" | grep -qE '(that worked|thanks|perfect|great|awesome|nailed it|solved|fixed it)'; then
161
+ SKILL_REMINDERS+=("🎯 LEARN: Consider calling ekkOS_Forge to capture this solution as a pattern")
162
+ fi
163
+
164
+ # ─────────────────────────────────────────────────────────────────────────────
165
+ # CODEBASE TRIGGERS (Project-specific code search)
166
+ # ─────────────────────────────────────────────────────────────────────────────
167
+ if echo "$QUERY_LOWER" | grep -qE '(where is|find.*file|search.*code|in this project|in the codebase)'; then
168
+ SKILL_REMINDERS+=("🔍 CODEBASE: Use ekkOS_Codebase for project-specific code search")
169
+ fi
170
+
171
+ # Combine skill reminders (only take first 3 to avoid noise)
172
+ SKILL_REMINDER=""
173
+ REMINDER_COUNT=${#SKILL_REMINDERS[@]}
174
+ if [ "$REMINDER_COUNT" -gt 0 ]; then
175
+ # Take up to 3 most relevant reminders
176
+ MAX_REMINDERS=3
177
+ [ "$REMINDER_COUNT" -lt "$MAX_REMINDERS" ] && MAX_REMINDERS="$REMINDER_COUNT"
178
+ for i in $(seq 0 $((MAX_REMINDERS - 1))); do
179
+ [ -n "$SKILL_REMINDER" ] && SKILL_REMINDER="$SKILL_REMINDER
180
+ "
181
+ SKILL_REMINDER="$SKILL_REMINDER${SKILL_REMINDERS[$i]}"
182
+ done
183
+ fi
184
+
185
+ # ═══════════════════════════════════════════════════════════════════════════
186
+ # Load auth
187
+ # ═══════════════════════════════════════════════════════════════════════════
188
+ EKKOS_CONFIG="$HOME/.ekkos/config.json"
189
+ AUTH_TOKEN=""
190
+ if [ -f "$EKKOS_CONFIG" ]; then
191
+ AUTH_TOKEN=$(jq -r '.hookApiKey // .apiKey // ""' "$EKKOS_CONFIG" 2>/dev/null || echo "")
192
+ fi
193
+ [ -z "$AUTH_TOKEN" ] && AUTH_TOKEN=$(grep -E "^SUPABASE_SECRET_KEY=" "$PROJECT_ROOT/.env.local" 2>/dev/null | cut -d'=' -f2- | tr -d '"' | tr -d "'" || echo "")
194
+
195
+ MEMORY_API_URL="https://mcp.ekkos.dev"
196
+
197
+ # ═══════════════════════════════════════════════════════════════════════════
198
+ # Session ID - NEW ID per conversation (not persisted 24h anymore)
199
+ # Each Claude Code session gets unique ID for proper Time Machine grouping
200
+ # ═══════════════════════════════════════════════════════════════════════════
201
+ STATE_DIR="$PROJECT_ROOT/.claude/state"
202
+ mkdir -p "$STATE_DIR" 2>/dev/null || true
203
+ SESSION_FILE="$STATE_DIR/current-session.json"
204
+
205
+ # Use Claude's RAW_SESSION_ID exclusively
206
+ SESSION_ID="$RAW_SESSION_ID"
207
+
208
+ # Skip if no valid session ID from Claude
209
+ if [ -z "$SESSION_ID" ] || [ "$SESSION_ID" = "unknown" ] || [ "$SESSION_ID" = "null" ]; then
210
+ exit 0
211
+ fi
212
+
213
+ # Save for other hooks to reference (but don't reuse across conversations)
214
+ echo "{\"session_id\": \"$SESSION_ID\", \"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}" > "$SESSION_FILE"
215
+
216
+ # ═══════════════════════════════════════════════════════════════════════════
217
+ # Turn counter - PROJECT-LOCAL storage
218
+ # ═══════════════════════════════════════════════════════════════════════════
219
+ PROJECT_SESSION_DIR="$STATE_DIR/sessions"
220
+ mkdir -p "$PROJECT_SESSION_DIR" 2>/dev/null || true
221
+ TURN_COUNTER_FILE="$PROJECT_SESSION_DIR/${SESSION_ID}.turn"
222
+
223
+ # Count actual user messages in transcript for accurate turn number
224
+ TURN_NUMBER=1
225
+ if [ -n "$TRANSCRIPT_PATH" ] && [ -f "$TRANSCRIPT_PATH" ]; then
226
+ # Count user message entries in JSONL transcript
227
+ TURN_NUMBER=$(grep -c '"type":"user"' "$TRANSCRIPT_PATH" 2>/dev/null || echo "1")
228
+ [ "$TURN_NUMBER" -eq 0 ] && TURN_NUMBER=1
229
+ fi
230
+
231
+ # PRESERVE HISTORY: Don't overwrite if saved count is higher (after /clear)
232
+ SAVED_TURN_COUNT=0
233
+ [ -f "$TURN_COUNTER_FILE" ] && SAVED_TURN_COUNT=$(cat "$TURN_COUNTER_FILE" 2>/dev/null || echo "0")
234
+ TRANSCRIPT_TURN_COUNT=$TURN_NUMBER # Save for post-clear detection
235
+ POST_CLEAR_DETECTED=false
236
+ if [ "$SAVED_TURN_COUNT" -gt "$TURN_NUMBER" ]; then
237
+ # Post-clear: INCREMENT from saved count (not just copy it)
238
+ TURN_NUMBER=$((SAVED_TURN_COUNT + 1))
239
+ POST_CLEAR_DETECTED=true
240
+ fi
241
+ echo "$TURN_NUMBER" > "$TURN_COUNTER_FILE"
242
+
243
+ # ═══════════════════════════════════════════════════════════════════════════
244
+ # 🧠 WORKING MEMORY: Fast capture each turn (async, non-blocking)
245
+ # ═══════════════════════════════════════════════════════════════════════════
246
+ MEMORY_API_URL="https://mcp.ekkos.dev"
247
+ if [ -f "$HOME/.ekkos/config.json" ]; then
248
+ CAPTURE_TOKEN=$(jq -r '.hookApiKey // .apiKey // ""' "$HOME/.ekkos/config.json" 2>/dev/null || echo "")
249
+ if [ -n "$CAPTURE_TOKEN" ] && [ "$CAPTURE_TOKEN" != "null" ]; then
250
+ # Async capture to Redis/Supabase - doesn't block hook execution
251
+ (curl -s -X POST "$MEMORY_API_URL/api/v1/working/fast-capture" \
252
+ -H "Authorization: Bearer $CAPTURE_TOKEN" \
253
+ -H "Content-Type: application/json" \
254
+ -d "{\"session_id\":\"$RAW_SESSION_ID\",\"turn\":$TURN_NUMBER,\"query\":$(echo "$USER_QUERY" | jq -Rs .)}" \
255
+ >/dev/null 2>&1) &
256
+ fi
257
+ fi
258
+
259
+ # ═══════════════════════════════════════════════════════════════════════════
260
+ # 💾 LOCAL CACHE: Tier 0 capture for instant /continue (async, non-blocking)
261
+ # ═══════════════════════════════════════════════════════════════════════════
262
+ if command -v ekkos-capture &>/dev/null; then
263
+ # Generate session name if not already set
264
+ if [ -z "$SESSION_NAME" ] || [ "$SESSION_NAME" = "unknown-session-starts" ]; then
265
+ SESSION_NAME=$(uuid_to_words "$RAW_SESSION_ID" 2>/dev/null || echo "unknown-session")
266
+ fi
267
+ # Async local capture - writes to ~/.ekkos/cache/sessions/<uuid>.jsonl
268
+ (ekkos-capture user "$RAW_SESSION_ID" "$SESSION_NAME" "$TURN_NUMBER" "$USER_QUERY" "$PROJECT_ROOT" \
269
+ >/dev/null 2>&1) &
270
+ fi
271
+
272
+ # ═══════════════════════════════════════════════════════════════════════════
273
+ # 📥 GOLDEN LOOP: CAPTURE PHASE - Track turn start
274
+ # ═══════════════════════════════════════════════════════════════════════════
275
+ GOLDEN_LOOP_FILE="$PROJECT_ROOT/.ekkos/golden-loop-current.json"
276
+ mkdir -p "$PROJECT_ROOT/.ekkos" 2>/dev/null || true
277
+
278
+ # Write current phase to file (extension watches this for real-time updates)
279
+ jq -n \
280
+ --arg phase "capture" \
281
+ --argjson turn "$TURN_NUMBER" \
282
+ --arg session "$SESSION_ID" \
283
+ --arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
284
+ '{
285
+ phase: $phase,
286
+ turn: $turn,
287
+ session: $session,
288
+ timestamp: $timestamp,
289
+ stats: {
290
+ retrieved: 0,
291
+ applied: 0,
292
+ forged: 0
293
+ }
294
+ }' > "$GOLDEN_LOOP_FILE" 2>/dev/null || true
295
+
296
+ # ═══════════════════════════════════════════════════════════════════════════
297
+ # 🔍 GOLDEN LOOP: RETRIEVE PHASE - Auto-retrieve patterns from ekkOS
298
+ # ═══════════════════════════════════════════════════════════════════════════
299
+ EKKOS_API_KEY=""
300
+ if [ -f "$HOME/.ekkos/.hookApiKey" ]; then
301
+ EKKOS_API_KEY=$(cat "$HOME/.ekkos/.hookApiKey" 2>/dev/null || echo "")
302
+ elif [ -f "$HOME/.ekkos/config.json" ]; then
303
+ EKKOS_API_KEY=$(jq -r '.hookApiKey // ""' "$HOME/.ekkos/config.json" 2>/dev/null || echo "")
304
+ fi
305
+
306
+ RETRIEVED_PATTERNS=""
307
+ PATTERN_COUNT=0
308
+ RETRIEVED_DIRECTIVES=""
309
+ DIRECTIVE_COUNT=0
310
+
311
+ # ═══════════════════════════════════════════════════════════════════════════
312
+ # 📦 DIRECTIVE CACHE: Local cache to avoid API calls every turn
313
+ # Only fetch from API if:
314
+ # 1. Cache doesn't exist
315
+ # 2. Cache is >1 hour old
316
+ # 3. Directive-related trigger detected in query
317
+ # ═══════════════════════════════════════════════════════════════════════════
318
+ DIRECTIVE_CACHE_DIR="$HOME/.ekkos/cache"
319
+ DIRECTIVE_CACHE_FILE="$DIRECTIVE_CACHE_DIR/directives.json"
320
+ DIRECTIVE_CACHE_TTL=3600 # 1 hour in seconds
321
+ mkdir -p "$DIRECTIVE_CACHE_DIR" 2>/dev/null || true
322
+
323
+ # Check if we need to refresh directive cache
324
+ DIRECTIVE_CACHE_VALID=false
325
+ DIRECTIVE_TRIGGER_DETECTED=false
326
+
327
+ # Smart detection: Check if query mentions directive-related keywords
328
+ if echo "$QUERY_LOWER" | grep -qE '(always |never |i prefer|i like |dont |don.t |avoid |remember that |from now on|directive|preference)'; then
329
+ DIRECTIVE_TRIGGER_DETECTED=true
330
+ fi
331
+
332
+ if [ -f "$DIRECTIVE_CACHE_FILE" ]; then
333
+ CACHE_TIMESTAMP=$(jq -r '.cached_at // 0' "$DIRECTIVE_CACHE_FILE" 2>/dev/null || echo "0")
334
+ CURRENT_TIMESTAMP=$(date +%s)
335
+ CACHE_AGE=$((CURRENT_TIMESTAMP - CACHE_TIMESTAMP))
336
+
337
+ # Cache is valid if <1 hour old AND no directive trigger detected
338
+ if [ "$CACHE_AGE" -lt "$DIRECTIVE_CACHE_TTL" ] && [ "$DIRECTIVE_TRIGGER_DETECTED" = "false" ]; then
339
+ DIRECTIVE_CACHE_VALID=true
340
+ fi
341
+ fi
342
+
343
+ # Decide whether to inject directives this turn
344
+ # SMART INJECTION: Only on Turn 1, post-clear, or directive trigger
345
+ SHOULD_INJECT_DIRECTIVES=false
346
+ if [ "$TURN_NUMBER" -eq 1 ] || [ "$POST_CLEAR_DETECTED" = "true" ] || [ "$DIRECTIVE_TRIGGER_DETECTED" = "true" ]; then
347
+ SHOULD_INJECT_DIRECTIVES=true
348
+ fi
349
+
350
+ if [ -n "$EKKOS_API_KEY" ] && [ -n "$USER_QUERY" ]; then
351
+ # Update phase to RETRIEVE
352
+ jq -n \
353
+ --arg phase "retrieve" \
354
+ --argjson turn "$TURN_NUMBER" \
355
+ --arg session "$SESSION_ID" \
356
+ --arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
357
+ '{
358
+ phase: $phase,
359
+ turn: $turn,
360
+ session: $session,
361
+ timestamp: $timestamp,
362
+ stats: {
363
+ retrieved: 0,
364
+ applied: 0,
365
+ forged: 0
366
+ }
367
+ }' > "$GOLDEN_LOOP_FILE" 2>/dev/null || true
368
+
369
+ # ═══════════════════════════════════════════════════════════════════════════
370
+ # PATTERN RETRIEVAL: Always search patterns (they're query-specific)
371
+ # DIRECTIVE RETRIEVAL: Only if cache is invalid or trigger detected
372
+ # ═══════════════════════════════════════════════════════════════════════════
373
+
374
+ # Build sources array - always include patterns, conditionally include directives
375
+ if [ "$DIRECTIVE_CACHE_VALID" = "true" ]; then
376
+ SEARCH_SOURCES='["patterns"]'
377
+ else
378
+ SEARCH_SOURCES='["patterns", "directives"]'
379
+ fi
380
+
381
+ # Call ekkOS MCP gateway
382
+ SEARCH_RESPONSE=$(curl -s -X POST "https://api.ekkos.dev/api/v1/mcp/call" \
383
+ -H "Authorization: Bearer $EKKOS_API_KEY" \
384
+ -H "Content-Type: application/json" \
385
+ --max-time 2 \
386
+ -d "{\"tool\": \"ekkOS_Search\", \"arguments\": {\"query\": $(echo "$USER_QUERY" | jq -Rs .), \"limit\": 5, \"sources\": $SEARCH_SOURCES}}" 2>/dev/null || echo '{"result": {"results": {"patterns": [], "directives": []}}}')
387
+
388
+ # Count patterns retrieved (MCP response: .result.results.patterns)
389
+ PATTERN_COUNT=$(echo "$SEARCH_RESPONSE" | jq -r '.result.results.patterns | length' 2>/dev/null || echo "0")
390
+
391
+ # Update golden loop with retrieved count
392
+ if [ "$PATTERN_COUNT" -gt 0 ]; then
393
+ jq -n \
394
+ --arg phase "inject" \
395
+ --argjson turn "$TURN_NUMBER" \
396
+ --arg session "$SESSION_ID" \
397
+ --arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
398
+ --argjson retrieved "$PATTERN_COUNT" \
399
+ '{
400
+ phase: $phase,
401
+ turn: $turn,
402
+ session: $session,
403
+ timestamp: $timestamp,
404
+ stats: {
405
+ retrieved: $retrieved,
406
+ applied: 0,
407
+ forged: 0
408
+ }
409
+ }' > "$GOLDEN_LOOP_FILE" 2>/dev/null || true
410
+
411
+ # Format patterns for injection (MCP response: .result.results.patterns)
412
+ RETRIEVED_PATTERNS=$(echo "$SEARCH_RESPONSE" | jq -r '
413
+ .result.results.patterns[]? |
414
+ "**\(.title)**\n\(.problem // .guidance // "")\n\n## Solution\n\(.solution // .content // "")\n\nSuccess Rate: \((.success_rate // 0) * 100)%\nApplied: \(.applied_count // 0) times\n"
415
+ ' 2>/dev/null || echo "")
416
+ fi
417
+
418
+ # ═══════════════════════════════════════════════════════════════════════════
419
+ # DIRECTIVE HANDLING: Use cache if valid, otherwise process from response
420
+ # ═══════════════════════════════════════════════════════════════════════════
421
+ if [ "$DIRECTIVE_CACHE_VALID" = "true" ]; then
422
+ # Load directives from cache
423
+ DIRECTIVE_COUNT=$(jq -r '.count // 0' "$DIRECTIVE_CACHE_FILE" 2>/dev/null || echo "0")
424
+ RETRIEVED_DIRECTIVES=$(jq -r '.formatted // ""' "$DIRECTIVE_CACHE_FILE" 2>/dev/null || echo "")
425
+ else
426
+ # Extract and format DIRECTIVES from API response
427
+ DIRECTIVE_COUNT=$(echo "$SEARCH_RESPONSE" | jq -r '.result.results.directives | length' 2>/dev/null || echo "0")
428
+
429
+ if [ "$DIRECTIVE_COUNT" -gt 0 ]; then
430
+ # Group directives by type for clean display
431
+ MUST_DIRECTIVES=$(echo "$SEARCH_RESPONSE" | jq -r '.result.results.directives[] | select(.type == "MUST") | " • \(.rule)"' 2>/dev/null || echo "")
432
+ NEVER_DIRECTIVES=$(echo "$SEARCH_RESPONSE" | jq -r '.result.results.directives[] | select(.type == "NEVER") | " • \(.rule)"' 2>/dev/null || echo "")
433
+ PREFER_DIRECTIVES=$(echo "$SEARCH_RESPONSE" | jq -r '.result.results.directives[] | select(.type == "PREFER") | " • \(.rule)"' 2>/dev/null || echo "")
434
+ AVOID_DIRECTIVES=$(echo "$SEARCH_RESPONSE" | jq -r '.result.results.directives[] | select(.type == "AVOID") | " • \(.rule)"' 2>/dev/null || echo "")
435
+
436
+ # Build directive section
437
+ if [ -n "$MUST_DIRECTIVES" ] || [ -n "$NEVER_DIRECTIVES" ] || [ -n "$PREFER_DIRECTIVES" ] || [ -n "$AVOID_DIRECTIVES" ]; then
438
+ RETRIEVED_DIRECTIVES="🔴 USER DIRECTIVES (FOLLOW THESE):"
439
+ [ -n "$MUST_DIRECTIVES" ] && RETRIEVED_DIRECTIVES="$RETRIEVED_DIRECTIVES
440
+
441
+ MUST:
442
+ $MUST_DIRECTIVES"
443
+ [ -n "$NEVER_DIRECTIVES" ] && RETRIEVED_DIRECTIVES="$RETRIEVED_DIRECTIVES
444
+
445
+ NEVER:
446
+ $NEVER_DIRECTIVES"
447
+ [ -n "$PREFER_DIRECTIVES" ] && RETRIEVED_DIRECTIVES="$RETRIEVED_DIRECTIVES
448
+
449
+ PREFER:
450
+ $PREFER_DIRECTIVES"
451
+ [ -n "$AVOID_DIRECTIVES" ] && RETRIEVED_DIRECTIVES="$RETRIEVED_DIRECTIVES
452
+
453
+ AVOID:
454
+ $AVOID_DIRECTIVES"
455
+ fi
456
+
457
+ # Save to cache for future turns
458
+ jq -n \
459
+ --argjson count "$DIRECTIVE_COUNT" \
460
+ --arg formatted "$RETRIEVED_DIRECTIVES" \
461
+ --argjson cached_at "$(date +%s)" \
462
+ '{
463
+ count: $count,
464
+ formatted: $formatted,
465
+ cached_at: $cached_at
466
+ }' > "$DIRECTIVE_CACHE_FILE" 2>/dev/null || true
467
+ fi
468
+ fi
469
+ fi
470
+
471
+ # Context tracking removed - Claude Code handles its own context management
472
+
473
+ # ═══════════════════════════════════════════════════════════════════════════
474
+ # COLORS
475
+ # ═══════════════════════════════════════════════════════════════════════════
476
+ CYAN='\033[0;36m'
477
+ GREEN='\033[0;32m'
478
+ YELLOW='\033[1;33m'
479
+ MAGENTA='\033[0;35m'
480
+ DIM='\033[2m'
481
+ BOLD='\033[1m'
482
+ RESET='\033[0m'
483
+
484
+ CURRENT_TIME=$(date "+%Y-%m-%d %I:%M:%S %p %Z")
485
+
486
+ # Generate session name (arrays and uuid_to_words defined at top of file)
487
+ SESSION_NAME=""
488
+ if [ -n "$SESSION_ID" ] && [ "$SESSION_ID" != "unknown" ] && [ "$SESSION_ID" != "null" ]; then
489
+ SESSION_NAME=$(uuid_to_words "$SESSION_ID")
490
+ fi
491
+
492
+ # ═══════════════════════════════════════════════════════════════════════════
493
+ # "/continue" COMMAND: Delegated to Skill system (DO NOT INTERCEPT)
494
+ # ═══════════════════════════════════════════════════════════════════════════
495
+ # REMOVED: Hook used to intercept /continue and do simple restoration
496
+ # NOW: Let /continue Skill handle it - supports session names + intelligent narrative
497
+ #
498
+ # Why this changed:
499
+ # - Hook was ignoring session name argument (always used "current")
500
+ # - Hook couldn't provide intelligent narrative briefing
501
+ # - Skill system now has proper name→UUID resolution in API
502
+ #
503
+ # OLD BEHAVIOR (removed):
504
+ # - Hook caught /continue → API call with "current" → exit
505
+ # NEW BEHAVIOR:
506
+ # - /continue groovy-cactus → Skill system → API with session name → intelligent briefing
507
+ # ═══════════════════════════════════════════════════════════════════════════
508
+
509
+ # Note: Session name is shown in status line for easy reference:
510
+ # Example: "🧠 ekkOS Memory | Turn 42 | groovy-cactus | 2026-01-12 09:40 AM EST"
511
+
512
+ # ═══════════════════════════════════════════════════════════════════════════
513
+ # AUTO-RESTORE REMOVED: Manual /continue only (saves 79% token burn!)
514
+ # ═══════════════════════════════════════════════════════════════════════════
515
+ # WHY REMOVED:
516
+ # - Auto-restore burns 5,000 tokens per turn (250K tokens over 50 turns)
517
+ # - Manual /continue: 2,000 tokens once + clean slate (52K total = 79% savings!)
518
+ # - Manual /continue is 10x more powerful (Bash + multi-source + narrative)
519
+ # - User has control (can choose session, can skip if starting fresh)
520
+ # - Explicit > implicit (user knows exactly what's happening)
521
+ #
522
+ # OLD BEHAVIOR (removed):
523
+ # - Compaction detection → auto-inject 10 turns
524
+ # - Post-clear detection → auto-inject 10 turns
525
+ # NEW BEHAVIOR:
526
+ # - User types: /continue groovy-cactus
527
+ # - Skill runs with full Bash power + intelligent narrative
528
+ # ═══════════════════════════════════════════════════════════════════════════
529
+
530
+ # Simple status line - no context warnings, Claude handles its own context
531
+ echo -e "${CYAN}${BOLD}🧠 ekkOS Memory${RESET} ${DIM}| Turn ${TURN_NUMBER} | ${SESSION_NAME} | ${CURRENT_TIME}${RESET}"
532
+
533
+ # Output skill reminder if detected
534
+ if [ -n "$SKILL_REMINDER" ]; then
535
+ echo ""
536
+ echo -e "${MAGENTA}${BOLD}$SKILL_REMINDER${RESET}"
537
+ fi
538
+
539
+ # 💉 GOLDEN LOOP: INJECT PHASE - Inject directives FIRST (highest priority)
540
+ # SMART INJECTION: Only on Turn 1, post-clear, or directive trigger
541
+ if [ "$SHOULD_INJECT_DIRECTIVES" = "true" ] && [ -n "$RETRIEVED_DIRECTIVES" ] && [ "$DIRECTIVE_COUNT" -gt 0 ]; then
542
+ echo ""
543
+ echo "<system-reminder>"
544
+ echo -e "$RETRIEVED_DIRECTIVES"
545
+ echo "</system-reminder>"
546
+ fi
547
+
548
+ # 💉 GOLDEN LOOP: INJECT PHASE - Inject retrieved patterns into context
549
+ if [ -n "$RETRIEVED_PATTERNS" ] && [ "$PATTERN_COUNT" -gt 0 ]; then
550
+ echo ""
551
+ echo "<system-reminder>"
552
+ echo "🔍 RETRIEVED PATTERNS FROM ekkOS MEMORY ($PATTERN_COUNT patterns found)"
553
+ echo ""
554
+ echo -e "$RETRIEVED_PATTERNS"
555
+ echo ""
556
+ echo "These patterns were automatically retrieved based on your query. Review and apply relevant solutions."
557
+ echo "</system-reminder>"
558
+ echo ""
559
+ echo "🔴 MANDATORY PATTERN ACKNOWLEDGMENT (PatternGuard):"
560
+ echo "You MUST acknowledge ALL $PATTERN_COUNT patterns above - either SELECT or SKIP each one."
561
+ echo ""
562
+ echo "For patterns you USE:"
563
+ echo "[ekkOS_SELECT]"
564
+ echo "- id: <pattern_id>"
565
+ echo " reason: <1-line why using>"
566
+ echo " confidence: <0.0-1.0>"
567
+ echo "[/ekkOS_SELECT]"
568
+ echo ""
569
+ echo "For patterns NOT relevant:"
570
+ echo "[ekkOS_SKIP]"
571
+ echo "- id: <pattern_id>"
572
+ echo " reason: <1-line why not relevant>"
573
+ echo "[/ekkOS_SKIP]"
574
+ echo ""
575
+ echo "⚡ AUTOMATIC APPLICATION: When pattern matches your task, APPLY IT immediately without asking."
576
+ echo "Track outcome after: ekkOS_Outcome({success: true/false})"
577
+ echo ""
578
+ echo "100% coverage required. This is how the system learns what works."
579
+ fi
580
+
581
+ # Inject footer format reminder (helps Claude remember session name)
582
+ if [ -n "$SESSION_NAME" ] && [ "$SESSION_NAME" != "unknown-session" ]; then
583
+ echo ""
584
+ echo "<footer-format>End responses with: Claude Code ({Model}) · 🧠 **ekkOS_™** · Turn ${TURN_NUMBER} · ${SESSION_NAME} · 📅 ${CURRENT_TIME}</footer-format>"
585
+ fi
586
+
587
+ exit 0