@ekkos/cli 1.2.17 → 1.3.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 (47) hide show
  1. package/dist/cache/capture.js +0 -0
  2. package/dist/commands/dashboard.js +57 -49
  3. package/dist/commands/hooks.d.ts +25 -36
  4. package/dist/commands/hooks.js +43 -615
  5. package/dist/commands/init.js +7 -23
  6. package/dist/commands/run.js +97 -11
  7. package/dist/commands/setup.js +10 -352
  8. package/dist/deploy/hooks.d.ts +8 -5
  9. package/dist/deploy/hooks.js +12 -105
  10. package/dist/deploy/settings.d.ts +8 -2
  11. package/dist/deploy/settings.js +22 -51
  12. package/dist/index.js +17 -39
  13. package/dist/utils/state.js +7 -2
  14. package/package.json +1 -1
  15. package/templates/CLAUDE.md +82 -292
  16. package/templates/cursor-rules/ekkos-memory.md +48 -108
  17. package/templates/windsurf-rules/ekkos-memory.md +62 -64
  18. package/templates/cursor-hooks/after-agent-response.sh +0 -117
  19. package/templates/cursor-hooks/before-submit-prompt.sh +0 -419
  20. package/templates/cursor-hooks/hooks.json +0 -20
  21. package/templates/cursor-hooks/lib/contract.sh +0 -320
  22. package/templates/cursor-hooks/stop.sh +0 -75
  23. package/templates/hooks/assistant-response.ps1 +0 -256
  24. package/templates/hooks/assistant-response.sh +0 -160
  25. package/templates/hooks/hooks.json +0 -40
  26. package/templates/hooks/lib/contract.sh +0 -332
  27. package/templates/hooks/lib/count-tokens.cjs +0 -86
  28. package/templates/hooks/lib/ekkos-reminders.sh +0 -98
  29. package/templates/hooks/lib/state.sh +0 -210
  30. package/templates/hooks/session-start.ps1 +0 -146
  31. package/templates/hooks/session-start.sh +0 -353
  32. package/templates/hooks/stop.ps1 +0 -349
  33. package/templates/hooks/stop.sh +0 -382
  34. package/templates/hooks/user-prompt-submit.ps1 +0 -419
  35. package/templates/hooks/user-prompt-submit.sh +0 -516
  36. package/templates/project-stubs/session-start.ps1 +0 -63
  37. package/templates/project-stubs/session-start.sh +0 -55
  38. package/templates/project-stubs/stop.ps1 +0 -63
  39. package/templates/project-stubs/stop.sh +0 -55
  40. package/templates/project-stubs/user-prompt-submit.ps1 +0 -63
  41. package/templates/project-stubs/user-prompt-submit.sh +0 -55
  42. package/templates/windsurf-hooks/README.md +0 -212
  43. package/templates/windsurf-hooks/hooks.json +0 -17
  44. package/templates/windsurf-hooks/install.sh +0 -148
  45. package/templates/windsurf-hooks/lib/contract.sh +0 -322
  46. package/templates/windsurf-hooks/post-cascade-response.sh +0 -251
  47. package/templates/windsurf-hooks/pre-user-prompt.sh +0 -435
@@ -1,98 +0,0 @@
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
@@ -1,210 +0,0 @@
1
- #!/bin/bash
2
- # ═══════════════════════════════════════════════════════════════════════════
3
- # ekkOS™ Hook State Management Library (Portable)
4
- # Shared state functions for coordinating between hooks
5
- # ═══════════════════════════════════════════════════════════════════════════
6
-
7
- # Get project root (where .claude directory lives)
8
- get_project_root() {
9
- local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10
- echo "$(dirname "$(dirname "$script_dir")")"
11
- }
12
-
13
- PROJECT_ROOT=$(get_project_root)
14
- STATE_DIR="$PROJECT_ROOT/.claude/state"
15
-
16
- # Ensure state directory exists
17
- mkdir -p "$STATE_DIR"
18
-
19
- # ═══════════════════════════════════════════════════════════════════════════
20
- # State File Management
21
- # ═══════════════════════════════════════════════════════════════════════════
22
-
23
- # Save patterns for session (with retrieval_token for verified tracking)
24
- save_patterns() {
25
- local session_id="$1"
26
- local patterns="$2"
27
- local model_used="$3"
28
- local retrieval_token="${4:-}" # Optional retrieval_token for verified applications
29
-
30
- local state_file="$STATE_DIR/patterns-${session_id}.json"
31
-
32
- jq -n \
33
- --argjson patterns "$patterns" \
34
- --arg model "$model_used" \
35
- --arg token "$retrieval_token" \
36
- --arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
37
- '{
38
- patterns: $patterns,
39
- model_used: $model,
40
- retrieval_token: $token,
41
- saved_at: $timestamp
42
- }' > "$state_file"
43
- }
44
-
45
- # Get retrieval token from saved patterns
46
- get_retrieval_token() {
47
- local session_id="$1"
48
- local state_file="$STATE_DIR/patterns-${session_id}.json"
49
-
50
- if [ -f "$state_file" ]; then
51
- jq -r '.retrieval_token // ""' "$state_file" 2>/dev/null
52
- else
53
- echo ""
54
- fi
55
- }
56
-
57
- # Load patterns for session
58
- load_patterns() {
59
- local session_id="$1"
60
- local state_file="$STATE_DIR/patterns-${session_id}.json"
61
-
62
- if [ -f "$state_file" ]; then
63
- cat "$state_file"
64
- else
65
- echo '{}'
66
- fi
67
- }
68
-
69
- # Clear patterns for session (after capture)
70
- clear_patterns() {
71
- local session_id="$1"
72
- rm -f "$STATE_DIR/patterns-${session_id}.json"
73
- }
74
-
75
- # ═══════════════════════════════════════════════════════════════════════════
76
- # Conversation Context (for Golden Loop MEASURE phase)
77
- # ═══════════════════════════════════════════════════════════════════════════
78
-
79
- # Save current conversation context for pattern tracking
80
- # Called by user-prompt-submit.sh when new query is submitted
81
- save_conversation_context() {
82
- local session_id="$1"
83
- local user_query="$2"
84
- local prev_response="$3"
85
-
86
- local context_file="$STATE_DIR/conversation-${session_id}.json"
87
-
88
- jq -n \
89
- --arg query "$user_query" \
90
- --arg response "$prev_response" \
91
- --arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
92
- '{
93
- query: $query,
94
- response: $response,
95
- saved_at: $timestamp
96
- }' > "$context_file" 2>/dev/null || true
97
- }
98
-
99
- # Load current conversation context
100
- # Called by post-tool-use.sh when tracking pattern applications
101
- load_conversation_context() {
102
- local session_id="$1"
103
- local context_file="$STATE_DIR/conversation-${session_id}.json"
104
-
105
- if [ -f "$context_file" ]; then
106
- cat "$context_file"
107
- else
108
- echo '{"query":"","response":""}'
109
- fi
110
- }
111
-
112
- # ═══════════════════════════════════════════════════════════════════════════
113
- # Capture Deduplication
114
- # ═══════════════════════════════════════════════════════════════════════════
115
-
116
- # Generate hash for conversation turn
117
- generate_turn_hash() {
118
- local user_query="$1"
119
- local assistant_response="$2"
120
-
121
- echo "${user_query}${assistant_response}" | md5sum | cut -d' ' -f1 2>/dev/null || \
122
- echo "${user_query}${assistant_response}" | md5 2>/dev/null
123
- }
124
-
125
- # Check if turn was already captured
126
- was_turn_captured() {
127
- local session_id="$1"
128
- local turn_hash="$2"
129
-
130
- local capture_log="$STATE_DIR/captures-${session_id}.log"
131
-
132
- if [ -f "$capture_log" ]; then
133
- grep -q "^${turn_hash}$" "$capture_log"
134
- return $?
135
- fi
136
-
137
- return 1 # Not captured
138
- }
139
-
140
- # Mark turn as captured
141
- mark_turn_captured() {
142
- local session_id="$1"
143
- local turn_hash="$2"
144
-
145
- local capture_log="$STATE_DIR/captures-${session_id}.log"
146
-
147
- echo "$turn_hash" >> "$capture_log"
148
-
149
- # Keep only last 100 hashes
150
- if [ $(wc -l < "$capture_log" 2>/dev/null || echo 0) -gt 100 ]; then
151
- tail -100 "$capture_log" > "${capture_log}.tmp"
152
- mv "${capture_log}.tmp" "$capture_log"
153
- fi
154
- }
155
-
156
- # ═══════════════════════════════════════════════════════════════════════════
157
- # Hook Coordination
158
- # ═══════════════════════════════════════════════════════════════════════════
159
-
160
- # Lock for preventing race conditions
161
- acquire_lock() {
162
- local session_id="$1"
163
- local lock_file="$STATE_DIR/lock-${session_id}.lock"
164
- local timeout=5
165
- local waited=0
166
-
167
- while [ -f "$lock_file" ] && [ $waited -lt $timeout ]; do
168
- sleep 0.1
169
- waited=$((waited + 1))
170
- done
171
-
172
- if [ -f "$lock_file" ]; then
173
- # Stale lock (older than 10 seconds)
174
- local lock_age=$(($(date +%s) - $(stat -f %m "$lock_file" 2>/dev/null || stat -c %Y "$lock_file" 2>/dev/null || echo 0)))
175
- if [ $lock_age -gt 10 ]; then
176
- rm -f "$lock_file"
177
- else
178
- return 1 # Failed to acquire
179
- fi
180
- fi
181
-
182
- # Acquire lock
183
- echo $$ > "$lock_file"
184
- return 0
185
- }
186
-
187
- # Release lock
188
- release_lock() {
189
- local session_id="$1"
190
- local lock_file="$STATE_DIR/lock-${session_id}.lock"
191
-
192
- if [ -f "$lock_file" ] && [ "$(cat "$lock_file")" = "$$" ]; then
193
- rm -f "$lock_file"
194
- fi
195
- }
196
-
197
- # ═══════════════════════════════════════════════════════════════════════════
198
- # Cleanup
199
- # ═══════════════════════════════════════════════════════════════════════════
200
-
201
- # Clean up old state files
202
- cleanup_old_state() {
203
- # Remove files older than 24 hours
204
- find "$STATE_DIR" -name "*.json" -mtime +1 -delete 2>/dev/null || true
205
- find "$STATE_DIR" -name "*.log" -mtime +1 -delete 2>/dev/null || true
206
- find "$STATE_DIR" -name "*.lock" -mtime +1 -delete 2>/dev/null || true
207
- }
208
-
209
- # Cleanup on exit
210
- trap cleanup_old_state EXIT
@@ -1,146 +0,0 @@
1
- # ═══════════════════════════════════════════════════════════════════════════
2
- # ekkOS_ Hook: SessionStart - Initialize session (Windows)
3
- # MANAGED BY ekkos-connect - DO NOT EDIT DIRECTLY
4
- # EKKOS_MANAGED=1
5
- # EKKOS_MANIFEST_SHA256=<computed-at-build>
6
- # EKKOS_TEMPLATE_VERSION=1.0.0
7
- #
8
- # Per ekkOS Onboarding Spec v1.2 FINAL + ADDENDUM:
9
- # - All persisted records MUST include: instanceId, sessionId, sessionName
10
- # - Uses EKKOS_INSTANCE_ID env var for multi-session isolation
11
- # ═══════════════════════════════════════════════════════════════════════════
12
-
13
- $ErrorActionPreference = "SilentlyContinue"
14
-
15
- # ═══════════════════════════════════════════════════════════════════════════
16
- # CONFIG PATHS - No hardcoded word arrays per spec v1.2 Addendum
17
- # ═══════════════════════════════════════════════════════════════════════════
18
- $EkkosConfigDir = if ($env:EKKOS_CONFIG_DIR) { $env:EKKOS_CONFIG_DIR } else { "$env:USERPROFILE\.ekkos" }
19
- $SessionWordsJson = "$EkkosConfigDir\session-words.json"
20
- $SessionWordsDefault = "$EkkosConfigDir\.defaults\session-words.json"
21
-
22
- # ═══════════════════════════════════════════════════════════════════════════
23
- # INSTANCE ID - Multi-session isolation per v1.2 ADDENDUM
24
- # ═══════════════════════════════════════════════════════════════════════════
25
- $EkkosInstanceId = if ($env:EKKOS_INSTANCE_ID) { $env:EKKOS_INSTANCE_ID } else { "default" }
26
-
27
- # ═══════════════════════════════════════════════════════════════════════════
28
- # Load session words from JSON file - NO HARDCODED ARRAYS
29
- # ═══════════════════════════════════════════════════════════════════════════
30
- $script:SessionWords = $null
31
-
32
- function Load-SessionWords {
33
- $wordsFile = $SessionWordsJson
34
-
35
- if (-not (Test-Path $wordsFile)) {
36
- $wordsFile = $SessionWordsDefault
37
- }
38
-
39
- if (-not (Test-Path $wordsFile)) {
40
- return $null
41
- }
42
-
43
- try {
44
- $script:SessionWords = Get-Content $wordsFile -Raw | ConvertFrom-Json
45
- } catch {
46
- return $null
47
- }
48
- }
49
-
50
- function Convert-UuidToWords {
51
- param([string]$uuid)
52
-
53
- if (-not $script:SessionWords) {
54
- Load-SessionWords
55
- }
56
-
57
- if (-not $script:SessionWords) {
58
- return "unknown-session"
59
- }
60
-
61
- $adjectives = $script:SessionWords.adjectives
62
- $nouns = $script:SessionWords.nouns
63
- $verbs = $script:SessionWords.verbs
64
-
65
- if (-not $adjectives -or -not $nouns -or -not $verbs) {
66
- return "unknown-session"
67
- }
68
-
69
- if (-not $uuid -or $uuid -eq "unknown") { return "unknown-session" }
70
-
71
- $clean = $uuid -replace "-", ""
72
- if ($clean.Length -lt 12) { return "unknown-session" }
73
-
74
- try {
75
- $a = [Convert]::ToInt32($clean.Substring(0,4), 16) % $adjectives.Length
76
- $n = [Convert]::ToInt32($clean.Substring(4,4), 16) % $nouns.Length
77
- $an = [Convert]::ToInt32($clean.Substring(8,4), 16) % $verbs.Length
78
-
79
- return "$($adjectives[$a])-$($nouns[$n])-$($verbs[$an])"
80
- } catch {
81
- return "unknown-session"
82
- }
83
- }
84
-
85
- # ═══════════════════════════════════════════════════════════════════════════
86
- # READ INPUT
87
- # ═══════════════════════════════════════════════════════════════════════════
88
- $inputJson = [Console]::In.ReadToEnd()
89
-
90
- try {
91
- $input = $inputJson | ConvertFrom-Json
92
- $sessionId = $input.session_id
93
- } catch {
94
- $sessionId = "unknown"
95
- }
96
-
97
- $sessionName = Convert-UuidToWords $sessionId
98
-
99
- # ═══════════════════════════════════════════════════════════════════════════
100
- # INITIALIZE STATE DIRECTORY
101
- # ═══════════════════════════════════════════════════════════════════════════
102
- $stateDir = Join-Path $env:USERPROFILE ".claude\state"
103
- if (-not (Test-Path $stateDir)) {
104
- New-Item -ItemType Directory -Path $stateDir -Force | Out-Null
105
- }
106
-
107
- # Reset turn counter for new session
108
- $stateFile = Join-Path $stateDir "hook-state.json"
109
- $state = @{
110
- turn = 0
111
- session_id = $sessionId
112
- session_name = $sessionName
113
- instance_id = $EkkosInstanceId
114
- started_at = (Get-Date).ToString("o")
115
- } | ConvertTo-Json -Depth 10
116
-
117
- Set-Content -Path $stateFile -Value $state -Force
118
-
119
- # Save session ID for other hooks
120
- $sessionFile = Join-Path $stateDir "current-session.json"
121
- $sessionData = @{
122
- session_id = $sessionId
123
- session_name = $sessionName
124
- instance_id = $EkkosInstanceId
125
- } | ConvertTo-Json -Depth 10
126
-
127
- Set-Content -Path $sessionFile -Value $sessionData -Force
128
-
129
- # ═══════════════════════════════════════════════════════════════════════════
130
- # LOCAL CACHE: Initialize session in Tier 0 cache
131
- # Per v1.2 ADDENDUM: Pass instanceId for namespacing
132
- # ═══════════════════════════════════════════════════════════════════════════
133
- $captureCmd = Get-Command "ekkos-capture" -ErrorAction SilentlyContinue
134
- if ($captureCmd -and $sessionId -ne "unknown") {
135
- try {
136
- # NEW format: ekkos-capture init <instance_id> <session_id> <session_name>
137
- Start-Job -ScriptBlock {
138
- param($instanceId, $sessId, $sessName)
139
- try {
140
- & ekkos-capture init $instanceId $sessId $sessName 2>&1 | Out-Null
141
- } catch {}
142
- } -ArgumentList $EkkosInstanceId, $sessionId, $sessionName | Out-Null
143
- } catch {}
144
- }
145
-
146
- Write-Output "ekkOS session initialized"