@ekkos/cli 1.0.33 → 1.0.35

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 (51) hide show
  1. package/dist/capture/jsonl-rewriter.js +72 -7
  2. package/dist/commands/dashboard.js +186 -557
  3. package/dist/commands/init.js +3 -15
  4. package/dist/commands/run.js +221 -259
  5. package/dist/commands/setup.js +0 -47
  6. package/dist/commands/swarm-dashboard.js +4 -13
  7. package/dist/deploy/instructions.d.ts +2 -5
  8. package/dist/deploy/instructions.js +8 -11
  9. package/dist/deploy/settings.js +21 -15
  10. package/dist/deploy/skills.d.ts +0 -8
  11. package/dist/deploy/skills.js +0 -26
  12. package/dist/index.js +2 -2
  13. package/dist/lib/usage-parser.js +1 -2
  14. package/dist/utils/platform.d.ts +0 -3
  15. package/dist/utils/platform.js +1 -4
  16. package/dist/utils/session-binding.d.ts +1 -1
  17. package/dist/utils/session-binding.js +2 -3
  18. package/package.json +4 -2
  19. package/templates/CLAUDE.md +23 -135
  20. package/templates/agents/README.md +182 -0
  21. package/templates/agents/code-reviewer.md +166 -0
  22. package/templates/agents/debug-detective.md +169 -0
  23. package/templates/agents/ekkOS_Vercel.md +99 -0
  24. package/templates/agents/extension-manager.md +229 -0
  25. package/templates/agents/git-companion.md +185 -0
  26. package/templates/agents/github-test-agent.md +321 -0
  27. package/templates/agents/railway-manager.md +179 -0
  28. package/templates/ekkos-manifest.json +8 -8
  29. package/templates/hooks/assistant-response.ps1 +160 -256
  30. package/templates/hooks/assistant-response.sh +66 -130
  31. package/templates/hooks/hooks.json +0 -6
  32. package/templates/hooks/lib/contract.sh +31 -43
  33. package/templates/hooks/lib/count-tokens.cjs +0 -0
  34. package/templates/hooks/lib/ekkos-reminders.sh +0 -0
  35. package/templates/hooks/lib/state.sh +1 -53
  36. package/templates/hooks/session-start.ps1 +391 -91
  37. package/templates/hooks/session-start.sh +166 -201
  38. package/templates/hooks/stop.ps1 +341 -202
  39. package/templates/hooks/stop.sh +948 -275
  40. package/templates/hooks/user-prompt-submit.ps1 +548 -224
  41. package/templates/hooks/user-prompt-submit.sh +456 -382
  42. package/templates/plan-template.md +0 -0
  43. package/templates/spec-template.md +0 -0
  44. package/templates/windsurf-hooks/before-submit-prompt.sh +238 -0
  45. package/templates/windsurf-hooks/hooks.json +2 -9
  46. package/templates/windsurf-hooks/install.sh +0 -0
  47. package/templates/windsurf-hooks/lib/contract.sh +0 -2
  48. package/templates/windsurf-hooks/post-cascade-response.sh +0 -0
  49. package/templates/windsurf-hooks/pre-user-prompt.sh +0 -0
  50. package/templates/windsurf-skills/ekkos-memory/SKILL.md +219 -0
  51. package/README.md +0 -57
@@ -1,8 +1,6 @@
1
1
  #!/bin/bash
2
2
  # ═══════════════════════════════════════════════════════════════════════════
3
3
  # ekkOS_ Hook: SessionStart - MINIMAL + AUTO-RESTORE + TIME MACHINE CONTINUE
4
- # MANAGED BY ekkos-connect - DO NOT EDIT DIRECTLY
5
- # EKKOS_MANAGED=1
6
4
  # ═══════════════════════════════════════════════════════════════════════════
7
5
  # This hook does THREE things:
8
6
  # 1. Check for pending Time Machine "Continue from here" requests
@@ -17,8 +15,6 @@
17
15
  # FAST TRIM FLOW:
18
16
  # User runs /clear → session-start detects fresh session →
19
17
  # Checks L2 for recent turns → Auto-injects last 15 turns → Seamless continuity
20
- #
21
- # Per spec v1.2 Addendum: NO jq dependency
22
18
  # ═══════════════════════════════════════════════════════════════════════════
23
19
 
24
20
  set +e
@@ -26,36 +22,10 @@ set +e
26
22
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
27
23
  PROJECT_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
28
24
 
29
- # ═══════════════════════════════════════════════════════════════════════════
30
- # CONFIG PATHS - Per spec v1.2 Addendum
31
- # ═══════════════════════════════════════════════════════════════════════════
32
- EKKOS_CONFIG_DIR="${EKKOS_CONFIG_DIR:-$HOME/.ekkos}"
33
- JSON_PARSE_HELPER="$EKKOS_CONFIG_DIR/.helpers/json-parse.cjs"
34
-
35
25
  INPUT=$(cat)
36
-
37
- # Parse input using Node (no jq)
38
- parse_json_value() {
39
- local json="$1"
40
- local path="$2"
41
- echo "$json" | node -e "
42
- const data = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8') || '{}');
43
- const path = '$path'.replace(/^\./,'').split('.').filter(Boolean);
44
- let result = data;
45
- for (const p of path) {
46
- if (result === undefined || result === null) { result = undefined; break; }
47
- result = result[p];
48
- }
49
- if (result !== undefined && result !== null) console.log(result);
50
- " 2>/dev/null || echo ""
51
- }
52
-
53
- SESSION_ID=$(parse_json_value "$INPUT" '.session_id')
54
- [ -z "$SESSION_ID" ] && SESSION_ID="unknown"
55
-
56
- TRANSCRIPT_PATH=$(parse_json_value "$INPUT" '.transcript_path')
57
- SOURCE=$(parse_json_value "$INPUT" '.source')
58
- [ -z "$SOURCE" ] && SOURCE="unknown"
26
+ SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
27
+ TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // ""')
28
+ SOURCE=$(echo "$INPUT" | jq -r '.source // "unknown"') # "startup", "resume", or "clear"
59
29
 
60
30
  # ═══════════════════════════════════════════════════════════════════════════
61
31
  # Load auth
@@ -64,16 +34,13 @@ EKKOS_CONFIG="$HOME/.ekkos/config.json"
64
34
  AUTH_TOKEN=""
65
35
  USER_ID=""
66
36
 
67
- if [ -f "$EKKOS_CONFIG" ] && [ -f "$JSON_PARSE_HELPER" ]; then
68
- AUTH_TOKEN=$(node "$JSON_PARSE_HELPER" "$EKKOS_CONFIG" '.hookApiKey' 2>/dev/null || echo "")
69
- if [ -z "$AUTH_TOKEN" ]; then
70
- AUTH_TOKEN=$(node "$JSON_PARSE_HELPER" "$EKKOS_CONFIG" '.apiKey' 2>/dev/null || echo "")
71
- fi
72
- USER_ID=$(node "$JSON_PARSE_HELPER" "$EKKOS_CONFIG" '.userId' 2>/dev/null || echo "")
37
+ if [ -f "$EKKOS_CONFIG" ]; then
38
+ AUTH_TOKEN=$(jq -r '.hookApiKey // .apiKey // ""' "$EKKOS_CONFIG" 2>/dev/null || echo "")
39
+ USER_ID=$(jq -r '.userId // ""' "$EKKOS_CONFIG" 2>/dev/null || echo "")
73
40
  fi
74
41
 
75
42
  if [ -z "$AUTH_TOKEN" ] && [ -f "$PROJECT_ROOT/.env.local" ]; then
76
- AUTH_TOKEN=$(grep -E "^SUPABASE_SECRET_KEY=" "$PROJECT_ROOT/.env.local" | cut -d'=' -f2- | tr -d '"' | tr -d "'" | tr -d '\r')
43
+ AUTH_TOKEN=$(grep -E "^SUPABASE_SECRET_KEY=" "$PROJECT_ROOT/.env.local" | cut -d'=' -f2- | tr -d '"' | tr -d "'" | tr -d '\r')
77
44
  fi
78
45
 
79
46
  [ -z "$AUTH_TOKEN" ] && exit 0
@@ -90,55 +57,39 @@ TIME_MACHINE_TO_TURN=""
90
57
 
91
58
  # Check via env var first, then API
92
59
  if [ -n "$RESTORE_REQUEST_ID" ]; then
93
- echo -e "\033[0;35m Time Machine request detected: $RESTORE_REQUEST_ID\033[0m" >&2
60
+ echo -e "\033[0;35mTime Machine request detected: $RESTORE_REQUEST_ID\033[0m" >&2
94
61
  fi
95
62
 
96
63
  # Check API for pending requests (if we have user_id)
97
64
  if [ -z "$TIME_MACHINE_SESSION" ] && [ -n "$USER_ID" ]; then
98
- PENDING_RESPONSE=$(curl -s -X GET "$MEMORY_API_URL/api/v1/context/restore-request/pending?user_id=$USER_ID" \
65
+ PENDING_RESPONSE=$(curl -s -X GET "$MEMORY_API_URL/api/v1/context/restore-request/pending?user_id=$USER_ID" \
66
+ -H "Authorization: Bearer $AUTH_TOKEN" \
67
+ --connect-timeout 2 \
68
+ --max-time 3 2>/dev/null || echo '{}')
69
+
70
+ IS_PENDING=$(echo "$PENDING_RESPONSE" | jq -r '.pending // false' 2>/dev/null)
71
+
72
+ if [ "$IS_PENDING" = "true" ]; then
73
+ TIME_MACHINE_SESSION=$(echo "$PENDING_RESPONSE" | jq -r '.request.session_id // ""')
74
+ TIME_MACHINE_FROM_TURN=$(echo "$PENDING_RESPONSE" | jq -r '.request.from_turn // ""')
75
+ TIME_MACHINE_TO_TURN=$(echo "$PENDING_RESPONSE" | jq -r '.request.to_turn // ""')
76
+ RESTORE_REQUEST_ID=$(echo "$PENDING_RESPONSE" | jq -r '.request.request_id // ""')
77
+
78
+ if [ -n "$TIME_MACHINE_SESSION" ]; then
79
+ echo "" >&2
80
+ echo -e "\033[0;35m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m" >&2
81
+ echo -e "\033[0;35m\033[1m⏰ TIME MACHINE\033[0m \033[2m| Restoring session from web request...\033[0m" >&2
82
+ echo -e "\033[0;35m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m" >&2
83
+
84
+ # Mark request as consumed
85
+ curl -s -X POST "$MEMORY_API_URL/api/v1/context/restore-request/consume" \
99
86
  -H "Authorization: Bearer $AUTH_TOKEN" \
87
+ -H "Content-Type: application/json" \
88
+ -d "{\"request_id\": \"$RESTORE_REQUEST_ID\"}" \
100
89
  --connect-timeout 2 \
101
- --max-time 3 2>/dev/null || echo '{}')
102
-
103
- # Parse using Node (no jq)
104
- IS_PENDING=$(echo "$PENDING_RESPONSE" | node -e "
105
- const data = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8') || '{}');
106
- console.log(data.pending || false);
107
- " 2>/dev/null || echo "false")
108
-
109
- if [ "$IS_PENDING" = "true" ]; then
110
- TIME_MACHINE_SESSION=$(echo "$PENDING_RESPONSE" | node -e "
111
- const d = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8') || '{}');
112
- console.log(d.request?.session_id || '');
113
- " 2>/dev/null || echo "")
114
- TIME_MACHINE_FROM_TURN=$(echo "$PENDING_RESPONSE" | node -e "
115
- const d = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8') || '{}');
116
- console.log(d.request?.from_turn || '');
117
- " 2>/dev/null || echo "")
118
- TIME_MACHINE_TO_TURN=$(echo "$PENDING_RESPONSE" | node -e "
119
- const d = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8') || '{}');
120
- console.log(d.request?.to_turn || '');
121
- " 2>/dev/null || echo "")
122
- RESTORE_REQUEST_ID=$(echo "$PENDING_RESPONSE" | node -e "
123
- const d = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8') || '{}');
124
- console.log(d.request?.request_id || '');
125
- " 2>/dev/null || echo "")
126
-
127
- if [ -n "$TIME_MACHINE_SESSION" ]; then
128
- echo "" >&2
129
- echo -e "\033[0;35m------------------------------------------------------------------------\033[0m" >&2
130
- echo -e "\033[0;35m\033[1m TIME MACHINE\033[0m \033[2m| Restoring session from web request...\033[0m" >&2
131
- echo -e "\033[0;35m------------------------------------------------------------------------\033[0m" >&2
132
-
133
- # Mark request as consumed
134
- curl -s -X POST "$MEMORY_API_URL/api/v1/context/restore-request/consume" \
135
- -H "Authorization: Bearer $AUTH_TOKEN" \
136
- -H "Content-Type: application/json" \
137
- -d "{\"request_id\": \"$RESTORE_REQUEST_ID\"}" \
138
- --connect-timeout 2 \
139
- --max-time 3 >/dev/null 2>&1 || true
140
- fi
90
+ --max-time 3 >/dev/null 2>&1 || true
141
91
  fi
92
+ fi
142
93
  fi
143
94
 
144
95
  # ═══════════════════════════════════════════════════════════════════════════
@@ -160,24 +111,24 @@ MOST_RECENT_SESSION=""
160
111
  SAVED_TURN_COUNT=0
161
112
 
162
113
  if [ -n "$CURRENT_SESSION_ID" ] && [ "$CURRENT_SESSION_ID" != "unknown" ]; then
163
- # Check if THIS session has saved turns (for /clear continuity)
164
- TURN_COUNTER_FILE="$PROJECT_SESSION_DIR/${CURRENT_SESSION_ID}.turn"
165
- if [ -f "$TURN_COUNTER_FILE" ]; then
166
- SAVED_TURN_COUNT=$(cat "$TURN_COUNTER_FILE" 2>/dev/null || echo "0")
167
- MOST_RECENT_SESSION="$CURRENT_SESSION_ID"
168
- else
169
- # Fresh start: find most recent session in project
170
- MOST_RECENT_FILE=$(ls -t "$PROJECT_SESSION_DIR"/*.turn 2>/dev/null | head -1)
171
- if [ -n "$MOST_RECENT_FILE" ]; then
172
- MOST_RECENT_SESSION=$(basename "$MOST_RECENT_FILE" .turn)
173
- SAVED_TURN_COUNT=$(cat "$MOST_RECENT_FILE" 2>/dev/null || echo "0")
174
- fi
114
+ # Check if THIS session has saved turns (for /clear continuity)
115
+ TURN_COUNTER_FILE="$PROJECT_SESSION_DIR/${CURRENT_SESSION_ID}.turn"
116
+ if [ -f "$TURN_COUNTER_FILE" ]; then
117
+ SAVED_TURN_COUNT=$(cat "$TURN_COUNTER_FILE" 2>/dev/null || echo "0")
118
+ MOST_RECENT_SESSION="$CURRENT_SESSION_ID"
119
+ else
120
+ # Fresh start: find most recent session in project
121
+ MOST_RECENT_FILE=$(ls -t "$PROJECT_SESSION_DIR"/*.turn 2>/dev/null | head -1)
122
+ if [ -n "$MOST_RECENT_FILE" ]; then
123
+ MOST_RECENT_SESSION=$(basename "$MOST_RECENT_FILE" .turn)
124
+ SAVED_TURN_COUNT=$(cat "$MOST_RECENT_FILE" 2>/dev/null || echo "0")
175
125
  fi
126
+ fi
176
127
  fi
177
128
 
178
129
  # Save current session info
179
130
  if [ -n "$CURRENT_SESSION_ID" ]; then
180
- cat > "$SESSION_FILE" << EOF
131
+ cat > "$SESSION_FILE" << EOF
181
132
  {
182
133
  "session_id": "$CURRENT_SESSION_ID",
183
134
  "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
@@ -187,23 +138,28 @@ EOF
187
138
  fi
188
139
 
189
140
  # ═══════════════════════════════════════════════════════════════════════════
190
- # GOLDEN LOOP: Initialize session tracking file
141
+ # 🔄 GOLDEN LOOP: Initialize session tracking file
191
142
  # ═══════════════════════════════════════════════════════════════════════════
192
143
  GOLDEN_LOOP_FILE="$PROJECT_ROOT/.ekkos/golden-loop-current.json"
193
144
  mkdir -p "$PROJECT_ROOT/.ekkos" 2>/dev/null || true
194
145
 
195
- # Initialize with session start state using Node (no jq)
196
- node -e "
197
- const fs = require('fs');
198
- const data = {
199
- phase: 'idle',
200
- turn: 0,
201
- session: '$CURRENT_SESSION_ID',
202
- timestamp: new Date().toISOString(),
203
- stats: { retrieved: 0, applied: 0, forged: 0 }
204
- };
205
- fs.writeFileSync('$GOLDEN_LOOP_FILE', JSON.stringify(data, null, 2));
206
- " 2>/dev/null || true
146
+ # Initialize with session start state
147
+ jq -n \
148
+ --arg phase "idle" \
149
+ --argjson turn 0 \
150
+ --arg session "${CURRENT_SESSION_ID}" \
151
+ --arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
152
+ '{
153
+ phase: $phase,
154
+ turn: $turn,
155
+ session: $session,
156
+ timestamp: $timestamp,
157
+ stats: {
158
+ retrieved: 0,
159
+ applied: 0,
160
+ forged: 0
161
+ }
162
+ }' > "$GOLDEN_LOOP_FILE" 2>/dev/null || true
207
163
 
208
164
  # ═══════════════════════════════════════════════════════════════════════════
209
165
  # COLORS
@@ -229,56 +185,44 @@ RESET='\033[0m'
229
185
 
230
186
  # Handle Time Machine requests (explicit user action)
231
187
  if [ -n "$TIME_MACHINE_SESSION" ]; then
188
+ echo "" >&2
189
+ echo -e "${MAGENTA}${BOLD}⏰ TIME MACHINE${RESET} ${DIM}| Restoring past session: ${TIME_MACHINE_SESSION:0:12}...${RESET}" >&2
190
+
191
+ # Build recall request with turn range
192
+ RECALL_BODY="{\"session_id\": \"${TIME_MACHINE_SESSION}\", \"last_n\": 15, \"format\": \"summary\"}"
193
+
194
+ if [ -n "$TIME_MACHINE_FROM_TURN" ] && [ -n "$TIME_MACHINE_TO_TURN" ]; then
195
+ RECALL_BODY="{\"session_id\": \"${TIME_MACHINE_SESSION}\", \"from_turn\": ${TIME_MACHINE_FROM_TURN}, \"to_turn\": ${TIME_MACHINE_TO_TURN}, \"format\": \"summary\"}"
196
+ elif [ -n "$TIME_MACHINE_FROM_TURN" ]; then
197
+ RECALL_BODY="{\"session_id\": \"${TIME_MACHINE_SESSION}\", \"from_turn\": ${TIME_MACHINE_FROM_TURN}, \"format\": \"summary\"}"
198
+ fi
199
+
200
+ # Fetch turns from L2
201
+ RESTORE_RESPONSE=$(curl -s -X POST "$MEMORY_API_URL/api/v1/turns/recall" \
202
+ -H "Authorization: Bearer $AUTH_TOKEN" \
203
+ -H "Content-Type: application/json" \
204
+ -d "$RECALL_BODY" \
205
+ --connect-timeout 3 \
206
+ --max-time 5 2>/dev/null || echo '{"error":"timeout"}')
207
+
208
+ # Check if we got turns back
209
+ RESTORED_COUNT=$(echo "$RESTORE_RESPONSE" | jq '.turns // [] | length' 2>/dev/null || echo "0")
210
+
211
+ if [ "$RESTORED_COUNT" -gt 0 ]; then
212
+ echo -e "${MAGENTA} ✓${RESET} Restored ${RESTORED_COUNT} turns from past session" >&2
213
+ echo "" >&2
214
+ echo -e "${MAGENTA}${BOLD}## Time Machine Context${RESET}" >&2
232
215
  echo "" >&2
233
- echo -e "${MAGENTA}${BOLD} TIME MACHINE${RESET} ${DIM}| Restoring past session: ${TIME_MACHINE_SESSION:0:12}...${RESET}" >&2
234
-
235
- # Build recall request with turn range
236
- RECALL_BODY="{\"session_id\": \"${TIME_MACHINE_SESSION}\", \"last_n\": 15, \"format\": \"summary\"}"
237
216
 
238
- if [ -n "$TIME_MACHINE_FROM_TURN" ] && [ -n "$TIME_MACHINE_TO_TURN" ]; then
239
- RECALL_BODY="{\"session_id\": \"${TIME_MACHINE_SESSION}\", \"from_turn\": ${TIME_MACHINE_FROM_TURN}, \"to_turn\": ${TIME_MACHINE_TO_TURN}, \"format\": \"summary\"}"
240
- elif [ -n "$TIME_MACHINE_FROM_TURN" ]; then
241
- RECALL_BODY="{\"session_id\": \"${TIME_MACHINE_SESSION}\", \"from_turn\": ${TIME_MACHINE_FROM_TURN}, \"format\": \"summary\"}"
242
- fi
217
+ # Output the turns as context (stderr for user, stdout for Claude)
218
+ TURNS_OUTPUT=$(echo "$RESTORE_RESPONSE" | jq -r '.turns[]? | "**Turn \(.turn_number // "?")**: \(.user_query[:100] // "...")...\n> \(.assistant_response[:200] // "...")...\n"' 2>/dev/null || true)
219
+ echo "$TURNS_OUTPUT" >&2
220
+ echo "$TURNS_OUTPUT" # Also to stdout for Claude's context
243
221
 
244
- # Fetch turns from L2
245
- RESTORE_RESPONSE=$(curl -s -X POST "$MEMORY_API_URL/api/v1/turns/recall" \
246
- -H "Authorization: Bearer $AUTH_TOKEN" \
247
- -H "Content-Type: application/json" \
248
- -d "$RECALL_BODY" \
249
- --connect-timeout 3 \
250
- --max-time 5 2>/dev/null || echo '{"error":"timeout"}')
251
-
252
- # Check if we got turns back using Node (no jq)
253
- RESTORED_COUNT=$(echo "$RESTORE_RESPONSE" | node -e "
254
- const d = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8') || '{}');
255
- console.log((d.turns || []).length);
256
- " 2>/dev/null || echo "0")
257
-
258
- if [ "$RESTORED_COUNT" -gt 0 ]; then
259
- echo -e "${MAGENTA} ✓${RESET} Restored ${RESTORED_COUNT} turns from past session" >&2
260
- echo "" >&2
261
- echo -e "${MAGENTA}${BOLD}## Time Machine Context${RESET}" >&2
262
- echo "" >&2
263
-
264
- # Output the turns as context using Node (no jq)
265
- TURNS_OUTPUT=$(echo "$RESTORE_RESPONSE" | node -e "
266
- const d = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8') || '{}');
267
- (d.turns || []).forEach(t => {
268
- const q = (t.user_query || '').substring(0, 100);
269
- const r = (t.assistant_response || '').substring(0, 200);
270
- console.log('**Turn ' + (t.turn_number || '?') + '**: ' + q + '...');
271
- console.log('> ' + r + '...');
272
- console.log('');
273
- });
274
- " 2>/dev/null || echo "")
275
- echo "$TURNS_OUTPUT" >&2
276
- echo "$TURNS_OUTPUT"
277
-
278
- echo "" >&2
279
- echo -e "${DIM}You've traveled to a past session. Continue from here!${RESET}" >&2
280
- echo "" >&2
281
- fi
222
+ echo "" >&2
223
+ echo -e "${DIM}You've traveled to a past session. Continue from here!${RESET}" >&2
224
+ echo "" >&2
225
+ fi
282
226
  fi
283
227
 
284
228
  # ═══════════════════════════════════════════════════════════════════════════
@@ -289,64 +233,85 @@ DIRECTIVE_COUNT=0
289
233
 
290
234
  # Only fetch if we have auth
291
235
  if [ -n "$AUTH_TOKEN" ]; then
292
- # Fetch directives (top 20 by priority to avoid token bloat)
293
- DIRECTIVES_RESPONSE=$(curl -s -X GET "$MEMORY_API_URL/api/v1/memory/directives?limit=20" \
294
- -H "Authorization: Bearer $AUTH_TOKEN" \
295
- --connect-timeout 2 \
296
- --max-time 3 2>/dev/null || echo '{}')
297
-
298
- # Parse response using Node (no jq)
299
- DIRECTIVE_COUNT=$(echo "$DIRECTIVES_RESPONSE" | node -e "
300
- const d = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8') || '{}');
301
- console.log(d.count || 0);
302
- " 2>/dev/null || echo "0")
303
-
304
- if [ "$DIRECTIVE_COUNT" -gt 0 ]; then
305
- DIRECTIVES_INJECTED=true
306
-
307
- # Extract MUST/NEVER/PREFER/AVOID arrays using Node
308
- echo "<system-reminder>"
309
- echo "USER DIRECTIVES (FOLLOW THESE):"
310
- echo ""
311
-
312
- echo "$DIRECTIVES_RESPONSE" | node -e "
313
- const d = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8') || '{}');
314
- const types = ['MUST', 'NEVER', 'PREFER', 'AVOID'];
315
- types.forEach(type => {
316
- const rules = (d[type] || []).slice(0, 5);
317
- if (rules.length > 0) {
318
- console.log(type + ':');
319
- rules.forEach(r => console.log(' - ' + (r.rule || '')));
320
- }
321
- });
322
- " 2>/dev/null || true
236
+ # Fetch directives (top 20 by priority to avoid token bloat)
237
+ DIRECTIVES_RESPONSE=$(curl -s -X GET "$MEMORY_API_URL/api/v1/memory/directives?limit=20" \
238
+ -H "Authorization: Bearer $AUTH_TOKEN" \
239
+ --connect-timeout 2 \
240
+ --max-time 3 2>/dev/null || echo '{}')
241
+
242
+ # Parse response
243
+ DIRECTIVE_COUNT=$(echo "$DIRECTIVES_RESPONSE" | jq '.count // 0' 2>/dev/null || echo "0")
244
+
245
+ if [ "$DIRECTIVE_COUNT" -gt 0 ]; then
246
+ DIRECTIVES_INJECTED=true
247
+
248
+ # Extract MUST/NEVER/PREFER/AVOID arrays
249
+ MUST_RULES=$(echo "$DIRECTIVES_RESPONSE" | jq -r '.MUST[]?.rule // empty' 2>/dev/null | head -5)
250
+ NEVER_RULES=$(echo "$DIRECTIVES_RESPONSE" | jq -r '.NEVER[]?.rule // empty' 2>/dev/null | head -5)
251
+ PREFER_RULES=$(echo "$DIRECTIVES_RESPONSE" | jq -r '.PREFER[]?.rule // empty' 2>/dev/null | head -5)
252
+ AVOID_RULES=$(echo "$DIRECTIVES_RESPONSE" | jq -r '.AVOID[]?.rule // empty' 2>/dev/null | head -5)
253
+
254
+ # Build compact directive block for injection
255
+ echo "<system-reminder>"
256
+ echo "USER DIRECTIVES (FOLLOW THESE):"
257
+ echo ""
258
+
259
+ if [ -n "$MUST_RULES" ]; then
260
+ echo "MUST:"
261
+ echo "$MUST_RULES" | while read -r rule; do
262
+ [ -n "$rule" ] && echo " • $rule"
263
+ done
264
+ fi
323
265
 
324
- echo "</system-reminder>"
325
- echo -e "${GREEN} ${DIRECTIVE_COUNT} directives loaded${RESET}" >&2
266
+ if [ -n "$NEVER_RULES" ]; then
267
+ echo "NEVER:"
268
+ echo "$NEVER_RULES" | while read -r rule; do
269
+ [ -n "$rule" ] && echo " • $rule"
270
+ done
326
271
  fi
272
+
273
+ if [ -n "$PREFER_RULES" ]; then
274
+ echo "PREFER:"
275
+ echo "$PREFER_RULES" | while read -r rule; do
276
+ [ -n "$rule" ] && echo " • $rule"
277
+ done
278
+ fi
279
+
280
+ if [ -n "$AVOID_RULES" ]; then
281
+ echo "AVOID:"
282
+ echo "$AVOID_RULES" | while read -r rule; do
283
+ [ -n "$rule" ] && echo " • $rule"
284
+ done
285
+ fi
286
+
287
+ echo "</system-reminder>"
288
+
289
+ echo -e "${GREEN}📋 ${DIRECTIVE_COUNT} directives loaded${RESET}" >&2
290
+ fi
327
291
  fi
328
292
 
329
293
  # Simple status display (no auto-restore)
330
294
  if [ "$SAVED_TURN_COUNT" -gt 0 ]; then
331
- echo "" >&2
332
- if [ "$SAVED_TURN_COUNT" -gt 0 ]; then
333
- echo -e "${CYAN}${BOLD} ekkOS${RESET} ${DIM}|${RESET} Session: ${CURRENT_SESSION_ID:-$SESSION_ID} ${DIM}|${RESET} ${GREEN}${SAVED_TURN_COUNT} turns${RESET}" >&2
334
- else
335
- echo -e "${CYAN}${BOLD} ekkOS${RESET} ${DIM}|${RESET} Session: ${CURRENT_SESSION_ID:-$SESSION_ID} ${DIM}| New session${RESET}" >&2
336
- fi
295
+ # New session or few turns - just show status
296
+ echo "" >&2
297
+ if [ "$SAVED_TURN_COUNT" -gt 0 ]; then
298
+ echo -e "${CYAN}${BOLD}🧠 ekkOS${RESET} ${DIM}|${RESET} Session: ${CURRENT_SESSION_ID:-$SESSION_ID} ${DIM}|${RESET} ${GREEN}${SAVED_TURN_COUNT} turns${RESET}" >&2
299
+ else
300
+ echo -e "${CYAN}${BOLD}🧠 ekkOS${RESET} ${DIM}|${RESET} Session: ${CURRENT_SESSION_ID:-$SESSION_ID} ${DIM}| New session${RESET}" >&2
301
+ fi
337
302
  fi
338
303
 
339
304
  # Final confirmation that's always visible
340
305
  if [ -n "$TIME_MACHINE_SESSION" ]; then
341
- echo -e "${MAGENTA}------------------------------------------------------------------------${RESET}" >&2
342
- echo -e "${MAGENTA} ${RESET} Time Machine active - Restored from session ${TIME_MACHINE_SESSION:0:12}..." >&2
343
- echo -e "${MAGENTA}------------------------------------------------------------------------${RESET}" >&2
306
+ echo -e "${MAGENTA}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" >&2
307
+ echo -e "${MAGENTA}⏰${RESET} Time Machine active · Restored from session ${TIME_MACHINE_SESSION:0:12}..." >&2
308
+ echo -e "${MAGENTA}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" >&2
344
309
  elif [ "$SAVED_TURN_COUNT" -gt 0 ]; then
345
- echo -e "${GREEN}------------------------------------------------------------------------${RESET}" >&2
346
- echo -e "${GREEN}✓${RESET} Session continued - ${SAVED_TURN_COUNT} turns preserved - Ready to resume" >&2
347
- echo -e "${GREEN}------------------------------------------------------------------------${RESET}" >&2
310
+ echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" >&2
311
+ echo -e "${GREEN}✓${RESET} Session continued · ${SAVED_TURN_COUNT} turns preserved · Ready to resume" >&2
312
+ echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" >&2
348
313
  else
349
- echo -e "${CYAN}✓${RESET} New session started" >&2
314
+ echo -e "${CYAN}✓${RESET} New session started" >&2
350
315
  fi
351
316
  echo "" >&2
352
317