loki-mode 6.61.0 → 6.62.1
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/app-runner.sh +34 -8
- package/autonomy/completion-council.sh +70 -32
- package/autonomy/hooks/migration-hooks.sh +10 -1
- package/autonomy/issue-parser.sh +4 -7
- package/autonomy/issue-providers.sh +7 -2
- package/autonomy/loki +234 -118
- package/autonomy/notification-checker.py +49 -23
- package/autonomy/run.sh +294 -139
- package/autonomy/sandbox.sh +96 -26
- package/bin/loki-mode.js +1 -2
- package/bin/postinstall.js +10 -4
- package/dashboard/__init__.py +1 -1
- package/dashboard/control.py +46 -36
- package/dashboard/server.py +49 -27
- package/docs/BUG-AUDIT-v6.61.0.md +957 -0
- package/docs/INSTALLATION.md +2 -2
- package/events/bus.py +129 -28
- package/events/bus.ts +41 -27
- package/events/emit.sh +1 -1
- package/integrations/openclaw/README.md +139 -0
- package/integrations/openclaw/SKILL.md +88 -0
- package/integrations/openclaw/bridge/__init__.py +1 -0
- package/integrations/openclaw/bridge/__main__.py +88 -0
- package/integrations/openclaw/bridge/schema_map.py +180 -0
- package/integrations/openclaw/bridge/watcher.py +100 -0
- package/integrations/openclaw/scripts/format-progress.sh +80 -0
- package/integrations/openclaw/scripts/poll-status.sh +74 -0
- package/integrations/vibe-kanban.md +289 -0
- package/mcp/__init__.py +1 -1
- package/mcp/server.py +96 -73
- package/memory/consolidation.py +21 -6
- package/memory/engine.py +54 -26
- package/memory/layers/index_layer.py +16 -3
- package/memory/layers/timeline_layer.py +16 -3
- package/memory/retrieval.py +4 -1
- package/memory/schemas.py +4 -2
- package/memory/storage.py +25 -4
- package/memory/token_economics.py +9 -2
- package/memory/vector_index.py +2 -2
- package/package.json +3 -1
- package/providers/cline.sh +5 -4
- package/providers/codex.sh +27 -5
- package/providers/gemini.sh +59 -23
- package/providers/loader.sh +3 -2
- package/skills/parallel-workflows.md +9 -7
- package/state/__init__.py +10 -0
- package/state/index.ts +18 -0
- package/state/manager.py +1896 -0
- package/state/manager.ts +1774 -0
- package/state/sqlite_backend.py +188 -0
- package/state/test_manager.py +703 -0
- package/state/test_manager.ts +366 -0
- package/templates/README.md +19 -4
- package/templates/dashboard.md +45 -0
- package/templates/data-pipeline.md +45 -0
- package/templates/game.md +48 -0
- package/templates/microservice.md +49 -0
- package/templates/npm-library.md +42 -0
- package/templates/rest-api.md +170 -33
- package/templates/slack-bot.md +48 -0
- package/templates/web-scraper.md +45 -0
- package/web-app/server.py +245 -151
- package/templates/saas-app.md +0 -42
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 minimal human intervention. Requires --dangerously-skip-permissions flag.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Loki Mode v6.
|
|
6
|
+
# Loki Mode v6.62.1
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -267,4 +267,4 @@ The following features are documented in skill modules but not yet fully automat
|
|
|
267
267
|
| Quality gates 3-reviewer system | Implemented (v5.35.0) | 5 specialist reviewers in `skills/quality-gates.md`; execution in run.sh |
|
|
268
268
|
| Benchmarks (HumanEval, SWE-bench) | Infrastructure only | Runner scripts and datasets exist in `benchmarks/`; no published results |
|
|
269
269
|
|
|
270
|
-
**v6.
|
|
270
|
+
**v6.62.1 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
6.
|
|
1
|
+
6.62.1
|
package/autonomy/app-runner.sh
CHANGED
|
@@ -42,6 +42,7 @@ _APP_RUNNER_PORT=""
|
|
|
42
42
|
_APP_RUNNER_PID=""
|
|
43
43
|
_APP_RUNNER_URL=""
|
|
44
44
|
_APP_RUNNER_IS_DOCKER=false
|
|
45
|
+
_APP_RUNNER_DOCKER_CONTAINER=""
|
|
45
46
|
_APP_RUNNER_HAS_SETSID=false
|
|
46
47
|
_APP_RUNNER_CRASH_COUNT=0
|
|
47
48
|
_APP_RUNNER_RESTART_COUNT=0
|
|
@@ -145,7 +146,8 @@ _detect_port() {
|
|
|
145
146
|
fi
|
|
146
147
|
local port
|
|
147
148
|
# Handle both simple (HOST:CONTAINER) and IP-bound (IP:HOST:CONTAINER) port formats
|
|
148
|
-
|
|
149
|
+
# Also handle port ranges like "8080-8090:8080-8090" by taking the first port
|
|
150
|
+
port=$(grep -E '^\s*-\s*"?[0-9]' "$compose_file" 2>/dev/null | head -1 | sed 's/.*- *"*//;s/".*//;' | awk -F: '{print $(NF-1)}' | awk -F- '{print $1}')
|
|
149
151
|
_APP_RUNNER_PORT="${port:-8080}"
|
|
150
152
|
;;
|
|
151
153
|
*docker\ build*)
|
|
@@ -244,7 +246,11 @@ app_runner_init() {
|
|
|
244
246
|
if [ -f "$dir/Dockerfile" ]; then
|
|
245
247
|
if command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1; then
|
|
246
248
|
_detect_port "docker build"
|
|
247
|
-
|
|
249
|
+
# Include project hash in container name to avoid collisions across projects
|
|
250
|
+
local _project_hash
|
|
251
|
+
_project_hash=$(echo "$dir" | (md5sum 2>/dev/null || md5 -r 2>/dev/null || echo "$$") | cut -c1-8)
|
|
252
|
+
_APP_RUNNER_DOCKER_CONTAINER="loki-app-${_project_hash}"
|
|
253
|
+
_APP_RUNNER_METHOD="docker build -t loki-app . && docker run -d -p ${_APP_RUNNER_PORT}:${_APP_RUNNER_PORT} --name ${_APP_RUNNER_DOCKER_CONTAINER} loki-app"
|
|
248
254
|
_APP_RUNNER_IS_DOCKER=true
|
|
249
255
|
_write_detection "dockerfile" "$_APP_RUNNER_METHOD"
|
|
250
256
|
log_info "App Runner: detected Dockerfile"
|
|
@@ -431,12 +437,28 @@ app_runner_start() {
|
|
|
431
437
|
# Start the process in a new process group
|
|
432
438
|
if command -v setsid >/dev/null 2>&1; then
|
|
433
439
|
_APP_RUNNER_HAS_SETSID=true
|
|
434
|
-
|
|
440
|
+
# Use setsid with a PID file so we capture the actual child PID (the process
|
|
441
|
+
# group leader) rather than the subshell PID, which would orphan the app.
|
|
442
|
+
local _pgid_file="$_APP_RUNNER_DIR/app.pgid.$$"
|
|
443
|
+
(cd "$dir" && setsid bash -c 'echo $$ > "'"$_pgid_file"'"; exec '"$_APP_RUNNER_METHOD" >> "$_APP_RUNNER_DIR/app.log" 2>&1) &
|
|
444
|
+
local _subshell_pid=$!
|
|
445
|
+
# Wait briefly for the pgid file to appear, then read the real PGID
|
|
446
|
+
local _pgid_wait=0
|
|
447
|
+
while [ ! -s "$_pgid_file" ] && [ "$_pgid_wait" -lt 10 ]; do
|
|
448
|
+
sleep 0.1
|
|
449
|
+
_pgid_wait=$(( _pgid_wait + 1 ))
|
|
450
|
+
done
|
|
451
|
+
if [ -s "$_pgid_file" ]; then
|
|
452
|
+
_APP_RUNNER_PID=$(cat "$_pgid_file")
|
|
453
|
+
else
|
|
454
|
+
_APP_RUNNER_PID=$_subshell_pid
|
|
455
|
+
fi
|
|
456
|
+
rm -f "$_pgid_file"
|
|
435
457
|
else
|
|
436
458
|
_APP_RUNNER_HAS_SETSID=false
|
|
437
459
|
(cd "$dir" && bash -c "$_APP_RUNNER_METHOD" >> "$_APP_RUNNER_DIR/app.log" 2>&1) &
|
|
460
|
+
_APP_RUNNER_PID=$!
|
|
438
461
|
fi
|
|
439
|
-
_APP_RUNNER_PID=$!
|
|
440
462
|
# Register with central PID registry if available
|
|
441
463
|
if type register_pid &>/dev/null; then
|
|
442
464
|
register_pid "$_APP_RUNNER_PID" "app-runner" "method=$_APP_RUNNER_METHOD"
|
|
@@ -494,8 +516,10 @@ app_runner_stop() {
|
|
|
494
516
|
|
|
495
517
|
# Docker cleanup
|
|
496
518
|
if [ "$_APP_RUNNER_IS_DOCKER" = true ]; then
|
|
497
|
-
|
|
498
|
-
|
|
519
|
+
if [ -n "$_APP_RUNNER_DOCKER_CONTAINER" ]; then
|
|
520
|
+
docker stop "$_APP_RUNNER_DOCKER_CONTAINER" 2>/dev/null || true
|
|
521
|
+
docker rm "$_APP_RUNNER_DOCKER_CONTAINER" 2>/dev/null || true
|
|
522
|
+
fi
|
|
499
523
|
if echo "$_APP_RUNNER_METHOD" | grep -q "docker compose"; then
|
|
500
524
|
(cd "${TARGET_DIR:-.}" && docker compose down 2>/dev/null) || true
|
|
501
525
|
fi
|
|
@@ -704,8 +728,10 @@ app_runner_cleanup() {
|
|
|
704
728
|
|
|
705
729
|
# Docker-specific cleanup
|
|
706
730
|
if [ "$_APP_RUNNER_IS_DOCKER" = true ]; then
|
|
707
|
-
|
|
708
|
-
|
|
731
|
+
if [ -n "$_APP_RUNNER_DOCKER_CONTAINER" ]; then
|
|
732
|
+
docker stop "$_APP_RUNNER_DOCKER_CONTAINER" 2>/dev/null || true
|
|
733
|
+
docker rm "$_APP_RUNNER_DOCKER_CONTAINER" 2>/dev/null || true
|
|
734
|
+
fi
|
|
709
735
|
if echo "$_APP_RUNNER_METHOD" | grep -q "docker compose"; then
|
|
710
736
|
(cd "${TARGET_DIR:-.}" && docker compose down 2>/dev/null) || true
|
|
711
737
|
fi
|
|
@@ -48,6 +48,10 @@ if ! [[ "$COUNCIL_CHECK_INTERVAL" =~ ^[1-9][0-9]*$ ]]; then
|
|
|
48
48
|
COUNCIL_CHECK_INTERVAL=5
|
|
49
49
|
fi
|
|
50
50
|
COUNCIL_MIN_ITERATIONS=${LOKI_COUNCIL_MIN_ITERATIONS:-3}
|
|
51
|
+
# BUG-QG-012: Enforce minimum of 1 to prevent council approving at iteration 0
|
|
52
|
+
if [ "$COUNCIL_MIN_ITERATIONS" -lt 1 ] 2>/dev/null; then
|
|
53
|
+
COUNCIL_MIN_ITERATIONS=1
|
|
54
|
+
fi
|
|
51
55
|
COUNCIL_CONVERGENCE_WINDOW=${LOKI_COUNCIL_CONVERGENCE_WINDOW:-3}
|
|
52
56
|
COUNCIL_STAGNATION_LIMIT=${LOKI_COUNCIL_STAGNATION_LIMIT:-5}
|
|
53
57
|
COUNCIL_DONE_SIGNAL_LIMIT=${LOKI_COUNCIL_DONE_SIGNAL_LIMIT:-10}
|
|
@@ -84,6 +88,7 @@ council_init() {
|
|
|
84
88
|
COUNCIL_PRD_PATH="$prd_path"
|
|
85
89
|
COUNCIL_CONSECUTIVE_NO_CHANGE=0
|
|
86
90
|
COUNCIL_DONE_SIGNALS=0
|
|
91
|
+
COUNCIL_TOTAL_DONE_SIGNALS=0
|
|
87
92
|
COUNCIL_LAST_DIFF_HASH=""
|
|
88
93
|
|
|
89
94
|
mkdir -p "$COUNCIL_STATE_DIR"
|
|
@@ -131,7 +136,11 @@ council_track_iteration() {
|
|
|
131
136
|
local staged_hash
|
|
132
137
|
staged_hash=$(git diff --cached --stat 2>/dev/null | (md5sum 2>/dev/null || md5 -r 2>/dev/null) | cut -d' ' -f1 || echo "unknown")
|
|
133
138
|
|
|
134
|
-
|
|
139
|
+
# Include latest commit hash so committed changes are detected (BUG-QG-004)
|
|
140
|
+
local commit_hash
|
|
141
|
+
commit_hash=$(git log --oneline -1 2>/dev/null | cut -d' ' -f1 || echo "unknown")
|
|
142
|
+
|
|
143
|
+
local combined_hash="${current_diff_hash}-${staged_hash}-${commit_hash}"
|
|
135
144
|
|
|
136
145
|
if [ "$combined_hash" = "$COUNCIL_LAST_DIFF_HASH" ]; then
|
|
137
146
|
((COUNCIL_CONSECUTIVE_NO_CHANGE++))
|
|
@@ -248,6 +257,9 @@ council_vote() {
|
|
|
248
257
|
log_header "COMPLETION COUNCIL - Iteration $ITERATION_COUNT"
|
|
249
258
|
log_info "Convening ${COUNCIL_SIZE}-member council..."
|
|
250
259
|
|
|
260
|
+
# Compute threshold using ceiling(2/3) formula, consistent with council_aggregate_votes
|
|
261
|
+
local effective_threshold=$(( (COUNCIL_SIZE * 2 + 2) / 3 ))
|
|
262
|
+
|
|
251
263
|
# Gather evidence for council members
|
|
252
264
|
local evidence_file="$vote_dir/evidence.md"
|
|
253
265
|
council_gather_evidence "$evidence_file" "$prd_path"
|
|
@@ -287,30 +299,57 @@ council_vote() {
|
|
|
287
299
|
# is based only on issues below the severity threshold
|
|
288
300
|
if [ "$vote_result" = "REJECT" ] && [ "$COUNCIL_SEVERITY_THRESHOLD" != "low" ] && [ -n "$member_issues" ]; then
|
|
289
301
|
local has_blocking_issue=false
|
|
302
|
+
local non_blocking_count=0
|
|
303
|
+
local total_issue_count=0
|
|
290
304
|
local severity_order="critical high medium low"
|
|
291
305
|
local threshold_reached=false
|
|
292
306
|
|
|
293
307
|
while IFS= read -r issue_line; do
|
|
294
308
|
local issue_severity
|
|
295
309
|
issue_severity=$(echo "$issue_line" | grep -oE "(CRITICAL|HIGH|MEDIUM|LOW)" | head -1 | tr '[:upper:]' '[:lower:]')
|
|
310
|
+
[ -z "$issue_severity" ] && continue
|
|
311
|
+
((total_issue_count++))
|
|
296
312
|
# Reset per issue line so previous iterations don't poison the check
|
|
297
313
|
threshold_reached=false
|
|
298
314
|
# Check if this severity meets or exceeds the threshold
|
|
315
|
+
local is_blocking=false
|
|
299
316
|
for sev in $severity_order; do
|
|
300
317
|
if [ "$sev" = "$issue_severity" ] && [ "$threshold_reached" = "false" ]; then
|
|
301
318
|
has_blocking_issue=true
|
|
319
|
+
is_blocking=true
|
|
302
320
|
break
|
|
303
321
|
fi
|
|
304
322
|
if [ "$sev" = "$COUNCIL_SEVERITY_THRESHOLD" ]; then
|
|
305
323
|
threshold_reached=true
|
|
306
324
|
fi
|
|
307
325
|
done
|
|
326
|
+
if [ "$is_blocking" = "false" ]; then
|
|
327
|
+
((non_blocking_count++))
|
|
328
|
+
fi
|
|
308
329
|
done <<< "$member_issues"
|
|
309
330
|
|
|
331
|
+
# Apply error budget: if no blocking issues, check non-blocking ratio
|
|
310
332
|
if [ "$has_blocking_issue" = "false" ]; then
|
|
311
|
-
|
|
312
|
-
|
|
333
|
+
local budget_exceeded=false
|
|
334
|
+
if [ "$total_issue_count" -gt 0 ] && [ "$COUNCIL_ERROR_BUDGET" != "0.0" ] && [ "$COUNCIL_ERROR_BUDGET" != "0" ]; then
|
|
335
|
+
# Check if non-blocking issue ratio exceeds the error budget
|
|
336
|
+
budget_exceeded=$(_NB="$non_blocking_count" _TOTAL="$total_issue_count" _BUDGET="$COUNCIL_ERROR_BUDGET" python3 -c "
|
|
337
|
+
import os
|
|
338
|
+
nb = int(os.environ['_NB'])
|
|
339
|
+
total = int(os.environ['_TOTAL'])
|
|
340
|
+
budget = float(os.environ['_BUDGET'])
|
|
341
|
+
ratio = nb / total if total > 0 else 0.0
|
|
342
|
+
print('true' if ratio > budget else 'false')
|
|
343
|
+
" 2>/dev/null || echo "false")
|
|
344
|
+
fi
|
|
345
|
+
if [ "$budget_exceeded" = "true" ]; then
|
|
346
|
+
log_info " Member $member ($role): REJECT maintained (non-blocking issue ratio exceeds error budget ${COUNCIL_ERROR_BUDGET})"
|
|
347
|
+
else
|
|
348
|
+
log_info " Member $member ($role): REJECT overridden to APPROVE (issues below ${COUNCIL_SEVERITY_THRESHOLD} threshold, within error budget)"
|
|
349
|
+
vote_result="APPROVE"
|
|
350
|
+
fi
|
|
313
351
|
fi
|
|
352
|
+
|
|
314
353
|
fi
|
|
315
354
|
|
|
316
355
|
if [ "$vote_result" = "APPROVE" ]; then
|
|
@@ -333,7 +372,7 @@ council_vote() {
|
|
|
333
372
|
done
|
|
334
373
|
|
|
335
374
|
# Anti-sycophancy check: if unanimous APPROVE, run devil's advocate
|
|
336
|
-
if [ $approve_count -eq $COUNCIL_SIZE ] && [ $COUNCIL_SIZE -ge
|
|
375
|
+
if [ $approve_count -eq $COUNCIL_SIZE ] && [ $COUNCIL_SIZE -ge 2 ]; then
|
|
337
376
|
log_warn "Unanimous approval detected - running anti-sycophancy check..."
|
|
338
377
|
local contrarian_verdict
|
|
339
378
|
contrarian_verdict=$(council_devils_advocate "$evidence_file" "$vote_dir")
|
|
@@ -356,7 +395,7 @@ council_vote() {
|
|
|
356
395
|
_COUNCIL_APPROVE="$approve_count" \
|
|
357
396
|
_COUNCIL_REJECT="$reject_count" \
|
|
358
397
|
_COUNCIL_ITERATION="${ITERATION_COUNT:-0}" \
|
|
359
|
-
_COUNCIL_THRESHOLD="$
|
|
398
|
+
_COUNCIL_THRESHOLD="$effective_threshold" \
|
|
360
399
|
python3 -c "
|
|
361
400
|
import json, os
|
|
362
401
|
from datetime import datetime, timezone
|
|
@@ -387,7 +426,7 @@ with open(state_file, 'w') as f:
|
|
|
387
426
|
" || log_warn "Failed to record council vote results"
|
|
388
427
|
|
|
389
428
|
echo ""
|
|
390
|
-
log_info "Council verdict: $approve_count APPROVE / $reject_count REJECT (threshold: $
|
|
429
|
+
log_info "Council verdict: $approve_count APPROVE / $reject_count REJECT (threshold: $effective_threshold)"
|
|
391
430
|
echo -e "$verdicts"
|
|
392
431
|
echo ""
|
|
393
432
|
|
|
@@ -396,10 +435,10 @@ with open(state_file, 'w') as f:
|
|
|
396
435
|
"iteration=$ITERATION_COUNT" \
|
|
397
436
|
"approve=$approve_count" \
|
|
398
437
|
"reject=$reject_count" \
|
|
399
|
-
"threshold=$
|
|
400
|
-
"result=$([ $approve_count -ge $
|
|
438
|
+
"threshold=$effective_threshold" \
|
|
439
|
+
"result=$([ $approve_count -ge $effective_threshold ] && echo 'APPROVED' || echo 'REJECTED')" 2>/dev/null || true
|
|
401
440
|
|
|
402
|
-
if [ $approve_count -ge $
|
|
441
|
+
if [ $approve_count -ge $effective_threshold ]; then
|
|
403
442
|
return 0 # Council says DONE
|
|
404
443
|
fi
|
|
405
444
|
return 1 # Council says CONTINUE
|
|
@@ -754,27 +793,27 @@ ISSUES: CRITICAL:description (optional, one per line per issue)"
|
|
|
754
793
|
claude)
|
|
755
794
|
if command -v claude &>/dev/null; then
|
|
756
795
|
local council_model="${PROVIDER_MODEL_FAST:-haiku}"
|
|
757
|
-
verdict=$(echo "$prompt" | claude --model "$council_model" -p 2>/dev/null | tail -
|
|
796
|
+
verdict=$(echo "$prompt" | claude --model "$council_model" -p 2>/dev/null | tail -20)
|
|
758
797
|
fi
|
|
759
798
|
;;
|
|
760
799
|
codex)
|
|
761
800
|
if command -v codex &>/dev/null; then
|
|
762
|
-
verdict=$(codex exec --full-auto "$prompt" 2>/dev/null | tail -
|
|
801
|
+
verdict=$(codex exec --full-auto "$prompt" 2>/dev/null | tail -20)
|
|
763
802
|
fi
|
|
764
803
|
;;
|
|
765
804
|
gemini)
|
|
766
805
|
if command -v gemini &>/dev/null; then
|
|
767
|
-
verdict=$(echo "$prompt" | gemini 2>/dev/null | tail -
|
|
806
|
+
verdict=$(echo "$prompt" | gemini 2>/dev/null | tail -20)
|
|
768
807
|
fi
|
|
769
808
|
;;
|
|
770
809
|
cline)
|
|
771
810
|
if command -v cline &>/dev/null; then
|
|
772
|
-
verdict=$(cline -y "$prompt" 2>/dev/null | tail -
|
|
811
|
+
verdict=$(cline -y "$prompt" 2>/dev/null | tail -20)
|
|
773
812
|
fi
|
|
774
813
|
;;
|
|
775
814
|
aider)
|
|
776
815
|
if command -v aider &>/dev/null; then
|
|
777
|
-
verdict=$(aider --message "$prompt" --yes-always --no-auto-commits --no-git 2>/dev/null | tail -
|
|
816
|
+
verdict=$(aider --message "$prompt" --yes-always --no-auto-commits --no-git 2>/dev/null | tail -20)
|
|
778
817
|
fi
|
|
779
818
|
;;
|
|
780
819
|
esac
|
|
@@ -808,19 +847,13 @@ council_devils_advocate() {
|
|
|
808
847
|
local evidence
|
|
809
848
|
evidence=$(cat "$evidence_file" 2>/dev/null || echo "No evidence available")
|
|
810
849
|
|
|
811
|
-
#
|
|
812
|
-
|
|
813
|
-
for f in "$vote_dir"/member-*.txt; do
|
|
814
|
-
[ -f "$f" ] && prev_verdicts="${prev_verdicts}\n$(cat "$f")"
|
|
815
|
-
done
|
|
850
|
+
# BUG-QG-009: Do NOT show prior verdicts to devil's advocate (blind review)
|
|
851
|
+
# Previous code read member-*.txt files here, biasing the contrarian reviewer
|
|
816
852
|
|
|
817
853
|
local prompt="ANTI-SYCOPHANCY CHECK: All council members unanimously APPROVED this project.
|
|
818
854
|
|
|
819
855
|
Your job is to be the CONTRARIAN. Find ANY reason this should NOT be approved.
|
|
820
856
|
|
|
821
|
-
Previous verdicts:
|
|
822
|
-
${prev_verdicts}
|
|
823
|
-
|
|
824
857
|
EVIDENCE:
|
|
825
858
|
${evidence}
|
|
826
859
|
|
|
@@ -843,27 +876,27 @@ REASON: your reasoning"
|
|
|
843
876
|
claude)
|
|
844
877
|
if command -v claude &>/dev/null; then
|
|
845
878
|
local council_model="${PROVIDER_MODEL_FAST:-haiku}"
|
|
846
|
-
verdict=$(echo "$prompt" | claude --model "$council_model" -p 2>/dev/null | tail -
|
|
879
|
+
verdict=$(echo "$prompt" | claude --model "$council_model" -p 2>/dev/null | tail -20)
|
|
847
880
|
fi
|
|
848
881
|
;;
|
|
849
882
|
codex)
|
|
850
883
|
if command -v codex &>/dev/null; then
|
|
851
|
-
verdict=$(codex exec --full-auto "$prompt" 2>/dev/null | tail -
|
|
884
|
+
verdict=$(codex exec --full-auto "$prompt" 2>/dev/null | tail -20)
|
|
852
885
|
fi
|
|
853
886
|
;;
|
|
854
887
|
gemini)
|
|
855
888
|
if command -v gemini &>/dev/null; then
|
|
856
|
-
verdict=$(echo "$prompt" | gemini 2>/dev/null | tail -
|
|
889
|
+
verdict=$(echo "$prompt" | gemini 2>/dev/null | tail -20)
|
|
857
890
|
fi
|
|
858
891
|
;;
|
|
859
892
|
cline)
|
|
860
893
|
if command -v cline &>/dev/null; then
|
|
861
|
-
verdict=$(cline -y "$prompt" 2>/dev/null | tail -
|
|
894
|
+
verdict=$(cline -y "$prompt" 2>/dev/null | tail -20)
|
|
862
895
|
fi
|
|
863
896
|
;;
|
|
864
897
|
aider)
|
|
865
898
|
if command -v aider &>/dev/null; then
|
|
866
|
-
verdict=$(aider --message "$prompt" --yes-always --no-auto-commits --no-git 2>/dev/null | tail -
|
|
899
|
+
verdict=$(aider --message "$prompt" --yes-always --no-auto-commits --no-git 2>/dev/null | tail -20)
|
|
867
900
|
fi
|
|
868
901
|
;;
|
|
869
902
|
esac
|
|
@@ -985,10 +1018,15 @@ council_evaluate_member() {
|
|
|
985
1018
|
# If code is still changing, work may not be done
|
|
986
1019
|
local current_diff_hash
|
|
987
1020
|
current_diff_hash=$(git diff --stat HEAD 2>/dev/null | (md5sum 2>/dev/null || md5 -r 2>/dev/null) | cut -d' ' -f1 || echo "unknown")
|
|
988
|
-
if [ "$COUNCIL_CONSECUTIVE_NO_CHANGE" -
|
|
989
|
-
# Code
|
|
990
|
-
|
|
991
|
-
|
|
1021
|
+
if [ "$COUNCIL_CONSECUTIVE_NO_CHANGE" -gt 0 ] && [ "$ITERATION_COUNT" -gt "$COUNCIL_MIN_ITERATIONS" ]; then
|
|
1022
|
+
# Code has stopped changing -- stagnation, not necessarily done
|
|
1023
|
+
# (BUG-QG-011: previously inverted -- forced CONTINUE when code was changing,
|
|
1024
|
+
# which penalized active progress. Now: stagnation with no passing checks = CONTINUE)
|
|
1025
|
+
if [ "$vote" = "COMPLETE" ]; then
|
|
1026
|
+
: # Other checks passed despite stagnation -- allow COMPLETE
|
|
1027
|
+
else
|
|
1028
|
+
reasons="${reasons}code stagnated with failing checks; "
|
|
1029
|
+
fi
|
|
992
1030
|
fi
|
|
993
1031
|
|
|
994
1032
|
# Check 3: Are there uncaught errors in logs?
|
|
@@ -1296,7 +1334,7 @@ council_evaluate() {
|
|
|
1296
1334
|
complete_count=$(_RF="$round_file" python3 -c "import json, os; print(json.load(open(os.environ['_RF'])).get('complete_votes', 0))" 2>/dev/null || echo "0")
|
|
1297
1335
|
fi
|
|
1298
1336
|
|
|
1299
|
-
if [ "$complete_count" -eq "$COUNCIL_SIZE" ] && [ "$COUNCIL_SIZE" -ge
|
|
1337
|
+
if [ "$complete_count" -eq "$COUNCIL_SIZE" ] && [ "$COUNCIL_SIZE" -ge 2 ]; then
|
|
1300
1338
|
# Step 3: Unanimous -- run devil's advocate
|
|
1301
1339
|
local da_result
|
|
1302
1340
|
da_result=$(council_devils_advocate_review "$ITERATION_COUNT")
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
|
|
32
32
|
set -euo pipefail
|
|
33
33
|
|
|
34
|
+
# shellcheck disable=SC2034
|
|
34
35
|
HOOKS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
35
36
|
|
|
36
37
|
# Load project-specific hook config if it exists
|
|
@@ -38,14 +39,22 @@ load_migration_hook_config() {
|
|
|
38
39
|
local codebase_path="${1:-.}"
|
|
39
40
|
local config_file="${codebase_path}/.loki/migration-hooks.yaml"
|
|
40
41
|
|
|
41
|
-
# Defaults
|
|
42
|
+
# Defaults (used by other functions in this file; SC2034 disabled for globals-via-function pattern)
|
|
43
|
+
# shellcheck disable=SC2034
|
|
42
44
|
HOOK_POST_FILE_EDIT_ENABLED=true
|
|
45
|
+
# shellcheck disable=SC2034
|
|
43
46
|
HOOK_POST_STEP_ENABLED=true
|
|
47
|
+
# shellcheck disable=SC2034
|
|
44
48
|
HOOK_PRE_PHASE_GATE_ENABLED=true
|
|
49
|
+
# shellcheck disable=SC2034
|
|
45
50
|
HOOK_ON_AGENT_STOP_ENABLED=true
|
|
51
|
+
# shellcheck disable=SC2034
|
|
46
52
|
HOOK_POST_FILE_EDIT_ACTION="run_tests"
|
|
53
|
+
# shellcheck disable=SC2034
|
|
47
54
|
HOOK_POST_FILE_EDIT_ON_FAILURE="block_and_rollback"
|
|
55
|
+
# shellcheck disable=SC2034
|
|
48
56
|
HOOK_POST_STEP_ON_FAILURE="reject_completion"
|
|
57
|
+
# shellcheck disable=SC2034
|
|
49
58
|
HOOK_ON_AGENT_STOP_ON_FAILURE="force_continue"
|
|
50
59
|
|
|
51
60
|
if [[ -f "$config_file" ]] && command -v python3 &>/dev/null; then
|
package/autonomy/issue-parser.sh
CHANGED
|
@@ -258,8 +258,7 @@ parse_github_issue() {
|
|
|
258
258
|
|
|
259
259
|
# Parse the reference
|
|
260
260
|
local parsed_ref
|
|
261
|
-
parsed_ref=$(parse_issue_ref "$issue_ref")
|
|
262
|
-
if [ $? -ne 0 ]; then
|
|
261
|
+
if ! parsed_ref=$(parse_issue_ref "$issue_ref"); then
|
|
263
262
|
return 1
|
|
264
263
|
fi
|
|
265
264
|
|
|
@@ -272,9 +271,7 @@ parse_github_issue() {
|
|
|
272
271
|
|
|
273
272
|
# Fetch issue data
|
|
274
273
|
local issue_data
|
|
275
|
-
issue_data=$(gh issue view "$number" --repo "$owner/$repo" --json number,title,body,labels,assignees,milestone,state,url,createdAt,author 2>&1)
|
|
276
|
-
|
|
277
|
-
if [ $? -ne 0 ]; then
|
|
274
|
+
if ! issue_data=$(gh issue view "$number" --repo "$owner/$repo" --json number,title,body,labels,assignees,milestone,state,url,createdAt,author 2>&1); then
|
|
278
275
|
log_error "Failed to fetch issue: $issue_data"
|
|
279
276
|
return 1
|
|
280
277
|
fi
|
|
@@ -612,8 +609,8 @@ main() {
|
|
|
612
609
|
|
|
613
610
|
# Parse the issue
|
|
614
611
|
local result
|
|
615
|
-
|
|
616
|
-
|
|
612
|
+
local exit_code=0
|
|
613
|
+
result=$(parse_github_issue "$issue_ref" "$format") || exit_code=$?
|
|
617
614
|
|
|
618
615
|
if [ $exit_code -ne 0 ]; then
|
|
619
616
|
exit $exit_code
|
|
@@ -15,14 +15,19 @@
|
|
|
15
15
|
# JSON with normalized fields: provider, number, title, body, labels, author, url, created_at
|
|
16
16
|
#===============================================================================
|
|
17
17
|
|
|
18
|
-
# Colors (safe to re-source)
|
|
18
|
+
# Colors (safe to re-source; used by scripts that source this file)
|
|
19
|
+
# shellcheck disable=SC2034
|
|
19
20
|
RED='\033[0;31m'
|
|
21
|
+
# shellcheck disable=SC2034
|
|
20
22
|
GREEN='\033[0;32m'
|
|
23
|
+
# shellcheck disable=SC2034
|
|
21
24
|
YELLOW='\033[1;33m'
|
|
25
|
+
# shellcheck disable=SC2034
|
|
22
26
|
CYAN='\033[0;36m'
|
|
23
27
|
NC='\033[0m'
|
|
24
28
|
|
|
25
|
-
# Supported issue providers
|
|
29
|
+
# Supported issue providers (exported for sourcing scripts)
|
|
30
|
+
# shellcheck disable=SC2034
|
|
26
31
|
ISSUE_PROVIDERS=("github" "gitlab" "jira" "azure_devops")
|
|
27
32
|
|
|
28
33
|
# Detect issue provider from a URL or reference
|