loki-mode 5.26.1 → 5.27.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/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/completion-council.sh +19 -18
- package/autonomy/hooks/quality-gate.sh +1 -1
- package/autonomy/hooks/track-metrics.sh +2 -1
- package/autonomy/hooks/validate-bash.sh +6 -5
- package/autonomy/loki +85 -46
- package/autonomy/run.sh +64 -30
- package/dashboard/__init__.py +1 -1
- package/dashboard/control.py +2 -2
- package/dashboard/server.py +88 -17
- package/dashboard/static/index.html +81 -78
- package/docs/INSTALLATION.md +1 -1
- package/events/emit.sh +5 -4
- package/learning/__init__.py +157 -0
- package/learning/aggregate.sh +251 -0
- package/learning/aggregator.py +1107 -0
- package/learning/emit.sh +520 -0
- package/learning/emitter.py +554 -0
- package/learning/signals.py +597 -0
- package/learning/signals.ts +759 -0
- package/learning/suggest.sh +298 -0
- package/learning/suggestions.py +839 -0
- package/memory/engine.py +4 -4
- package/memory/retrieval.py +29 -24
- package/memory/storage.py +9 -2
- package/memory/vector_index.py +9 -5
- package/package.json +2 -1
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: loki-mode
|
|
|
3
3
|
description: Multi-agent autonomous startup system. Triggers on "Loki Mode". Takes PRD to deployed product with zero human intervention. Requires --dangerously-skip-permissions flag.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Loki Mode v5.
|
|
6
|
+
# Loki Mode v5.27.0
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -260,4 +260,4 @@ Auto-detected or force with `LOKI_COMPLEXITY`:
|
|
|
260
260
|
|
|
261
261
|
---
|
|
262
262
|
|
|
263
|
-
**v5.
|
|
263
|
+
**v5.27.0 | 57-bug audit fix (10 parallel agents, 3-member council review) | ~270 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
5.
|
|
1
|
+
5.27.0
|
|
@@ -226,6 +226,7 @@ council_vote() {
|
|
|
226
226
|
1) role="requirements_verifier" ;;
|
|
227
227
|
2) role="test_auditor" ;;
|
|
228
228
|
3) role="devils_advocate" ;;
|
|
229
|
+
*) role="generalist" ;;
|
|
229
230
|
esac
|
|
230
231
|
|
|
231
232
|
log_info "Council member $member/$COUNCIL_SIZE ($role) reviewing..."
|
|
@@ -255,7 +256,24 @@ council_vote() {
|
|
|
255
256
|
((member++))
|
|
256
257
|
done
|
|
257
258
|
|
|
258
|
-
#
|
|
259
|
+
# Anti-sycophancy check: if unanimous APPROVE, run devil's advocate
|
|
260
|
+
if [ $approve_count -eq $COUNCIL_SIZE ] && [ $COUNCIL_SIZE -ge 3 ]; then
|
|
261
|
+
log_warn "Unanimous approval detected - running anti-sycophancy check..."
|
|
262
|
+
local contrarian_verdict
|
|
263
|
+
contrarian_verdict=$(council_devils_advocate "$evidence_file" "$vote_dir")
|
|
264
|
+
local contrarian_vote
|
|
265
|
+
contrarian_vote=$(echo "$contrarian_verdict" | grep -oE "VOTE:\s*(APPROVE|REJECT)" | grep -oE "APPROVE|REJECT" | head -1)
|
|
266
|
+
|
|
267
|
+
if [ "$contrarian_vote" = "REJECT" ]; then
|
|
268
|
+
log_warn "Anti-sycophancy: Devil's advocate REJECTED unanimous approval"
|
|
269
|
+
log_warn "Overriding to require one more iteration for verification"
|
|
270
|
+
approve_count=$((approve_count - 1))
|
|
271
|
+
else
|
|
272
|
+
log_info "Anti-sycophancy: Devil's advocate confirmed approval"
|
|
273
|
+
fi
|
|
274
|
+
fi
|
|
275
|
+
|
|
276
|
+
# Record vote results (AFTER anti-sycophancy check so verdict reflects any override)
|
|
259
277
|
_COUNCIL_STATE_FILE="$COUNCIL_STATE_DIR/state.json" \
|
|
260
278
|
_COUNCIL_SIZE="$COUNCIL_SIZE" \
|
|
261
279
|
_COUNCIL_APPROVE="$approve_count" \
|
|
@@ -291,23 +309,6 @@ with open(state_file, 'w') as f:
|
|
|
291
309
|
json.dump(state, f, indent=2)
|
|
292
310
|
" || log_warn "Failed to record council vote results"
|
|
293
311
|
|
|
294
|
-
# Anti-sycophancy check: if unanimous APPROVE, run devil's advocate
|
|
295
|
-
if [ $approve_count -eq $COUNCIL_SIZE ] && [ $COUNCIL_SIZE -ge 3 ]; then
|
|
296
|
-
log_warn "Unanimous approval detected - running anti-sycophancy check..."
|
|
297
|
-
local contrarian_verdict
|
|
298
|
-
contrarian_verdict=$(council_devils_advocate "$evidence_file" "$vote_dir")
|
|
299
|
-
local contrarian_vote
|
|
300
|
-
contrarian_vote=$(echo "$contrarian_verdict" | grep -oE "VOTE:\s*(APPROVE|REJECT)" | grep -oE "APPROVE|REJECT" | head -1)
|
|
301
|
-
|
|
302
|
-
if [ "$contrarian_vote" = "REJECT" ]; then
|
|
303
|
-
log_warn "Anti-sycophancy: Devil's advocate REJECTED unanimous approval"
|
|
304
|
-
log_warn "Overriding to require one more iteration for verification"
|
|
305
|
-
approve_count=$((approve_count - 1))
|
|
306
|
-
else
|
|
307
|
-
log_info "Anti-sycophancy: Devil's advocate confirmed approval"
|
|
308
|
-
fi
|
|
309
|
-
fi
|
|
310
|
-
|
|
311
312
|
echo ""
|
|
312
313
|
log_info "Council verdict: $approve_count APPROVE / $reject_count REJECT (threshold: $COUNCIL_THRESHOLD)"
|
|
313
314
|
echo -e "$verdicts"
|
|
@@ -29,7 +29,7 @@ fi
|
|
|
29
29
|
|
|
30
30
|
# Check for TODO/FIXME in recent changes
|
|
31
31
|
if [ -d "$CWD/.git" ]; then
|
|
32
|
-
TODOS=$(git -C "$CWD" diff HEAD~1 2>/dev/null | grep -c "TODO\|FIXME" ||
|
|
32
|
+
TODOS=$(git -C "$CWD" diff HEAD~1 2>/dev/null | grep -c "TODO\|FIXME" 2>/dev/null) || TODOS=0
|
|
33
33
|
if [ "$TODOS" -gt 0 ]; then
|
|
34
34
|
GATE_RESULTS+=("new_todos: $TODOS")
|
|
35
35
|
fi
|
|
@@ -11,6 +11,7 @@ METRICS_DIR="$CWD/.loki/metrics"
|
|
|
11
11
|
mkdir -p "$METRICS_DIR"
|
|
12
12
|
|
|
13
13
|
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
14
|
-
|
|
14
|
+
tool_escaped=$(printf '%s' "$TOOL_NAME" | sed 's/\\/\\\\/g; s/"/\\"/g')
|
|
15
|
+
echo "{\"timestamp\":\"$TIMESTAMP\",\"tool\":\"$tool_escaped\",\"event\":\"PostToolUse\"}" >> "$METRICS_DIR/tool-usage.jsonl"
|
|
15
16
|
|
|
16
17
|
exit 0
|
|
@@ -10,13 +10,13 @@ CWD=$(echo "$INPUT" | python3 -c "import sys,json; print(json.load(sys.stdin).ge
|
|
|
10
10
|
|
|
11
11
|
# Dangerous command patterns
|
|
12
12
|
BLOCKED_PATTERNS=(
|
|
13
|
-
"^rm -rf
|
|
14
|
-
"^rm -rf
|
|
15
|
-
"^rm -rf \\\$HOME
|
|
13
|
+
"^rm -rf /"
|
|
14
|
+
"^rm -rf ~"
|
|
15
|
+
"^rm -rf \\\$HOME"
|
|
16
16
|
"> /dev/sd"
|
|
17
17
|
"^mkfs "
|
|
18
18
|
"^dd if=/dev/zero"
|
|
19
|
-
"^chmod -R 777
|
|
19
|
+
"^chmod -R 777 /"
|
|
20
20
|
)
|
|
21
21
|
|
|
22
22
|
# Check for blocked patterns
|
|
@@ -38,7 +38,8 @@ done
|
|
|
38
38
|
# Log command to audit trail
|
|
39
39
|
LOG_DIR="$CWD/.loki/logs"
|
|
40
40
|
mkdir -p "$LOG_DIR"
|
|
41
|
-
|
|
41
|
+
printf '%s' "{\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"command\":$(echo "$COMMAND" | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))')}" >> "$LOG_DIR/bash-audit.jsonl"
|
|
42
|
+
echo >> "$LOG_DIR/bash-audit.jsonl"
|
|
42
43
|
|
|
43
44
|
# Allow command
|
|
44
45
|
cat << EOF
|
package/autonomy/loki
CHANGED
|
@@ -55,9 +55,12 @@ find_skill_dir() {
|
|
|
55
55
|
local script_dir
|
|
56
56
|
script_dir=$(dirname "$script_path")
|
|
57
57
|
|
|
58
|
+
# Check script's own parent first (most likely current), then installed skill, then cwd
|
|
59
|
+
local script_parent
|
|
60
|
+
script_parent="$(cd "$script_dir/.." 2>/dev/null && pwd)"
|
|
58
61
|
local dirs=(
|
|
62
|
+
"$script_parent"
|
|
59
63
|
"$HOME/.claude/skills/loki-mode"
|
|
60
|
-
"$script_dir/.."
|
|
61
64
|
"."
|
|
62
65
|
)
|
|
63
66
|
|
|
@@ -444,6 +447,18 @@ cmd_start() {
|
|
|
444
447
|
|
|
445
448
|
if [ -n "$prd_file" ]; then
|
|
446
449
|
args+=("$prd_file")
|
|
450
|
+
else
|
|
451
|
+
# No PRD file specified -- warn and confirm before consuming API credits
|
|
452
|
+
echo -e "${YELLOW}Warning: No PRD file specified.${NC}"
|
|
453
|
+
echo "Loki Mode will start autonomous execution in the current directory"
|
|
454
|
+
echo "without a requirements document."
|
|
455
|
+
echo ""
|
|
456
|
+
echo -e "This will consume API credits. Continue? [y/N] \c"
|
|
457
|
+
read -r confirm
|
|
458
|
+
if [[ ! "$confirm" =~ ^[Yy] ]]; then
|
|
459
|
+
echo "Aborted. Usage: loki start <path-to-prd.md>"
|
|
460
|
+
exit 0
|
|
461
|
+
fi
|
|
447
462
|
fi
|
|
448
463
|
|
|
449
464
|
# Load saved provider if not specified on command line
|
|
@@ -604,15 +619,16 @@ cmd_stop() {
|
|
|
604
619
|
if [ -f "$LOKI_DIR/session.json" ]; then
|
|
605
620
|
# Use python for reliable JSON update, fall back to overwrite
|
|
606
621
|
python3 -c "
|
|
607
|
-
import json, sys
|
|
622
|
+
import json, sys, os
|
|
608
623
|
try:
|
|
609
|
-
|
|
624
|
+
p = os.path.join(sys.argv[1], 'session.json')
|
|
625
|
+
with open(p, 'r+') as f:
|
|
610
626
|
d = json.load(f)
|
|
611
627
|
d['status'] = 'stopped'
|
|
612
628
|
f.seek(0); f.truncate()
|
|
613
629
|
json.dump(d, f)
|
|
614
630
|
except: pass
|
|
615
|
-
" 2>/dev/null || true
|
|
631
|
+
" "$LOKI_DIR" 2>/dev/null || true
|
|
616
632
|
fi
|
|
617
633
|
|
|
618
634
|
# Clean up control files
|
|
@@ -692,15 +708,31 @@ cmd_pause() {
|
|
|
692
708
|
cmd_resume() {
|
|
693
709
|
if [ ! -d "$LOKI_DIR" ]; then
|
|
694
710
|
echo -e "${YELLOW}No .loki directory found.${NC}"
|
|
695
|
-
echo "
|
|
711
|
+
echo "No session to resume. Start a session with: loki start"
|
|
712
|
+
exit 0
|
|
713
|
+
fi
|
|
714
|
+
|
|
715
|
+
# Check if there is anything to resume before touching signal files
|
|
716
|
+
local has_pause_signal=false
|
|
717
|
+
local has_stop_signal=false
|
|
718
|
+
[ -f "$LOKI_DIR/PAUSE" ] && has_pause_signal=true
|
|
719
|
+
[ -f "$LOKI_DIR/STOP" ] && has_stop_signal=true
|
|
720
|
+
local session_running=false
|
|
721
|
+
is_session_running && session_running=true
|
|
722
|
+
|
|
723
|
+
# If nothing is paused/stopped and no session is running, exit early
|
|
724
|
+
if ! $has_pause_signal && ! $has_stop_signal && ! $session_running; then
|
|
725
|
+
echo -e "${YELLOW}No session to resume.${NC}"
|
|
726
|
+
echo "Start a session with: loki start"
|
|
696
727
|
exit 0
|
|
697
728
|
fi
|
|
698
729
|
|
|
730
|
+
# Clear the signal file if one exists
|
|
699
731
|
local removed_signal=""
|
|
700
|
-
if
|
|
732
|
+
if $has_pause_signal; then
|
|
701
733
|
rm -f "$LOKI_DIR/PAUSE"
|
|
702
734
|
removed_signal="PAUSE"
|
|
703
|
-
elif
|
|
735
|
+
elif $has_stop_signal; then
|
|
704
736
|
rm -f "$LOKI_DIR/STOP"
|
|
705
737
|
removed_signal="STOP"
|
|
706
738
|
fi
|
|
@@ -716,19 +748,15 @@ cmd_resume() {
|
|
|
716
748
|
--action-sequence '["check_signals", "clear_signal", "resume"]' \
|
|
717
749
|
--outcome success \
|
|
718
750
|
--confidence 0.85
|
|
719
|
-
if
|
|
751
|
+
if $session_running; then
|
|
720
752
|
echo -e "${GREEN}$removed_signal signal cleared. Session will resume automatically.${NC}"
|
|
721
753
|
else
|
|
722
754
|
echo -e "${GREEN}$removed_signal signal cleared.${NC}"
|
|
723
755
|
echo "Session is not running. Start with: loki start"
|
|
724
756
|
fi
|
|
725
757
|
else
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
else
|
|
729
|
-
echo -e "${YELLOW}No pause/stop signals found.${NC}"
|
|
730
|
-
echo "Session is not running. Start with: loki start"
|
|
731
|
-
fi
|
|
758
|
+
# Session is running but no signals to clear
|
|
759
|
+
echo -e "${CYAN}Session is running normally. Nothing to resume.${NC}"
|
|
732
760
|
fi
|
|
733
761
|
}
|
|
734
762
|
|
|
@@ -914,7 +942,7 @@ cmd_provider_set() {
|
|
|
914
942
|
echo "Install: npm install -g @openai/codex"
|
|
915
943
|
;;
|
|
916
944
|
gemini)
|
|
917
|
-
echo "Install: npm install -g @
|
|
945
|
+
echo "Install: npm install -g @google/gemini-cli"
|
|
918
946
|
;;
|
|
919
947
|
esac
|
|
920
948
|
echo ""
|
|
@@ -998,7 +1026,7 @@ cmd_provider_info() {
|
|
|
998
1026
|
echo "Name: Codex CLI"
|
|
999
1027
|
echo "Vendor: OpenAI"
|
|
1000
1028
|
echo "CLI: codex"
|
|
1001
|
-
echo "Flag:
|
|
1029
|
+
echo "Flag: --full-auto"
|
|
1002
1030
|
echo ""
|
|
1003
1031
|
echo "Features:"
|
|
1004
1032
|
echo " - Autonomous mode"
|
|
@@ -1010,7 +1038,7 @@ cmd_provider_info() {
|
|
|
1010
1038
|
echo "Name: Gemini CLI"
|
|
1011
1039
|
echo "Vendor: Google"
|
|
1012
1040
|
echo "CLI: gemini"
|
|
1013
|
-
echo "Flag: --yolo"
|
|
1041
|
+
echo "Flag: --approval-mode=yolo"
|
|
1014
1042
|
echo ""
|
|
1015
1043
|
echo "Features:"
|
|
1016
1044
|
echo " - Autonomous mode"
|
|
@@ -1544,7 +1572,7 @@ cmd_issue_parse() {
|
|
|
1544
1572
|
;;
|
|
1545
1573
|
--format)
|
|
1546
1574
|
format="${2:-yaml}"
|
|
1547
|
-
shift 2
|
|
1575
|
+
if [ $# -ge 2 ]; then shift 2; else shift; fi
|
|
1548
1576
|
;;
|
|
1549
1577
|
--format=*)
|
|
1550
1578
|
format="${1#*=}"
|
|
@@ -1552,7 +1580,7 @@ cmd_issue_parse() {
|
|
|
1552
1580
|
;;
|
|
1553
1581
|
--output|-o)
|
|
1554
1582
|
output_file="${2:-}"
|
|
1555
|
-
shift 2
|
|
1583
|
+
if [ $# -ge 2 ]; then shift 2; else shift; fi
|
|
1556
1584
|
;;
|
|
1557
1585
|
--output=*)
|
|
1558
1586
|
output_file="${1#*=}"
|
|
@@ -2263,7 +2291,7 @@ cmd_api() {
|
|
|
2263
2291
|
fi
|
|
2264
2292
|
|
|
2265
2293
|
# Start server
|
|
2266
|
-
mkdir -p "$LOKI_DIR"
|
|
2294
|
+
mkdir -p "$LOKI_DIR/logs"
|
|
2267
2295
|
nohup node "$api_server" --port "$port" > "$LOKI_DIR/logs/api.log" 2>&1 &
|
|
2268
2296
|
local new_pid=$!
|
|
2269
2297
|
echo "$new_pid" > "$pid_file"
|
|
@@ -2584,6 +2612,8 @@ send_slack_notification() {
|
|
|
2584
2612
|
project_name=$(basename "$(pwd)")
|
|
2585
2613
|
local timestamp
|
|
2586
2614
|
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
2615
|
+
local message_escaped
|
|
2616
|
+
message_escaped=$(printf '%s' "$message" | sed 's/\\/\\\\/g; s/"/\\"/g; s/ /\\t/g')
|
|
2587
2617
|
|
|
2588
2618
|
# Build Slack payload with blocks for better formatting
|
|
2589
2619
|
local payload
|
|
@@ -2601,7 +2631,7 @@ send_slack_notification() {
|
|
|
2601
2631
|
"type": "section",
|
|
2602
2632
|
"text": {
|
|
2603
2633
|
"type": "mrkdwn",
|
|
2604
|
-
"text": "$
|
|
2634
|
+
"text": "$message_escaped"
|
|
2605
2635
|
}
|
|
2606
2636
|
},
|
|
2607
2637
|
{
|
|
@@ -2638,6 +2668,8 @@ send_discord_notification() {
|
|
|
2638
2668
|
project_name=$(basename "$(pwd)")
|
|
2639
2669
|
local timestamp
|
|
2640
2670
|
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
2671
|
+
local message_escaped
|
|
2672
|
+
message_escaped=$(printf '%s' "$message" | sed 's/\\/\\\\/g; s/"/\\"/g; s/ /\\t/g')
|
|
2641
2673
|
|
|
2642
2674
|
# Build Discord embed payload
|
|
2643
2675
|
local payload
|
|
@@ -2646,7 +2678,7 @@ send_discord_notification() {
|
|
|
2646
2678
|
"embeds": [
|
|
2647
2679
|
{
|
|
2648
2680
|
"title": "Loki Mode: $event_type",
|
|
2649
|
-
"description": "$
|
|
2681
|
+
"description": "$message_escaped",
|
|
2650
2682
|
"color": 5814783,
|
|
2651
2683
|
"footer": {
|
|
2652
2684
|
"text": "Project: $project_name | $timestamp"
|
|
@@ -2677,6 +2709,8 @@ send_webhook_notification() {
|
|
|
2677
2709
|
project_name=$(basename "$(pwd)")
|
|
2678
2710
|
local timestamp
|
|
2679
2711
|
timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
2712
|
+
local message_escaped
|
|
2713
|
+
message_escaped=$(printf '%s' "$message" | sed 's/\\/\\\\/g; s/"/\\"/g; s/ /\\t/g')
|
|
2680
2714
|
|
|
2681
2715
|
# Build generic JSON payload
|
|
2682
2716
|
local payload
|
|
@@ -2684,7 +2718,7 @@ send_webhook_notification() {
|
|
|
2684
2718
|
{
|
|
2685
2719
|
"source": "loki-mode",
|
|
2686
2720
|
"event": "$event_type",
|
|
2687
|
-
"message": "$
|
|
2721
|
+
"message": "$message_escaped",
|
|
2688
2722
|
"project": "$project_name",
|
|
2689
2723
|
"timestamp": "$timestamp",
|
|
2690
2724
|
"cwd": "$(pwd)"
|
|
@@ -2855,14 +2889,15 @@ cmd_reset() {
|
|
|
2855
2889
|
# Reset only retry count
|
|
2856
2890
|
if command -v python3 &> /dev/null; then
|
|
2857
2891
|
python3 -c "
|
|
2858
|
-
import json
|
|
2859
|
-
|
|
2892
|
+
import json, sys, os
|
|
2893
|
+
p = os.path.join(sys.argv[1], 'autonomy-state.json')
|
|
2894
|
+
with open(p, 'r') as f:
|
|
2860
2895
|
state = json.load(f)
|
|
2861
2896
|
state['retryCount'] = 0
|
|
2862
2897
|
state['status'] = 'reset'
|
|
2863
|
-
with open(
|
|
2898
|
+
with open(p, 'w') as f:
|
|
2864
2899
|
json.dump(state, f, indent=4)
|
|
2865
|
-
" 2>/dev/null
|
|
2900
|
+
" "$LOKI_DIR" 2>/dev/null
|
|
2866
2901
|
echo -e "${GREEN}Retry count reset to 0${NC}"
|
|
2867
2902
|
else
|
|
2868
2903
|
rm -f "$LOKI_DIR/autonomy-state.json"
|
|
@@ -2970,11 +3005,12 @@ cmd_memory() {
|
|
|
2970
3005
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
2971
3006
|
if [ -f "$learnings_dir/patterns.jsonl" ]; then
|
|
2972
3007
|
python3 -c "
|
|
2973
|
-
import json
|
|
2974
|
-
limit =
|
|
2975
|
-
project_filter =
|
|
3008
|
+
import json, sys, os
|
|
3009
|
+
limit = int(sys.argv[1])
|
|
3010
|
+
project_filter = sys.argv[2]
|
|
3011
|
+
filepath = os.path.join(sys.argv[3], 'patterns.jsonl')
|
|
2976
3012
|
count = 0
|
|
2977
|
-
with open(
|
|
3013
|
+
with open(filepath, 'r') as f:
|
|
2978
3014
|
for line in f:
|
|
2979
3015
|
if count >= limit:
|
|
2980
3016
|
break
|
|
@@ -2988,7 +3024,7 @@ with open('$learnings_dir/patterns.jsonl', 'r') as f:
|
|
|
2988
3024
|
except: pass
|
|
2989
3025
|
if count == 0:
|
|
2990
3026
|
print('(empty - no patterns recorded)')
|
|
2991
|
-
" 2>/dev/null
|
|
3027
|
+
" "$limit" "$project" "$learnings_dir" 2>/dev/null
|
|
2992
3028
|
else
|
|
2993
3029
|
echo "(empty - no patterns recorded)"
|
|
2994
3030
|
fi
|
|
@@ -2999,11 +3035,12 @@ if count == 0:
|
|
|
2999
3035
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
3000
3036
|
if [ -f "$learnings_dir/mistakes.jsonl" ]; then
|
|
3001
3037
|
python3 -c "
|
|
3002
|
-
import json
|
|
3003
|
-
limit =
|
|
3004
|
-
project_filter =
|
|
3038
|
+
import json, sys, os
|
|
3039
|
+
limit = int(sys.argv[1])
|
|
3040
|
+
project_filter = sys.argv[2]
|
|
3041
|
+
filepath = os.path.join(sys.argv[3], 'mistakes.jsonl')
|
|
3005
3042
|
count = 0
|
|
3006
|
-
with open(
|
|
3043
|
+
with open(filepath, 'r') as f:
|
|
3007
3044
|
for line in f:
|
|
3008
3045
|
if count >= limit:
|
|
3009
3046
|
break
|
|
@@ -3017,7 +3054,7 @@ with open('$learnings_dir/mistakes.jsonl', 'r') as f:
|
|
|
3017
3054
|
except: pass
|
|
3018
3055
|
if count == 0:
|
|
3019
3056
|
print('(empty - no mistakes recorded)')
|
|
3020
|
-
" 2>/dev/null
|
|
3057
|
+
" "$limit" "$project" "$learnings_dir" 2>/dev/null
|
|
3021
3058
|
else
|
|
3022
3059
|
echo "(empty - no mistakes recorded)"
|
|
3023
3060
|
fi
|
|
@@ -3028,11 +3065,12 @@ if count == 0:
|
|
|
3028
3065
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
3029
3066
|
if [ -f "$learnings_dir/successes.jsonl" ]; then
|
|
3030
3067
|
python3 -c "
|
|
3031
|
-
import json
|
|
3032
|
-
limit =
|
|
3033
|
-
project_filter =
|
|
3068
|
+
import json, sys, os
|
|
3069
|
+
limit = int(sys.argv[1])
|
|
3070
|
+
project_filter = sys.argv[2]
|
|
3071
|
+
filepath = os.path.join(sys.argv[3], 'successes.jsonl')
|
|
3034
3072
|
count = 0
|
|
3035
|
-
with open(
|
|
3073
|
+
with open(filepath, 'r') as f:
|
|
3036
3074
|
for line in f:
|
|
3037
3075
|
if count >= limit:
|
|
3038
3076
|
break
|
|
@@ -3046,18 +3084,18 @@ with open('$learnings_dir/successes.jsonl', 'r') as f:
|
|
|
3046
3084
|
except: pass
|
|
3047
3085
|
if count == 0:
|
|
3048
3086
|
print('(empty - no successes recorded)')
|
|
3049
|
-
" 2>/dev/null
|
|
3087
|
+
" "$limit" "$project" "$learnings_dir" 2>/dev/null
|
|
3050
3088
|
else
|
|
3051
3089
|
echo "(empty - no successes recorded)"
|
|
3052
3090
|
fi
|
|
3053
3091
|
;;
|
|
3054
3092
|
|
|
3055
3093
|
all)
|
|
3056
|
-
cmd_memory show patterns --limit "$limit"
|
|
3094
|
+
cmd_memory show patterns --limit "$limit" --project "$project"
|
|
3057
3095
|
echo ""
|
|
3058
|
-
cmd_memory show mistakes --limit "$limit"
|
|
3096
|
+
cmd_memory show mistakes --limit "$limit" --project "$project"
|
|
3059
3097
|
echo ""
|
|
3060
|
-
cmd_memory show successes --limit "$limit"
|
|
3098
|
+
cmd_memory show successes --limit "$limit" --project "$project"
|
|
3061
3099
|
;;
|
|
3062
3100
|
|
|
3063
3101
|
*)
|
|
@@ -3078,12 +3116,13 @@ if count == 0:
|
|
|
3078
3116
|
echo -e "${BOLD}Search Results for: $query${NC}"
|
|
3079
3117
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
3080
3118
|
|
|
3119
|
+
local query_escaped="${query//\'/\'\\\'\'}"
|
|
3081
3120
|
python3 -c "
|
|
3082
3121
|
import json
|
|
3083
3122
|
import os
|
|
3084
3123
|
|
|
3085
3124
|
learnings_dir = '$learnings_dir'
|
|
3086
|
-
query = '$
|
|
3125
|
+
query = '${query_escaped}'.lower()
|
|
3087
3126
|
|
|
3088
3127
|
for filename in ['patterns.jsonl', 'mistakes.jsonl', 'successes.jsonl']:
|
|
3089
3128
|
filepath = os.path.join(learnings_dir, filename)
|