@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.
- package/dist/capture/jsonl-rewriter.js +72 -7
- package/dist/commands/dashboard.js +186 -557
- package/dist/commands/init.js +3 -15
- package/dist/commands/run.js +221 -259
- package/dist/commands/setup.js +0 -47
- package/dist/commands/swarm-dashboard.js +4 -13
- package/dist/deploy/instructions.d.ts +2 -5
- package/dist/deploy/instructions.js +8 -11
- package/dist/deploy/settings.js +21 -15
- package/dist/deploy/skills.d.ts +0 -8
- package/dist/deploy/skills.js +0 -26
- package/dist/index.js +2 -2
- package/dist/lib/usage-parser.js +1 -2
- package/dist/utils/platform.d.ts +0 -3
- package/dist/utils/platform.js +1 -4
- package/dist/utils/session-binding.d.ts +1 -1
- package/dist/utils/session-binding.js +2 -3
- package/package.json +4 -2
- package/templates/CLAUDE.md +23 -135
- 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/ekkos-manifest.json +8 -8
- package/templates/hooks/assistant-response.ps1 +160 -256
- package/templates/hooks/assistant-response.sh +66 -130
- package/templates/hooks/hooks.json +0 -6
- package/templates/hooks/lib/contract.sh +31 -43
- package/templates/hooks/lib/count-tokens.cjs +0 -0
- package/templates/hooks/lib/ekkos-reminders.sh +0 -0
- package/templates/hooks/lib/state.sh +1 -53
- package/templates/hooks/session-start.ps1 +391 -91
- package/templates/hooks/session-start.sh +166 -201
- package/templates/hooks/stop.ps1 +341 -202
- package/templates/hooks/stop.sh +948 -275
- package/templates/hooks/user-prompt-submit.ps1 +548 -224
- package/templates/hooks/user-prompt-submit.sh +456 -382
- package/templates/plan-template.md +0 -0
- package/templates/spec-template.md +0 -0
- package/templates/windsurf-hooks/before-submit-prompt.sh +238 -0
- package/templates/windsurf-hooks/hooks.json +2 -9
- package/templates/windsurf-hooks/install.sh +0 -0
- package/templates/windsurf-hooks/lib/contract.sh +0 -2
- package/templates/windsurf-hooks/post-cascade-response.sh +0 -0
- package/templates/windsurf-hooks/pre-user-prompt.sh +0 -0
- package/templates/windsurf-skills/ekkos-memory/SKILL.md +219 -0
- 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
|
-
|
|
38
|
-
|
|
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" ]
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
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
|
-
|
|
60
|
+
echo -e "\033[0;35m⏰ Time 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
|
-
|
|
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
|
|
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
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
|
|
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
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
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
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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
|
-
|
|
325
|
-
|
|
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
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
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
|
-
|
|
342
|
-
|
|
343
|
-
|
|
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
|
-
|
|
346
|
-
|
|
347
|
-
|
|
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
|
-
|
|
314
|
+
echo -e "${CYAN}✓${RESET} New session started" >&2
|
|
350
315
|
fi
|
|
351
316
|
echo "" >&2
|
|
352
317
|
|