loki-mode 7.29.0 → 7.31.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 +5 -3
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/context-tracker.py +8 -0
- package/autonomy/loki +525 -122
- package/autonomy/mcp-launch.sh +384 -0
- package/autonomy/run.sh +148 -1
- package/bin/loki +19 -0
- package/dashboard/__init__.py +1 -1
- package/dashboard/server.py +226 -1
- package/dashboard/static/index.html +105 -39
- package/docs/INSTALLATION.md +1 -1
- package/docs/competitive/emergence-others-analysis.md +1 -1
- package/docs/competitive/replit-lovable-analysis.md +2 -2
- package/loki-ts/data/model-pricing.json +1 -0
- package/loki-ts/dist/loki.js +233 -232
- package/mcp/__init__.py +1 -1
- package/mcp/_sdk_loader.py +157 -0
- package/mcp/lsp_proxy.py +61 -61
- package/mcp/server.py +74 -38
- package/package.json +1 -1
- package/providers/claude.sh +76 -19
- package/providers/model_catalog.json +9 -0
- package/skills/model-selection.md +44 -0
- package/templates/simple-todo-app.md +3 -0
package/autonomy/loki
CHANGED
|
@@ -132,8 +132,12 @@ find_skill_dir() {
|
|
|
132
132
|
return 1
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
# Use || true to prevent set -e from exiting before error message
|
|
136
|
-
SKILL_DIR
|
|
135
|
+
# Use || true to prevent set -e from exiting before error message.
|
|
136
|
+
# Honor a pre-set SKILL_DIR (test harnesses point it at a fixture); fall back to
|
|
137
|
+
# auto-detection when unset. No production code exports SKILL_DIR into a child
|
|
138
|
+
# loki invocation (children receive LOKI_SKILL_DIR instead), so this only changes
|
|
139
|
+
# behavior when a caller deliberately exports SKILL_DIR.
|
|
140
|
+
SKILL_DIR="${SKILL_DIR:-$(find_skill_dir)}" || true
|
|
137
141
|
if [ -z "$SKILL_DIR" ]; then
|
|
138
142
|
# Check if installation exists but is incomplete (missing run.sh)
|
|
139
143
|
_check_dir1="$HOME/.claude/skills/loki-mode"
|
|
@@ -324,6 +328,70 @@ emit_event() {
|
|
|
324
328
|
fi
|
|
325
329
|
}
|
|
326
330
|
|
|
331
|
+
# --- CLI consolidation (Phase A): deprecated-alias back-compat contract -------
|
|
332
|
+
# An old command token continues to dispatch and forward 1:1 to its canonical
|
|
333
|
+
# command. It prints exactly ONE pointer line to STDERR and never touches
|
|
334
|
+
# machine-readable stdout. The deprecation line is suppressed whenever an
|
|
335
|
+
# explicit machine-output flag (--json, -q, --quiet) is present in the args, so
|
|
336
|
+
# callers that capture combined 2>&1 (and JSON consumers) see a clean stream.
|
|
337
|
+
# It is ALSO suppressed for the positional machine-output formats of forwarded
|
|
338
|
+
# commands (json|csv|timeline as the first arg, e.g. `loki export json`), since
|
|
339
|
+
# those formats emit a pure machine-readable stream that a combined 2>&1 capture
|
|
340
|
+
# would otherwise dirty with the note line. The human-readable `markdown` format
|
|
341
|
+
# is intentionally NOT suppressed.
|
|
342
|
+
# Non-TTY stdout is intentionally NOT a suppression trigger (some callers pipe
|
|
343
|
+
# stdout but read stderr).
|
|
344
|
+
#
|
|
345
|
+
# Usage:
|
|
346
|
+
# _deprecated_alias <old> <new> "$@" # emit pointer + telemetry (suppressed
|
|
347
|
+
# # under --json/-q/--quiet); then the
|
|
348
|
+
# # caller forwards to the canonical cmd.
|
|
349
|
+
# Reference implementation: the run->start deprecation (cmd_run / v6.84.0).
|
|
350
|
+
_deprecated_alias_should_suppress() {
|
|
351
|
+
# Returns 0 (suppress) when a machine-output flag is present anywhere in
|
|
352
|
+
# "$@", OR when the FIRST arg is a positional machine-output format
|
|
353
|
+
# (json|csv|timeline) used by forwarded commands like `loki export json`.
|
|
354
|
+
# The positional check is first-arg-only so we never suppress on an
|
|
355
|
+
# incidental later token; markdown (human-readable) is deliberately excluded.
|
|
356
|
+
case "${1:-}" in
|
|
357
|
+
json|csv|timeline) return 0 ;;
|
|
358
|
+
esac
|
|
359
|
+
local a
|
|
360
|
+
for a in "$@"; do
|
|
361
|
+
case "$a" in
|
|
362
|
+
--json|-q|--quiet) return 0 ;;
|
|
363
|
+
esac
|
|
364
|
+
done
|
|
365
|
+
return 1
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
_deprecated_alias() {
|
|
369
|
+
local old="$1"; shift
|
|
370
|
+
local new="$1"; shift
|
|
371
|
+
# "$@" is now the user-supplied argv for the alias invocation.
|
|
372
|
+
if _deprecated_alias_should_suppress "$@"; then
|
|
373
|
+
return 0
|
|
374
|
+
fi
|
|
375
|
+
echo "note: 'loki ${old}' is now 'loki ${new}'. The old form still works." >&2
|
|
376
|
+
# Reuse the existing cli_command_deprecated telemetry event (from=/to=).
|
|
377
|
+
# IMPORTANT: a forwarding alias must add no side effect the canonical command
|
|
378
|
+
# lacks. events/emit.sh creates "$LOKI_DIR/events/pending" as a side effect,
|
|
379
|
+
# which would make a no-session directory suddenly contain .loki and flip the
|
|
380
|
+
# exit code of downstream guards (e.g. cmd_share's "No .loki/ directory"
|
|
381
|
+
# check). It also removes a bash-vs-bun race for read-only reporters
|
|
382
|
+
# (cmd_stats sees .loki appear vs Bun seeing it absent). So we only emit
|
|
383
|
+
# telemetry when .loki already exists; the stderr pointer line is always
|
|
384
|
+
# printed (modulo the machine-output suppression above). The matching Bun
|
|
385
|
+
# helper (loki-ts/src/util/deprecated_alias.ts) emits no telemetry, so the
|
|
386
|
+
# two routes are side-effect consistent.
|
|
387
|
+
if [ -d "${LOKI_DIR:-.loki}" ]; then
|
|
388
|
+
emit_event cli_command_deprecated cli alias \
|
|
389
|
+
"from=${old}" \
|
|
390
|
+
"to=${new}" \
|
|
391
|
+
"argv=${*:-}"
|
|
392
|
+
fi
|
|
393
|
+
}
|
|
394
|
+
|
|
327
395
|
# Emit learning signal (non-blocking) - SYN-018
|
|
328
396
|
# Usage: emit_learning_signal <signal_type> [options]
|
|
329
397
|
# Signal types: user_preference, error_pattern, success_pattern, tool_efficiency, workflow_pattern
|
|
@@ -523,6 +591,12 @@ PYEOF
|
|
|
523
591
|
# Show help
|
|
524
592
|
show_help() {
|
|
525
593
|
local version=$(get_version)
|
|
594
|
+
# Strip color when stdout is not a TTY (piped/redirected) so captured help
|
|
595
|
+
# output is clean, matching the bare-loki welcome path. Local overrides only.
|
|
596
|
+
local BOLD="$BOLD" NC="$NC"
|
|
597
|
+
if [ ! -t 1 ]; then
|
|
598
|
+
BOLD=''; NC=''
|
|
599
|
+
fi
|
|
526
600
|
echo -e "${BOLD}Loki Mode v$version${NC}"
|
|
527
601
|
echo ""
|
|
528
602
|
echo "Usage: loki <command> [options]"
|
|
@@ -534,82 +608,62 @@ show_help() {
|
|
|
534
608
|
echo " loki start ./prd.md Build from a spec (PRD file, GitHub issue, or no arg)"
|
|
535
609
|
echo " Docs: https://github.com/asklokesh/loki-mode | Report a problem: loki crash"
|
|
536
610
|
echo ""
|
|
611
|
+
# CLI consolidation (Phase A): the front page presents ~17 canonical
|
|
612
|
+
# workflow-oriented entries grouped by section. Deprecated alias names
|
|
613
|
+
# (stats, metrics, cost, trust-metrics, serve, open, otel, cp, wt, rc, ...)
|
|
614
|
+
# do NOT appear here; they live in the collapsed footer below and in
|
|
615
|
+
# `loki help aliases`. The full long-tail surface is still dispatchable and
|
|
616
|
+
# documented per-command via `loki <command> --help`.
|
|
537
617
|
echo "Commands:"
|
|
538
|
-
echo "
|
|
539
|
-
echo "
|
|
540
|
-
echo "
|
|
541
|
-
echo "
|
|
542
|
-
echo "
|
|
618
|
+
echo ""
|
|
619
|
+
echo "Build:"
|
|
620
|
+
echo " start [SPEC] Start a build (PRD file, GitHub issue, or no arg)"
|
|
621
|
+
echo " plan <PRD-file> Dry-run analysis: complexity, cost, execution plan"
|
|
622
|
+
echo " grill [SPEC] Devil's-advocate spec interrogation before you build"
|
|
623
|
+
echo " spec [cmd] Living spec: lock|status|sync (drift detection)"
|
|
543
624
|
echo " quickstart [idea] Guided first build: setup, idea, template, plan, go"
|
|
544
|
-
echo "
|
|
545
|
-
echo "
|
|
546
|
-
echo "
|
|
547
|
-
echo " export <format> Export session data: json|markdown|csv|timeline (v6.0.0)"
|
|
625
|
+
echo ""
|
|
626
|
+
echo "Session:"
|
|
627
|
+
echo " status [--json] Show current status (--json for machine-readable)"
|
|
548
628
|
echo " stop Stop execution immediately"
|
|
549
|
-
echo " cleanup Kill orphaned processes from crashed sessions"
|
|
550
629
|
echo " pause Pause after current session"
|
|
551
630
|
echo " resume Resume paused execution"
|
|
552
|
-
echo "
|
|
553
|
-
echo "
|
|
554
|
-
echo "
|
|
555
|
-
echo "
|
|
556
|
-
echo "
|
|
557
|
-
echo "
|
|
558
|
-
echo "
|
|
559
|
-
echo "
|
|
560
|
-
echo "
|
|
561
|
-
echo "
|
|
562
|
-
echo "
|
|
563
|
-
echo "
|
|
564
|
-
echo "
|
|
565
|
-
echo "
|
|
566
|
-
echo "
|
|
567
|
-
echo " config [cmd] Manage configuration (show|init|edit|path|set|get)"
|
|
568
|
-
echo " completions [bash|zsh] Output shell completion scripts"
|
|
631
|
+
echo " cleanup Kill orphaned processes from crashed sessions"
|
|
632
|
+
echo ""
|
|
633
|
+
echo "Verify / trust:"
|
|
634
|
+
echo " verify [base] Deterministic PR verification (CI-gate exit codes)"
|
|
635
|
+
echo " review [opts] Standalone code review with quality gates"
|
|
636
|
+
echo " trust [cmd] Visible trust trajectory; 'trust detail' for metrics"
|
|
637
|
+
echo ""
|
|
638
|
+
echo "Observe:"
|
|
639
|
+
echo " dashboard [cmd] Operations UI server (start|stop|status|url|open)"
|
|
640
|
+
echo " mcp Launch the MCP server (Model Context Protocol, stdio)"
|
|
641
|
+
echo ""
|
|
642
|
+
echo "Report:"
|
|
643
|
+
echo " report [cmd] Reporting: session|metrics|cost|export|share|dogfood"
|
|
644
|
+
echo ""
|
|
645
|
+
echo "Knowledge:"
|
|
569
646
|
echo " memory [cmd] Cross-project learnings (list|show|search|stats)"
|
|
570
|
-
echo "
|
|
571
|
-
echo "
|
|
572
|
-
echo " checkpoint|cp Save/restore session checkpoints"
|
|
573
|
-
echo " projects Multi-project registry management"
|
|
574
|
-
echo " audit [cmd] Agent audit log and quality scanning (log|scan)"
|
|
647
|
+
echo ""
|
|
648
|
+
echo "Modernize:"
|
|
575
649
|
echo " heal <path> Legacy system healing (archaeology, stabilize, modernize)"
|
|
576
|
-
echo "
|
|
577
|
-
echo "
|
|
578
|
-
echo "
|
|
579
|
-
echo " review [opts] Standalone code review with quality gates (diff, staged, PR, files)"
|
|
580
|
-
echo " optimize Optimize prompts based on session history"
|
|
581
|
-
echo " enterprise Enterprise feature management (tokens, OIDC)"
|
|
582
|
-
echo " metrics [opts] Session productivity report (--json, --last N, --save, --share)"
|
|
583
|
-
echo " cost [opts] Transparent cost view: per-run/project spend + budget (--json, --last N)"
|
|
584
|
-
echo " trust [--json] Visible trust trajectory: council/gate pass-rate + interventions over runs [R4]"
|
|
585
|
-
echo " trust-metrics Trust-layer metrics: evidence-block rate, gate distribution, council split, cost/verified (--json)"
|
|
586
|
-
echo " dogfood Show self-development statistics"
|
|
587
|
-
echo " secrets [cmd] API key status and validation (status|validate)"
|
|
588
|
-
echo " reset [target] Reset session state (all|retries|failed)"
|
|
650
|
+
echo ""
|
|
651
|
+
echo "Config:"
|
|
652
|
+
echo " config [cmd] Manage configuration + provider (show|set|get|provider)"
|
|
589
653
|
echo " doctor [--json] Check system prerequisites and skill symlinks"
|
|
590
|
-
echo "
|
|
591
|
-
echo " self-update Upgrade loki via current manager (use --to bun|npm|brew to switch)"
|
|
592
|
-
echo " watchdog [cmd] Process health monitoring (status|help)"
|
|
593
|
-
echo " worktree [cmd] Parallel worktree management (list|merge|clean|status)"
|
|
594
|
-
echo " agent [cmd] Agent type dispatch (list|info|run|start|review)"
|
|
595
|
-
echo " remote [PRD] Start remote session (connect from phone/browser, Claude Pro/Max)"
|
|
596
|
-
echo " trigger Event-driven autonomous execution (schedules, webhooks)"
|
|
597
|
-
echo " failover [cmd] Cross-provider auto-failover (status|--enable|--test|--chain)"
|
|
598
|
-
echo " onboard [path] Analyze a repo and generate CLAUDE.md (structure, conventions, commands)"
|
|
599
|
-
echo ' explain [path] Analyze any codebase and explain its architecture in plain English'
|
|
600
|
-
echo " docs [cmd] Generate, update, check project documentation"
|
|
601
|
-
echo " magic [cmd] Spec-driven component generation (MagicModules + MoMoA)"
|
|
602
|
-
echo " plan <PRD> Dry-run PRD analysis: complexity, cost, and execution plan"
|
|
603
|
-
echo " ci [opts] CI/CD quality gate integration (--pr, --report, --github-comment)"
|
|
604
|
-
echo " test [opts] AI-powered test generation (--file, --dir, --changed, --dry-run)"
|
|
605
|
-
echo " context [cmd] Context window management (show|files|tools|add|clear)"
|
|
606
|
-
echo " code [cmd] Codebase intelligence (overview|symbols|deps|hotspots|diff|search)"
|
|
607
|
-
echo " report [opts] Session report generator (--format text|markdown|html, --output)"
|
|
608
|
-
echo " share [opts] Share session report as GitHub Gist (--private, --format)"
|
|
609
|
-
echo " proof [cmd] Inspect/share proof-of-run artifacts (list|show|open|share)"
|
|
610
|
-
echo " bench [cmd] Head-to-head benchmark harness (run|vs|list|verify|report)"
|
|
654
|
+
echo ""
|
|
611
655
|
echo " version Show version"
|
|
612
|
-
echo " help Show this help"
|
|
656
|
+
echo " help Show this help ('loki help aliases' for old names)"
|
|
657
|
+
echo ""
|
|
658
|
+
echo "More commands (init, watch, demo, web, api, logs, github,"
|
|
659
|
+
echo "import, council, proof, audit, agent, template, magic, onboard, explain,"
|
|
660
|
+
echo "code, context, docs, wiki, ci, test, bench, secrets, telemetry, crash,"
|
|
661
|
+
echo "worktree, failover, monitor, remote, kpis, ...) are dispatchable and"
|
|
662
|
+
echo "documented via 'loki <command> --help'."
|
|
663
|
+
echo ""
|
|
664
|
+
echo "Aliases (deprecated): older command names still work; they print a"
|
|
665
|
+
echo "one-line pointer to stderr and never alter --json output. See the full"
|
|
666
|
+
echo "list with 'loki help aliases'."
|
|
613
667
|
echo ""
|
|
614
668
|
echo "Options for 'start':"
|
|
615
669
|
echo " --provider NAME AI provider: claude (default), codex, cline, aider"
|
|
@@ -655,11 +709,11 @@ show_help() {
|
|
|
655
709
|
echo ""
|
|
656
710
|
echo " # Session ops + observability"
|
|
657
711
|
echo " loki status [--json] # Current status"
|
|
658
|
-
echo " loki
|
|
712
|
+
echo " loki report session --efficiency # Token + cost stats"
|
|
659
713
|
echo " loki kpis [--json] # Accuracy + efficiency KPI snapshot"
|
|
660
714
|
echo " loki doctor [--json] # System prereq + skill symlinks"
|
|
661
715
|
echo " loki logs # Tail recent log output"
|
|
662
|
-
echo " loki export json|markdown|csv|timeline # Export session"
|
|
716
|
+
echo " loki report export json|markdown|csv|timeline # Export session"
|
|
663
717
|
echo " loki assets export team.tgz # Export shareable team assets (redacted)"
|
|
664
718
|
echo " loki cleanup # Kill orphaned processes"
|
|
665
719
|
echo ""
|
|
@@ -694,6 +748,47 @@ show_help() {
|
|
|
694
748
|
echo " See: $RUN_SH (header comments) for full list."
|
|
695
749
|
}
|
|
696
750
|
|
|
751
|
+
# CLI consolidation (Phase A): `loki help aliases` subview. Lists every
|
|
752
|
+
# deprecated alias and its canonical command for users with scripts. The old
|
|
753
|
+
# forms continue to work (they print a one-line stderr pointer and never alter
|
|
754
|
+
# --json output); they are supported through at least two MAJOR versions and
|
|
755
|
+
# considered for removal no earlier than vN+2.0.0.
|
|
756
|
+
show_help_aliases() {
|
|
757
|
+
# Strip color when stdout is not a TTY (piped/redirected), matching the
|
|
758
|
+
# bare-loki welcome path and show_help. Local overrides only.
|
|
759
|
+
local BOLD="$BOLD" NC="$NC"
|
|
760
|
+
if [ ! -t 1 ]; then
|
|
761
|
+
BOLD=''; NC=''
|
|
762
|
+
fi
|
|
763
|
+
echo -e "${BOLD}Loki Mode -- deprecated command aliases${NC}"
|
|
764
|
+
echo ""
|
|
765
|
+
echo "These older command names still work. Each forwards 1:1 to its"
|
|
766
|
+
echo "canonical command, prints exactly one pointer line to stderr, and"
|
|
767
|
+
echo "never alters --json output (the pointer is suppressed under --json,"
|
|
768
|
+
echo "-q, and --quiet). They are supported through at least two MAJOR"
|
|
769
|
+
echo "versions; removal no earlier than vN+2.0.0."
|
|
770
|
+
echo ""
|
|
771
|
+
echo " Old command Canonical command"
|
|
772
|
+
echo " ----------- -----------------"
|
|
773
|
+
echo " run <issue> start <issue>"
|
|
774
|
+
echo " serve api start"
|
|
775
|
+
echo " open preview"
|
|
776
|
+
echo " otel telemetry"
|
|
777
|
+
echo " cp checkpoint"
|
|
778
|
+
echo " wt worktree"
|
|
779
|
+
echo " rc remote"
|
|
780
|
+
echo " stats report session"
|
|
781
|
+
echo " metrics report metrics"
|
|
782
|
+
echo " cost report cost"
|
|
783
|
+
echo " export report export"
|
|
784
|
+
echo " share report share"
|
|
785
|
+
echo " dogfood report dogfood"
|
|
786
|
+
echo " trust-metrics trust detail"
|
|
787
|
+
echo ""
|
|
788
|
+
echo "More groupings (ui, analyze, modernize, new, admin) land in Phase B."
|
|
789
|
+
echo "See internal/CLI-CONSOLIDATION-DESIGN.md for the full migration plan."
|
|
790
|
+
}
|
|
791
|
+
|
|
697
792
|
# Tight newcomer landing for the bare `loki` invocation (no args).
|
|
698
793
|
# v7.28.x UX: the full 70-command table lives in `loki help`; a no-args run
|
|
699
794
|
# now shows only a calm ~12-line orientation so the "what do I do first"
|
|
@@ -702,6 +797,13 @@ show_help() {
|
|
|
702
797
|
show_landing() {
|
|
703
798
|
local version
|
|
704
799
|
version=$(get_version)
|
|
800
|
+
# v7.30.0 (item 5): strip color when stdout is not a TTY (piped/redirected)
|
|
801
|
+
# in addition to the global NO_COLOR honoring above, so captured landing
|
|
802
|
+
# output is clean. Local overrides only; the rest of the CLI is untouched.
|
|
803
|
+
local BOLD="$BOLD" CYAN="$CYAN" NC="$NC"
|
|
804
|
+
if [ ! -t 1 ]; then
|
|
805
|
+
BOLD=''; CYAN=''; NC=''
|
|
806
|
+
fi
|
|
705
807
|
echo -e "${BOLD}Loki Mode v$version${NC} - the spec-driven builder that verifies its own work."
|
|
706
808
|
echo ""
|
|
707
809
|
echo -e "First time here? ${CYAN}loki doctor${NC} checks your setup (an AI provider CLI is required)."
|
|
@@ -709,6 +811,7 @@ show_landing() {
|
|
|
709
811
|
echo "Get started:"
|
|
710
812
|
echo -e " ${CYAN}loki start ./prd.md${NC} Build from a spec (PRD file, GitHub issue, or no arg)"
|
|
711
813
|
echo -e " ${CYAN}loki demo${NC} Build a sample todo app end to end (real run)"
|
|
814
|
+
echo -e " ${CYAN}loki web${NC} Open the visual builder to input a spec and watch agents build"
|
|
712
815
|
echo -e " ${CYAN}loki dashboard start${NC} Start the live run monitor (then: loki dashboard open)"
|
|
713
816
|
echo ""
|
|
714
817
|
echo -e "Need help? ${CYAN}loki help${NC} lists every command."
|
|
@@ -4736,8 +4839,10 @@ cmd_web_stop() {
|
|
|
4736
4839
|
rm -f "$pids_file" 2>/dev/null || true
|
|
4737
4840
|
fi
|
|
4738
4841
|
|
|
4739
|
-
#
|
|
4740
|
-
#
|
|
4842
|
+
# Companion cleanup: stop the dashboard server that the web UI runs
|
|
4843
|
+
# alongside. Scoped to the dashboard, NOT to every loki process: the
|
|
4844
|
+
# documented intent of "loki web stop" is to stop the Purple Lab web UI
|
|
4845
|
+
# session, not to reap unrelated builds.
|
|
4741
4846
|
|
|
4742
4847
|
# Kill any dashboard server (by process name and by port)
|
|
4743
4848
|
local dash_port="${LOKI_DASHBOARD_PORT:-57374}"
|
|
@@ -4762,21 +4867,14 @@ cmd_web_stop() {
|
|
|
4762
4867
|
kill -0 "$dash_port_pid" 2>/dev/null && kill -9 "$dash_port_pid" 2>/dev/null || true
|
|
4763
4868
|
fi
|
|
4764
4869
|
|
|
4765
|
-
#
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
for rpid in $run_pids; do
|
|
4774
|
-
kill -0 "$rpid" 2>/dev/null && kill -9 "$rpid" 2>/dev/null || true
|
|
4775
|
-
done
|
|
4776
|
-
if [ "$stopped" = true ]; then
|
|
4777
|
-
echo "Background processes cleaned up"
|
|
4778
|
-
fi
|
|
4779
|
-
fi
|
|
4870
|
+
# FIX-563 (v7.30.0): do NOT blanket-kill loki-run-* orchestrators here.
|
|
4871
|
+
# The prior unscoped `pgrep -f "loki-run-..."` reaped EVERY orchestrator on
|
|
4872
|
+
# the machine, including foreign `loki start` sessions launched from other
|
|
4873
|
+
# terminals/CWDs that the web UI never owned. Purple Lab's own build
|
|
4874
|
+
# processes are already reaped authoritatively above via child-pids.json
|
|
4875
|
+
# (the only PIDs this session actually started). Foreign builds survive,
|
|
4876
|
+
# mirroring the cwd-scoped dashboard-stop pattern (FIX rationale: a user
|
|
4877
|
+
# invoking "loki web stop" expects the web UI gone, not their other builds).
|
|
4780
4878
|
|
|
4781
4879
|
# Clean up all PID files globally
|
|
4782
4880
|
rm -f "${LOKI_DIR}/dashboard/dashboard.pid" 2>/dev/null || true
|
|
@@ -5346,17 +5444,28 @@ cmd_run() {
|
|
|
5346
5444
|
break
|
|
5347
5445
|
fi
|
|
5348
5446
|
done
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5447
|
+
# CLI consolidation (Phase A): align the run->start notice with the
|
|
5448
|
+
# standardized one-line alias contract (stderr-only, suppressed under
|
|
5449
|
+
# --json/-q/--quiet, contains "is now 'loki start'"). The word
|
|
5450
|
+
# "deprecated" is kept so existing run/start unification tests still
|
|
5451
|
+
# match. Telemetry reuses the cli_command_deprecated event.
|
|
5452
|
+
if [ "$_show_warn" = "true" ] && ! _deprecated_alias_should_suppress "$@"; then
|
|
5453
|
+
echo "note: 'loki run' is now 'loki start <issue-ref>' (run is deprecated). The old form still works." >&2
|
|
5353
5454
|
# Emit telemetry event so we can measure adoption of the unified command.
|
|
5354
5455
|
# Signature: emit_event <type> <source> <action> [key=value ...]
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5456
|
+
# No-side-effect alias contract (matches _deprecated_alias at :371):
|
|
5457
|
+
# events/emit.sh creates "$LOKI_DIR/events/pending" as a side effect,
|
|
5458
|
+
# which would make a clean directory suddenly contain .loki and flip
|
|
5459
|
+
# downstream guards (cmd_share's "No .loki/" check, bash-vs-bun read
|
|
5460
|
+
# divergence). Only emit when .loki already exists; the stderr pointer
|
|
5461
|
+
# is always printed (modulo machine-output suppression above).
|
|
5462
|
+
if [ -d "${LOKI_DIR:-.loki}" ]; then
|
|
5463
|
+
emit_event cli_command_deprecated cli run_to_start \
|
|
5464
|
+
"from=run" \
|
|
5465
|
+
"to=start" \
|
|
5466
|
+
"version=6.84.0" \
|
|
5467
|
+
"argv=${*:-}"
|
|
5468
|
+
fi
|
|
5360
5469
|
fi
|
|
5361
5470
|
fi
|
|
5362
5471
|
|
|
@@ -9082,6 +9191,14 @@ cmd_sandbox() {
|
|
|
9082
9191
|
# caller then falls back to a no-number confirm). Never fabricates a number.
|
|
9083
9192
|
emit_demo_estimate() {
|
|
9084
9193
|
local prd_path="$1"
|
|
9194
|
+
# v7.30.0 (item 5): the demo estimate always prints before spending, incl.
|
|
9195
|
+
# non-TTY (--dry-run / --yes piped), so gate color on a TTY here too (the
|
|
9196
|
+
# global vars are only blanked on NO_COLOR). Mirrors provider-offer.sh and
|
|
9197
|
+
# quickstart.sh. Local overrides only.
|
|
9198
|
+
local BOLD="$BOLD" YELLOW="$YELLOW" DIM="$DIM" NC="$NC"
|
|
9199
|
+
if [ ! -t 1 ]; then
|
|
9200
|
+
BOLD=''; YELLOW=''; DIM=''; NC=''
|
|
9201
|
+
fi
|
|
9085
9202
|
local plan_json=""
|
|
9086
9203
|
plan_json=$(LOKI_COMPLEXITY=simple show_prd_plan "$prd_path" "true" "false" 2>/dev/null) || plan_json=""
|
|
9087
9204
|
|
|
@@ -9160,6 +9277,16 @@ cmd_demo() {
|
|
|
9160
9277
|
return 0
|
|
9161
9278
|
fi
|
|
9162
9279
|
|
|
9280
|
+
# v7.30.0 (item 5): demo emits user-facing color (header, dry-run block,
|
|
9281
|
+
# cancel/refuse messages) on paths that always run even when piped/non-TTY,
|
|
9282
|
+
# so gate color on a TTY here (the global vars are only blanked on NO_COLOR).
|
|
9283
|
+
# Placed AFTER the --help early return so help output is untouched. Local
|
|
9284
|
+
# overrides only; mirrors provider-offer.sh / quickstart.sh.
|
|
9285
|
+
local BOLD="$BOLD" CYAN="$CYAN" YELLOW="$YELLOW" GREEN="$GREEN" DIM="$DIM" RED="$RED" NC="$NC"
|
|
9286
|
+
if [ ! -t 1 ]; then
|
|
9287
|
+
BOLD=''; CYAN=''; YELLOW=''; GREEN=''; DIM=''; RED=''; NC=''
|
|
9288
|
+
fi
|
|
9289
|
+
|
|
9163
9290
|
local version
|
|
9164
9291
|
version=$(get_version)
|
|
9165
9292
|
local demo_prd="$SKILL_DIR/templates/simple-todo-app.md"
|
|
@@ -10455,17 +10582,29 @@ cmd_dogfood() {
|
|
|
10455
10582
|
return 0
|
|
10456
10583
|
fi
|
|
10457
10584
|
|
|
10458
|
-
local stats_script="$SKILL_DIR/scripts/dogfood-stats.sh"
|
|
10459
|
-
if [ ! -f "$stats_script" ]; then
|
|
10460
|
-
echo -e "${RED}Error: dogfood-stats.sh not found${NC}"
|
|
10461
|
-
exit 1
|
|
10462
|
-
fi
|
|
10463
|
-
|
|
10464
10585
|
local json_flag=""
|
|
10465
10586
|
if [[ "${1:-}" == "--json" ]]; then
|
|
10466
10587
|
json_flag="--json"
|
|
10467
10588
|
fi
|
|
10468
10589
|
|
|
10590
|
+
# Honest degradation: scripts/dogfood-stats.sh is a development-only helper
|
|
10591
|
+
# that is NOT shipped in the npm tarball (package.json `files` omits
|
|
10592
|
+
# scripts/). On a packaged install it is absent, so report that plainly
|
|
10593
|
+
# rather than a bare "not found" that reads like a bug. Message goes to
|
|
10594
|
+
# STDERR so a --json caller's stdout stays clean; --json gets a structured
|
|
10595
|
+
# degraded payload on stdout so consumers do not choke on prose.
|
|
10596
|
+
local stats_script="$SKILL_DIR/scripts/dogfood-stats.sh"
|
|
10597
|
+
if [ ! -f "$stats_script" ]; then
|
|
10598
|
+
if [ -n "$json_flag" ]; then
|
|
10599
|
+
printf '{"available": false, "reason": "dogfood-stats.sh is a dev-only helper not shipped in the published package"}\n'
|
|
10600
|
+
else
|
|
10601
|
+
echo "loki report dogfood: self-development stats are unavailable in this install." >&2
|
|
10602
|
+
echo "The dogfood-stats.sh helper is a development-only script and is not" >&2
|
|
10603
|
+
echo "shipped in the published package. Run it from a loki-mode source checkout." >&2
|
|
10604
|
+
fi
|
|
10605
|
+
return 0
|
|
10606
|
+
fi
|
|
10607
|
+
|
|
10469
10608
|
bash "$stats_script" $json_flag
|
|
10470
10609
|
}
|
|
10471
10610
|
|
|
@@ -11636,6 +11775,28 @@ cmd_grill() {
|
|
|
11636
11775
|
return $?
|
|
11637
11776
|
}
|
|
11638
11777
|
|
|
11778
|
+
# ---------------------------------------------------------------------------
|
|
11779
|
+
# loki mcp - launch the MCP (Model Context Protocol) server
|
|
11780
|
+
#
|
|
11781
|
+
# Thin dispatcher that sources autonomy/mcp-launch.sh and delegates to
|
|
11782
|
+
# mcp_launch_main(). The launcher checks for python3 + the MCP SDK and, when
|
|
11783
|
+
# the SDK is missing, offers a consent-gated bootstrap into a project-local
|
|
11784
|
+
# virtualenv (.loki/mcp-venv) before exec'ing the server over stdio. This
|
|
11785
|
+
# closes the fresh-npm-consumer gap where the only bin was `loki` and the
|
|
11786
|
+
# Python MCP dependencies were never installed (task 562).
|
|
11787
|
+
# ---------------------------------------------------------------------------
|
|
11788
|
+
cmd_mcp() {
|
|
11789
|
+
local mcp_mod="$_LOKI_SCRIPT_DIR/mcp-launch.sh"
|
|
11790
|
+
if [ ! -f "$mcp_mod" ]; then
|
|
11791
|
+
echo -e "${RED}Error: mcp launcher not found at $mcp_mod${NC}" >&2
|
|
11792
|
+
return 3
|
|
11793
|
+
fi
|
|
11794
|
+
# shellcheck source=/dev/null
|
|
11795
|
+
source "$mcp_mod"
|
|
11796
|
+
mcp_launch_main "$@"
|
|
11797
|
+
return $?
|
|
11798
|
+
}
|
|
11799
|
+
|
|
11639
11800
|
cmd_heal_help() {
|
|
11640
11801
|
echo -e "${BOLD}loki heal${NC} - Legacy system healing (v6.67.0)"
|
|
11641
11802
|
echo ""
|
|
@@ -13018,6 +13179,95 @@ show_verbose = sys.argv[3] == 'true'
|
|
|
13018
13179
|
session_model_env = (os.environ.get('LOKI_SESSION_MODEL', 'sonnet') or 'sonnet').strip().lower()
|
|
13019
13180
|
legacy_tier_switching = (os.environ.get('LOKI_LEGACY_TIER_SWITCHING', 'false') or 'false').strip().lower() == 'true'
|
|
13020
13181
|
|
|
13182
|
+
# Model-honesty contract: the estimator must quote the model the runner will
|
|
13183
|
+
# actually invoke, and name the lever that selected it. The runner honors only
|
|
13184
|
+
# two session-level levers (LOKI_MODEL was estimator-only and is removed):
|
|
13185
|
+
# 1. A pending mid-flight override file (.loki/state/model-override) -- the
|
|
13186
|
+
# most specific, just-requested intent; it wins.
|
|
13187
|
+
# 2. LOKI_SESSION_MODEL (the session pin the runner reads at run.sh:12309).
|
|
13188
|
+
# Canonical normalization is shared with run.sh + the dashboard: trim +
|
|
13189
|
+
# lowercase + EXACT allowlist match. A value with interior whitespace (fab le)
|
|
13190
|
+
# is rejected everywhere, so the three readers agree.
|
|
13191
|
+
def _loki_norm_alias(raw):
|
|
13192
|
+
raw = (raw or '').strip().lower()
|
|
13193
|
+
return raw if raw in ('haiku', 'sonnet', 'opus', 'fable') else ''
|
|
13194
|
+
|
|
13195
|
+
# session_model_env starts from LOKI_SESSION_MODEL; track the lever that set it
|
|
13196
|
+
# so the provenance line names the real source (never a false attribution).
|
|
13197
|
+
_session_model_source = 'LOKI_SESSION_MODEL'
|
|
13198
|
+
session_model_env = _loki_norm_alias(os.environ.get('LOKI_SESSION_MODEL', '')) or 'sonnet'
|
|
13199
|
+
|
|
13200
|
+
_fable_override = ''
|
|
13201
|
+
try:
|
|
13202
|
+
_ov_path = os.path.join('.loki', 'state', 'model-override')
|
|
13203
|
+
if os.path.isfile(_ov_path):
|
|
13204
|
+
with open(_ov_path) as _ovf:
|
|
13205
|
+
_fable_override = _loki_norm_alias(_ovf.read())
|
|
13206
|
+
except Exception:
|
|
13207
|
+
_fable_override = ''
|
|
13208
|
+
if _fable_override:
|
|
13209
|
+
session_model_env = _fable_override
|
|
13210
|
+
_session_model_source = '.loki/state/model-override'
|
|
13211
|
+
|
|
13212
|
+
# Architect opt-in (LOKI_FABLE_ARCHITECT=1): the runner routes ONLY the first
|
|
13213
|
+
# (architecture) iteration to fable. Disclose that here so the quote is not
|
|
13214
|
+
# blind to the lever (it would otherwise under-quote by one fable iteration).
|
|
13215
|
+
# Suppressed when an explicit planning-model override or a fable session/override
|
|
13216
|
+
# already applies. The maxTier clamp below still caps the disclosed cost.
|
|
13217
|
+
_fable_architect = (
|
|
13218
|
+
(os.environ.get('LOKI_FABLE_ARCHITECT', '0') or '0').strip() == '1'
|
|
13219
|
+
and not os.environ.get('LOKI_CLAUDE_MODEL_PLANNING')
|
|
13220
|
+
and not os.environ.get('LOKI_MODEL_PLANNING')
|
|
13221
|
+
and session_model_env != 'fable'
|
|
13222
|
+
and not (os.environ.get('LOKI_LEGACY_TIER_SWITCHING', 'false') or 'false').strip().lower() == 'true'
|
|
13223
|
+
)
|
|
13224
|
+
|
|
13225
|
+
# Apply the SAME LOKI_MAX_TIER ceiling the runner applies, so the quoted model
|
|
13226
|
+
# (and the architect disclosure) never exceed the operator cost cap.
|
|
13227
|
+
#
|
|
13228
|
+
# SYNC: This resolves the clamp result through the SAME provider config the runner
|
|
13229
|
+
# uses, a byte-faithful port of providers/claude.sh loki_apply_max_tier_clamp plus
|
|
13230
|
+
# the PROVIDER_MODEL_FAST / PROVIDER_MODEL_DEVELOPMENT resolution chains
|
|
13231
|
+
# (claude.sh:55-67, :318). The same port also lives in the dashboard
|
|
13232
|
+
# (dashboard/server.py _provider_model_fast / _provider_model_development /
|
|
13233
|
+
# _clamp_to_max_tier). All three readers MUST agree; the agreement is locked by
|
|
13234
|
+
# the parity test in tests/test-model-override.sh (resolver parity matrix) and the
|
|
13235
|
+
# cross-route tests in test-plan-command.sh. If you change resolution here, change
|
|
13236
|
+
# it in claude.sh AND dashboard/server.py, and re-run those tests. The 'or' chains
|
|
13237
|
+
# mirror bash ':-' empty-string-fallthrough; allow_haiku uses an exact 'true'
|
|
13238
|
+
# match to mirror bash [ \"\$x\" = \"true\" ]. PROVIDER_MODEL_DEVELOPMENT is opus
|
|
13239
|
+
# by default; PROVIDER_MODEL_FAST is sonnet by default (haiku when ALLOW_HAIKU).
|
|
13240
|
+
_allow_haiku = (os.environ.get('LOKI_ALLOW_HAIKU', 'false') or 'false') == 'true'
|
|
13241
|
+
def _provider_model_fast():
|
|
13242
|
+
return (os.environ.get('LOKI_CLAUDE_MODEL_FAST')
|
|
13243
|
+
or os.environ.get('LOKI_MODEL_FAST')
|
|
13244
|
+
or ('haiku' if _allow_haiku else 'sonnet'))
|
|
13245
|
+
def _provider_model_development():
|
|
13246
|
+
return (os.environ.get('LOKI_CLAUDE_MODEL_DEVELOPMENT')
|
|
13247
|
+
or os.environ.get('LOKI_MODEL_DEVELOPMENT')
|
|
13248
|
+
or ('sonnet' if _allow_haiku else 'opus'))
|
|
13249
|
+
_max_tier = (os.environ.get('LOKI_MAX_TIER', '') or '').strip().lower()
|
|
13250
|
+
def _loki_clamp_alias(alias):
|
|
13251
|
+
if not _max_tier:
|
|
13252
|
+
return alias
|
|
13253
|
+
if _max_tier == 'haiku':
|
|
13254
|
+
return _provider_model_fast()
|
|
13255
|
+
if _max_tier == 'sonnet':
|
|
13256
|
+
# alias passed as both model and tier (override-path convention): the
|
|
13257
|
+
# runner's sonnet arm reduces to 'downgrade iff alias==fable'.
|
|
13258
|
+
return _provider_model_development() if alias == 'fable' else alias
|
|
13259
|
+
if _max_tier == 'opus':
|
|
13260
|
+
return 'opus' if alias == 'fable' else alias
|
|
13261
|
+
return alias
|
|
13262
|
+
if _max_tier:
|
|
13263
|
+
_clamped = _loki_clamp_alias(session_model_env)
|
|
13264
|
+
if _clamped != session_model_env:
|
|
13265
|
+
session_model_env = _clamped
|
|
13266
|
+
_session_model_source = 'LOKI_MAX_TIER (clamped)'
|
|
13267
|
+
if _fable_architect and _loki_clamp_alias('fable') != 'fable':
|
|
13268
|
+
# The architect iteration would clamp down too; do not disclose fable.
|
|
13269
|
+
_fable_architect = False
|
|
13270
|
+
|
|
13021
13271
|
# v7.29.0: Honor LOKI_COMPLEXITY -- the SAME env var the runner honors at
|
|
13022
13272
|
# run.sh:920 -- so a forced-tier run (e.g. 'loki demo' / 'loki start --simple'
|
|
13023
13273
|
# which export LOKI_COMPLEXITY=simple) quotes the tier it will actually run,
|
|
@@ -13035,6 +13285,7 @@ if forced_complexity not in ('simple', 'moderate', 'complex', 'enterprise'):
|
|
|
13035
13285
|
# Map session model name to tier key used in tokens_per_tier below.
|
|
13036
13286
|
# Unknown models fall through to 'development' (Sonnet) as a safe default.
|
|
13037
13287
|
_session_tier_map = {
|
|
13288
|
+
'fable': 'advisor',
|
|
13038
13289
|
'opus': 'planning',
|
|
13039
13290
|
'sonnet': 'development',
|
|
13040
13291
|
'haiku': 'fast',
|
|
@@ -13213,16 +13464,25 @@ estimated_iterations = (min_iter + max_iter) // 2
|
|
|
13213
13464
|
# RARV cycle: 4 iterations per cycle (plan, develop, develop, test)
|
|
13214
13465
|
# Tokens estimated per iteration step
|
|
13215
13466
|
tokens_per_tier = {
|
|
13467
|
+
'advisor': {'input': 50000, 'output': 8000, 'model': 'Fable'},
|
|
13216
13468
|
'planning': {'input': 50000, 'output': 8000, 'model': 'Opus'},
|
|
13217
13469
|
'development': {'input': 80000, 'output': 15000, 'model': 'Sonnet'},
|
|
13218
13470
|
'fast': {'input': 30000, 'output': 5000, 'model': 'Haiku'},
|
|
13219
13471
|
}
|
|
13220
13472
|
|
|
13221
|
-
# Pricing per 1M tokens
|
|
13473
|
+
# Pricing per 1M tokens. Fable 5 is the top-tier advisory model at exactly 2x
|
|
13474
|
+
# Opus per token (published \$10/\$50 in/out vs Opus \$5/\$25). The Opus row was
|
|
13475
|
+
# corrected from a stale \$15/\$75 to the real Opus 4.8 \$5/\$25, and the Haiku
|
|
13476
|
+
# row from a stale \$0.25/\$1.25 (Haiku 3.5) to the published Claude Haiku 4.5
|
|
13477
|
+
# price of \$1/\$5 (anthropic.com/news/claude-haiku-4-5), so all four rows now
|
|
13478
|
+
# match the three canonical model-keyed tables (run.sh pricing.json, run.sh
|
|
13479
|
+
# check_budget_limit, dashboard _DEFAULT_PRICING) and a fable-forced quote
|
|
13480
|
+
# honestly shows MORE than Opus, not less.
|
|
13222
13481
|
pricing = {
|
|
13223
|
-
'
|
|
13482
|
+
'Fable': {'input': 10.00, 'output': 50.00},
|
|
13483
|
+
'Opus': {'input': 5.00, 'output': 25.00},
|
|
13224
13484
|
'Sonnet': {'input': 3.00, 'output': 15.00},
|
|
13225
|
-
'Haiku': {'input':
|
|
13485
|
+
'Haiku': {'input': 1.00, 'output': 5.00},
|
|
13226
13486
|
}
|
|
13227
13487
|
|
|
13228
13488
|
# Build per-iteration plan
|
|
@@ -13230,8 +13490,8 @@ iteration_plan = []
|
|
|
13230
13490
|
total_input_tokens = 0
|
|
13231
13491
|
total_output_tokens = 0
|
|
13232
13492
|
total_cost = 0.0
|
|
13233
|
-
tier_totals = {'Opus': 0.0, 'Sonnet': 0.0, 'Haiku': 0.0}
|
|
13234
|
-
tier_iterations = {'Opus': 0, 'Sonnet': 0, 'Haiku': 0}
|
|
13493
|
+
tier_totals = {'Fable': 0.0, 'Opus': 0.0, 'Sonnet': 0.0, 'Haiku': 0.0}
|
|
13494
|
+
tier_iterations = {'Fable': 0, 'Opus': 0, 'Sonnet': 0, 'Haiku': 0}
|
|
13235
13495
|
|
|
13236
13496
|
for i in range(estimated_iterations):
|
|
13237
13497
|
rarv_step = i % 4
|
|
@@ -13257,6 +13517,11 @@ for i in range(estimated_iterations):
|
|
|
13257
13517
|
# MUST use the same tier for all iterations to avoid quoting a
|
|
13258
13518
|
# cost higher than the user will actually pay.
|
|
13259
13519
|
tier = session_tier
|
|
13520
|
+
# Architect opt-in: the runner routes ONLY the first iteration to fable
|
|
13521
|
+
# (the architecture pass). Mirror that here so the quote is not blind to
|
|
13522
|
+
# the lever: iteration 0 -> advisor (fable), the rest -> session tier.
|
|
13523
|
+
if _fable_architect and i == 0:
|
|
13524
|
+
tier = 'advisor'
|
|
13260
13525
|
|
|
13261
13526
|
info = tokens_per_tier[tier]
|
|
13262
13527
|
model = info['model']
|
|
@@ -13433,6 +13698,7 @@ for reason in complexity_reasons:
|
|
|
13433
13698
|
print(f'\n{CYAN}Estimated Iterations{NC}')
|
|
13434
13699
|
print(f' Count: {BOLD}{estimated_iterations}{NC} (range: {min_iter}-{max_iter})')
|
|
13435
13700
|
print(f' RARV cycles: {cycle_count} (4 iterations per cycle)')
|
|
13701
|
+
fable_n = tier_iterations.get('Fable', 0)
|
|
13436
13702
|
opus_n = tier_iterations.get('Opus', 0)
|
|
13437
13703
|
sonnet_n = tier_iterations.get('Sonnet', 0)
|
|
13438
13704
|
haiku_n = tier_iterations.get('Haiku', 0)
|
|
@@ -13442,6 +13708,8 @@ if legacy_tier_switching:
|
|
|
13442
13708
|
else:
|
|
13443
13709
|
# Session-pinned: exactly one tier has all iterations.
|
|
13444
13710
|
pinned_parts = []
|
|
13711
|
+
if fable_n > 0:
|
|
13712
|
+
pinned_parts.append(f'Fable x{fable_n}')
|
|
13445
13713
|
if opus_n > 0:
|
|
13446
13714
|
pinned_parts.append(f'Opus x{opus_n}')
|
|
13447
13715
|
if sonnet_n > 0:
|
|
@@ -13449,7 +13717,14 @@ else:
|
|
|
13449
13717
|
if haiku_n > 0:
|
|
13450
13718
|
pinned_parts.append(f'Haiku x{haiku_n}')
|
|
13451
13719
|
print(' Model distribution: ' + (' | '.join(pinned_parts) if pinned_parts else '(none)'))
|
|
13452
|
-
|
|
13720
|
+
# Provenance: name the lever that actually selected the pinned model, never a
|
|
13721
|
+
# false attribution. _session_model_source is the real source (env, override
|
|
13722
|
+
# file, or maxTier clamp) tracked at selection time.
|
|
13723
|
+
print(f' {DIM}(pinned via {_session_model_source}={session_model_env}; set LOKI_LEGACY_TIER_SWITCHING=true to rotate){NC}')
|
|
13724
|
+
if _fable_architect:
|
|
13725
|
+
print(f' {DIM}(+ 1 architecture iteration on Fable via LOKI_FABLE_ARCHITECT=1){NC}')
|
|
13726
|
+
if fable_n > 0:
|
|
13727
|
+
print(f' {YELLOW}Fable 5 is the top-tier advisory model priced at 2x Opus ({chr(36)}10/{chr(36)}50 per MTok).{NC}')
|
|
13453
13728
|
|
|
13454
13729
|
# Tokens
|
|
13455
13730
|
total_tok = total_input_tokens + total_output_tokens
|
|
@@ -13462,7 +13737,7 @@ print(f' Total: {total_tok:>12,} tokens')
|
|
|
13462
13737
|
ds = chr(36) # dollar sign
|
|
13463
13738
|
print(f'\n{CYAN}Cost Estimate{NC}')
|
|
13464
13739
|
print(f' {BOLD}Total: {ds}{total_cost:.2f}{NC}')
|
|
13465
|
-
for model in ['Opus', 'Sonnet', 'Haiku']:
|
|
13740
|
+
for model in ['Fable', 'Opus', 'Sonnet', 'Haiku']:
|
|
13466
13741
|
# v6.81.1: suppress zero-cost tiers (e.g. session-pinned runs). Keeps
|
|
13467
13742
|
# the breakdown focused on models actually used. Legacy mode still
|
|
13468
13743
|
# shows all three because each tier has non-zero iterations.
|
|
@@ -13547,7 +13822,7 @@ cmd_plan() {
|
|
|
13547
13822
|
echo ""
|
|
13548
13823
|
echo "Environment Variables:"
|
|
13549
13824
|
echo " LOKI_SESSION_MODEL Pin cost estimate to a single tier"
|
|
13550
|
-
echo " (opus|sonnet|haiku, default: sonnet)"
|
|
13825
|
+
echo " (opus|sonnet|haiku|fable, default: sonnet)"
|
|
13551
13826
|
echo " LOKI_LEGACY_TIER_SWITCHING Set to 'true' to restore the legacy"
|
|
13552
13827
|
echo " Opus/Sonnet/Haiku per-iteration rotation"
|
|
13553
13828
|
echo ""
|
|
@@ -13681,7 +13956,12 @@ main() {
|
|
|
13681
13956
|
cmd_status "$@"
|
|
13682
13957
|
;;
|
|
13683
13958
|
stats)
|
|
13684
|
-
|
|
13959
|
+
# CLI consolidation (Phase A): 'stats' is a deprecated alias of
|
|
13960
|
+
# 'report session'. On the Bun route this arm is never reached
|
|
13961
|
+
# (stats is Bun-native); the matching deprecation lives in
|
|
13962
|
+
# loki-ts/src/commands/stats.ts so both routes behave identically.
|
|
13963
|
+
_deprecated_alias stats "report session" "$@"
|
|
13964
|
+
cmd_report session "$@"
|
|
13685
13965
|
;;
|
|
13686
13966
|
dashboard)
|
|
13687
13967
|
cmd_dashboard "$@"
|
|
@@ -13689,13 +13969,24 @@ main() {
|
|
|
13689
13969
|
web)
|
|
13690
13970
|
cmd_web "$@"
|
|
13691
13971
|
;;
|
|
13692
|
-
preview
|
|
13972
|
+
preview)
|
|
13973
|
+
cmd_preview "$@"
|
|
13974
|
+
;;
|
|
13975
|
+
open)
|
|
13976
|
+
# CLI consolidation (Phase A): 'open' is a deprecated alias of 'preview'.
|
|
13977
|
+
_deprecated_alias open preview "$@"
|
|
13693
13978
|
cmd_preview "$@"
|
|
13694
13979
|
;;
|
|
13695
13980
|
logs)
|
|
13696
13981
|
cmd_logs "$@"
|
|
13697
13982
|
;;
|
|
13698
13983
|
serve)
|
|
13984
|
+
# CLI consolidation (Phase A): 'serve' is a deprecated alias of
|
|
13985
|
+
# 'api start'. Emit the pointer BEFORE the --help short-circuit so it
|
|
13986
|
+
# fires on every form (including 'serve --help'), consistent with the
|
|
13987
|
+
# other short aliases and testable without binding a TCP port.
|
|
13988
|
+
# Suppressed under --json/-q/--quiet by the helper.
|
|
13989
|
+
_deprecated_alias serve "api start" "$@"
|
|
13699
13990
|
# v7.6.2 B-12 fix: 'serve --help' previously routed to 'cmd_api start --help'
|
|
13700
13991
|
# which started the dashboard as a side effect instead of printing help.
|
|
13701
13992
|
case "${1:-}" in
|
|
@@ -13741,7 +14032,9 @@ main() {
|
|
|
13741
14032
|
cmd_watch "$@"
|
|
13742
14033
|
;;
|
|
13743
14034
|
export)
|
|
13744
|
-
|
|
14035
|
+
# CLI consolidation (Phase A): 'export' -> 'report export'.
|
|
14036
|
+
_deprecated_alias export "report export" "$@"
|
|
14037
|
+
cmd_report export "$@"
|
|
13745
14038
|
;;
|
|
13746
14039
|
assets)
|
|
13747
14040
|
cmd_assets "$@"
|
|
@@ -13762,6 +14055,8 @@ main() {
|
|
|
13762
14055
|
cmd_compound "$@"
|
|
13763
14056
|
;;
|
|
13764
14057
|
checkpoint|cp)
|
|
14058
|
+
# CLI consolidation (Phase A): 'cp' is a deprecated alias of 'checkpoint'.
|
|
14059
|
+
[ "$command" = "cp" ] && _deprecated_alias cp checkpoint "$@"
|
|
13765
14060
|
cmd_checkpoint "$@"
|
|
13766
14061
|
;;
|
|
13767
14062
|
rollback)
|
|
@@ -13771,7 +14066,9 @@ main() {
|
|
|
13771
14066
|
cmd_council "$@"
|
|
13772
14067
|
;;
|
|
13773
14068
|
dogfood)
|
|
13774
|
-
|
|
14069
|
+
# CLI consolidation (Phase A): 'dogfood' -> 'report dogfood'.
|
|
14070
|
+
_deprecated_alias dogfood "report dogfood" "$@"
|
|
14071
|
+
cmd_report dogfood "$@"
|
|
13775
14072
|
;;
|
|
13776
14073
|
projects)
|
|
13777
14074
|
cmd_projects "$@"
|
|
@@ -13822,6 +14119,9 @@ main() {
|
|
|
13822
14119
|
grill)
|
|
13823
14120
|
cmd_grill "$@"
|
|
13824
14121
|
;;
|
|
14122
|
+
mcp)
|
|
14123
|
+
cmd_mcp "$@"
|
|
14124
|
+
;;
|
|
13825
14125
|
migrate)
|
|
13826
14126
|
cmd_migrate "$@"
|
|
13827
14127
|
;;
|
|
@@ -13829,6 +14129,8 @@ main() {
|
|
|
13829
14129
|
cmd_cluster "$@"
|
|
13830
14130
|
;;
|
|
13831
14131
|
worktree|wt)
|
|
14132
|
+
# CLI consolidation (Phase A): 'wt' is a deprecated alias of 'worktree'.
|
|
14133
|
+
[ "$command" = "wt" ] && _deprecated_alias wt worktree "$@"
|
|
13832
14134
|
cmd_worktree "$@"
|
|
13833
14135
|
;;
|
|
13834
14136
|
agent)
|
|
@@ -13841,24 +14143,34 @@ main() {
|
|
|
13841
14143
|
cmd_state "$@"
|
|
13842
14144
|
;;
|
|
13843
14145
|
metrics)
|
|
13844
|
-
|
|
14146
|
+
# CLI consolidation (Phase A): 'metrics' -> 'report metrics'.
|
|
14147
|
+
_deprecated_alias metrics "report metrics" "$@"
|
|
14148
|
+
cmd_report metrics "$@"
|
|
13845
14149
|
;;
|
|
13846
14150
|
cost)
|
|
13847
|
-
|
|
14151
|
+
# CLI consolidation (Phase A): 'cost' -> 'report cost'.
|
|
14152
|
+
_deprecated_alias cost "report cost" "$@"
|
|
14153
|
+
cmd_report cost "$@"
|
|
13848
14154
|
;;
|
|
13849
14155
|
trust)
|
|
13850
14156
|
cmd_trust "$@"
|
|
13851
14157
|
;;
|
|
13852
14158
|
trust-metrics)
|
|
13853
|
-
|
|
14159
|
+
# CLI consolidation (Phase A): 'trust-metrics' -> 'trust detail'.
|
|
14160
|
+
_deprecated_alias trust-metrics "trust detail" "$@"
|
|
14161
|
+
cmd_trust detail "$@"
|
|
13854
14162
|
;;
|
|
13855
14163
|
syslog)
|
|
13856
14164
|
cmd_syslog "$@"
|
|
13857
14165
|
;;
|
|
13858
14166
|
telemetry|otel)
|
|
14167
|
+
# CLI consolidation (Phase A): 'otel' is a deprecated alias of 'telemetry'.
|
|
14168
|
+
[ "$command" = "otel" ] && _deprecated_alias otel telemetry "$@"
|
|
13859
14169
|
cmd_telemetry "$@"
|
|
13860
14170
|
;;
|
|
13861
14171
|
remote|rc)
|
|
14172
|
+
# CLI consolidation (Phase A): 'rc' is a deprecated alias of 'remote'.
|
|
14173
|
+
[ "$command" = "rc" ] && _deprecated_alias rc remote "$@"
|
|
13862
14174
|
cmd_remote "$@"
|
|
13863
14175
|
;;
|
|
13864
14176
|
trigger)
|
|
@@ -13898,7 +14210,9 @@ main() {
|
|
|
13898
14210
|
cmd_crash "$@"
|
|
13899
14211
|
;;
|
|
13900
14212
|
share)
|
|
13901
|
-
|
|
14213
|
+
# CLI consolidation (Phase A): 'share' -> 'report share'.
|
|
14214
|
+
_deprecated_alias share "report share" "$@"
|
|
14215
|
+
cmd_report share "$@"
|
|
13902
14216
|
;;
|
|
13903
14217
|
proof)
|
|
13904
14218
|
cmd_proof "$@"
|
|
@@ -13918,8 +14232,30 @@ main() {
|
|
|
13918
14232
|
completions)
|
|
13919
14233
|
cmd_completions "$@"
|
|
13920
14234
|
;;
|
|
14235
|
+
kpis)
|
|
14236
|
+
# kpis is a Bun-only command (Phase K, v7.5.28+): it ships in the
|
|
14237
|
+
# Bun runtime (loki-ts) and bin/loki routes it there. On the bash
|
|
14238
|
+
# route (LOKI_LEGACY_BASH=1, or a machine without Bun installed)
|
|
14239
|
+
# there is no bash implementation. Rather than the generic
|
|
14240
|
+
# "Unknown command" -- which contradicts `loki help` listing kpis --
|
|
14241
|
+
# state the requirement honestly. Respect --json with a structured
|
|
14242
|
+
# payload so a machine consumer is not handed prose.
|
|
14243
|
+
if [ "${1:-}" = "--json" ]; then
|
|
14244
|
+
printf '{"available": false, "reason": "loki kpis requires the Bun runtime; it is not implemented on the bash (LOKI_LEGACY_BASH) route"}\n'
|
|
14245
|
+
else
|
|
14246
|
+
echo "loki kpis requires the Bun runtime and is not available on the bash route." >&2
|
|
14247
|
+
echo "Remove LOKI_LEGACY_BASH=1 (or install Bun: https://bun.sh) to use 'loki kpis'." >&2
|
|
14248
|
+
fi
|
|
14249
|
+
exit 1
|
|
14250
|
+
;;
|
|
13921
14251
|
help|--help|-h)
|
|
13922
|
-
|
|
14252
|
+
# CLI consolidation (Phase A): `loki help aliases` prints the full
|
|
14253
|
+
# deprecated-alias table; bare help prints the grouped front page.
|
|
14254
|
+
if [ "${1:-}" = "aliases" ]; then
|
|
14255
|
+
show_help_aliases
|
|
14256
|
+
else
|
|
14257
|
+
show_help
|
|
14258
|
+
fi
|
|
13923
14259
|
;;
|
|
13924
14260
|
*)
|
|
13925
14261
|
echo -e "${RED}Unknown command: $command${NC}"
|
|
@@ -19054,6 +19390,31 @@ cmd_syslog() {
|
|
|
19054
19390
|
# dashboard endpoint, and the tests all agree. Honest: with <2 runs it prints
|
|
19055
19391
|
# "not enough history yet", never a fabricated trend.
|
|
19056
19392
|
cmd_trust() {
|
|
19393
|
+
# CLI consolidation (Phase A): `trust detail` is the grouped form of the
|
|
19394
|
+
# trust-metrics breakdown. It forwards 1:1 to cmd_trust_metrics (no handler
|
|
19395
|
+
# logic moves). The bare `loki trust` remains the trajectory view. The
|
|
19396
|
+
# deprecation pointer for the old `trust-metrics` name is emitted at the
|
|
19397
|
+
# alias dispatch arm (main()), never here, so `trust detail` stays clean.
|
|
19398
|
+
#
|
|
19399
|
+
# Flag-anywhere: `detail` is accepted in any position (`trust detail`,
|
|
19400
|
+
# `trust --json detail`, `trust detail --json`) so the bash route matches the
|
|
19401
|
+
# bin/loki routing (which forwards on `detail` anywhere) and both routes
|
|
19402
|
+
# behave byte-identically for the same input. The `detail` token is stripped
|
|
19403
|
+
# and the remaining args (e.g. --json) forward to cmd_trust_metrics.
|
|
19404
|
+
local _trust_detail=0
|
|
19405
|
+
local _trust_rest=()
|
|
19406
|
+
local _ta
|
|
19407
|
+
for _ta in "$@"; do
|
|
19408
|
+
if [ "$_ta" = "detail" ]; then
|
|
19409
|
+
_trust_detail=1
|
|
19410
|
+
else
|
|
19411
|
+
_trust_rest+=("$_ta")
|
|
19412
|
+
fi
|
|
19413
|
+
done
|
|
19414
|
+
if [ "$_trust_detail" -eq 1 ]; then
|
|
19415
|
+
cmd_trust_metrics ${_trust_rest[@]+"${_trust_rest[@]}"}
|
|
19416
|
+
return $?
|
|
19417
|
+
fi
|
|
19057
19418
|
local pass_args=()
|
|
19058
19419
|
while [[ $# -gt 0 ]]; do
|
|
19059
19420
|
case "$1" in
|
|
@@ -19077,7 +19438,9 @@ cmd_trust() {
|
|
|
19077
19438
|
exit 0
|
|
19078
19439
|
;;
|
|
19079
19440
|
--json) pass_args+=("--json"); shift ;;
|
|
19080
|
-
|
|
19441
|
+
# Errors go to STDERR (not stdout) so a --json consumer's stdout
|
|
19442
|
+
# stays clean, matching the Bun route (trust.ts writes to stderr).
|
|
19443
|
+
*) echo -e "${RED}Unknown option: $1${NC}" >&2; echo "Run 'loki trust --help' for usage." >&2; exit 1 ;;
|
|
19081
19444
|
esac
|
|
19082
19445
|
done
|
|
19083
19446
|
|
|
@@ -25871,7 +26234,35 @@ _test_gen_bats() {
|
|
|
25871
26234
|
}
|
|
25872
26235
|
|
|
25873
26236
|
# Session report generator (v6.27.0)
|
|
26237
|
+
# CLI consolidation (Phase A): `report` noun dispatcher.
|
|
26238
|
+
# Groups the read-only reporting cluster under one noun:
|
|
26239
|
+
# report session -> cmd_stats (session statistics)
|
|
26240
|
+
# report metrics -> cmd_metrics (productivity report)
|
|
26241
|
+
# report cost -> cmd_cost (cost + budget view)
|
|
26242
|
+
# report export -> cmd_export (session data export)
|
|
26243
|
+
# report share -> cmd_share (share report as Gist)
|
|
26244
|
+
# report dogfood -> cmd_dogfood (self-development stats)
|
|
26245
|
+
# Any other first token (including a flag like --format, or no token) falls
|
|
26246
|
+
# through to the legacy session-report generator (cmd_report_legacy) so that the
|
|
26247
|
+
# pre-existing `loki report [--format ...]` surface is byte-for-byte unchanged.
|
|
26248
|
+
# No handler logic moves in Phase A: each subcommand calls the existing bare
|
|
26249
|
+
# cmd_* function so the canonical `report <sub>` output is identical to the
|
|
26250
|
+
# legacy top-level command. The deprecation pointer for the old top-level names
|
|
26251
|
+
# is emitted at the alias dispatch arm (main()), never here, so `report <sub>`
|
|
26252
|
+
# stays clean.
|
|
25874
26253
|
cmd_report() {
|
|
26254
|
+
case "${1:-}" in
|
|
26255
|
+
session) shift; cmd_stats "$@"; return $? ;;
|
|
26256
|
+
metrics) shift; cmd_metrics "$@"; return $? ;;
|
|
26257
|
+
cost) shift; cmd_cost "$@"; return $? ;;
|
|
26258
|
+
export) shift; cmd_export "$@"; return $? ;;
|
|
26259
|
+
share) shift; cmd_share "$@"; return $? ;;
|
|
26260
|
+
dogfood) shift; cmd_dogfood "$@"; return $? ;;
|
|
26261
|
+
esac
|
|
26262
|
+
cmd_report_legacy "$@"
|
|
26263
|
+
}
|
|
26264
|
+
|
|
26265
|
+
cmd_report_legacy() {
|
|
25875
26266
|
local session_id=""
|
|
25876
26267
|
local format="text"
|
|
25877
26268
|
local output_file=""
|
|
@@ -25884,10 +26275,22 @@ cmd_report() {
|
|
|
25884
26275
|
--help|-h)
|
|
25885
26276
|
echo -e "${BOLD}loki report${NC} - Session report generator (v6.27.0)"
|
|
25886
26277
|
echo ""
|
|
25887
|
-
echo "Usage: loki report [options]"
|
|
26278
|
+
echo "Usage: loki report [subcommand] [options]"
|
|
25888
26279
|
echo ""
|
|
25889
26280
|
echo "Generates a readable session report from .loki/ data."
|
|
25890
26281
|
echo ""
|
|
26282
|
+
echo "Subcommands (grouped reporting surface, v7.31):"
|
|
26283
|
+
echo " session Session statistics (was: loki stats)"
|
|
26284
|
+
echo " metrics Efficiency/reward metrics (was: loki metrics)"
|
|
26285
|
+
echo " cost Token cost breakdown (was: loki cost)"
|
|
26286
|
+
echo " export Export session data (was: loki export) [json|markdown|csv|timeline]"
|
|
26287
|
+
echo " share Share session assets (was: loki share)"
|
|
26288
|
+
echo " dogfood Self-development stats (was: loki dogfood)"
|
|
26289
|
+
echo " (Run 'loki report <subcommand> --help' for each. The old"
|
|
26290
|
+
echo " top-level names still work; see 'loki help aliases'.)"
|
|
26291
|
+
echo ""
|
|
26292
|
+
echo "With no subcommand, generates the legacy session report below."
|
|
26293
|
+
echo ""
|
|
25891
26294
|
echo "Options:"
|
|
25892
26295
|
echo " --session <id> Report for specific session (default: latest)"
|
|
25893
26296
|
echo " --format <fmt> Output format: text, markdown, html (default: text)"
|