loki-mode 7.88.0 → 7.89.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/autonomy/loki CHANGED
@@ -1017,29 +1017,35 @@ detect_arg_type() {
1017
1017
  return 0
1018
1018
  fi
1019
1019
 
1020
- # Path-like (contains / or starts with . or /) -> treat as PRD
1021
- if [[ "$arg" == */* ]] || [[ "$arg" == .* ]] || [[ "$arg" == /* ]]; then
1022
- echo "prd"
1023
- return 0
1024
- fi
1025
-
1026
- # Existing file on disk -> PRD
1020
+ # An existing file on disk is unambiguously a PRD, even if its name has
1021
+ # spaces -- a real path the user pointed at wins over the brief heuristic.
1027
1022
  if [ -e "$arg" ]; then
1028
1023
  echo "prd"
1029
1024
  return 0
1030
1025
  fi
1031
1026
 
1032
1027
  # R7 (zero-config first run): a one-line brief. An arg that contains
1033
- # whitespace and matched none of the file/issue/path patterns above is a
1034
- # natural-language brief (e.g. "build a todo app"), NOT a PRD path. This is
1035
- # additive: a single-token arg with no whitespace still falls through to
1036
- # "unknown" (PRD-path back-compat) below. The `--brief` flag is the
1037
- # deterministic escape hatch for the rare single-word brief.
1028
+ # WHITESPACE and is not an existing file is a natural-language brief, NOT a
1029
+ # path -- a real PRD path argument essentially never contains spaces, whereas
1030
+ # a brief routinely contains slashes/punctuation ("add/list/done", "CI/CD",
1031
+ # "input/output"). This MUST come before the path-like (contains "/")
1032
+ # heuristic below, else a brief like "a todo app with add/list/done" is
1033
+ # misrouted to PRD mode and dies with "PRD file not found" (W1 E2E bug,
1034
+ # v7.89.1). The `--brief` flag remains the escape hatch for a single-word
1035
+ # brief with no whitespace.
1038
1036
  if [[ "$arg" == *[[:space:]]* ]]; then
1039
1037
  echo "brief"
1040
1038
  return 0
1041
1039
  fi
1042
1040
 
1041
+ # Path-like (contains / or starts with . or /) -> treat as PRD. Reached only
1042
+ # for a NO-WHITESPACE arg (a brief with spaces was already handled above), so
1043
+ # this is a genuine file path like ./prd.md or docs/spec.md.
1044
+ if [[ "$arg" == */* ]] || [[ "$arg" == .* ]] || [[ "$arg" == /* ]]; then
1045
+ echo "prd"
1046
+ return 0
1047
+ fi
1048
+
1043
1049
  # Fallback: unknown. Caller treats as PRD for backward compat.
1044
1050
  echo "unknown"
1045
1051
  }
@@ -5315,14 +5321,17 @@ cmd_welcome_terminal() {
5315
5321
  echo -e " Quick start: ${BOLD}loki quickstart${NC} (from your idea) or ${BOLD}loki start ./prd.md${NC} (from a spec)"
5316
5322
  echo -e " Docs: ${BOLD}https://www.autonomi.dev/docs${NC}"
5317
5323
  echo ""
5324
+ # One-time honest disclosure (this welcome screen shows once, via the
5325
+ # WELCOME_MARKER). On-by-default anonymous diagnostics must be disclosed
5326
+ # somewhere so collection is never covert; this single line is that
5327
+ # disclosure. It is NOT repeated on later runs. Enterprise/CI/air-gapped
5328
+ # installs auto-disable collection, so the line only appears when it is
5329
+ # actually on. Opt out anytime: loki telemetry off.
5318
5330
  if _loki_welcome_analytics_on; then
5319
- echo -e " ${DIM}Anonymous usage analytics are ON (you opted in). We never collect${NC}"
5320
- echo -e " ${DIM}prompts, PRDs, or code. Opt out: loki telemetry off${NC}"
5321
- else
5322
- echo -e " ${DIM}Anonymous analytics are off by default. Nothing is sent unless you${NC}"
5323
- echo -e " ${DIM}opt in with: loki telemetry on${NC}"
5331
+ echo -e " ${DIM}Anonymous diagnostics on (os/arch/version/error type only -- never${NC}"
5332
+ echo -e " ${DIM}code, prompts, or paths). Off: loki telemetry off - docs/PRIVACY.md${NC}"
5333
+ echo ""
5324
5334
  fi
5325
- echo ""
5326
5335
  }
5327
5336
 
5328
5337
  cmd_welcome() {
@@ -5419,7 +5428,7 @@ cmd_web() {
5419
5428
  case "$subcommand" in
5420
5429
  start)
5421
5430
  shift || true
5422
- cmd_web_start "$@"
5431
+ cmd_web_redirect_to_dashboard "$@"
5423
5432
  ;;
5424
5433
  stop)
5425
5434
  cmd_web_stop
@@ -5449,51 +5458,87 @@ cmd_web() {
5449
5458
  *)
5450
5459
  # Treat unknown args as options to start (e.g., loki web --no-open)
5451
5460
  shift
5452
- cmd_web_start "$subcommand" "$@"
5461
+ cmd_web_redirect_to_dashboard "$subcommand" "$@"
5453
5462
  ;;
5454
5463
  esac
5455
5464
  }
5456
5465
 
5466
+ # v7.x (F55): `loki web` (the command a user intuitively types) used to launch
5467
+ # the deprecated Purple Lab, whose '/' redirects to '/lab/' and whose port has
5468
+ # none of the real dashboard APIs (/api/status, /trust, etc. all 404). A user
5469
+ # typing the obvious command landed on the wrong, broken-looking surface. The
5470
+ # value-preserving fix: the START path now launches the real dashboard instead.
5471
+ # 'loki web stop|status|logs' still operate on Purple Lab so anyone who started
5472
+ # it the old way (or via scripts) is never stranded. The deprecation banner has
5473
+ # already printed in cmd_web() before we get here.
5474
+ cmd_web_redirect_to_dashboard() {
5475
+ # The dashboard start path does not accept Purple-Lab-only flags
5476
+ # (--no-open, --prd). Filter them so `loki web --no-open` (used in CI) and
5477
+ # `loki web --prd X` keep working instead of erroring on an unknown option.
5478
+ # --port is shared and passes straight through.
5479
+ local orig_args=("$@")
5480
+ local dash_args=()
5481
+ while [[ $# -gt 0 ]]; do
5482
+ case "$1" in
5483
+ --no-open)
5484
+ # Dashboard has no browser-open behavior to suppress; drop it.
5485
+ shift
5486
+ ;;
5487
+ --prd)
5488
+ # Purple-Lab-only prefill; not supported by the dashboard.
5489
+ shift 2 2>/dev/null || shift
5490
+ ;;
5491
+ --prd=*)
5492
+ shift
5493
+ ;;
5494
+ *)
5495
+ dash_args+=("$1")
5496
+ shift
5497
+ ;;
5498
+ esac
5499
+ done
5500
+
5501
+ # Safe empty-array expansion (bash 3.2 + set -u): ${arr[@]+"${arr[@]}"}
5502
+ if ! _deprecated_alias_should_suppress ${orig_args[@]+"${orig_args[@]}"}; then
5503
+ echo "Launching the dashboard (http://localhost:${DASHBOARD_DEFAULT_PORT}) instead of the deprecated Purple Lab." >&2
5504
+ fi
5505
+ cmd_dashboard_start ${dash_args[@]+"${dash_args[@]}"}
5506
+ }
5507
+
5457
5508
  cmd_web_help() {
5458
5509
  echo -e "${BOLD}Purple Lab -- Loki Mode Web UI (deprecated -- use the dashboard)${NC}"
5459
5510
  echo ""
5460
5511
  echo "Usage: loki web [command] [options]"
5461
5512
  echo ""
5462
5513
  echo "DEPRECATED as of v7.44.0: Purple Lab is consolidated into the dashboard."
5463
- echo " For local build + monitoring, use the dashboard (auto-launches at"
5464
- echo " 'loki start', http://localhost:${DASHBOARD_DEFAULT_PORT}; or 'loki dashboard')."
5465
- echo " For the hosted platform, see Autonomi Cloud."
5466
- echo " 'loki web' still works for now (it launches after a deprecation notice),"
5467
- echo " but it will be removed in a future release. Migrate to the dashboard."
5514
+ echo " 'loki web' (no subcommand) now LAUNCHES THE DASHBOARD"
5515
+ echo " (http://localhost:${DASHBOARD_DEFAULT_PORT}) instead of the deprecated Purple"
5516
+ echo " Lab, so the obvious command lands you on the working UI. Use the embedded"
5517
+ echo " 'Lab' tab there to submit a PRD. For the hosted platform, see Autonomi Cloud."
5468
5518
  echo ""
5469
- echo "Note: 'loki web' is Purple Lab (the PRD-input/build-watch UI, port ${PURPLE_LAB_DEFAULT_PORT})."
5470
- echo " It is NOT the same as 'loki dashboard' (operations UI, port ${DASHBOARD_DEFAULT_PORT})."
5471
- echo " Use 'loki dashboard' to monitor running agents, tasks, costs, council, escalations."
5519
+ echo "Note: the canonical command is 'loki dashboard' (operations UI, port ${DASHBOARD_DEFAULT_PORT})."
5520
+ echo " Use it to monitor running agents, tasks, costs, council, escalations."
5472
5521
  echo ""
5473
5522
  echo "Commands:"
5474
- echo " start Start Purple Lab (default)"
5475
- echo " stop Stop Purple Lab server"
5523
+ echo " start Launch the dashboard (default; Purple Lab is deprecated)"
5524
+ echo " stop Stop the Purple Lab server (if one was started the old way)"
5476
5525
  echo " status Show Purple Lab server status"
5477
5526
  echo " logs Show Purple Lab server logs"
5478
5527
  echo " help Show this help"
5479
5528
  echo ""
5480
5529
  echo "Options (for start):"
5481
- echo " --no-open Don't open browser automatically"
5482
- echo " --port PORT Use custom port (default: ${PURPLE_LAB_DEFAULT_PORT})"
5483
- echo ""
5484
- echo "Purple Lab is the product UI where you input PRDs and watch agents build."
5485
- echo "It runs its own backend (web-app/server.py) on port ${PURPLE_LAB_DEFAULT_PORT}."
5530
+ echo " --port PORT Use custom port (default: ${DASHBOARD_DEFAULT_PORT})"
5531
+ echo " --no-open Accepted for back-compat; ignored (no-op on the dashboard)"
5486
5532
  echo ""
5487
5533
  echo "Examples:"
5488
- echo " loki web Start Purple Lab and open in browser"
5489
- echo " loki web --no-open Start without opening browser"
5490
- echo " loki web stop Stop the Purple Lab server"
5534
+ echo " loki web Launch the dashboard"
5535
+ echo " loki web --no-open Launch the dashboard (--no-open is a no-op)"
5536
+ echo " loki web stop Stop a Purple Lab server started the old way"
5491
5537
  echo ""
5492
5538
  echo "Note (since v7.5.30):"
5493
- echo " Purple Lab is also embedded in the Dashboard as a Lab sidebar entry."
5494
- echo " Run 'loki dashboard start' and click 'Lab' to use the same UI"
5495
- echo " without spawning a second port. 'loki web' standalone remains"
5496
- echo " supported (Rule 0); both modes serve the same React bundle."
5539
+ echo " The same PRD-input UI is embedded in the dashboard as a 'Lab' sidebar entry."
5540
+ echo " 'loki web stop|status|logs' still operate on a standalone Purple Lab"
5541
+ echo " process so anyone who started one the old way is never stranded."
5497
5542
  }
5498
5543
 
5499
5544
  cmd_web_start() {
@@ -16110,6 +16155,18 @@ worktree wt projects cp rc trust-metrics serve agent code self_update test help
16110
16155
 
16111
16156
  # Main command dispatcher
16112
16157
  main() {
16158
+ # v7.89.0 telemetry TTY fix (council cH_r1 AC1): resolve interactivity EXACTLY
16159
+ # ONCE here, while autonomy/loki main still owns the user's real TTY, and
16160
+ # export the explicit signal that the telemetry/crash gates trust instead of a
16161
+ # late `-t` re-probe. When invoked via the bin/loki shim the var is already
16162
+ # exported (and re-exporting the same value is a no-op); this covers the path
16163
+ # where autonomy/loki is invoked directly (LOKI_LEGACY_BASH, no-Bun, or a
16164
+ # direct call). Only set when a terminal is actually present; leave UNSET
16165
+ # otherwise so isolated gate unit tests fall back to their own `-t` probe.
16166
+ if [ -z "${LOKI_TTY_INTERACTIVE:-}" ] && { [ -t 1 ] || [ -t 0 ]; }; then
16167
+ export LOKI_TTY_INTERACTIVE=1
16168
+ fi
16169
+
16113
16170
  # v7.5.18: early guard -- LOKI_PROVIDER=gemini is no longer supported.
16114
16171
  if [ "${LOKI_PROVIDER:-}" = "gemini" ]; then
16115
16172
  echo -e "${RED}Error: Provider 'gemini' is deprecated as of v7.5.18 and has been removed.${NC}" >&2
@@ -16131,6 +16188,19 @@ main() {
16131
16188
  # v7.4.13: first-run telemetry moved to bin/loki shim so it fires for
16132
16189
  # both Bun-routed and bash-routed commands (autonomy/loki main() never
16133
16190
  # runs for the 8 ported commands). Marker file: ~/.loki-first-run.
16191
+ #
16192
+ # v7.89.0 (council cH_r1 AC4): this is a FOREGROUND egress on the bash route.
16193
+ # Before it can phone home, the user must have seen the disclosure once -- a
16194
+ # bash-routed first command must never be covert. Evaluate the SAME gate the
16195
+ # egress uses, and if collection is genuinely enabled, disclose once (shared
16196
+ # impl from telemetry.sh, keyed on its own marker, so it never double-prints
16197
+ # with the Bun route or repeats). loki_telemetry itself re-checks the gate, so
16198
+ # this only adds the disclosure; it never changes whether we send.
16199
+ if declare -f _loki_telemetry_enabled >/dev/null 2>&1 \
16200
+ && declare -f _loki_disclose_telemetry_once >/dev/null 2>&1 \
16201
+ && _loki_telemetry_enabled; then
16202
+ _loki_disclose_telemetry_once
16203
+ fi
16134
16204
  loki_telemetry "cli_command" "command=$command" 2>/dev/null || true
16135
16205
 
16136
16206
  # Unified config-file pre-pass (#691). For session commands ONLY, honor
@@ -21947,13 +22017,32 @@ try {
21947
22017
 
21948
22018
  # Unified collection state (PostHog usage telemetry + crash reporting).
21949
22019
  # loki_collection_enabled is the single source of truth (crash.sh).
21950
- # Collection is OPT-IN: OFF by default, enabled only after opt-in.
22020
+ # Collection is ON BY DEFAULT for individual interactive installs and
22021
+ # auto-off in enterprise/CI/air-gapped/non-interactive contexts; an
22022
+ # explicit opt-out always wins. AC8 (council cH_r1): the status copy
22023
+ # must distinguish "on by default" from an explicit "you opted in".
21951
22024
  echo ""
21952
22025
  if type loki_collection_enabled &>/dev/null; then
21953
22026
  if loki_collection_enabled; then
21954
- echo -e " Collection: ${GREEN}enabled${NC} (you opted in; anonymous diagnostics; opt out with: loki telemetry off)"
22027
+ # Detect an EXPLICIT opt-in (env LOKI_TELEMETRY=on, or the
22028
+ # persistent ~/.loki/config TELEMETRY_ENABLED=true written by
22029
+ # `loki telemetry on`). Anything else that is enabled is the
22030
+ # individual on-by-default path.
22031
+ local _telem_lower_status
22032
+ _telem_lower_status="$(printf '%s' "${LOKI_TELEMETRY:-}" | tr '[:upper:]' '[:lower:]')"
22033
+ local _explicit_optin=false
22034
+ if [ "$_telem_lower_status" = "on" ]; then
22035
+ _explicit_optin=true
22036
+ elif [ -f "$global_config" ] && grep -q "^TELEMETRY_ENABLED=true" "$global_config" 2>/dev/null; then
22037
+ _explicit_optin=true
22038
+ fi
22039
+ if [ "$_explicit_optin" = true ]; then
22040
+ echo -e " Collection: ${GREEN}enabled${NC} (you opted in; anonymous diagnostics; opt out with: loki telemetry off)"
22041
+ else
22042
+ echo -e " Collection: ${GREEN}on by default${NC} (anonymous diagnostics; opt out with: loki telemetry off)"
22043
+ fi
21955
22044
  else
21956
- echo -e " Collection: ${YELLOW}off by default${NC} (nothing sent; opt in with: loki telemetry on)"
22045
+ echo -e " Collection: ${YELLOW}off${NC} (nothing sent; enterprise/CI/air-gapped or opted out; opt in with: loki telemetry on)"
21957
22046
  fi
21958
22047
  fi
21959
22048
 
@@ -30649,7 +30738,7 @@ cmd_proof() {
30649
30738
  # "No proofs found" line -- matching the Bun route (proof.ts
30650
30739
  # listProofs, which returns before the header when rows is empty).
30651
30740
  if [ "$found" -eq 0 ]; then
30652
- printf "%-26s %-20s %-10s %-9s %s\n" "RUN_ID" "GENERATED_AT" "VERDICT" "COST_USD" "FILES"
30741
+ printf "%-26s %-20s %-18s %-9s %s\n" "RUN_ID" "GENERATED_AT" "VERDICT" "COST_USD" "FILES"
30653
30742
  fi
30654
30743
  found=1
30655
30744
  LOKI_PROOF_JSON="$pj" python3 - <<'PYEOF'
@@ -30667,10 +30756,14 @@ def s(v):
30667
30756
  return "-" if v is None else str(v)
30668
30757
  run_id = d.get("run_id")
30669
30758
  gen = d.get("generated_at")
30670
- verdict = (d.get("council") or {}).get("final_verdict")
30759
+ # The honest verdict lives in honesty.headline (VERIFIED / VERIFIED WITH GAPS /
30760
+ # NOT VERIFIED); fall back to legacy council.final_verdict for older proofs.
30761
+ verdict = (d.get("honesty") or {}).get("headline")
30762
+ if verdict is None:
30763
+ verdict = (d.get("council") or {}).get("final_verdict")
30671
30764
  cost = (d.get("cost") or {}).get("usd")
30672
30765
  files = (d.get("files_changed") or {}).get("count")
30673
- print("{:<26} {:<20} {:<10} {:<9} {}".format(
30766
+ print("{:<26} {:<20} {:<18} {:<9} {}".format(
30674
30767
  s(run_id), s(gen), s(verdict), s(cost), s(files)))
30675
30768
  PYEOF
30676
30769
  done