loki-mode 9.73.0 → 9.74.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.
Files changed (73) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/autonomy/lib/proof-generator.py +7 -0
  4. package/autonomy/loki +18 -7
  5. package/autonomy/run.sh +14 -1
  6. package/dashboard/__init__.py +1 -1
  7. package/dashboard/server.py +22 -13
  8. package/dashboard/static/index.html +5 -5
  9. package/docs/INSTALLATION.md +1 -1
  10. package/docs/v10/ARCHITECT-CUTS.md +257 -314
  11. package/docs/v10/BOARD.md +25 -5
  12. package/loki-ts/dist/loki.js +251 -250
  13. package/mcp/__init__.py +1 -1
  14. package/package.json +1 -1
  15. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  16. package/web-app/dist/assets/{AdminPage-B11jqriL.js → AdminPage-DaeYgQSE.js} +1 -1
  17. package/web-app/dist/assets/{Avatar-vmIEiL2U.js → Avatar-CgwQi58_.js} +1 -1
  18. package/web-app/dist/assets/{Badge-DxtrDGcl.js → Badge-Bwq-lpRh.js} +1 -1
  19. package/web-app/dist/assets/{Button-BiPlRkkg.js → Button-BEf4Nher.js} +1 -1
  20. package/web-app/dist/assets/{CockpitPage-DXKAc0jc.js → CockpitPage-Bj41Xtg9.js} +1 -1
  21. package/web-app/dist/assets/{ComparePage-B4ddvt9J.js → ComparePage-tFbdo90G.js} +1 -1
  22. package/web-app/dist/assets/{ErrorBoundary-BIJy59N_.js → ErrorBoundary-Brewvgm9.js} +1 -1
  23. package/web-app/dist/assets/{EvidenceReceiptPanel-C4-Phh1f.js → EvidenceReceiptPanel-h_82QBVa.js} +1 -1
  24. package/web-app/dist/assets/GitHubIssuesPanel-Dcg5xDMm.js +7 -0
  25. package/web-app/dist/assets/{GitHubPRsPanel-B_VHTB-t.js → GitHubPRsPanel-DFKzVyA1.js} +1 -1
  26. package/web-app/dist/assets/{HomePage-cxONjTSm.js → HomePage-D21cM1Je.js} +2 -2
  27. package/web-app/dist/assets/{LoginPage-D49p6aVy.js → LoginPage-DJ9yqMn4.js} +1 -1
  28. package/web-app/dist/assets/{MagicPage-C5GUEIuM.js → MagicPage-mwkjJhBy.js} +1 -1
  29. package/web-app/dist/assets/{MetricsPage-I-OXi9kG.js → MetricsPage-D2q-PD-s.js} +1 -1
  30. package/web-app/dist/assets/{NotFoundPage-Do19cbOP.js → NotFoundPage-BtusJvgS.js} +1 -1
  31. package/web-app/dist/assets/{ProjectPage-TRyzTIFH.js → ProjectPage-CRPALtO8.js} +63 -63
  32. package/web-app/dist/assets/{ProjectsPage-BLSDhtVb.js → ProjectsPage-DuzABpfc.js} +1 -1
  33. package/web-app/dist/assets/{SettingsPage-BvixtAw7.js → SettingsPage-DhJPX-Rf.js} +1 -1
  34. package/web-app/dist/assets/{ShowcasePage-By96BMJz.js → ShowcasePage-CvgS47nu.js} +1 -1
  35. package/web-app/dist/assets/{SystemSettingsPage-AvVujpIo.js → SystemSettingsPage-l3Cv9YjY.js} +1 -1
  36. package/web-app/dist/assets/{TeamsPage-BiT3N4px.js → TeamsPage-DridGcnR.js} +1 -1
  37. package/web-app/dist/assets/{TemplatesPage-Y_m-dzfd.js → TemplatesPage-CTNsfp03.js} +1 -1
  38. package/web-app/dist/assets/{TerminalOutput-oPTCcEGy.js → TerminalOutput-BuyksqLh.js} +1 -1
  39. package/web-app/dist/assets/{activity-DCa9Pi7k.js → activity-DM2TKaBi.js} +1 -1
  40. package/web-app/dist/assets/{bell-Br7Xsjam.js → bell-D2PMLbbX.js} +1 -1
  41. package/web-app/dist/assets/{bot-BsQKlSP5.js → bot-BnN32Jxp.js} +1 -1
  42. package/web-app/dist/assets/{check-Cb49hCzQ.js → check-CU128nw_.js} +1 -1
  43. package/web-app/dist/assets/{chevron-left-Cs63FOmY.js → chevron-left-ehNW1Do7.js} +1 -1
  44. package/web-app/dist/assets/{circle-alert-C8A636Wl.js → circle-alert-Cpw2gtOC.js} +1 -1
  45. package/web-app/dist/assets/{clock-DhlnHjQI.js → clock-BOZHdPVS.js} +1 -1
  46. package/web-app/dist/assets/{cloud-uOYQxGRY.js → cloud-BZ2L9Fzi.js} +1 -1
  47. package/web-app/dist/assets/{code-xml-9O9XlVo9.js → code-xml-sSo522gu.js} +1 -1
  48. package/web-app/dist/assets/{database-D9Oek2JS.js → database-DrR1xHzS.js} +1 -1
  49. package/web-app/dist/assets/{dollar-sign-CHetUBPR.js → dollar-sign-CHE3T_rh.js} +1 -1
  50. package/web-app/dist/assets/{file-code-corner-oTJV_ce4.js → file-code-corner-CgcssyRQ.js} +1 -1
  51. package/web-app/dist/assets/{file-plus-vuloOqQB.js → file-plus-DtwfrxYH.js} +1 -1
  52. package/web-app/dist/assets/{globe-DMVdf8bk.js → globe-Dzla77iL.js} +1 -1
  53. package/web-app/dist/assets/{hammer-15WRQJ1o.js → hammer-BAMdG66t.js} +1 -1
  54. package/web-app/dist/assets/{index-SRKz3Imw.js → index-mQOnSYoW.js} +2 -2
  55. package/web-app/dist/assets/{layers-C-QQQP9K.js → layers-DhuyLqmc.js} +1 -1
  56. package/web-app/dist/assets/{loader-circle-DqoJevCK.js → loader-circle-DclFyQ3B.js} +1 -1
  57. package/web-app/dist/assets/{lock-B68yfqau.js → lock-C8v_bXNl.js} +1 -1
  58. package/web-app/dist/assets/{package-DAxTtm-S.js → package-B4AnjM5D.js} +1 -1
  59. package/web-app/dist/assets/{plus-BSbdI5QI.js → plus-DM95CmZI.js} +1 -1
  60. package/web-app/dist/assets/{refresh-cw-DlvFuI3J.js → refresh-cw-CWaauzqX.js} +1 -1
  61. package/web-app/dist/assets/{rotate-ccw-BF03pKE0.js → rotate-ccw-DxcvylpJ.js} +1 -1
  62. package/web-app/dist/assets/{scroll-text-QFZ1JdTD.js → scroll-text-Dx-V_BpP.js} +1 -1
  63. package/web-app/dist/assets/{server-tyIvmSke.js → server-Cj2EfoGN.js} +1 -1
  64. package/web-app/dist/assets/{shield-alert-DHeqbtBK.js → shield-alert-OlmWv7sU.js} +1 -1
  65. package/web-app/dist/assets/{thumbs-up-CRag1Tn5.js → thumbs-up-CIpJhyTd.js} +1 -1
  66. package/web-app/dist/assets/{trash-2-B0n4x-Ds.js → trash-2-BIkoZkY6.js} +1 -1
  67. package/web-app/dist/assets/{trending-down-DC4Aqzso.js → trending-down-CI-OcCGt.js} +1 -1
  68. package/web-app/dist/assets/{trending-up-DFG157ke.js → trending-up-B0dpgKi-.js} +1 -1
  69. package/web-app/dist/assets/{upload-BdWQ4cWx.js → upload-NhOBAjKA.js} +1 -1
  70. package/web-app/dist/assets/{usePolling-DMgD-dJ5.js → usePolling-_QRF6f7x.js} +1 -1
  71. package/web-app/dist/assets/{user-DXaZeAe4.js → user-kRNvOpun.js} +1 -1
  72. package/web-app/dist/index.html +1 -1
  73. package/web-app/dist/assets/GitHubIssuesPanel-CVIG0uwi.js +0 -7
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: loki-mode
3
3
  description: Autonomous spec-driven build system with a built-in trust layer. It does not call work done until it is verified (RARV-C closure loop, 8 quality gates, completion council, verified-completion evidence gate). Triggers on "Loki Mode". Takes a spec (PRD, GitHub issue, OpenAPI doc, etc.) to deployed product with minimal human intervention. Provider-agnostic. Requires --dangerously-skip-permissions flag.
4
4
  ---
5
5
 
6
- # Loki Mode v9.73.0
6
+ # Loki Mode v9.74.0
7
7
 
8
8
  **You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
9
9
 
@@ -470,4 +470,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
470
470
 
471
471
  ---
472
472
 
473
- **v9.73.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
473
+ **v9.74.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 9.73.0
1
+ 9.74.0
@@ -911,6 +911,7 @@ def _collect_tests(loki_dir):
911
911
  "status": "not_run",
912
912
  "duration_sec": None,
913
913
  }
914
+ empty = dict(out)
914
915
  if not isinstance(raw, dict):
915
916
  return out
916
917
  out["runner"] = str(raw.get("runner") or "")
@@ -944,6 +945,12 @@ def _collect_tests(loki_dir):
944
945
  out["status"] = "inconclusive"
945
946
  else:
946
947
  out["status"] = "not_run"
948
+ # BACKLOG 98: a test-results.json left by an earlier iteration is not this
949
+ # run's evidence, so it cannot lift the headline (the gates' rule). An
950
+ # earlier red is never discarded: a stale failure still reads failed.
951
+ if out["status"] != "failed" and not _test_results_fresh(
952
+ os.path.join(loki_dir, "quality")):
953
+ return empty
947
954
  return out
948
955
 
949
956
 
package/autonomy/loki CHANGED
@@ -28444,16 +28444,23 @@ if budget_limit is not None:
28444
28444
 
28445
28445
  # Prefer the recorded cumulative spend; fall back to the current run only when
28446
28446
  # the state file carries no figure. Never silently substitute 0.0 for "unknown".
28447
- if isinstance(budget_used_recorded, (int, float)):
28447
+ # A recorded ZERO is not a reading: run.sh check_budget_limit writes
28448
+ # "budget_used": 0 for a run it never measured. Same rule as the dashboard
28449
+ # (server.py budget readers): only a positive recorded figure counts, and a
28450
+ # measured zero comes from current_cost, which collect_efficiency leaves None
28451
+ # unless a record passes record_is_measured.
28452
+ if isinstance(budget_used_recorded, (int, float)) and budget_used_recorded > 0:
28448
28453
  budget_used = budget_used_recorded
28449
28454
  elif isinstance(current_cost, (int, float)):
28450
28455
  budget_used = current_cost
28451
28456
  else:
28452
- budget_used = 0.0
28457
+ budget_used = None
28453
28458
  status = "none"
28454
28459
  percent_used = None
28455
28460
  remaining = None
28456
- if budget_limit is not None and budget_limit > 0:
28461
+ if budget_limit is not None and budget_limit > 0 and budget_used is None:
28462
+ status = "unknown"
28463
+ elif budget_limit is not None and budget_limit > 0:
28457
28464
  percent_used = round(budget_used / budget_limit * 100, 2)
28458
28465
  remaining = max(0.0, budget_limit - budget_used)
28459
28466
  if budget_used >= budget_limit:
@@ -28487,7 +28494,7 @@ if show_json:
28487
28494
  "by_model": {k: round(v, 6) for k, v in by_model.items()},
28488
28495
  "budget": {
28489
28496
  "limit": budget_limit,
28490
- "used": round(budget_used, 6),
28497
+ "used": round(budget_used, 6) if budget_used is not None else None,
28491
28498
  "remaining": round(remaining, 6) if remaining is not None else None,
28492
28499
  "percent_used": percent_used,
28493
28500
  "status": status,
@@ -28538,13 +28545,17 @@ if budget_limit is None:
28538
28545
  print(DIM + " When set, Loki warns at 80% and hard-stops at 100%." + NC)
28539
28546
  else:
28540
28547
  col = GREEN
28541
- if status == "warn":
28548
+ if status in ("warn", "unknown"):
28542
28549
  col = YELLOW
28543
28550
  elif status == "exceeded":
28544
28551
  col = RED
28545
28552
  print(" Cap: " + _fmt_usd(budget_limit))
28546
- print(" Used: " + _fmt_usd(budget_used) + " (" + col + str(percent_used) + "%" + NC + ")")
28547
- print(" Remaining: " + _fmt_usd(remaining))
28553
+ if budget_used is None:
28554
+ print(" Used: not recorded (no measured iteration cost)")
28555
+ print(" Remaining: not recorded")
28556
+ else:
28557
+ print(" Used: " + _fmt_usd(budget_used) + " (" + col + str(percent_used) + "%" + NC + ")")
28558
+ print(" Remaining: " + _fmt_usd(remaining))
28548
28559
  print(" Status: " + col + BOLD + status.upper() + NC)
28549
28560
  if status == "warn":
28550
28561
  print(YELLOW + " Warning: at or above 80% of cap. Run continues; hard-stop at 100%." + NC)
package/autonomy/run.sh CHANGED
@@ -13875,7 +13875,20 @@ sys.stdout.write(t.strip())
13875
13875
  echo "$LOKI_MONOREPO_TEST_CMD" | grep -qE '[;|`$]|&&|\|\||>>|<<'; then
13876
13876
  log_error "LOKI_MONOREPO_TEST_CMD rejected (only [A-Za-z0-9_./= -] allowed): $LOKI_MONOREPO_TEST_CMD"
13877
13877
  test_runner="monorepo-custom-rejected"
13878
- details="monorepo-custom: rejected by whitelist (gate skipped, inconclusive)"
13878
+ # BACKLOG 62: nothing ran, so record the no-runner shape
13879
+ # (see the runner=="none" return below) instead of falling
13880
+ # through with test_passed=true, which wrote pass:true and
13881
+ # touched unit-tests.pass. The runner label stays distinct:
13882
+ # the council reads a non-boolean pass on a named runner as
13883
+ # NO_PASS (inconclusive pass-through). The command itself is
13884
+ # not echoed into the JSON (it failed the whitelist).
13885
+ rm -f "$quality_dir/unit-tests.pass" 2>/dev/null || true
13886
+ cat > "$quality_dir/test-results.json" << TREOF
13887
+ {"timestamp":"$(date -u +%Y-%m-%dT%H:%M:%SZ)","runner":"monorepo-custom-rejected","pass":"inconclusive","summary":"LOKI_MONOREPO_TEST_CMD rejected by whitelist (not run)","command":null,"exit_code":null,"status":"not_run","passed_count":null,"failed_count":null,"verification_gap":"test_command_rejected"}
13888
+ TREOF
13889
+ printf '%s\n' "${ITERATION_COUNT:-0}" > "$quality_dir/.test-results.iter" 2>/dev/null || true
13890
+ _LOKI_TEST_SUITE_STATUS=not_run
13891
+ return 0
13879
13892
  else
13880
13893
  test_runner="monorepo-custom"
13881
13894
  local output
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "9.73.0"
10
+ __version__ = "9.74.0"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -7852,6 +7852,8 @@ def _compute_cost_snapshot() -> dict:
7852
7852
  budget_remaining = None
7853
7853
  # Did ANY record carry an observed value? Not "was a file present".
7854
7854
  cost_recorded = False
7855
+ # Tokens were measured (tracker fallback) but no USD figure was recorded.
7856
+ cost_unknown = False
7855
7857
 
7856
7858
  # Read efficiency files (one JSON file per iteration/task).
7857
7859
  # Use the iteration-*.json pattern so this reader sees the same
@@ -7929,25 +7931,32 @@ def _compute_cost_snapshot() -> dict:
7929
7931
  total_input = totals.get("total_input", 0)
7930
7932
  total_output = totals.get("total_output", 0)
7931
7933
  if total_input > 0 or total_output > 0:
7932
- # Real observed tokens from the context tracker: this IS a
7933
- # measurement, even if the recorded USD total happens to
7934
- # be 0.
7934
+ # Real observed tokens from the context tracker: the TOKENS
7935
+ # are a measurement. The USD figure is only a measurement
7936
+ # when the tracker recorded a number; a missing one is
7937
+ # unknown (null), while a recorded 0.0 stays 0.0.
7935
7938
  cost_recorded = True
7936
- estimated_cost = totals.get("total_cost_usd", 0.0)
7939
+ usd = totals.get("total_cost_usd")
7940
+ if isinstance(usd, (int, float)) and not isinstance(usd, bool):
7941
+ estimated_cost = usd
7942
+ else:
7943
+ cost_unknown = True
7944
+ # No provider recorded -> the model is unknown, not sonnet.
7945
+ model = str(ctx.get("provider") or "unknown").lower()
7937
7946
  # Rebuild by_model and by_phase from per_iteration data
7938
7947
  for it in ctx.get("per_iteration", []):
7939
7948
  inp = it.get("input_tokens", 0)
7940
7949
  out = it.get("output_tokens", 0)
7941
- cost = it.get("cost_usd", 0)
7942
- model = ctx.get("provider", "sonnet").lower()
7950
+ cost = it.get("cost_usd")
7951
+ cost_is_num = isinstance(cost, (int, float)) and not isinstance(cost, bool)
7943
7952
  if model not in by_model:
7944
- by_model[model] = {"input_tokens": 0, "output_tokens": 0, "cost_usd": 0.0}
7953
+ by_model[model] = {"input_tokens": 0, "output_tokens": 0, "cost_usd": 0.0,
7954
+ "measured": False, "tokens_measured": True}
7945
7955
  by_model[model]["input_tokens"] += inp
7946
7956
  by_model[model]["output_tokens"] += out
7947
- by_model[model]["cost_usd"] += cost
7948
- # Observed tokens from the tracker (cost_recorded above).
7949
- by_model[model]["measured"] = True
7950
- by_model[model]["tokens_measured"] = True
7957
+ if cost_is_num:
7958
+ by_model[model]["cost_usd"] += cost
7959
+ by_model[model]["measured"] = True
7951
7960
  except (json.JSONDecodeError, KeyError, TypeError, AttributeError):
7952
7961
  pass
7953
7962
 
@@ -7964,7 +7973,7 @@ def _compute_cost_snapshot() -> dict:
7964
7973
  # Spend against the cap only when something was measured: with
7965
7974
  # nothing recorded, "used" is unknown, not $0.00, and "remaining"
7966
7975
  # is unknown, not the whole cap.
7967
- if budget_limit is not None and cost_recorded:
7976
+ if budget_limit is not None and cost_recorded and not cost_unknown:
7968
7977
  budget_used = estimated_cost
7969
7978
  budget_remaining = max(0.0, budget_limit - budget_used)
7970
7979
  except (json.JSONDecodeError, KeyError):
@@ -7988,7 +7997,7 @@ def _compute_cost_snapshot() -> dict:
7988
7997
  total_input + total_output + total_cache_read + total_cache_creation
7989
7998
  ) if cost_recorded else None,
7990
7999
  "cache_hit_ratio": round(total_cache_read / _read_in, 4) if _read_in > 0 else None,
7991
- "estimated_cost_usd": round(estimated_cost, 6) if cost_recorded else None,
8000
+ "estimated_cost_usd": round(estimated_cost, 6) if cost_recorded and not cost_unknown else None,
7992
8001
  "cost_recorded": cost_recorded,
7993
8002
  "by_phase": {k: {
7994
8003
  "input_tokens": v["input_tokens"] if v.get("tokens_measured") else None,
@@ -5406,7 +5406,7 @@ var LokiDashboard=(()=>{var Le=Object.defineProperty;var kt=Object.getOwnPropert
5406
5406
  ${t}
5407
5407
  </div>
5408
5408
  </div>
5409
- `,this._attachEventListeners()}_attachEventListeners(){let e=this.shadowRoot.querySelectorAll(".tab");e.forEach((n,l)=>{n.addEventListener("click",()=>this._setTab(n.dataset.tab)),n.addEventListener("keydown",c=>{if(c.key==="ArrowRight"||c.key==="ArrowLeft"){c.preventDefault();let p=Array.from(e),u=c.key==="ArrowRight"?(l+1)%p.length:(l-1+p.length)%p.length;p[u].focus(),this._setTab(p[u].dataset.tab)}})}),this.shadowRoot.querySelectorAll(".item-card").forEach(n=>{n.addEventListener("click",()=>this._handleItemClick(n)),n.addEventListener("keydown",l=>{l.key==="Enter"||l.key===" "?(l.preventDefault(),this._handleItemClick(n)):(l.key==="ArrowDown"||l.key==="ArrowUp")&&(l.preventDefault(),this._navigateItemCards(n,l.key==="ArrowDown"?"next":"prev"))})});let t=this.shadowRoot.getElementById("close-detail");t&&t.addEventListener("click",()=>this._closeDetail());let i=this.shadowRoot.getElementById("consolidate-btn");i&&i.addEventListener("click",()=>this._triggerConsolidation());let a=this.shadowRoot.getElementById("refresh-btn");a&&a.addEventListener("click",()=>this._loadData());let s=this.shadowRoot.getElementById("memory-search-input"),r=this.shadowRoot.getElementById("search-btn"),o=this.shadowRoot.getElementById("memory-search-collection");s&&(s.addEventListener("keydown",n=>{n.key==="Enter"&&(n.preventDefault(),this._searchQuery=s.value,this._executeSearch())}),s.addEventListener("input",n=>{this._searchQuery=n.target.value})),r&&r.addEventListener("click",()=>{let n=this.shadowRoot.getElementById("memory-search-input");n&&(this._searchQuery=n.value),this._executeSearch()}),o&&o.addEventListener("change",n=>{this._searchCollection=n.target.value})}_handleItemClick(e){let t=e.dataset.id;switch(e.dataset.type){case"episode":this._selectEpisode(t);break;case"pattern":this._selectPattern(t);break;case"skill":this._selectSkill(t);break}}_navigateItemCards(e,t){let i=Array.from(this.shadowRoot.querySelectorAll(".item-card")),a=i.indexOf(e);if(a===-1)return;let s=t==="next"?a+1:a-1;s>=0&&s<i.length&&i[s].focus()}};customElements.get("loki-memory-browser")||customElements.define("loki-memory-browser",te);var Lt=[{id:"1h",label:"1 Hour",hours:1},{id:"24h",label:"24 Hours",hours:24},{id:"7d",label:"7 Days",hours:168},{id:"30d",label:"30 Days",hours:720}],zt=[{id:"all",label:"All Signals"},{id:"user_preference",label:"User Preferences"},{id:"error_pattern",label:"Error Patterns"},{id:"success_pattern",label:"Success Patterns"},{id:"tool_efficiency",label:"Tool Efficiency"},{id:"context_relevance",label:"Context Relevance"}],Ht=[{id:"all",label:"All Sources"},{id:"cli",label:"CLI"},{id:"api",label:"API"},{id:"vscode",label:"VS Code"},{id:"mcp",label:"MCP"},{id:"dashboard",label:"Dashboard"}],ie=class extends v{static get observedAttributes(){return["api-url","theme","time-range","signal-type","source"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._timeRange="7d",this._signalType="all",this._source="all",this._metrics=null,this._trends=null,this._signals=[],this._selectedMetric=null}connectedCallback(){super.connectedCallback(),this._timeRange=this.getAttribute("time-range")||"7d",this._signalType=this.getAttribute("signal-type")||"all",this._source=this.getAttribute("source")||"all",this._setupApi(),this._loadData()}attributeChangedCallback(e,t,i){if(t!==i)switch(e){case"api-url":this._api&&(this._api=g({baseUrl:i}),this._loadData());break;case"theme":this._applyTheme();break;case"time-range":this._timeRange=i,this._loadData();break;case"signal-type":this._signalType=i,this._loadData();break;case"source":this._source=i,this._loadData();break}}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=g({baseUrl:e})}async _loadData(){this._loading=!0,this._error=null,this.render();let e=this._api;try{let t={timeRange:this._timeRange,signalType:this._signalType!=="all"?this._signalType:void 0,source:this._source!=="all"?this._source:void 0},[i,a,s]=await Promise.all([e.getLearningMetrics(t).catch(()=>null),e.getLearningTrends(t).catch(()=>null),e.getLearningSignals({...t,limit:50}).catch(()=>null)]);if(e!==this._api)return;this._metrics=i,this._trends=a,this._signals=s}catch(t){if(e!==this._api)return;this._error=t.message||"Failed to load learning data"}this._loading=!1,this.render()}_setFilter(e,t){switch(e){case"timeRange":this._timeRange=t,this.setAttribute("time-range",t);break;case"signalType":this._signalType=t,this.setAttribute("signal-type",t);break;case"source":this._source=t,this.setAttribute("source",t);break}this.dispatchEvent(new CustomEvent("filter-change",{detail:{timeRange:this._timeRange,signalType:this._signalType,source:this._source}})),this._loadData()}_selectMetric(e,t){this._selectedMetric={type:e,item:t},this.dispatchEvent(new CustomEvent("metric-select",{detail:{type:e,item:t}})),this.render()}_closeDetail(){this._selectedMetric=null,this.render()}_num(e){let t=e==null?NaN:Number(e);return Number.isFinite(t)?t:null}_formatNumber(e){let t=this._num(e);return t==null?"--":t>=1e6?(t/1e6).toFixed(1)+"M":t>=1e3?(t/1e3).toFixed(1)+"K":String(t)}_formatPercent(e){let t=this._num(e);return t==null?"--":(t*100).toFixed(1)+"%"}_formatDuration(e){let t=this._num(e);return t==null?"--":t<60?t.toFixed(0)+"s":t<3600?(t/60).toFixed(1)+"m":(t/3600).toFixed(1)+"h"}_escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}_renderFilters(){return`
5409
+ `,this._attachEventListeners()}_attachEventListeners(){let e=this.shadowRoot.querySelectorAll(".tab");e.forEach((n,l)=>{n.addEventListener("click",()=>this._setTab(n.dataset.tab)),n.addEventListener("keydown",c=>{if(c.key==="ArrowRight"||c.key==="ArrowLeft"){c.preventDefault();let p=Array.from(e),u=c.key==="ArrowRight"?(l+1)%p.length:(l-1+p.length)%p.length;p[u].focus(),this._setTab(p[u].dataset.tab)}})}),this.shadowRoot.querySelectorAll(".item-card").forEach(n=>{n.addEventListener("click",()=>this._handleItemClick(n)),n.addEventListener("keydown",l=>{l.key==="Enter"||l.key===" "?(l.preventDefault(),this._handleItemClick(n)):(l.key==="ArrowDown"||l.key==="ArrowUp")&&(l.preventDefault(),this._navigateItemCards(n,l.key==="ArrowDown"?"next":"prev"))})});let t=this.shadowRoot.getElementById("close-detail");t&&t.addEventListener("click",()=>this._closeDetail());let i=this.shadowRoot.getElementById("consolidate-btn");i&&i.addEventListener("click",()=>this._triggerConsolidation());let a=this.shadowRoot.getElementById("refresh-btn");a&&a.addEventListener("click",()=>this._loadData());let s=this.shadowRoot.getElementById("memory-search-input"),r=this.shadowRoot.getElementById("search-btn"),o=this.shadowRoot.getElementById("memory-search-collection");s&&(s.addEventListener("keydown",n=>{n.key==="Enter"&&(n.preventDefault(),this._searchQuery=s.value,this._executeSearch())}),s.addEventListener("input",n=>{this._searchQuery=n.target.value})),r&&r.addEventListener("click",()=>{let n=this.shadowRoot.getElementById("memory-search-input");n&&(this._searchQuery=n.value),this._executeSearch()}),o&&o.addEventListener("change",n=>{this._searchCollection=n.target.value})}_handleItemClick(e){let t=e.dataset.id;switch(e.dataset.type){case"episode":this._selectEpisode(t);break;case"pattern":this._selectPattern(t);break;case"skill":this._selectSkill(t);break}}_navigateItemCards(e,t){let i=Array.from(this.shadowRoot.querySelectorAll(".item-card")),a=i.indexOf(e);if(a===-1)return;let s=t==="next"?a+1:a-1;s>=0&&s<i.length&&i[s].focus()}};customElements.get("loki-memory-browser")||customElements.define("loki-memory-browser",te);var Lt=[{id:"1h",label:"1 Hour",hours:1},{id:"24h",label:"24 Hours",hours:24},{id:"7d",label:"7 Days",hours:168},{id:"30d",label:"30 Days",hours:720}],zt=[{id:"all",label:"All Signals"},{id:"user_preference",label:"User Preferences"},{id:"error_pattern",label:"Error Patterns"},{id:"success_pattern",label:"Success Patterns"},{id:"tool_efficiency",label:"Tool Efficiency"},{id:"context_relevance",label:"Context Relevance"}],Ht=[{id:"all",label:"All Sources"},{id:"cli",label:"CLI"},{id:"api",label:"API"},{id:"vscode",label:"VS Code"},{id:"mcp",label:"MCP"},{id:"dashboard",label:"Dashboard"}],ie=class extends v{static get observedAttributes(){return["api-url","theme","time-range","signal-type","source"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._timeRange="7d",this._signalType="all",this._source="all",this._metrics=null,this._trends=null,this._signals=[],this._selectedMetric=null}connectedCallback(){super.connectedCallback(),this._timeRange=this.getAttribute("time-range")||"7d",this._signalType=this.getAttribute("signal-type")||"all",this._source=this.getAttribute("source")||"all",this._setupApi(),this._loadData()}attributeChangedCallback(e,t,i){if(t!==i)switch(e){case"api-url":this._api&&(this._api=g({baseUrl:i}),this._loadData());break;case"theme":this._applyTheme();break;case"time-range":this._timeRange=i,this._loadData();break;case"signal-type":this._signalType=i,this._loadData();break;case"source":this._source=i,this._loadData();break}}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=g({baseUrl:e})}async _loadData(){this._loading=!0,this._error=null,this.render();let e=this._api;try{let t={timeRange:this._timeRange,signalType:this._signalType!=="all"?this._signalType:void 0,source:this._source!=="all"?this._source:void 0},i=!1,a=!1,[s,r,o]=await Promise.all([e.getLearningMetrics(t).catch(()=>(i=!0,null)),e.getLearningTrends(t).catch(()=>(a=!0,null)),e.getLearningSignals({...t,limit:50}).catch(()=>null)]);if(e!==this._api)return;this._metrics=s,this._trends=r,this._metricsFailed=i,this._trendsFailed=a,this._signals=o}catch(t){if(e!==this._api)return;this._error=t.message||"Failed to load learning data"}this._loading=!1,this.render()}_setFilter(e,t){switch(e){case"timeRange":this._timeRange=t,this.setAttribute("time-range",t);break;case"signalType":this._signalType=t,this.setAttribute("signal-type",t);break;case"source":this._source=t,this.setAttribute("source",t);break}this.dispatchEvent(new CustomEvent("filter-change",{detail:{timeRange:this._timeRange,signalType:this._signalType,source:this._source}})),this._loadData()}_selectMetric(e,t){this._selectedMetric={type:e,item:t},this.dispatchEvent(new CustomEvent("metric-select",{detail:{type:e,item:t}})),this.render()}_closeDetail(){this._selectedMetric=null,this.render()}_num(e){let t=e==null?NaN:Number(e);return Number.isFinite(t)?t:null}_formatNumber(e){let t=this._num(e);return t==null?"--":t>=1e6?(t/1e6).toFixed(1)+"M":t>=1e3?(t/1e3).toFixed(1)+"K":String(t)}_formatPercent(e){let t=this._num(e);return t==null?"--":(t*100).toFixed(1)+"%"}_formatDuration(e){let t=this._num(e);return t==null?"--":t<60?t.toFixed(0)+"s":t<3600?(t/60).toFixed(1)+"m":(t/3600).toFixed(1)+"h"}_escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}_renderFilters(){return`
5410
5410
  <div class="filters">
5411
5411
  <div class="filter-group">
5412
5412
  <label>Time Range</label>
@@ -5440,7 +5440,7 @@ var LokiDashboard=(()=>{var Le=Object.defineProperty;var kt=Object.getOwnPropert
5440
5440
  Refresh
5441
5441
  </button>
5442
5442
  </div>
5443
- `}_renderSummaryCards(){if(!this._metrics)return'<div class="empty-state">No metrics available</div>';let{totalSignals:e,signalsByType:t,signalsBySource:i,aggregation:a}=this._metrics,s=e>0?this._num(this._metrics.avgConfidence):null;return`
5443
+ `}_renderSummaryCards(){if(this._metricsFailed)return'<div class="empty-state">Could not load metrics</div>';if(!this._metrics)return'<div class="empty-state">No metrics available</div>';let{totalSignals:e,signalsByType:t,signalsBySource:i,aggregation:a}=this._metrics,s=e>0?this._num(this._metrics.avgConfidence):null;return`
5444
5444
  <div class="summary-cards">
5445
5445
  <div class="summary-card">
5446
5446
  <div class="summary-card-header">
@@ -5509,7 +5509,7 @@ var LokiDashboard=(()=>{var Le=Object.defineProperty;var kt=Object.getOwnPropert
5509
5509
  </div>
5510
5510
  </div>
5511
5511
  </div>
5512
- `}_renderTrendChart(){if(!this._trends||!this._trends.dataPoints||this._trends.dataPoints.length===0)return'<div class="chart-empty">No trend data available</div>';let{dataPoints:e,maxValue:t}=this._trends,i=120,a=400,s=20,r=e.map((n,l)=>{let c=s+l/(e.length-1||1)*(a-s*2),p=i-s-n.count/(t||1)*(i-s*2);return`${c},${p}`}).join(" "),o=`${s},${i-s} ${r} ${a-s},${i-s}`;return`
5512
+ `}_renderTrendChart(){if(this._trendsFailed)return'<div class="chart-empty">Could not load trend data</div>';if(!this._trends||!this._trends.dataPoints||this._trends.dataPoints.length===0)return'<div class="chart-empty">No trend data available</div>';let{dataPoints:e,maxValue:t}=this._trends,i=120,a=400,s=20,r=e.map((n,l)=>{let c=s+l/(e.length-1||1)*(a-s*2),p=i-s-n.count/(t||1)*(i-s*2);return`${c},${p}`}).join(" "),o=`${s},${i-s} ${r} ${a-s},${i-s}`;return`
5513
5513
  <div class="trend-chart">
5514
5514
  <div class="chart-header">
5515
5515
  <span class="chart-title">Signal Volume Over Time</span>
@@ -10823,7 +10823,7 @@ var LokiDashboard=(()=>{var Le=Object.defineProperty;var kt=Object.getOwnPropert
10823
10823
  ${t}
10824
10824
  <span class="migration-title">Migration Dashboard</span>
10825
10825
  </div>
10826
- <div class="empty-state">No migration data available</div>
10826
+ <div class="empty-state status-failed">Could not load migrations: ${this._escapeHtml(this._error)}</div>
10827
10827
  </div>
10828
10828
  `;return}if(this._migration){let i=this._migration,a=this._escapeHtml(i.migration_id||i.id||"--"),s=this._escapeHtml(i.source||"--"),r=this._escapeHtml(i.target||"--"),o=i.current_phase||i.phase||"unknown",n=i.completed_phases||[];this.shadowRoot.innerHTML=`
10829
10829
  <style>${e}</style>
@@ -13706,7 +13706,7 @@ var LokiDashboard=(()=>{var Le=Object.defineProperty;var kt=Object.getOwnPropert
13706
13706
  </div>
13707
13707
  </div>
13708
13708
  </div>
13709
- `,this._bindEvents()}};customElements.get("loki-cost-waterfall")||customElements.define("loki-cost-waterfall",we);var vt=50,$e=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._api=null,this._statusLoading=!1,this._statusError=null,this._status=null,this._eventsLoading=!1,this._eventsError=null,this._events=[],this._eventsSource=null,this._eventsCount=0,this._lookupId="",this._lookupLoading=!1,this._lookupError=null,this._lookupResult=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadStatus()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){if(t!==i)switch(e){case"api-url":this._api&&(this._api=g({baseUrl:i}),this._loadStatus());break;case"theme":this._applyTheme(),this.render();break}}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=g({baseUrl:e})}_stopPolling(){}async _loadStatus(){let e=this._api;this._statusLoading=!0,this._statusError=null,this.render();try{let t=await e.get("/api/managed/status");if(e!==this._api)return;this._status=t}catch(t){if(e!==this._api)return;this._statusError=t&&t.message?t.message:"Failed to load managed status",this._status=null}finally{this._statusLoading=!1}this._status&&this._status.enabled?await this._loadEvents():this.render()}async _loadEvents(e=vt){let t=this._api;this._eventsLoading=!0,this._eventsError=null,this.render();try{let i=await t.get("/api/managed/events?limit="+encodeURIComponent(e));if(t!==this._api)return;Array.isArray(i)?(this._events=i,this._eventsCount=i.length,this._eventsSource=null):i&&typeof i=="object"?(this._events=Array.isArray(i.events)?i.events:[],this._eventsCount=typeof i.count=="number"?i.count:this._events.length,this._eventsSource=i.source||null):(this._events=[],this._eventsCount=0,this._eventsSource=null)}catch(i){if(t!==this._api)return;this._eventsError=i&&i.message?i.message:"Failed to load managed events",this._events=[],this._eventsCount=0,this._eventsSource=null}finally{this._eventsLoading=!1,this.render()}}async _lookupMemoryVersion(){let e=(this._lookupId||"").trim();if(!e){this._lookupError="Enter a memory ID to look up",this._lookupResult=null,this.render();return}let t=this._api;this._lookupLoading=!0,this._lookupError=null,this._lookupResult=null,this.render();try{let i="/api/managed/memory_versions/"+encodeURIComponent(e),a=await t.get(i);if(t!==this._api)return;this._lookupResult=a}catch(i){if(t!==this._api)return;this._lookupError=i&&i.message?i.message:"Failed to load memory versions",this._lookupResult=null}finally{this._lookupLoading=!1,this.render()}}_onLookupInput(e){this._lookupId=e&&e.target?e.target.value:""}_onLookupKeyDown(e){e&&e.key==="Enter"&&(e.preventDefault(),this._lookupMemoryVersion())}_attachEventHandlers(){let e=this.shadowRoot;if(!e)return;let t=e.querySelector("#refresh-status-btn");t&&t.addEventListener("click",()=>this._loadStatus());let i=e.querySelector("#refresh-events-btn");i&&i.addEventListener("click",()=>this._loadEvents());let a=e.querySelector("#lookup-input");a&&(a.addEventListener("input",r=>this._onLookupInput(r)),a.addEventListener("keydown",r=>this._onLookupKeyDown(r)));let s=e.querySelector("#lookup-btn");s&&s.addEventListener("click",()=>this._lookupMemoryVersion())}_escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}_formatTimestamp(e){if(!e)return"";let t;return typeof e=="number"?t=new Date(e>1e12?e:e*1e3):t=new Date(e),Number.isNaN(t.getTime())?String(e):t.toISOString().replace("T"," ").replace(/\.\d+Z$/,"Z")}_renderStatusSection(){if(this._statusLoading)return'<div class="status-row muted">Loading managed memory status...</div>';if(this._statusError)return`
13709
+ `,this._bindEvents()}};customElements.get("loki-cost-waterfall")||customElements.define("loki-cost-waterfall",we);var vt=50,$e=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._api=null,this._statusLoading=!1,this._statusError=null,this._status=null,this._eventsLoading=!1,this._eventsError=null,this._events=[],this._eventsSource=null,this._eventsCount=0,this._lookupId="",this._lookupLoading=!1,this._lookupError=null,this._lookupResult=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadStatus()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){if(t!==i)switch(e){case"api-url":this._api&&(this._api=g({baseUrl:i}),this._loadStatus());break;case"theme":this._applyTheme(),this.render();break}}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=g({baseUrl:e})}_stopPolling(){}async _loadStatus(){let e=this._api;this._statusLoading=!0,this._statusError=null,this.render();try{let t=await e.get("/api/managed/status");if(e!==this._api)return;this._status=t}catch(t){if(e!==this._api)return;this._statusError=t&&t.message?t.message:"Failed to load managed status",this._status=null}finally{this._statusLoading=!1}this._status&&this._status.enabled?await this._loadEvents():this.render()}async _loadEvents(e=vt){let t=this._api;this._eventsLoading=!0,this._eventsError=null,this.render();try{let i=await t.get("/api/managed/events?limit="+encodeURIComponent(e));if(t!==this._api)return;Array.isArray(i)?(this._events=i,this._eventsCount=i.length,this._eventsSource=null):i&&typeof i=="object"?(this._events=Array.isArray(i.events)?i.events:[],this._eventsCount=typeof i.count=="number"?i.count:this._events.length,this._eventsSource=i.source||null,i.error&&(this._eventsError=String(i.error))):(this._events=[],this._eventsCount=0,this._eventsSource=null)}catch(i){if(t!==this._api)return;this._eventsError=i&&i.message?i.message:"Failed to load managed events",this._events=[],this._eventsCount=0,this._eventsSource=null}finally{this._eventsLoading=!1,this.render()}}async _lookupMemoryVersion(){let e=(this._lookupId||"").trim();if(!e){this._lookupError="Enter a memory ID to look up",this._lookupResult=null,this.render();return}let t=this._api;this._lookupLoading=!0,this._lookupError=null,this._lookupResult=null,this.render();try{let i="/api/managed/memory_versions/"+encodeURIComponent(e),a=await t.get(i);if(t!==this._api)return;this._lookupResult=a}catch(i){if(t!==this._api)return;this._lookupError=i&&i.message?i.message:"Failed to load memory versions",this._lookupResult=null}finally{this._lookupLoading=!1,this.render()}}_onLookupInput(e){this._lookupId=e&&e.target?e.target.value:""}_onLookupKeyDown(e){e&&e.key==="Enter"&&(e.preventDefault(),this._lookupMemoryVersion())}_attachEventHandlers(){let e=this.shadowRoot;if(!e)return;let t=e.querySelector("#refresh-status-btn");t&&t.addEventListener("click",()=>this._loadStatus());let i=e.querySelector("#refresh-events-btn");i&&i.addEventListener("click",()=>this._loadEvents());let a=e.querySelector("#lookup-input");a&&(a.addEventListener("input",r=>this._onLookupInput(r)),a.addEventListener("keydown",r=>this._onLookupKeyDown(r)));let s=e.querySelector("#lookup-btn");s&&s.addEventListener("click",()=>this._lookupMemoryVersion())}_escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}_formatTimestamp(e){if(!e)return"";let t;return typeof e=="number"?t=new Date(e>1e12?e:e*1e3):t=new Date(e),Number.isNaN(t.getTime())?String(e):t.toISOString().replace("T"," ").replace(/\.\d+Z$/,"Z")}_renderStatusSection(){if(this._statusLoading)return'<div class="status-row muted">Loading managed memory status...</div>';if(this._statusError)return`
13710
13710
  <div class="error-banner" role="alert">
13711
13711
  <strong>Status error:</strong>
13712
13712
  <span>${this._escapeHtml(this._statusError)}</span>
@@ -2,7 +2,7 @@
2
2
 
3
3
  The flagship product of [Autonomi](https://www.autonomi.dev/). Loki Mode is a spec-driven autonomous builder with a built-in trust layer that takes any spec to a deployed product and verifies completion with evidence (quality gates plus a completion council), not just a "done" claim. Complete installation instructions for all platforms and use cases.
4
4
 
5
- **Version:** v9.73.0
5
+ **Version:** v9.74.0
6
6
 
7
7
  ---
8
8