loki-mode 6.66.0 → 6.67.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.
@@ -320,12 +320,13 @@ def check_compaction_frequency(trigger, loki_dir, iteration, notifications):
320
320
  return None
321
321
 
322
322
  max_per_hour = trigger.get("max_per_hour", 3)
323
- now = time.time()
324
- one_hour_ago = now - 3600
323
+ one_hour_ago_str = datetime.fromtimestamp(
324
+ time.time() - 3600, tz=timezone.utc
325
+ ).isoformat()
325
326
 
326
327
  recent = [
327
328
  c for c in compactions
328
- if c.get("timestamp", "") > datetime.fromtimestamp(one_hour_ago, tz=timezone.utc).isoformat()
329
+ if c.get("timestamp", "") >= one_hour_ago_str
329
330
  ]
330
331
 
331
332
  if len(recent) >= max_per_hour:
package/autonomy/run.sh CHANGED
@@ -1699,7 +1699,10 @@ import_github_issues() {
1699
1699
  temp_file=$(mktemp ".loki/queue/pending.json.tmp.XXXXXX")
1700
1700
  local lockfile=".loki/queue/.pending.lock"
1701
1701
  (
1702
- flock -w 5 200 2>/dev/null || true
1702
+ if ! flock -w 5 200 2>/dev/null; then
1703
+ log_warn "Could not acquire queue lock for issue #$number, skipping"
1704
+ exit 1
1705
+ fi
1703
1706
  if jq ". += [$task_json]" "$pending_file" > "$temp_file" && mv "$temp_file" "$pending_file"; then
1704
1707
  log_info "Imported issue #$number: $title"
1705
1708
  task_count=$((task_count + 1))
@@ -3074,10 +3077,11 @@ invoke_cline() {
3074
3077
  local prompt="$1"
3075
3078
  shift
3076
3079
  local model="${LOKI_CLINE_MODEL:-}"
3077
- local model_flag=""
3078
- [[ -n "$model" ]] && model_flag="-m $model"
3079
- # shellcheck disable=SC2086
3080
- cline -y $model_flag "$prompt" "$@" 2>&1
3080
+ if [[ -n "$model" ]]; then
3081
+ cline -y -m "$model" "$prompt" "$@" 2>&1
3082
+ else
3083
+ cline -y "$prompt" "$@" 2>&1
3084
+ fi
3081
3085
  }
3082
3086
 
3083
3087
  # Invoke Cline and capture output (for variable assignment)
@@ -3086,10 +3090,11 @@ invoke_cline_capture() {
3086
3090
  local prompt="$1"
3087
3091
  shift
3088
3092
  local model="${LOKI_CLINE_MODEL:-}"
3089
- local model_flag=""
3090
- [[ -n "$model" ]] && model_flag="-m $model"
3091
- # shellcheck disable=SC2086
3092
- cline -y $model_flag "$prompt" "$@" 2>&1
3093
+ if [[ -n "$model" ]]; then
3094
+ cline -y -m "$model" "$prompt" "$@" 2>&1
3095
+ else
3096
+ cline -y "$prompt" "$@" 2>&1
3097
+ fi
3093
3098
  }
3094
3099
 
3095
3100
  #===============================================================================
@@ -5711,6 +5716,12 @@ SPECIALISTS = {
5711
5716
  "focus": "Outdated packages, CVEs, bloat, unused deps, license issues",
5712
5717
  "checks": "outdated dependencies, known CVEs, unnecessary imports, dependency bloat, license compatibility, unused packages",
5713
5718
  "priority": 3
5719
+ },
5720
+ "legacy-healing-auditor": {
5721
+ "keywords": ["legacy", "heal", "migrate", "cobol", "fortran", "refactor", "modernize", "deprecat", "adapter", "friction", "characterization"],
5722
+ "focus": "Behavioral preservation, friction safety, institutional knowledge retention",
5723
+ "checks": "behavioral change without characterization test, removal of quirky code without friction map check, missing adapter layer for replaced components, institutional knowledge loss (deleted comments, removed error messages), breaking changes to undocumented APIs",
5724
+ "priority": 4
5714
5725
  }
5715
5726
  }
5716
5727
 
@@ -9299,7 +9310,8 @@ run_autonomous() {
9299
9310
  # Auto-track iteration start (for dashboard task queue)
9300
9311
  track_iteration_start "$ITERATION_COUNT" "$prd_path"
9301
9312
 
9302
- local prompt=$(build_prompt $retry "$prd_path" $ITERATION_COUNT)
9313
+ local prompt
9314
+ prompt=$(build_prompt "$retry" "$prd_path" "$ITERATION_COUNT")
9303
9315
 
9304
9316
  # BUG #5 fix: Clear LOKI_HUMAN_INPUT in the parent shell after build_prompt
9305
9317
  # consumed it. build_prompt runs in a subshell (command substitution), so
@@ -0,0 +1,471 @@
1
+ #!/usr/bin/env bash
2
+ # shellcheck disable=SC2034 # Variables exported for consumers that source this library
3
+ #===============================================================================
4
+ # Loki Mode TUI Library
5
+ # Rich terminal output: spinners, progress bars, tables, boxes, diffs
6
+ #
7
+ # Inspired by Kiro CLI's TUI (kiro.dev/changelog/cli/1-24)
8
+ # Source: arXiv:2602.22518 (RepoMod-Bench) for progress visualization patterns
9
+ #
10
+ # Usage:
11
+ # source "$(dirname "${BASH_SOURCE[0]}")/tui.sh"
12
+ # spinner_start "Analyzing codebase..."
13
+ # spinner_stop
14
+ # progress_bar 75 100 "Files processed"
15
+ # draw_box "Title" "Content here"
16
+ #===============================================================================
17
+
18
+ # Guard against double-sourcing
19
+ [[ -n "${_LOKI_TUI_LOADED:-}" ]] && return 0
20
+ _LOKI_TUI_LOADED=1
21
+
22
+ # Terminal capabilities
23
+ TUI_HAS_COLOR=false
24
+ TUI_COLS=80
25
+ if [ -t 1 ]; then
26
+ TUI_HAS_COLOR=true
27
+ TUI_COLS=$(tput cols 2>/dev/null || echo 80)
28
+ fi
29
+
30
+ # Unicode box drawing (degrade to ASCII if terminal doesn't support)
31
+ if echo -e "\xe2\x94\x80" 2>/dev/null | grep -q "─" 2>/dev/null; then
32
+ BOX_H="─"
33
+ BOX_V="│"
34
+ BOX_TL="┌"
35
+ BOX_TR="┐"
36
+ BOX_BL="└"
37
+ BOX_BR="┘"
38
+ BOX_ML="├"
39
+ BOX_MR="┤"
40
+ BULLET=">"
41
+ CHECK_MARK="[ok]"
42
+ CROSS_MARK="[!!]"
43
+ ARROW_R="->"
44
+ SPINNER_CHARS=("/" "-" "\\" "|")
45
+ BAR_FILL="="
46
+ BAR_EMPTY="-"
47
+ else
48
+ BOX_H="-"
49
+ BOX_V="|"
50
+ BOX_TL="+"
51
+ BOX_TR="+"
52
+ BOX_BL="+"
53
+ BOX_BR="+"
54
+ BOX_ML="+"
55
+ BOX_MR="+"
56
+ BULLET=">"
57
+ CHECK_MARK="[ok]"
58
+ CROSS_MARK="[!!]"
59
+ ARROW_R="->"
60
+ SPINNER_CHARS=("/" "-" "\\" "|")
61
+ BAR_FILL="="
62
+ BAR_EMPTY="-"
63
+ fi
64
+
65
+ # Colors (only if terminal supports)
66
+ if $TUI_HAS_COLOR; then
67
+ TUI_RED='\033[0;31m'
68
+ TUI_GREEN='\033[0;32m'
69
+ TUI_YELLOW='\033[1;33m'
70
+ TUI_BLUE='\033[0;34m'
71
+ TUI_CYAN='\033[0;36m'
72
+ TUI_MAGENTA='\033[0;35m'
73
+ TUI_BOLD='\033[1m'
74
+ TUI_DIM='\033[2m'
75
+ TUI_NC='\033[0m'
76
+ TUI_UNDERLINE='\033[4m'
77
+ TUI_REVERSE='\033[7m'
78
+ # Model-specific colors (matching dashboard theme)
79
+ TUI_OPUS='\033[0;33m' # amber
80
+ TUI_SONNET='\033[0;35m' # purple
81
+ TUI_HAIKU='\033[0;36m' # teal
82
+ else
83
+ TUI_RED='' TUI_GREEN='' TUI_YELLOW='' TUI_BLUE='' TUI_CYAN=''
84
+ TUI_MAGENTA='' TUI_BOLD='' TUI_DIM='' TUI_NC='' TUI_UNDERLINE=''
85
+ TUI_REVERSE='' TUI_OPUS='' TUI_SONNET='' TUI_HAIKU=''
86
+ fi
87
+
88
+ #--- Spinner -------------------------------------------------------------------
89
+
90
+ _SPINNER_PID=""
91
+ _SPINNER_MSG=""
92
+
93
+ spinner_start() {
94
+ local msg="${1:-Working...}"
95
+ _SPINNER_MSG="$msg"
96
+
97
+ # Don't spin in non-interactive terminals
98
+ if ! [ -t 1 ]; then
99
+ echo "$msg"
100
+ return
101
+ fi
102
+
103
+ (
104
+ local i=0
105
+ while true; do
106
+ local char="${SPINNER_CHARS[$((i % ${#SPINNER_CHARS[@]}))]}"
107
+ printf "\r${TUI_CYAN}%s${TUI_NC} %s" "$char" "$msg" >&2
108
+ sleep 0.1
109
+ i=$((i + 1))
110
+ done
111
+ ) &
112
+ _SPINNER_PID=$!
113
+ disown $_SPINNER_PID 2>/dev/null
114
+ }
115
+
116
+ spinner_stop() {
117
+ local result="${1:-done}"
118
+ if [ -n "$_SPINNER_PID" ]; then
119
+ kill "$_SPINNER_PID" 2>/dev/null
120
+ wait "$_SPINNER_PID" 2>/dev/null
121
+ _SPINNER_PID=""
122
+ fi
123
+ if [ -t 1 ]; then
124
+ printf "\r${TUI_GREEN}${CHECK_MARK}${TUI_NC} %s ${TUI_DIM}(%s)${TUI_NC}\n" "$_SPINNER_MSG" "$result" >&2
125
+ fi
126
+ }
127
+
128
+ spinner_fail() {
129
+ local reason="${1:-failed}"
130
+ if [ -n "$_SPINNER_PID" ]; then
131
+ kill "$_SPINNER_PID" 2>/dev/null
132
+ wait "$_SPINNER_PID" 2>/dev/null
133
+ _SPINNER_PID=""
134
+ fi
135
+ if [ -t 1 ]; then
136
+ printf "\r${TUI_RED}${CROSS_MARK}${TUI_NC} %s ${TUI_RED}(%s)${TUI_NC}\n" "$_SPINNER_MSG" "$reason" >&2
137
+ fi
138
+ }
139
+
140
+ #--- Progress Bar --------------------------------------------------------------
141
+
142
+ progress_bar() {
143
+ local current="$1"
144
+ local total="$2"
145
+ local label="${3:-Progress}"
146
+ local width="${4:-40}"
147
+
148
+ if [ "$total" -eq 0 ]; then
149
+ return
150
+ fi
151
+
152
+ local pct=$((current * 100 / total))
153
+ local filled=$((current * width / total))
154
+ local empty=$((width - filled))
155
+
156
+ local bar=""
157
+ for ((i=0; i<filled; i++)); do bar+="$BAR_FILL"; done
158
+ for ((i=0; i<empty; i++)); do bar+="$BAR_EMPTY"; done
159
+
160
+ # Color based on percentage
161
+ local color="$TUI_RED"
162
+ if [ "$pct" -ge 80 ]; then color="$TUI_GREEN"
163
+ elif [ "$pct" -ge 50 ]; then color="$TUI_YELLOW"
164
+ elif [ "$pct" -ge 25 ]; then color="$TUI_BLUE"
165
+ fi
166
+
167
+ printf "\r %s ${color}[%s]${TUI_NC} %3d%% (%d/%d)" "$label" "$bar" "$pct" "$current" "$total"
168
+ }
169
+
170
+ progress_bar_done() {
171
+ echo "" # newline after progress bar
172
+ }
173
+
174
+ #--- Context Window Gauge ------------------------------------------------------
175
+
176
+ context_gauge() {
177
+ local used="$1" # tokens used
178
+ local total="$2" # context window size
179
+ local label="${3:-Context}"
180
+ local width=30
181
+
182
+ if [ "$total" -eq 0 ]; then return; fi
183
+
184
+ local pct=$((used * 100 / total))
185
+ local filled=$((used * width / total))
186
+ [ "$filled" -gt "$width" ] && filled="$width"
187
+ local empty=$((width - filled))
188
+
189
+ # Color: green < 50%, yellow < 80%, red >= 80%
190
+ local color="$TUI_GREEN"
191
+ if [ "$pct" -ge 80 ]; then color="$TUI_RED"
192
+ elif [ "$pct" -ge 50 ]; then color="$TUI_YELLOW"
193
+ fi
194
+
195
+ local bar=""
196
+ for ((i=0; i<filled; i++)); do bar+="$BAR_FILL"; done
197
+ for ((i=0; i<empty; i++)); do bar+=" "; done
198
+
199
+ local used_fmt
200
+ local total_fmt
201
+ used_fmt=$(format_tokens "$used")
202
+ total_fmt=$(format_tokens "$total")
203
+
204
+ echo -e " ${TUI_BOLD}$label${TUI_NC} ${color}[${bar}]${TUI_NC} ${pct}% (${used_fmt} / ${total_fmt})"
205
+ }
206
+
207
+ format_tokens() {
208
+ local n="$1"
209
+ if [ "$n" -ge 1000000 ]; then
210
+ printf "%.1fM" "$(echo "scale=1; $n / 1000000" | bc 2>/dev/null || echo "$n")"
211
+ elif [ "$n" -ge 1000 ]; then
212
+ printf "%.1fK" "$(echo "scale=1; $n / 1000" | bc 2>/dev/null || echo "$n")"
213
+ else
214
+ echo "$n"
215
+ fi
216
+ }
217
+
218
+ #--- Box Drawing ---------------------------------------------------------------
219
+
220
+ draw_box() {
221
+ local title="$1"
222
+ shift
223
+ local content="$*"
224
+ local inner_width=$((TUI_COLS - 4))
225
+ [ "$inner_width" -gt 76 ] && inner_width=76
226
+
227
+ # Top border with title
228
+ local title_len=${#title}
229
+ local padding=$((inner_width - title_len - 2))
230
+ [ "$padding" -lt 0 ] && padding=0
231
+
232
+ local top_line="${BOX_TL}"
233
+ top_line+="${BOX_H} ${TUI_BOLD}${title}${TUI_NC} "
234
+ for ((i=0; i<padding; i++)); do top_line+="${BOX_H}"; done
235
+ top_line+="${BOX_TR}"
236
+ echo -e "$top_line"
237
+
238
+ # Content lines
239
+ while IFS= read -r line; do
240
+ local line_plain
241
+ line_plain=$(echo -e "$line" | sed 's/\x1b\[[0-9;]*m//g')
242
+ local line_len=${#line_plain}
243
+ local pad=$((inner_width - line_len))
244
+ [ "$pad" -lt 0 ] && pad=0
245
+ local spaces=""
246
+ for ((i=0; i<pad; i++)); do spaces+=" "; done
247
+ echo -e "${BOX_V} ${line}${spaces} ${BOX_V}"
248
+ done <<< "$content"
249
+
250
+ # Bottom border
251
+ local bottom_line="${BOX_BL}"
252
+ for ((i=0; i<inner_width+2; i++)); do bottom_line+="${BOX_H}"; done
253
+ bottom_line+="${BOX_BR}"
254
+ echo -e "$bottom_line"
255
+ }
256
+
257
+ #--- Table Rendering -----------------------------------------------------------
258
+
259
+ # Usage: table_render "Col1|Col2|Col3" "val1|val2|val3" "val4|val5|val6"
260
+ table_render() {
261
+ local header="$1"
262
+ shift
263
+ local rows=("$@")
264
+
265
+ # Calculate column widths
266
+ IFS='|' read -ra hcols <<< "$header"
267
+ local ncols=${#hcols[@]}
268
+ local -a widths=()
269
+ for ((i=0; i<ncols; i++)); do
270
+ widths[$i]=${#hcols[$i]}
271
+ done
272
+
273
+ for row in "${rows[@]}"; do
274
+ IFS='|' read -ra rcols <<< "$row"
275
+ for ((i=0; i<ncols; i++)); do
276
+ local cell="${rcols[$i]:-}"
277
+ local clen=${#cell}
278
+ if [ "$clen" -gt "${widths[$i]}" ]; then
279
+ widths[$i]=$clen
280
+ fi
281
+ done
282
+ done
283
+
284
+ # Header
285
+ local hline=" "
286
+ local sep=" "
287
+ for ((i=0; i<ncols; i++)); do
288
+ local w=${widths[$i]}
289
+ hline+=$(printf "${TUI_BOLD}%-${w}s${TUI_NC} " "${hcols[$i]}")
290
+ local dashes=""
291
+ for ((j=0; j<w; j++)); do dashes+="-"; done
292
+ sep+=$(printf "%s " "$dashes")
293
+ done
294
+ echo -e "$hline"
295
+ echo -e "${TUI_DIM}$sep${TUI_NC}"
296
+
297
+ # Rows
298
+ for row in "${rows[@]}"; do
299
+ IFS='|' read -ra rcols <<< "$row"
300
+ local rline=" "
301
+ for ((i=0; i<ncols; i++)); do
302
+ local w=${widths[$i]}
303
+ rline+=$(printf "%-${w}s " "${rcols[$i]:-}")
304
+ done
305
+ echo -e "$rline"
306
+ done
307
+ }
308
+
309
+ #--- Diff Display (colored) ----------------------------------------------------
310
+
311
+ diff_colored() {
312
+ local file1="$1"
313
+ local file2="$2"
314
+
315
+ if command -v delta &>/dev/null; then
316
+ delta "$file1" "$file2"
317
+ elif command -v diff &>/dev/null; then
318
+ diff -u "$file1" "$file2" | while IFS= read -r line; do
319
+ case "$line" in
320
+ ---*) echo -e "${TUI_BOLD}${line}${TUI_NC}" ;;
321
+ +++*) echo -e "${TUI_BOLD}${line}${TUI_NC}" ;;
322
+ @@*) echo -e "${TUI_CYAN}${line}${TUI_NC}" ;;
323
+ +*) echo -e "${TUI_GREEN}${line}${TUI_NC}" ;;
324
+ -*) echo -e "${TUI_RED}${line}${TUI_NC}" ;;
325
+ *) echo "$line" ;;
326
+ esac
327
+ done
328
+ fi
329
+ }
330
+
331
+ # Inline diff from string
332
+ diff_inline() {
333
+ local label="$1"
334
+ local old_val="$2"
335
+ local new_val="$3"
336
+ echo -e " ${label}: ${TUI_RED}${old_val}${TUI_NC} ${ARROW_R} ${TUI_GREEN}${new_val}${TUI_NC}"
337
+ }
338
+
339
+ #--- Status Line ---------------------------------------------------------------
340
+
341
+ status_line() {
342
+ local phase="$1"
343
+ local iteration="$2"
344
+ local model="$3"
345
+ local context_pct="${4:-0}"
346
+
347
+ # Model color
348
+ local model_color="$TUI_NC"
349
+ case "$model" in
350
+ *opus*) model_color="$TUI_OPUS" ;;
351
+ *sonnet*) model_color="$TUI_SONNET" ;;
352
+ *haiku*) model_color="$TUI_HAIKU" ;;
353
+ esac
354
+
355
+ # Context color
356
+ local ctx_color="$TUI_GREEN"
357
+ if [ "$context_pct" -ge 80 ]; then ctx_color="$TUI_RED"
358
+ elif [ "$context_pct" -ge 50 ]; then ctx_color="$TUI_YELLOW"
359
+ fi
360
+
361
+ printf "${TUI_DIM}[${TUI_NC}${TUI_BOLD}%s${TUI_NC}${TUI_DIM}]${TUI_NC} " "$phase"
362
+ printf "iter:%s " "$iteration"
363
+ printf "${model_color}%s${TUI_NC} " "$model"
364
+ printf "${ctx_color}ctx:%d%%${TUI_NC}" "$context_pct"
365
+ echo ""
366
+ }
367
+
368
+ #--- Section Headers -----------------------------------------------------------
369
+
370
+ section_header() {
371
+ local title="$1"
372
+ local width=${2:-$TUI_COLS}
373
+ [ "$width" -gt 80 ] && width=80
374
+
375
+ echo ""
376
+ echo -e "${TUI_BOLD}${title}${TUI_NC}"
377
+ local line=""
378
+ for ((i=0; i<${#title}; i++)); do line+="${BOX_H}"; done
379
+ echo -e "${TUI_DIM}${line}${TUI_NC}"
380
+ }
381
+
382
+ #--- Token Cost Display --------------------------------------------------------
383
+
384
+ display_token_cost() {
385
+ local model="$1"
386
+ local input_tokens="$2"
387
+ local output_tokens="$3"
388
+
389
+ # Pricing per 1M tokens (March 2026 rates)
390
+ local input_rate=0
391
+ local output_rate=0
392
+ case "$model" in
393
+ *opus*) input_rate=15.0; output_rate=75.0 ;;
394
+ *sonnet*) input_rate=3.0; output_rate=15.0 ;;
395
+ *haiku*) input_rate=0.25; output_rate=1.25 ;;
396
+ *gpt-4o*) input_rate=2.5; output_rate=10.0 ;;
397
+ *gpt-4o-mini*) input_rate=0.15; output_rate=0.6 ;;
398
+ *) input_rate=3.0; output_rate=15.0 ;; # default sonnet-like
399
+ esac
400
+
401
+ local input_cost
402
+ local output_cost
403
+ input_cost=$(echo "scale=4; $input_tokens * $input_rate / 1000000" | bc 2>/dev/null || echo "0")
404
+ output_cost=$(echo "scale=4; $output_tokens * $output_rate / 1000000" | bc 2>/dev/null || echo "0")
405
+ local total_cost
406
+ total_cost=$(echo "scale=4; $input_cost + $output_cost" | bc 2>/dev/null || echo "0")
407
+
408
+ local in_fmt out_fmt
409
+ in_fmt=$(format_tokens "$input_tokens")
410
+ out_fmt=$(format_tokens "$output_tokens")
411
+
412
+ echo -e " ${TUI_DIM}Input:${TUI_NC} ${in_fmt} tokens (\$${input_cost})"
413
+ echo -e " ${TUI_DIM}Output:${TUI_NC} ${out_fmt} tokens (\$${output_cost})"
414
+ echo -e " ${TUI_DIM}Total:${TUI_NC} \$${total_cost}"
415
+ }
416
+
417
+ #--- Tree Display --------------------------------------------------------------
418
+
419
+ # Display a directory tree (simple, no external deps)
420
+ tree_display() {
421
+ local dir="${1:-.}"
422
+ local prefix="${2:-}"
423
+ local depth="${3:-3}"
424
+
425
+ if [ "$depth" -le 0 ]; then
426
+ echo "${prefix}..."
427
+ return
428
+ fi
429
+
430
+ local items=()
431
+ while IFS= read -r item; do
432
+ [ -n "$item" ] && items+=("$item")
433
+ done < <(ls -1 "$dir" 2>/dev/null | grep -v '^\.' | head -20)
434
+
435
+ local count=${#items[@]}
436
+ local i=0
437
+ for item in "${items[@]}"; do
438
+ i=$((i + 1))
439
+ local connector="${BOX_ML}${BOX_H}${BOX_H}"
440
+ local next_prefix="${prefix}${BOX_V} "
441
+ if [ "$i" -eq "$count" ]; then
442
+ connector="${BOX_BL}${BOX_H}${BOX_H}"
443
+ next_prefix="${prefix} "
444
+ fi
445
+
446
+ if [ -d "$dir/$item" ]; then
447
+ echo -e "${prefix}${connector} ${TUI_BOLD}${item}/${TUI_NC}"
448
+ tree_display "$dir/$item" "$next_prefix" $((depth - 1))
449
+ else
450
+ echo -e "${prefix}${connector} ${item}"
451
+ fi
452
+ done
453
+ }
454
+
455
+ #--- Notification Banner -------------------------------------------------------
456
+
457
+ banner_info() {
458
+ echo -e "${TUI_BLUE}${BOX_H}${BOX_H}${BOX_H} ${TUI_BOLD}$*${TUI_NC}"
459
+ }
460
+
461
+ banner_warn() {
462
+ echo -e "${TUI_YELLOW}${BOX_H}${BOX_H}${BOX_H} ${TUI_BOLD}$*${TUI_NC}"
463
+ }
464
+
465
+ banner_error() {
466
+ echo -e "${TUI_RED}${BOX_H}${BOX_H}${BOX_H} ${TUI_BOLD}$*${TUI_NC}"
467
+ }
468
+
469
+ banner_success() {
470
+ echo -e "${TUI_GREEN}${BOX_H}${BOX_H}${BOX_H} ${TUI_BOLD}$*${TUI_NC}"
471
+ }
package/completions/_loki CHANGED
@@ -91,6 +91,12 @@ function _loki {
91
91
  completions)
92
92
  _arguments '1:shell:(bash zsh)'
93
93
  ;;
94
+ context|ctx)
95
+ _loki_context
96
+ ;;
97
+ code)
98
+ _loki_code
99
+ ;;
94
100
  esac
95
101
  ;;
96
102
  esac
@@ -130,6 +136,8 @@ function _loki_commands {
130
136
  'onboard:Analyze repo and generate CLAUDE.md'
131
137
  'metrics:Session productivity report'
132
138
  'share:Share session report as GitHub Gist'
139
+ 'context:Context window management'
140
+ 'code:Codebase intelligence'
133
141
  'version:Show version'
134
142
  'completions:Output shell completions'
135
143
  'help:Show help'
@@ -343,4 +351,53 @@ function _loki_issue {
343
351
  '1:subcommand:(parse view)'
344
352
  }
345
353
 
354
+ function _loki_context {
355
+ local -a cmds
356
+ cmds=(
357
+ 'show:Show context window usage breakdown'
358
+ 'files:List files in context with token estimates'
359
+ 'tools:Show tool token usage per origin'
360
+ 'add:Add file to context'
361
+ 'clear:Clear accumulated context'
362
+ 'help:Context help'
363
+ )
364
+ _describe -t cmds 'context subcommand' cmds
365
+
366
+ case $line[1] in
367
+ add)
368
+ _files
369
+ ;;
370
+ esac
371
+ }
372
+
373
+ function _loki_code {
374
+ local -a cmds
375
+ cmds=(
376
+ 'overview:Generate workspace overview'
377
+ 'symbols:Search for symbols'
378
+ 'deps:Show dependency graph'
379
+ 'hotspots:Find code hotspots'
380
+ 'diff:Show colored diff'
381
+ 'help:Code help'
382
+ )
383
+ _describe -t cmds 'code subcommand' cmds
384
+
385
+ case $line[1] in
386
+ overview)
387
+ _arguments \
388
+ '--silent[Compact output]' \
389
+ '*:directory:_directories'
390
+ ;;
391
+ deps)
392
+ _files
393
+ ;;
394
+ hotspots)
395
+ _arguments \
396
+ '--top[Number of results]:number:'
397
+ ;;
398
+ symbols)
399
+ ;;
400
+ esac
401
+ }
402
+
346
403
  _loki "$@"
@@ -5,7 +5,7 @@ _loki_completion() {
5
5
  _init_completion || return
6
6
 
7
7
  # Main subcommands (must match autonomy/loki main case statement)
8
- local main_commands="start quick demo init stop pause resume status dashboard logs serve api sandbox notify import github issue config provider reset memory compound checkpoint council dogfood projects enterprise secrets doctor watchdog audit metrics syslog onboard share explain plan report test ci watch telemetry agent version completions help"
8
+ local main_commands="start quick demo init stop pause resume status dashboard logs serve api sandbox notify import github issue config provider reset memory compound checkpoint council dogfood projects enterprise secrets doctor watchdog audit metrics syslog onboard share explain plan report test ci watch telemetry agent context code run export review optimize heal migrate cluster worktree trigger failover remote version completions help"
9
9
 
10
10
  # 1. If we are on the first argument (subcommand)
11
11
  if [[ $cword -eq 1 ]]; then
@@ -181,6 +181,44 @@ _loki_completion() {
181
181
  completions)
182
182
  COMPREPLY=( $(compgen -W "bash zsh" -- "$cur") )
183
183
  ;;
184
+
185
+ context|ctx)
186
+ if [[ $cword -eq 2 ]]; then
187
+ COMPREPLY=( $(compgen -W "show files tools add clear help" -- "$cur") )
188
+ return 0
189
+ fi
190
+ if [[ "${words[2]}" == "add" ]]; then
191
+ COMPREPLY=( $(compgen -f -- "$cur") )
192
+ return 0
193
+ fi
194
+ ;;
195
+
196
+ code)
197
+ if [[ $cword -eq 2 ]]; then
198
+ COMPREPLY=( $(compgen -W "overview symbols deps hotspots diff help" -- "$cur") )
199
+ return 0
200
+ fi
201
+ case "${words[2]}" in
202
+ overview)
203
+ if [[ "$cur" == -* ]]; then
204
+ COMPREPLY=( $(compgen -W "--silent" -- "$cur") )
205
+ return 0
206
+ fi
207
+ _filedir -d
208
+ ;;
209
+ deps)
210
+ COMPREPLY=( $(compgen -f -- "$cur") )
211
+ ;;
212
+ hotspots)
213
+ if [[ "$cur" == -* ]]; then
214
+ COMPREPLY=( $(compgen -W "--top" -- "$cur") )
215
+ return 0
216
+ fi
217
+ ;;
218
+ symbols)
219
+ ;;
220
+ esac
221
+ ;;
184
222
  esac
185
223
  }
186
224
 
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "6.66.0"
10
+ __version__ = "6.67.0"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try: