@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.
- package/dist/cache/LocalSessionStore.d.ts +129 -0
- package/dist/cache/LocalSessionStore.js +688 -0
- package/dist/cache/capture.d.ts +26 -0
- package/dist/cache/capture.js +461 -0
- package/dist/cache/index.d.ts +7 -0
- package/dist/cache/index.js +23 -0
- package/dist/cache/types.d.ts +147 -0
- package/dist/cache/types.js +40 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.js +478 -0
- package/dist/commands/run.d.ts +12 -0
- package/dist/commands/run.js +829 -0
- package/dist/commands/setup.d.ts +6 -0
- package/dist/commands/setup.js +658 -0
- package/dist/commands/status.d.ts +1 -0
- package/dist/commands/status.js +109 -0
- package/dist/commands/test.d.ts +1 -0
- package/dist/commands/test.js +157 -0
- package/dist/deploy/agents.d.ts +15 -0
- package/dist/deploy/agents.js +72 -0
- package/dist/deploy/hooks.d.ts +16 -0
- package/dist/deploy/hooks.js +121 -0
- package/dist/deploy/index.d.ts +7 -0
- package/dist/deploy/index.js +24 -0
- package/dist/deploy/instructions.d.ts +12 -0
- package/dist/deploy/instructions.js +36 -0
- package/dist/deploy/mcp.d.ts +19 -0
- package/dist/deploy/mcp.js +109 -0
- package/dist/deploy/plugins.d.ts +19 -0
- package/dist/deploy/plugins.js +62 -0
- package/dist/deploy/settings.d.ts +8 -0
- package/dist/deploy/settings.js +84 -0
- package/dist/deploy/skills.d.ts +19 -0
- package/dist/deploy/skills.js +60 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +71 -0
- package/dist/restore/RestoreOrchestrator.d.ts +48 -0
- package/dist/restore/RestoreOrchestrator.js +481 -0
- package/dist/restore/index.d.ts +4 -0
- package/dist/restore/index.js +20 -0
- package/dist/utils/platform.d.ts +29 -0
- package/dist/utils/platform.js +65 -0
- package/dist/utils/session-words.json +119 -0
- package/dist/utils/state.d.ts +57 -0
- package/dist/utils/state.js +186 -0
- package/dist/utils/templates.d.ts +24 -0
- package/dist/utils/templates.js +118 -0
- package/package.json +48 -0
- package/templates/CLAUDE.md +287 -0
- package/templates/README.md +378 -0
- package/templates/agents/README.md +182 -0
- package/templates/agents/code-reviewer.md +166 -0
- package/templates/agents/debug-detective.md +169 -0
- package/templates/agents/ekkOS_Vercel.md +99 -0
- package/templates/agents/extension-manager.md +229 -0
- package/templates/agents/git-companion.md +185 -0
- package/templates/agents/github-test-agent.md +321 -0
- package/templates/agents/railway-manager.md +179 -0
- package/templates/claude-plugins/PHASE2_COMPLETION.md +346 -0
- package/templates/claude-plugins/PLUGIN_PROPOSALS.md +1776 -0
- package/templates/claude-plugins/README.md +587 -0
- package/templates/claude-plugins/agents/code-reviewer.json +14 -0
- package/templates/claude-plugins/agents/debug-detective.json +15 -0
- package/templates/claude-plugins/agents/git-companion.json +14 -0
- package/templates/claude-plugins/blog-manager/.claude-plugin/plugin.json +8 -0
- package/templates/claude-plugins/blog-manager/commands/blog.md +691 -0
- package/templates/claude-plugins/golden-loop-monitor/.claude-plugin/plugin.json +8 -0
- package/templates/claude-plugins/golden-loop-monitor/commands/loop-status.md +434 -0
- package/templates/claude-plugins/learning-tracker/.claude-plugin/plugin.json +8 -0
- package/templates/claude-plugins/learning-tracker/commands/my-patterns.md +282 -0
- package/templates/claude-plugins/memory-lens/.claude-plugin/plugin.json +8 -0
- package/templates/claude-plugins/memory-lens/commands/memory-search.md +181 -0
- package/templates/claude-plugins/pattern-coach/.claude-plugin/plugin.json +8 -0
- package/templates/claude-plugins/pattern-coach/commands/forge.md +365 -0
- package/templates/claude-plugins/project-schema-validator/.claude-plugin/plugin.json +8 -0
- package/templates/claude-plugins/project-schema-validator/commands/validate-schema.md +582 -0
- package/templates/claude-plugins-admin/AGENT_TEAM_PROPOSALS.md +819 -0
- package/templates/claude-plugins-admin/README.md +446 -0
- package/templates/claude-plugins-admin/autonomous-admin-agent/.claude-plugin/plugin.json +8 -0
- package/templates/claude-plugins-admin/autonomous-admin-agent/commands/agent.md +595 -0
- package/templates/claude-plugins-admin/backend-agent/.claude-plugin/plugin.json +8 -0
- package/templates/claude-plugins-admin/backend-agent/commands/backend.md +798 -0
- package/templates/claude-plugins-admin/deploy-guardian/.claude-plugin/plugin.json +8 -0
- package/templates/claude-plugins-admin/deploy-guardian/commands/deploy.md +554 -0
- package/templates/claude-plugins-admin/frontend-agent/.claude-plugin/plugin.json +8 -0
- package/templates/claude-plugins-admin/frontend-agent/commands/frontend.md +881 -0
- package/templates/claude-plugins-admin/mcp-server-manager/.claude-plugin/plugin.json +8 -0
- package/templates/claude-plugins-admin/mcp-server-manager/commands/mcp.md +85 -0
- package/templates/claude-plugins-admin/memory-system-monitor/.claude-plugin/plugin.json +8 -0
- package/templates/claude-plugins-admin/memory-system-monitor/commands/memory-health.md +569 -0
- package/templates/claude-plugins-admin/qa-agent/.claude-plugin/plugin.json +8 -0
- package/templates/claude-plugins-admin/qa-agent/commands/qa.md +863 -0
- package/templates/claude-plugins-admin/tech-lead-agent/.claude-plugin/plugin.json +8 -0
- package/templates/claude-plugins-admin/tech-lead-agent/commands/lead.md +732 -0
- package/templates/commands/continue.md +47 -0
- package/templates/cursor-hooks/after-agent-response.sh +117 -0
- package/templates/cursor-hooks/before-submit-prompt.sh +419 -0
- package/templates/cursor-hooks/hooks.json +20 -0
- package/templates/cursor-hooks/lib/contract.sh +320 -0
- package/templates/cursor-hooks/stop.sh +75 -0
- package/templates/cursor-rules/ekkos-memory.md +187 -0
- package/templates/hooks/assistant-response.sh +96 -0
- package/templates/hooks/hooks.json +28 -0
- package/templates/hooks/lib/contract.sh +320 -0
- package/templates/hooks/lib/state.sh +158 -0
- package/templates/hooks/session-start.ps1 +41 -0
- package/templates/hooks/session-start.sh +318 -0
- package/templates/hooks/stop.ps1 +16 -0
- package/templates/hooks/stop.sh +989 -0
- package/templates/hooks/user-prompt-submit.ps1 +174 -0
- package/templates/hooks/user-prompt-submit.sh +587 -0
- package/templates/hooks-node/lib/state.js +187 -0
- package/templates/hooks-node/stop.js +416 -0
- package/templates/hooks-node/user-prompt-submit.js +337 -0
- package/templates/plan-template.md +306 -0
- package/templates/rules/00-hooks-contract.mdc +89 -0
- package/templates/rules/30-ekkos-core.mdc +188 -0
- package/templates/rules/31-ekkos-messages.mdc +78 -0
- package/templates/skills/continue/SKILL.md +169 -0
- package/templates/skills/ekkOS_Deep_Recall/Skill.md +282 -0
- package/templates/skills/ekkOS_Learn/Skill.md +265 -0
- package/templates/skills/ekkOS_Memory_First/Skill.md +206 -0
- package/templates/skills/ekkOS_Plan_Assist/Skill.md +302 -0
- package/templates/skills/ekkOS_Preferences/Skill.md +247 -0
- package/templates/skills/ekkOS_Reflect/Skill.md +257 -0
- package/templates/skills/ekkOS_Safety/Skill.md +265 -0
- package/templates/skills/ekkOS_Schema/Skill.md +251 -0
- package/templates/skills/ekkOS_Summary/Skill.md +257 -0
- package/templates/skills/ekkOS_Vault/Skill.md +287 -0
- package/templates/skills/permissions/Skill.md +322 -0
- package/templates/spec-template.md +159 -0
- package/templates/windsurf-hooks/before-submit-prompt.sh +238 -0
- package/templates/windsurf-hooks/hooks.json +10 -0
- package/templates/windsurf-hooks/lib/contract.sh +320 -0
- package/templates/windsurf-rules/ekkos-memory.md +129 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
3
|
+
# ekkOS_ Turn Contract Library
|
|
4
|
+
#
|
|
5
|
+
# Shared functions for Golden Loop compliance enforcement.
|
|
6
|
+
# Used by BOTH Claude Code (.claude/) and Cursor (.cursor/) hooks.
|
|
7
|
+
#
|
|
8
|
+
# TURN CONTRACT: Evidence that retrieval occurred before answering.
|
|
9
|
+
# This is the SINGLE SOURCE OF TRUTH for compliance auditing.
|
|
10
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
11
|
+
|
|
12
|
+
# Get contract directory based on environment
|
|
13
|
+
get_contract_dir() {
|
|
14
|
+
local source="${1:-claude-code}"
|
|
15
|
+
local project_root="${2:-$PROJECT_ROOT}"
|
|
16
|
+
|
|
17
|
+
if [ "$source" = "cursor" ]; then
|
|
18
|
+
echo "$project_root/.cursor/state/ekkos"
|
|
19
|
+
else
|
|
20
|
+
echo "$project_root/.claude/state/ekkos"
|
|
21
|
+
fi
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
# Generate stable hash of user prompt (for deduplication)
|
|
25
|
+
generate_query_hash() {
|
|
26
|
+
local query="$1"
|
|
27
|
+
# Use md5 on macOS, md5sum on Linux
|
|
28
|
+
if command -v md5 >/dev/null 2>&1; then
|
|
29
|
+
echo -n "$query" | md5 | cut -c1-16
|
|
30
|
+
elif command -v md5sum >/dev/null 2>&1; then
|
|
31
|
+
echo -n "$query" | md5sum | cut -c1-16
|
|
32
|
+
else
|
|
33
|
+
# Fallback: simple hash using cksum
|
|
34
|
+
echo -n "$query" | cksum | cut -d' ' -f1
|
|
35
|
+
fi
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# Write turn contract at RETRIEVAL time
|
|
39
|
+
# This is the EVIDENCE that retrieval happened before answering
|
|
40
|
+
write_turn_contract() {
|
|
41
|
+
local session_id="$1"
|
|
42
|
+
local retrieval_ok="$2"
|
|
43
|
+
local retrieval_source="$3"
|
|
44
|
+
local pattern_ids="$4" # Comma-separated list
|
|
45
|
+
local directive_ids="$5" # Comma-separated list
|
|
46
|
+
local query_hash="$6"
|
|
47
|
+
local project_root="${7:-$PROJECT_ROOT}"
|
|
48
|
+
|
|
49
|
+
local contract_dir
|
|
50
|
+
contract_dir=$(get_contract_dir "$retrieval_source" "$project_root")
|
|
51
|
+
mkdir -p "$contract_dir" 2>/dev/null || return 1
|
|
52
|
+
|
|
53
|
+
local contract_file="$contract_dir/turn-contract-${session_id}.json"
|
|
54
|
+
local timestamp
|
|
55
|
+
timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
56
|
+
|
|
57
|
+
# Convert comma-separated IDs to JSON array
|
|
58
|
+
local pattern_array
|
|
59
|
+
local directive_array
|
|
60
|
+
if [ -n "$pattern_ids" ]; then
|
|
61
|
+
pattern_array=$(echo "$pattern_ids" | tr ',' '\n' | grep -v '^$' | jq -R . | jq -s .)
|
|
62
|
+
else
|
|
63
|
+
pattern_array="[]"
|
|
64
|
+
fi
|
|
65
|
+
if [ -n "$directive_ids" ]; then
|
|
66
|
+
directive_array=$(echo "$directive_ids" | tr ',' '\n' | grep -v '^$' | jq -R . | jq -s .)
|
|
67
|
+
else
|
|
68
|
+
directive_array="[]"
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
# Write contract
|
|
72
|
+
cat > "$contract_file" << EOF
|
|
73
|
+
{
|
|
74
|
+
"session_id": "$session_id",
|
|
75
|
+
"retrieval_ok": $retrieval_ok,
|
|
76
|
+
"retrieval_source": "$retrieval_source",
|
|
77
|
+
"retrieved_pattern_ids": $pattern_array,
|
|
78
|
+
"retrieved_directive_ids": $directive_array,
|
|
79
|
+
"timestamp": "$timestamp",
|
|
80
|
+
"query_hash": "$query_hash",
|
|
81
|
+
"ekkos_strict": ${EKKOS_STRICT:-0}
|
|
82
|
+
}
|
|
83
|
+
EOF
|
|
84
|
+
|
|
85
|
+
return 0
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# Read turn contract
|
|
89
|
+
read_turn_contract() {
|
|
90
|
+
local session_id="$1"
|
|
91
|
+
local retrieval_source="$2"
|
|
92
|
+
local project_root="${3:-$PROJECT_ROOT}"
|
|
93
|
+
|
|
94
|
+
local contract_dir
|
|
95
|
+
contract_dir=$(get_contract_dir "$retrieval_source" "$project_root")
|
|
96
|
+
local contract_file="$contract_dir/turn-contract-${session_id}.json"
|
|
97
|
+
|
|
98
|
+
if [ -f "$contract_file" ]; then
|
|
99
|
+
cat "$contract_file"
|
|
100
|
+
return 0
|
|
101
|
+
else
|
|
102
|
+
return 1
|
|
103
|
+
fi
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
# Extract field from contract JSON
|
|
107
|
+
get_contract_field() {
|
|
108
|
+
local contract_json="$1"
|
|
109
|
+
local field="$2"
|
|
110
|
+
|
|
111
|
+
echo "$contract_json" | jq -r ".$field // \"\"" 2>/dev/null
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# Get array field as comma-separated string
|
|
115
|
+
get_contract_array() {
|
|
116
|
+
local contract_json="$1"
|
|
117
|
+
local field="$2"
|
|
118
|
+
|
|
119
|
+
echo "$contract_json" | jq -r ".$field // [] | join(\",\")" 2>/dev/null
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# Cleanup turn contract (only after successful capture)
|
|
123
|
+
cleanup_turn_contract() {
|
|
124
|
+
local session_id="$1"
|
|
125
|
+
local retrieval_source="$2"
|
|
126
|
+
local project_root="${3:-$PROJECT_ROOT}"
|
|
127
|
+
|
|
128
|
+
local contract_dir
|
|
129
|
+
contract_dir=$(get_contract_dir "$retrieval_source" "$project_root")
|
|
130
|
+
local contract_file="$contract_dir/turn-contract-${session_id}.json"
|
|
131
|
+
|
|
132
|
+
rm -f "$contract_file" 2>/dev/null
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
# Check if strict mode is enabled
|
|
136
|
+
is_strict_mode() {
|
|
137
|
+
[ "${EKKOS_STRICT:-0}" = "1" ]
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
# Generate strict mode blocker message for Claude Code
|
|
141
|
+
get_strict_blocker_message() {
|
|
142
|
+
cat << 'EOF'
|
|
143
|
+
════════════════════════════════════════════════════════════════════════════
|
|
144
|
+
⛔ EKKOS_STRICT MODE: RETRIEVAL FAILED — DO NOT ANSWER
|
|
145
|
+
|
|
146
|
+
ekkOS memory retrieval failed or was not authenticated.
|
|
147
|
+
In STRICT mode, you MUST NOT answer technical questions without memory context.
|
|
148
|
+
|
|
149
|
+
ACTION REQUIRED:
|
|
150
|
+
1. Check if ekkOS is connected: Run `ekkOS: Connect` in VS Code
|
|
151
|
+
2. Verify auth token exists: ~/.ekkos/config.json
|
|
152
|
+
3. Retry the request after connecting
|
|
153
|
+
|
|
154
|
+
DO NOT proceed with answering. The Golden Loop requires retrieval FIRST.
|
|
155
|
+
════════════════════════════════════════════════════════════════════════════
|
|
156
|
+
EOF
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
# Validate PatternGuard coverage (returns 0-100)
|
|
160
|
+
calculate_pattern_guard_coverage() {
|
|
161
|
+
local assistant_response="$1"
|
|
162
|
+
local pattern_ids="$2" # Comma-separated
|
|
163
|
+
|
|
164
|
+
# Count total patterns
|
|
165
|
+
local total_count
|
|
166
|
+
total_count=$(echo "$pattern_ids" | tr ',' '\n' | grep -c '.' || echo 0)
|
|
167
|
+
|
|
168
|
+
if [ "$total_count" -eq 0 ]; then
|
|
169
|
+
echo "100" # No patterns = 100% coverage by definition
|
|
170
|
+
return 0
|
|
171
|
+
fi
|
|
172
|
+
|
|
173
|
+
# Extract acknowledged IDs from [ekkOS_SELECT] and [ekkOS_SKIP] blocks
|
|
174
|
+
local acknowledged_count=0
|
|
175
|
+
|
|
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
|
|
193
|
+
|
|
194
|
+
# Legacy: Check for [ekkOS_APPLY] markers (fallback)
|
|
195
|
+
if [ "$acknowledged_count" -eq 0 ]; then
|
|
196
|
+
local apply_count
|
|
197
|
+
apply_count=$(echo "$assistant_response" | grep -c '\[ekkOS_APPLY\]' || echo 0)
|
|
198
|
+
acknowledged_count=$apply_count
|
|
199
|
+
fi
|
|
200
|
+
|
|
201
|
+
# Calculate coverage percentage
|
|
202
|
+
local coverage
|
|
203
|
+
coverage=$((acknowledged_count * 100 / total_count))
|
|
204
|
+
|
|
205
|
+
# Cap at 100%
|
|
206
|
+
if [ "$coverage" -gt 100 ]; then
|
|
207
|
+
coverage=100
|
|
208
|
+
fi
|
|
209
|
+
|
|
210
|
+
echo "$coverage"
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
# Check for ekkOS footer presence
|
|
214
|
+
check_footer_present() {
|
|
215
|
+
local assistant_response="$1"
|
|
216
|
+
|
|
217
|
+
# Look for the mandatory footer format:
|
|
218
|
+
# 🧠 **ekkOS_™** · 📅 YYYY-MM-DD
|
|
219
|
+
# OR
|
|
220
|
+
# {IDE} ({Model}) · 🧠 **ekkOS_™** · 📅 {Timestamp}
|
|
221
|
+
|
|
222
|
+
if echo "$assistant_response" | grep -qE '🧠.*ekkOS.*📅.*[0-9]{4}-[0-9]{2}-[0-9]{2}'; then
|
|
223
|
+
echo "true"
|
|
224
|
+
return 0
|
|
225
|
+
else
|
|
226
|
+
echo "false"
|
|
227
|
+
return 1
|
|
228
|
+
fi
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
# Build compliance metadata for capture
|
|
232
|
+
build_compliance_metadata() {
|
|
233
|
+
local retrieval_ok="$1"
|
|
234
|
+
local pattern_guard_coverage="$2"
|
|
235
|
+
local footer_present="$3"
|
|
236
|
+
local ekkos_strict="$4"
|
|
237
|
+
local retrieved_count="$5"
|
|
238
|
+
|
|
239
|
+
local pattern_guard_required="false"
|
|
240
|
+
if [ "$retrieved_count" -gt 0 ]; then
|
|
241
|
+
pattern_guard_required="true"
|
|
242
|
+
fi
|
|
243
|
+
|
|
244
|
+
cat << EOF
|
|
245
|
+
{
|
|
246
|
+
"retrieval_ok": $retrieval_ok,
|
|
247
|
+
"pattern_guard_required": $pattern_guard_required,
|
|
248
|
+
"pattern_guard_coverage_pct": $pattern_guard_coverage,
|
|
249
|
+
"footer_present": $footer_present,
|
|
250
|
+
"ekkos_strict": $ekkos_strict,
|
|
251
|
+
"retrieved_count": $retrieved_count,
|
|
252
|
+
"compliance_version": "1.0"
|
|
253
|
+
}
|
|
254
|
+
EOF
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
# Determine if turn is compliant
|
|
258
|
+
is_turn_compliant() {
|
|
259
|
+
local retrieval_ok="$1"
|
|
260
|
+
local pattern_guard_coverage="$2"
|
|
261
|
+
local footer_present="$3"
|
|
262
|
+
local pattern_count="$4"
|
|
263
|
+
|
|
264
|
+
# Retrieval must have succeeded
|
|
265
|
+
if [ "$retrieval_ok" != "true" ]; then
|
|
266
|
+
echo "false"
|
|
267
|
+
return 1
|
|
268
|
+
fi
|
|
269
|
+
|
|
270
|
+
# If patterns were retrieved, PatternGuard must be 100%
|
|
271
|
+
if [ "$pattern_count" -gt 0 ] && [ "$pattern_guard_coverage" -lt 100 ]; then
|
|
272
|
+
echo "false"
|
|
273
|
+
return 1
|
|
274
|
+
fi
|
|
275
|
+
|
|
276
|
+
# Footer must be present
|
|
277
|
+
if [ "$footer_present" != "true" ]; then
|
|
278
|
+
echo "false"
|
|
279
|
+
return 1
|
|
280
|
+
fi
|
|
281
|
+
|
|
282
|
+
echo "true"
|
|
283
|
+
return 0
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
# Generate violation reason
|
|
287
|
+
get_violation_reason() {
|
|
288
|
+
local retrieval_ok="$1"
|
|
289
|
+
local pattern_guard_coverage="$2"
|
|
290
|
+
local footer_present="$3"
|
|
291
|
+
local pattern_count="$4"
|
|
292
|
+
|
|
293
|
+
local reasons=""
|
|
294
|
+
|
|
295
|
+
if [ "$retrieval_ok" != "true" ]; then
|
|
296
|
+
reasons="retrieval_failed"
|
|
297
|
+
fi
|
|
298
|
+
|
|
299
|
+
if [ "$pattern_count" -gt 0 ] && [ "$pattern_guard_coverage" -lt 100 ]; then
|
|
300
|
+
if [ -n "$reasons" ]; then
|
|
301
|
+
reasons="$reasons,pattern_guard_incomplete"
|
|
302
|
+
else
|
|
303
|
+
reasons="pattern_guard_incomplete"
|
|
304
|
+
fi
|
|
305
|
+
fi
|
|
306
|
+
|
|
307
|
+
if [ "$footer_present" != "true" ]; then
|
|
308
|
+
if [ -n "$reasons" ]; then
|
|
309
|
+
reasons="$reasons,footer_missing"
|
|
310
|
+
else
|
|
311
|
+
reasons="footer_missing"
|
|
312
|
+
fi
|
|
313
|
+
fi
|
|
314
|
+
|
|
315
|
+
if [ -z "$reasons" ]; then
|
|
316
|
+
reasons="none"
|
|
317
|
+
fi
|
|
318
|
+
|
|
319
|
+
echo "$reasons"
|
|
320
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
3
|
+
# ekkOS_ Hook: Stop (Cursor Agent Mode)
|
|
4
|
+
#
|
|
5
|
+
# Fires when agent iteration completes. Can:
|
|
6
|
+
# 1. Clear Time Machine consumed flag (allow new requests)
|
|
7
|
+
# 2. Capture session summary
|
|
8
|
+
# 3. Optionally submit follow-up message
|
|
9
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
10
|
+
|
|
11
|
+
set +e
|
|
12
|
+
|
|
13
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
|
+
PROJECT_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
|
|
15
|
+
STATE_DIR="$PROJECT_ROOT/.cursor/state"
|
|
16
|
+
|
|
17
|
+
# Read JSON input
|
|
18
|
+
INPUT=$(cat)
|
|
19
|
+
|
|
20
|
+
# Extract status
|
|
21
|
+
STATUS=$(echo "$INPUT" | jq -r '.status // "unknown"' 2>/dev/null || echo "unknown")
|
|
22
|
+
LOOP_COUNT=$(echo "$INPUT" | jq -r '.loop_count // 0' 2>/dev/null || echo "0")
|
|
23
|
+
|
|
24
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
25
|
+
# Clear Time Machine flag on session end (allow new requests next session)
|
|
26
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
27
|
+
if [ "$STATUS" = "completed" ] || [ "$STATUS" = "aborted" ]; then
|
|
28
|
+
rm -f "$STATE_DIR/time-machine-consumed.flag" 2>/dev/null || true
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
32
|
+
# Optional: Load auth for session summary
|
|
33
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
34
|
+
EKKOS_CONFIG="$HOME/.ekkos/config.json"
|
|
35
|
+
AUTH_TOKEN=""
|
|
36
|
+
USER_ID=""
|
|
37
|
+
|
|
38
|
+
if [ -f "$EKKOS_CONFIG" ]; then
|
|
39
|
+
AUTH_TOKEN=$(jq -r '.hookApiKey // .apiKey // ""' "$EKKOS_CONFIG" 2>/dev/null || echo "")
|
|
40
|
+
USER_ID=$(jq -r '.userId // ""' "$EKKOS_CONFIG" 2>/dev/null || echo "")
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
if [ -z "$AUTH_TOKEN" ] && [ -f "$PROJECT_ROOT/.env.local" ]; then
|
|
44
|
+
AUTH_TOKEN=$(grep -E "^SUPABASE_SECRET_KEY=" "$PROJECT_ROOT/.env.local" | cut -d'=' -f2- | tr -d '"' | tr -d "'" | tr -d '\r')
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
48
|
+
# Log session end (fire and forget)
|
|
49
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
50
|
+
if [ -n "$AUTH_TOKEN" ]; then
|
|
51
|
+
SESSION_ID=""
|
|
52
|
+
if [ -f "$STATE_DIR/current_session_id.txt" ]; then
|
|
53
|
+
SESSION_ID=$(cat "$STATE_DIR/current_session_id.txt" 2>/dev/null || echo "")
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
TURN_COUNT=0
|
|
57
|
+
TURN_FILE="$STATE_DIR/turn_${SESSION_ID}.txt"
|
|
58
|
+
if [ -f "$TURN_FILE" ]; then
|
|
59
|
+
TURN_COUNT=$(cat "$TURN_FILE" 2>/dev/null || echo "0")
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# Could capture session end event here
|
|
63
|
+
# For now, just clean up
|
|
64
|
+
|
|
65
|
+
# Clean up turn counter for next session
|
|
66
|
+
# (commented out - might want to persist across agent runs)
|
|
67
|
+
# rm -f "$TURN_FILE" 2>/dev/null || true
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
71
|
+
# Return empty response (no follow-up)
|
|
72
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
73
|
+
echo '{}'
|
|
74
|
+
|
|
75
|
+
exit 0
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "ekkOS Memory - 11-layer cognitive memory with 31 MCP tools"
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ekkOS Memory System
|
|
7
|
+
|
|
8
|
+
You have access to **ekkOS memory** via 31 MCP tools. This is an 11-layer cognitive memory system that makes AI smarter over time by learning from past sessions.
|
|
9
|
+
|
|
10
|
+
## MANDATORY RULES
|
|
11
|
+
|
|
12
|
+
### RULE 1: SEARCH BEFORE ANSWERING
|
|
13
|
+
Before answering ANY technical question, call `ekkOS_Search` first.
|
|
14
|
+
Do not skip this. Do not assume you know the answer.
|
|
15
|
+
|
|
16
|
+
### RULE 2: ACKNOWLEDGE RETRIEVED PATTERNS
|
|
17
|
+
When patterns are retrieved, acknowledge each one:
|
|
18
|
+
```
|
|
19
|
+
[ekkOS_SELECT]
|
|
20
|
+
- id: <pattern_id>
|
|
21
|
+
reason: <why using this>
|
|
22
|
+
confidence: <0.0-1.0>
|
|
23
|
+
[/ekkOS_SELECT]
|
|
24
|
+
|
|
25
|
+
[ekkOS_SKIP]
|
|
26
|
+
- id: <pattern_id>
|
|
27
|
+
reason: <why not relevant>
|
|
28
|
+
[/ekkOS_SKIP]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### RULE 3: FORGE WHAT YOU LEARN
|
|
32
|
+
When you fix a bug, get corrected, or learn something new, call `ekkOS_Forge` immediately.
|
|
33
|
+
|
|
34
|
+
### RULE 4: FAILURES ARE VALUABLE
|
|
35
|
+
When something DOES NOT work, forge it as an anti-pattern.
|
|
36
|
+
|
|
37
|
+
## MCP Tools (31 Total)
|
|
38
|
+
|
|
39
|
+
### Core Memory Tools
|
|
40
|
+
| Tool | Description |
|
|
41
|
+
|------|-------------|
|
|
42
|
+
| `ekkOS_Search` | Search across all 11 memory layers |
|
|
43
|
+
| `ekkOS_Context` | Get relevant context for a task |
|
|
44
|
+
| `ekkOS_Capture` | Capture memory events |
|
|
45
|
+
| `ekkOS_Forge` | Create pattern from learned solution |
|
|
46
|
+
| `ekkOS_Directive` | Create MUST/NEVER/PREFER/AVOID rules |
|
|
47
|
+
| `ekkOS_Outcome` | Track if pattern worked or failed |
|
|
48
|
+
| `ekkOS_Detect` | Auto-detect which patterns were used |
|
|
49
|
+
| `ekkOS_Summary` | Get summary of recent MCP activity |
|
|
50
|
+
| `ekkOS_Conflict` | Check for directive/pattern conflicts |
|
|
51
|
+
| `ekkOS_Recall` | Recall past conversations by time |
|
|
52
|
+
| `ekkOS_Codebase` | Search project code embeddings |
|
|
53
|
+
| `ekkOS_Stats` | Get statistics for all layers |
|
|
54
|
+
| `ekkOS_Track` | Track when pattern is applied |
|
|
55
|
+
| `ekkOS_Reflect` | Analyze response for improvements |
|
|
56
|
+
|
|
57
|
+
### Schema Awareness Tools
|
|
58
|
+
| Tool | Description |
|
|
59
|
+
|------|-------------|
|
|
60
|
+
| `ekkOS_IndexSchema` | Index database schemas (Supabase/Prisma/TS) |
|
|
61
|
+
| `ekkOS_GetSchema` | Get schema for a specific table/type |
|
|
62
|
+
|
|
63
|
+
### Portability Tools
|
|
64
|
+
| Tool | Description |
|
|
65
|
+
|------|-------------|
|
|
66
|
+
| `ekkOS_Export` | Export your memory data as portable JSON backup |
|
|
67
|
+
| `ekkOS_Import` | Import memory from backup (auto-deduplication) |
|
|
68
|
+
|
|
69
|
+
### Plan Management
|
|
70
|
+
| Tool | Description |
|
|
71
|
+
|------|-------------|
|
|
72
|
+
| `ekkOS_Plan` | Create structured task plan |
|
|
73
|
+
| `ekkOS_Plans` | List user's plans |
|
|
74
|
+
| `ekkOS_PlanStatus` | Update plan status |
|
|
75
|
+
| `ekkOS_PlanStep` | Mark step complete/incomplete |
|
|
76
|
+
| `ekkOS_Generate` | AI-generate plan from context |
|
|
77
|
+
| `ekkOS_SaveTemplate` | Save plan as reusable template |
|
|
78
|
+
| `ekkOS_Templates` | List available templates |
|
|
79
|
+
| `ekkOS_FromTemplate` | Create plan from template |
|
|
80
|
+
|
|
81
|
+
### Secrets Management (Layer 11)
|
|
82
|
+
| Tool | Description |
|
|
83
|
+
|------|-------------|
|
|
84
|
+
| `ekkOS_StoreSecret` | Encrypt and store sensitive data |
|
|
85
|
+
| `ekkOS_GetSecret` | Retrieve and decrypt a secret |
|
|
86
|
+
| `ekkOS_ListSecrets` | List secrets metadata (no values) |
|
|
87
|
+
| `ekkOS_DeleteSecret` | Permanently delete a secret |
|
|
88
|
+
| `ekkOS_RotateSecret` | Update secret with new value |
|
|
89
|
+
|
|
90
|
+
## 11-Layer Architecture
|
|
91
|
+
|
|
92
|
+
| # | Layer | Purpose |
|
|
93
|
+
|---|-------|---------|
|
|
94
|
+
| 1 | Working | Current session state |
|
|
95
|
+
| 2 | Episodic | Past conversations |
|
|
96
|
+
| 3 | Semantic | Embeddings/knowledge |
|
|
97
|
+
| 4 | Patterns | Proven solutions |
|
|
98
|
+
| 5 | Procedural | Step-by-step guides |
|
|
99
|
+
| 6 | Collective | Cross-project wisdom |
|
|
100
|
+
| 7 | Meta | Pattern effectiveness |
|
|
101
|
+
| 8 | Codebase | Project-specific code |
|
|
102
|
+
| 9 | Directives | MUST/NEVER/PREFER/AVOID rules |
|
|
103
|
+
| 10 | Conflict Resolution | Auto-resolves contradictions |
|
|
104
|
+
| 11 | Secrets | Encrypted credentials (AES-256-GCM) |
|
|
105
|
+
|
|
106
|
+
## FORGE TRIGGERS
|
|
107
|
+
|
|
108
|
+
Call `ekkOS_Forge` when you:
|
|
109
|
+
- Fix a bug (especially non-obvious)
|
|
110
|
+
- Discover a better approach
|
|
111
|
+
- Find a pitfall or gotcha
|
|
112
|
+
- Get corrected by the user
|
|
113
|
+
- Solve auth/config issues
|
|
114
|
+
- Make architectural decisions
|
|
115
|
+
- Debug non-trivially
|
|
116
|
+
- Find something that DOESN'T work
|
|
117
|
+
|
|
118
|
+
Call `ekkOS_Directive` when user says:
|
|
119
|
+
- "always..." → MUST
|
|
120
|
+
- "never..." → NEVER
|
|
121
|
+
- "I prefer..." → PREFER
|
|
122
|
+
- "don't..." / "avoid..." → AVOID
|
|
123
|
+
|
|
124
|
+
## Response Format
|
|
125
|
+
|
|
126
|
+
End every response with:
|
|
127
|
+
```
|
|
128
|
+
---
|
|
129
|
+
🧠 **ekkOS_™** · 📅 YYYY-MM-DD H:MM AM/PM TZ
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Post-response hook: Validates and enforces ekkOS footer format
|
|
3
|
+
# Runs AFTER assistant response, checks footer compliance
|
|
4
|
+
|
|
5
|
+
RESPONSE_FILE="$1"
|
|
6
|
+
HOOK_ENV="$2"
|
|
7
|
+
|
|
8
|
+
# Exit if no response file
|
|
9
|
+
if [[ ! -f "$RESPONSE_FILE" ]]; then
|
|
10
|
+
exit 0
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
# Parse metadata from hook environment
|
|
14
|
+
SESSION_ID=$(echo "$HOOK_ENV" | jq -r '.sessionId // "unknown"')
|
|
15
|
+
TURN=$(echo "$HOOK_ENV" | jq -r '.turn // 0')
|
|
16
|
+
CONTEXT_PERCENT=$(echo "$HOOK_ENV" | jq -r '.contextUsagePercent // 0')
|
|
17
|
+
MODEL=$(echo "$HOOK_ENV" | jq -r '.model // "Claude Code (Opus 4.5)"')
|
|
18
|
+
|
|
19
|
+
# Convert session UUID to word-based name
|
|
20
|
+
convert_uuid_to_name() {
|
|
21
|
+
local uuid="$1"
|
|
22
|
+
|
|
23
|
+
# Word lists (same as MCP)
|
|
24
|
+
local ADJECTIVES=("cosmic" "turbo" "mega" "hyper" "quantum" "atomic" "stellar" "epic"
|
|
25
|
+
"mighty" "groovy" "zippy" "snappy" "jazzy" "funky" "zesty" "peppy"
|
|
26
|
+
"spicy" "crispy" "fluffy" "sparkly" "chunky" "bouncy" "bubbly" "sassy"
|
|
27
|
+
"slick" "sleek" "bold" "nifty" "perky" "plucky" "witty" "nimble"
|
|
28
|
+
"dapper" "fancy" "quirky" "punchy" "swift" "brave" "clever" "dandy"
|
|
29
|
+
"eager" "fiery" "golden" "hasty" "icy" "jolly" "keen" "lively"
|
|
30
|
+
"merry" "noble" "odd" "plush" "quick" "royal" "silly" "tidy"
|
|
31
|
+
"ultra" "vivid" "wacky" "zany" "alpha" "beta" "cyber" "delta"
|
|
32
|
+
"electric" "foggy" "giga" "hazy" "ionic" "jumpy" "kinky" "lunar"
|
|
33
|
+
"magic" "nerdy" "omega" "pixel" "quaint" "retro" "solar" "techno"
|
|
34
|
+
"unified" "viral" "wonky" "xerox" "yappy" "zen" "agile" "binary"
|
|
35
|
+
"chrome" "disco" "elastic" "fizzy" "glossy" "humble" "itchy" "jiffy"
|
|
36
|
+
"kooky" "loopy" "moody" "noisy")
|
|
37
|
+
|
|
38
|
+
local NOUNS=("penguin" "panda" "otter" "narwhal" "alpaca" "llama" "badger" "walrus"
|
|
39
|
+
"waffle" "pickle" "noodle" "pretzel" "muffin" "taco" "nugget" "biscuit"
|
|
40
|
+
"rocket" "comet" "nebula" "quasar" "meteor" "photon" "pulsar" "nova"
|
|
41
|
+
"ninja" "pirate" "wizard" "robot" "yeti" "phoenix" "sphinx" "kraken"
|
|
42
|
+
"thunder" "blizzard" "tornado" "avalanche" "mango" "kiwi" "banana" "coconut"
|
|
43
|
+
"donut" "espresso" "falafel" "gyro" "hummus" "icecream" "jambon" "kebab"
|
|
44
|
+
"latte" "mocha" "nachos" "olive" "pasta" "quinoa" "ramen" "sushi"
|
|
45
|
+
"tamale" "udon" "velvet" "wasabi" "xmas" "yogurt" "ziti" "anchor"
|
|
46
|
+
"beacon" "canyon" "drifter" "echo" "falcon" "glacier" "harbor" "island"
|
|
47
|
+
"jetpack" "kayak" "lagoon" "meadow" "orbit" "parrot" "quest"
|
|
48
|
+
"rapids" "summit" "tunnel" "umbrella" "volcano" "whisper" "xylophone" "yacht"
|
|
49
|
+
"zephyr" "acorn" "bobcat" "cactus" "dolphin" "eagle" "ferret" "gopher"
|
|
50
|
+
"hedgehog" "iguana" "jackal" "koala")
|
|
51
|
+
|
|
52
|
+
# Extract first 8 hex chars
|
|
53
|
+
local hex="${uuid:0:8}"
|
|
54
|
+
hex="${hex//-/}"
|
|
55
|
+
|
|
56
|
+
# Convert to number
|
|
57
|
+
local num=$((16#$hex))
|
|
58
|
+
|
|
59
|
+
# Calculate indices
|
|
60
|
+
local adj_idx=$((num % 100))
|
|
61
|
+
local noun_idx=$(((num / 100) % 100))
|
|
62
|
+
|
|
63
|
+
echo "${ADJECTIVES[$adj_idx]}-${NOUNS[$noun_idx]}"
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
SESSION_NAME=$(convert_uuid_to_name "$SESSION_ID")
|
|
67
|
+
TIMESTAMP=$(date "+%Y-%m-%d %I:%M %p %Z")
|
|
68
|
+
|
|
69
|
+
# Required footer format
|
|
70
|
+
REQUIRED_FOOTER="---
|
|
71
|
+
$MODEL · $SESSION_NAME · Turn $TURN · ${CONTEXT_PERCENT}% · 🧠 **ekkOS_™** · 📅 $TIMESTAMP"
|
|
72
|
+
|
|
73
|
+
# Check if response has correct footer
|
|
74
|
+
RESPONSE_CONTENT=$(cat "$RESPONSE_FILE")
|
|
75
|
+
LAST_LINE=$(echo "$RESPONSE_CONTENT" | tail -1)
|
|
76
|
+
|
|
77
|
+
# Check if footer exists and is correct
|
|
78
|
+
if [[ "$LAST_LINE" == *"ekkOS"* ]] && [[ "$LAST_LINE" == *"Turn"* ]]; then
|
|
79
|
+
# Footer exists - validate format
|
|
80
|
+
if [[ "$LAST_LINE" == *"Turn $TURN"* ]] && [[ "$LAST_LINE" == *"${CONTEXT_PERCENT}%"* ]] && [[ "$LAST_LINE" == *"$SESSION_NAME"* ]]; then
|
|
81
|
+
# Footer is correct
|
|
82
|
+
exit 0
|
|
83
|
+
else
|
|
84
|
+
# Footer exists but is malformed - replace it
|
|
85
|
+
RESPONSE_WITHOUT_FOOTER=$(echo "$RESPONSE_CONTENT" | head -n -2) # Remove last 2 lines (--- and footer)
|
|
86
|
+
echo "$RESPONSE_WITHOUT_FOOTER" > "$RESPONSE_FILE"
|
|
87
|
+
echo "" >> "$RESPONSE_FILE"
|
|
88
|
+
echo "$REQUIRED_FOOTER" >> "$RESPONSE_FILE"
|
|
89
|
+
fi
|
|
90
|
+
else
|
|
91
|
+
# Footer missing - append it
|
|
92
|
+
echo "" >> "$RESPONSE_FILE"
|
|
93
|
+
echo "$REQUIRED_FOOTER" >> "$RESPONSE_FILE"
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
exit 0
|