loki-mode 6.31.0 → 6.32.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/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
  [![Autonomi](https://img.shields.io/badge/Autonomi-autonomi.dev-5B4EEA)](https://www.autonomi.dev/)
11
11
  [![Docker Pulls](https://img.shields.io/docker/pulls/asklokesh/loki-mode)](https://hub.docker.com/r/asklokesh/loki-mode)
12
12
 
13
- **Current Version: v6.31.0**
13
+ **Current Version: v6.32.0**
14
14
 
15
15
  ### Traction
16
16
 
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.31.0
6
+ # Loki Mode v6.32.0
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.31.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
270
+ **v6.32.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 6.31.0
1
+ 6.32.0
package/autonomy/loki CHANGED
@@ -424,7 +424,7 @@ show_help() {
424
424
  echo " review [opts] Standalone code review with quality gates (diff, staged, PR, files)"
425
425
  echo " optimize Optimize prompts based on session history"
426
426
  echo " enterprise Enterprise feature management (tokens, OIDC)"
427
- echo " metrics Prometheus/OpenMetrics metrics from dashboard"
427
+ echo " metrics [opts] Session productivity report (--json, --last N, --save, --share)"
428
428
  echo " dogfood Show self-development statistics"
429
429
  echo " secrets [cmd] API key status and validation (status|validate)"
430
430
  echo " reset [target] Reset session state (all|retries|failed)"
@@ -13833,47 +13833,448 @@ cmd_syslog() {
13833
13833
 
13834
13834
  # Fetch and display Prometheus metrics from dashboard
13835
13835
  cmd_metrics() {
13836
- local subcommand="${1:-}"
13837
- local port="${LOKI_DASHBOARD_PORT:-57374}"
13838
- local host="127.0.0.1"
13836
+ local show_json=false
13837
+ local last_n=0
13838
+ local save_file=false
13839
+ local share_flag=false
13839
13840
 
13840
- case "$subcommand" in
13841
- help|--help|-h)
13842
- echo -e "${BOLD}loki metrics${NC} - Prometheus/OpenMetrics metrics"
13843
- echo ""
13844
- echo "Usage: loki metrics [options]"
13845
- echo ""
13846
- echo "Fetches metrics from the dashboard API in Prometheus/OpenMetrics format."
13847
- echo "The dashboard must be running (loki dashboard start or loki serve)."
13848
- echo ""
13849
- echo "Options:"
13850
- echo " help Show this help"
13851
- echo ""
13852
- echo "Environment:"
13853
- echo " LOKI_DASHBOARD_PORT Dashboard port (default: 57374)"
13854
- echo ""
13855
- echo "Examples:"
13856
- echo " loki metrics # Display all metrics"
13857
- echo " loki metrics | grep loki_cost_usd # Filter specific metric"
13858
- ;;
13859
- "")
13860
- # Fetch metrics from dashboard
13861
- local url="http://${host}:${port}/metrics"
13862
- local response
13863
- response=$(curl -sf "$url" 2>/dev/null) || true
13864
- if [ -z "$response" ]; then
13865
- echo -e "${RED}Error: Could not connect to dashboard at ${url}${NC}"
13866
- echo "Make sure the dashboard is running: loki serve"
13867
- exit 1
13868
- fi
13869
- echo "$response"
13870
- ;;
13871
- *)
13872
- echo -e "${RED}Unknown metrics command: $subcommand${NC}"
13873
- echo "Run 'loki metrics help' for usage."
13841
+ while [[ $# -gt 0 ]]; do
13842
+ case "$1" in
13843
+ --help|-h)
13844
+ echo -e "${BOLD}loki metrics${NC} - Session productivity reporter"
13845
+ echo ""
13846
+ echo "Usage: loki metrics [options]"
13847
+ echo ""
13848
+ echo "Analyzes past Loki Mode session data and generates a productivity"
13849
+ echo "stats report showing agents deployed, iterations completed, files"
13850
+ echo "changed, and estimated time saved."
13851
+ echo ""
13852
+ echo "Options:"
13853
+ echo " --json Machine-readable JSON output"
13854
+ echo " --last N Analyze only the last N sessions (default: all)"
13855
+ echo " --save Write report to METRICS.md in project root"
13856
+ echo " --share Upload report as GitHub Gist (via loki share)"
13857
+ echo " --help, -h Show this help"
13858
+ echo ""
13859
+ echo "Subcommands:"
13860
+ echo " prometheus Fetch Prometheus/OpenMetrics from dashboard"
13861
+ echo ""
13862
+ echo "Examples:"
13863
+ echo " loki metrics # Full productivity report"
13864
+ echo " loki metrics --json # Machine-readable output"
13865
+ echo " loki metrics --last 5 # Last 5 sessions only"
13866
+ echo " loki metrics --save # Write METRICS.md"
13867
+ echo " loki metrics --share # Share as GitHub Gist"
13868
+ echo " loki metrics prometheus # Prometheus metrics from dashboard"
13869
+ exit 0
13870
+ ;;
13871
+ --json) show_json=true; shift ;;
13872
+ --last) last_n="${2:-0}"; shift 2 ;;
13873
+ --last=*) last_n="${1#*=}"; shift ;;
13874
+ --save) save_file=true; shift ;;
13875
+ --share) share_flag=true; shift ;;
13876
+ prometheus)
13877
+ # Legacy Prometheus metrics subcommand
13878
+ shift
13879
+ local port="${LOKI_DASHBOARD_PORT:-57374}"
13880
+ local host="127.0.0.1"
13881
+ local url="http://${host}:${port}/metrics"
13882
+ local response
13883
+ response=$(curl -sf "$url" 2>/dev/null) || true
13884
+ if [ -z "$response" ]; then
13885
+ echo -e "${RED}Error: Could not connect to dashboard at ${url}${NC}"
13886
+ echo "Make sure the dashboard is running: loki serve"
13887
+ exit 1
13888
+ fi
13889
+ echo "$response"
13890
+ exit 0
13891
+ ;;
13892
+ *) echo -e "${RED}Unknown option: $1${NC}"; echo "Run 'loki metrics --help' for usage."; exit 1 ;;
13893
+ esac
13894
+ done
13895
+
13896
+ local loki_dir="${LOKI_DIR:-.loki}"
13897
+
13898
+ if ! command -v python3 &>/dev/null; then
13899
+ echo -e "${RED}python3 is required for metrics generation${NC}"
13900
+ exit 1
13901
+ fi
13902
+
13903
+ local metrics_output
13904
+ metrics_output=$(LOKI_DIR="$loki_dir" \
13905
+ METRICS_JSON="$show_json" \
13906
+ METRICS_LAST_N="$last_n" \
13907
+ METRICS_SAVE="$save_file" \
13908
+ python3 << 'METRICS_SCRIPT'
13909
+ import json
13910
+ import os
13911
+ import sys
13912
+ import glob
13913
+ import subprocess
13914
+ from datetime import datetime
13915
+
13916
+ loki_dir = os.environ.get("LOKI_DIR", ".loki")
13917
+ show_json = os.environ.get("METRICS_JSON", "false") == "true"
13918
+ last_n = int(os.environ.get("METRICS_LAST_N", "0"))
13919
+ save_flag = os.environ.get("METRICS_SAVE", "false") == "true"
13920
+
13921
+ def load_json(path):
13922
+ try:
13923
+ with open(path) as f:
13924
+ return json.load(f)
13925
+ except Exception:
13926
+ return None
13927
+
13928
+ def fmt_number(n):
13929
+ return f"{n:,}"
13930
+
13931
+ def load_queue(path):
13932
+ data = load_json(path)
13933
+ if isinstance(data, list):
13934
+ return data
13935
+ if isinstance(data, dict) and "tasks" in data:
13936
+ return data["tasks"]
13937
+ return []
13938
+
13939
+ # --- Gather project name ---
13940
+ project_name = os.path.basename(os.getcwd())
13941
+
13942
+ # --- Session data ---
13943
+ sessions_analyzed = 0
13944
+ total_iterations = 0
13945
+ total_tasks_completed = 0
13946
+ total_tasks_failed = 0
13947
+ agent_types_seen = set()
13948
+ total_duration_seconds = 0
13949
+
13950
+ # Count sessions from checkpoints index or autonomy-state
13951
+ checkpoint_index = os.path.join(loki_dir, "state", "checkpoints", "index.jsonl")
13952
+ session_entries = []
13953
+ if os.path.isfile(checkpoint_index):
13954
+ try:
13955
+ with open(checkpoint_index) as f:
13956
+ for line in f:
13957
+ line = line.strip()
13958
+ if line:
13959
+ try:
13960
+ session_entries.append(json.loads(line))
13961
+ except Exception:
13962
+ pass
13963
+ except Exception:
13964
+ pass
13965
+
13966
+ # Orchestrator state
13967
+ orch = load_json(os.path.join(loki_dir, "state", "orchestrator.json")) or {}
13968
+ current_phase = orch.get("currentPhase", "N/A")
13969
+ orch_metrics = orch.get("metrics", {})
13970
+ tasks_completed_orch = orch_metrics.get("tasksCompleted", 0)
13971
+ tasks_failed_orch = orch_metrics.get("tasksFailed", 0)
13972
+
13973
+ # Per-iteration efficiency files
13974
+ eff_dir = os.path.join(loki_dir, "metrics", "efficiency")
13975
+ iterations = []
13976
+ if os.path.isdir(eff_dir):
13977
+ for path in sorted(glob.glob(os.path.join(eff_dir, "iteration-*.json"))):
13978
+ data = load_json(path)
13979
+ if data:
13980
+ iterations.append(data)
13981
+
13982
+ # Apply --last N filter
13983
+ if last_n > 0 and len(iterations) > last_n:
13984
+ iterations = iterations[-last_n:]
13985
+
13986
+ total_iterations = len(iterations) if iterations else max(orch.get("currentIteration", 0), 0)
13987
+
13988
+ # Gather agent types from iterations and agents.json
13989
+ for it in iterations:
13990
+ model = it.get("model", "")
13991
+ if model:
13992
+ agent_types_seen.add(model)
13993
+ total_duration_seconds += it.get("duration_seconds", 0)
13994
+
13995
+ agents_file = os.path.join(loki_dir, "state", "agents.json")
13996
+ agents_data = load_json(agents_file)
13997
+ if isinstance(agents_data, list):
13998
+ for agent in agents_data:
13999
+ atype = agent.get("agent_type", "")
14000
+ if atype:
14001
+ agent_types_seen.add(atype)
14002
+
14003
+ # Queue data for task counts
14004
+ completed_tasks = load_queue(os.path.join(loki_dir, "queue", "completed.json"))
14005
+ failed_tasks = load_queue(os.path.join(loki_dir, "queue", "failed.json"))
14006
+ pending_tasks = load_queue(os.path.join(loki_dir, "queue", "pending.json"))
14007
+ in_progress_tasks = load_queue(os.path.join(loki_dir, "queue", "in-progress.json"))
14008
+
14009
+ total_tasks_completed = len(completed_tasks) if completed_tasks else tasks_completed_orch
14010
+ total_tasks_failed = len(failed_tasks) if failed_tasks else tasks_failed_orch
14011
+ total_tasks = total_tasks_completed + total_tasks_failed + len(pending_tasks) + len(in_progress_tasks)
14012
+ success_rate = (total_tasks_completed / total_tasks * 100) if total_tasks > 0 else 0.0
14013
+
14014
+ # Session count: count unique session directories or fall back to 1 if .loki exists
14015
+ sessions_dir = os.path.join(loki_dir, "state", "sessions")
14016
+ if os.path.isdir(sessions_dir):
14017
+ sessions_analyzed = len([d for d in os.listdir(sessions_dir) if os.path.isdir(os.path.join(sessions_dir, d))])
14018
+ if sessions_analyzed == 0:
14019
+ # Check autonomy-state.json retryCount as proxy for session attempts
14020
+ auto_state = load_json(os.path.join(loki_dir, "autonomy-state.json"))
14021
+ if auto_state:
14022
+ sessions_analyzed = max(1, auto_state.get("retryCount", 1))
14023
+ elif os.path.isdir(loki_dir):
14024
+ sessions_analyzed = 1
14025
+
14026
+ # Apply --last N to sessions
14027
+ if last_n > 0:
14028
+ sessions_analyzed = min(sessions_analyzed, last_n)
14029
+
14030
+ # --- Git stats ---
14031
+ lines_added = 0
14032
+ lines_removed = 0
14033
+ commits_made = 0
14034
+ files_changed_git = 0
14035
+ tests_written = 0
14036
+
14037
+ try:
14038
+ result = subprocess.run(
14039
+ ["git", "log", "--shortstat", "--format="],
14040
+ capture_output=True, text=True, timeout=10
14041
+ )
14042
+ if result.returncode == 0:
14043
+ for line in result.stdout.strip().split("\n"):
14044
+ line = line.strip()
14045
+ if not line:
14046
+ continue
14047
+ parts = line.split(",")
14048
+ for part in parts:
14049
+ part = part.strip()
14050
+ if "file" in part and "changed" in part:
14051
+ try:
14052
+ files_changed_git += int(part.split()[0])
14053
+ except (ValueError, IndexError):
14054
+ pass
14055
+ elif "insertion" in part:
14056
+ try:
14057
+ lines_added += int(part.split()[0])
14058
+ except (ValueError, IndexError):
14059
+ pass
14060
+ elif "deletion" in part:
14061
+ try:
14062
+ lines_removed += int(part.split()[0])
14063
+ except (ValueError, IndexError):
14064
+ pass
14065
+
14066
+ # Count commits
14067
+ result2 = subprocess.run(
14068
+ ["git", "rev-list", "--count", "HEAD"],
14069
+ capture_output=True, text=True, timeout=10
14070
+ )
14071
+ if result2.returncode == 0:
14072
+ commits_made = int(result2.stdout.strip())
14073
+ except Exception:
14074
+ pass
14075
+
14076
+ # Estimate tests written from git log (files matching test/spec patterns)
14077
+ try:
14078
+ result3 = subprocess.run(
14079
+ ["git", "log", "--diff-filter=A", "--name-only", "--format="],
14080
+ capture_output=True, text=True, timeout=10
14081
+ )
14082
+ if result3.returncode == 0:
14083
+ for fname in result3.stdout.strip().split("\n"):
14084
+ fname = fname.strip().lower()
14085
+ if any(kw in fname for kw in ["test", "spec", ".test.", ".spec.", "_test.", "_spec."]):
14086
+ tests_written += 1
14087
+ except Exception:
14088
+ pass
14089
+
14090
+ # --- Token/cost data ---
14091
+ total_cost = sum(it.get("cost_usd", 0) for it in iterations)
14092
+ total_input_tokens = sum(it.get("input_tokens", 0) for it in iterations)
14093
+ total_output_tokens = sum(it.get("output_tokens", 0) for it in iterations)
14094
+
14095
+ # Also check context tracking for cost data
14096
+ ctx_file = os.path.join(loki_dir, "context", "tracking.json")
14097
+ ctx = load_json(ctx_file)
14098
+ if ctx and total_cost == 0:
14099
+ totals = ctx.get("totals", {})
14100
+ total_cost = totals.get("total_cost_usd", 0)
14101
+ total_input_tokens = totals.get("total_input", 0)
14102
+ total_output_tokens = totals.get("total_output", 0)
14103
+
14104
+ # --- Time saved estimate ---
14105
+ # Each Loki iteration replaces ~15min of manual work
14106
+ time_saved_hours = round(total_iterations * 15 / 60, 2)
14107
+
14108
+ # --- Memory stats ---
14109
+ episodic_count = 0
14110
+ semantic_count = 0
14111
+ episodic_dir = os.path.join(loki_dir, "memory", "episodic")
14112
+ semantic_dir = os.path.join(loki_dir, "memory", "semantic")
14113
+ if os.path.isdir(episodic_dir):
14114
+ for root, dirs, files in os.walk(episodic_dir):
14115
+ episodic_count += len([f for f in files if f.endswith(".json")])
14116
+ if os.path.isdir(semantic_dir):
14117
+ for root, dirs, files in os.walk(semantic_dir):
14118
+ semantic_count += len([f for f in files if f.endswith(".json")])
14119
+
14120
+ # --- Build output ---
14121
+ version = "6.32.0"
14122
+ try:
14123
+ version_file = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "VERSION")
14124
+ # In heredoc context, __file__ is not reliable; try relative
14125
+ for vf in ["VERSION", "../VERSION", os.path.join(loki_dir, "..", "VERSION")]:
14126
+ if os.path.isfile(vf):
14127
+ with open(vf) as f:
14128
+ version = f.read().strip()
14129
+ break
14130
+ except Exception:
14131
+ pass
14132
+
14133
+ data = {
14134
+ "project": project_name,
14135
+ "sessions_analyzed": sessions_analyzed,
14136
+ "agent_activity": {
14137
+ "total_iterations": total_iterations,
14138
+ "agent_types": len(agent_types_seen),
14139
+ "tasks_completed": total_tasks_completed,
14140
+ "tasks_failed": total_tasks_failed,
14141
+ "success_rate": round(success_rate, 1)
14142
+ },
14143
+ "code_output": {
14144
+ "files_changed": files_changed_git,
14145
+ "lines_added": lines_added,
14146
+ "lines_removed": lines_removed,
14147
+ "commits": commits_made,
14148
+ "tests_written": tests_written
14149
+ },
14150
+ "tokens": {
14151
+ "input": total_input_tokens,
14152
+ "output": total_output_tokens,
14153
+ "total": total_input_tokens + total_output_tokens,
14154
+ "cost_usd": round(total_cost, 2)
14155
+ },
14156
+ "time_saved": {
14157
+ "hours": time_saved_hours,
14158
+ "iterations": total_iterations,
14159
+ "minutes_per_iteration": 15
14160
+ },
14161
+ "memory": {
14162
+ "episodic_entries": episodic_count,
14163
+ "semantic_patterns": semantic_count
14164
+ },
14165
+ "version": version
14166
+ }
14167
+
14168
+ if show_json:
14169
+ print(json.dumps(data, indent=2))
14170
+ else:
14171
+ # ASCII stats card
14172
+ lines = []
14173
+ lines.append("")
14174
+ lines.append("LOKI MODE PRODUCTIVITY REPORT")
14175
+ lines.append("=" * 40)
14176
+ lines.append(f"Project: {project_name}")
14177
+ lines.append(f"Sessions analyzed: {sessions_analyzed}")
14178
+ lines.append("")
14179
+ lines.append("AGENT ACTIVITY")
14180
+ lines.append(f" Total iterations: {fmt_number(total_iterations)}")
14181
+ lines.append(f" Agent types used: {len(agent_types_seen)}")
14182
+ lines.append(f" Tasks completed: {fmt_number(total_tasks_completed)}")
14183
+ if total_tasks_failed > 0:
14184
+ lines.append(f" Tasks failed: {fmt_number(total_tasks_failed)}")
14185
+ if total_tasks > 0:
14186
+ lines.append(f" Success rate: {success_rate:.1f}%")
14187
+ lines.append("")
14188
+ lines.append("CODE OUTPUT")
14189
+ lines.append(f" Files changed: {fmt_number(files_changed_git)}")
14190
+ lines.append(f" Lines added: {fmt_number(lines_added)}")
14191
+ lines.append(f" Lines removed: {fmt_number(lines_removed)}")
14192
+ lines.append(f" Commits: {fmt_number(commits_made)}")
14193
+ lines.append(f" Tests written: {fmt_number(tests_written)}")
14194
+ lines.append("")
14195
+ if total_cost > 0 or total_input_tokens > 0:
14196
+ lines.append("TOKEN USAGE")
14197
+ lines.append(f" Input tokens: {fmt_number(total_input_tokens)}")
14198
+ lines.append(f" Output tokens: {fmt_number(total_output_tokens)}")
14199
+ lines.append(f" Estimated cost: ${total_cost:.2f}")
14200
+ lines.append("")
14201
+ lines.append("TIME SAVED")
14202
+ lines.append(f" Estimated: {time_saved_hours} hours")
14203
+ lines.append(f" (based on {fmt_number(total_iterations)} iterations x 15min each)")
14204
+ lines.append("")
14205
+ if episodic_count > 0 or semantic_count > 0:
14206
+ lines.append("MEMORY")
14207
+ lines.append(f" Episodic entries: {fmt_number(episodic_count)}")
14208
+ lines.append(f" Semantic patterns: {fmt_number(semantic_count)}")
14209
+ lines.append("")
14210
+ lines.append(f"Generated by Loki Mode v{version} | autonomi.dev")
14211
+ lines.append("Share your stats: loki metrics --share")
14212
+ lines.append("")
14213
+
14214
+ output_text = "\n".join(lines)
14215
+ print(output_text)
14216
+
14217
+ # Save to METRICS.md if requested
14218
+ if save_flag:
14219
+ try:
14220
+ with open("METRICS.md", "w") as f:
14221
+ f.write("# Loki Mode Productivity Report\n\n")
14222
+ f.write(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
14223
+ f.write("```\n")
14224
+ f.write(output_text.strip())
14225
+ f.write("\n```\n")
14226
+ print("Saved to METRICS.md")
14227
+ except Exception as e:
14228
+ print(f"Error saving METRICS.md: {e}", file=sys.stderr)
14229
+
14230
+ METRICS_SCRIPT
14231
+ )
14232
+ local metrics_exit=$?
14233
+
14234
+ if [ $metrics_exit -ne 0 ]; then
14235
+ echo -e "${RED}Failed to generate metrics report${NC}"
14236
+ echo "$metrics_output"
14237
+ exit 1
14238
+ fi
14239
+
14240
+ echo "$metrics_output"
14241
+
14242
+ # Handle --share flag
14243
+ if [ "$share_flag" = true ]; then
14244
+ local tmpfile
14245
+ tmpfile=$(mktemp "/tmp/loki-metrics-XXXXXX.md")
14246
+ echo "$metrics_output" > "$tmpfile"
14247
+
14248
+ if ! command -v gh &>/dev/null; then
14249
+ echo -e "${RED}gh CLI not found -- cannot share${NC}"
14250
+ echo "Install: brew install gh"
14251
+ rm -f "$tmpfile"
13874
14252
  exit 1
13875
- ;;
13876
- esac
14253
+ fi
14254
+
14255
+ if ! gh auth status &>/dev/null 2>&1; then
14256
+ echo -e "${RED}GitHub CLI not authenticated${NC}"
14257
+ echo "Run 'gh auth login' to authenticate."
14258
+ rm -f "$tmpfile"
14259
+ exit 1
14260
+ fi
14261
+
14262
+ echo "Uploading metrics report..."
14263
+ local gist_desc="Loki Mode productivity report - ${project_name:-project} ($(date +%Y-%m-%d))"
14264
+ local project_name
14265
+ project_name=$(basename "$(pwd)")
14266
+ local gist_url
14267
+ gist_url=$(gh gist create "$tmpfile" --desc "$gist_desc" --public 2>&1)
14268
+ local gist_exit=$?
14269
+ rm -f "$tmpfile"
14270
+
14271
+ if [ $gist_exit -ne 0 ]; then
14272
+ echo -e "${RED}Failed to create gist${NC}"
14273
+ echo "$gist_url"
14274
+ exit 1
14275
+ fi
14276
+ echo -e "${GREEN}Shared: ${gist_url}${NC}"
14277
+ fi
13877
14278
  }
13878
14279
 
13879
14280
  # Output shell completion scripts
package/completions/_loki CHANGED
@@ -70,6 +70,15 @@ function _loki {
70
70
  issue)
71
71
  _loki_issue
72
72
  ;;
73
+ metrics)
74
+ _arguments \
75
+ '--json[Machine-readable JSON output]' \
76
+ '--last[Analyze last N sessions]:number:' \
77
+ '--save[Write report to METRICS.md]' \
78
+ '--share[Upload report as GitHub Gist]' \
79
+ '--help[Show help]' \
80
+ '1:subcommand:(prometheus)'
81
+ ;;
73
82
  share)
74
83
  _arguments \
75
84
  '--private[Create a secret gist]' \
@@ -115,6 +124,7 @@ function _loki_commands {
115
124
  'voice:Voice input commands'
116
125
  'doctor:Check system prerequisites'
117
126
  'onboard:Analyze repo and generate CLAUDE.md'
127
+ 'metrics:Session productivity report'
118
128
  'share:Share session report as GitHub Gist'
119
129
  'version:Show version'
120
130
  'completions:Output shell completions'
@@ -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 voice secrets doctor watchdog audit metrics syslog onboard share 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 voice secrets doctor watchdog audit metrics syslog onboard share explain plan report test ci version completions help"
9
9
 
10
10
  # 1. If we are on the first argument (subcommand)
11
11
  if [[ $cword -eq 1 ]]; then
@@ -144,6 +144,15 @@ _loki_completion() {
144
144
  _filedir -d
145
145
  ;;
146
146
 
147
+ metrics)
148
+ if [[ "$cur" == -* ]]; then
149
+ COMPREPLY=( $(compgen -W "--json --last --save --share --help" -- "$cur") )
150
+ return 0
151
+ fi
152
+ local metrics_cmds="prometheus"
153
+ COMPREPLY=( $(compgen -W "${metrics_cmds}" -- "$cur") )
154
+ ;;
155
+
147
156
  share)
148
157
  if [[ "$cur" == -* ]]; then
149
158
  COMPREPLY=( $(compgen -W "--private --format --help" -- "$cur") )
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "6.31.0"
10
+ __version__ = "6.32.0"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -2,7 +2,7 @@
2
2
 
3
3
  The flagship product of [Autonomi](https://www.autonomi.dev/). Complete installation instructions for all platforms and use cases.
4
4
 
5
- **Version:** v6.31.0
5
+ **Version:** v6.32.0
6
6
 
7
7
  ---
8
8
 
package/mcp/__init__.py CHANGED
@@ -57,4 +57,4 @@ try:
57
57
  except ImportError:
58
58
  __all__ = ['mcp']
59
59
 
60
- __version__ = '6.31.0'
60
+ __version__ = '6.32.0'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loki-mode",
3
- "version": "6.31.0",
3
+ "version": "6.32.0",
4
4
  "description": "Loki Mode by Autonomi - Multi-agent autonomous startup system for Claude Code, Codex CLI, and Gemini CLI",
5
5
  "keywords": [
6
6
  "agent",