loki-mode 11.3.1 → 11.3.2

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 (107) hide show
  1. package/SKILL.md +4 -4
  2. package/VERSION +1 -1
  3. package/autonomy/lib/efficiency_cost.py +8 -0
  4. package/autonomy/lib/engine10-push.sh +22 -8
  5. package/autonomy/loki +62 -30
  6. package/bin/loki +30 -1
  7. package/completions/_loki +6 -0
  8. package/completions/loki.bash +2 -2
  9. package/dashboard/__init__.py +1 -1
  10. package/dashboard/server.py +22 -14
  11. package/docs/AGENT-CHANGE-RECEIPT.md +2 -2
  12. package/docs/CLI-REFERENCE.md +5 -1
  13. package/docs/INSTALLATION.md +1 -1
  14. package/docs/OTEL-COLLECTOR.md +24 -0
  15. package/docs/ROUTING-EVIDENCE.md +32 -0
  16. package/docs/environment-variables.md +1 -0
  17. package/docs/spec-first-intent.md +28 -0
  18. package/docs/v10/CLI-MODERN.md +6 -3
  19. package/docs/v10/DECISIONS.md +15 -0
  20. package/docs/v10/FAILURE-CLASSES.md +95 -1
  21. package/docs/v10/GUARDS.md +18 -0
  22. package/docs/v10/GUIDE.md +7 -5
  23. package/docs/v10/METRICS.md +12 -0
  24. package/docs/v10/OPERATING-MODEL.md +3 -3
  25. package/docs/v10/PROGRESS.md +6 -0
  26. package/docs/v11/INTOTO-AGENT-CHANGE-PREDICATE.md +77 -0
  27. package/docs/v11/MCP-2026-07-28.md +55 -0
  28. package/docs/v11/VERIFY-PR-SANDBOX.md +41 -0
  29. package/loki-ts/dist/loki.js +1130 -969
  30. package/mcp/__init__.py +1 -1
  31. package/mcp/v10_tools.py +29 -0
  32. package/package.json +9 -11
  33. package/packages/control-plane/dist/ask-tools-server.js +8 -2
  34. package/packages/control-plane/dist/server.js +15728 -13988
  35. package/packages/control-plane/drizzle/0006_token_sessions.sql +1 -0
  36. package/packages/control-plane/drizzle/meta/0006_snapshot.json +807 -0
  37. package/packages/control-plane/drizzle/meta/_journal.json +7 -0
  38. package/packages/control-plane/src/db/schema.ts +1 -0
  39. package/packages/control-plane/src/server/routes/cost.ts +4 -3
  40. package/packages/control-plane/src/server/runs.ts +3 -3
  41. package/packages/control-plane/ui/dist/assets/index-DbLzr87u.js +190 -0
  42. package/packages/control-plane/ui/dist/index.html +1 -1
  43. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  44. package/providers/opencode.sh +2 -3
  45. package/src/observability/genai-spans.js +104 -0
  46. package/src/observability/otel-bridge.js +49 -1
  47. package/src/observability/otel.js +2 -2
  48. package/src/protocols/mcp-server.js +180 -5
  49. package/src/protocols/transport/sse.js +23 -2
  50. package/web-app/dist/assets/{AdminPage-CMkHNJbF.js → AdminPage-DuRQZsF9.js} +1 -1
  51. package/web-app/dist/assets/{Avatar-BJyjV7Zi.js → Avatar-7GtOQvsO.js} +1 -1
  52. package/web-app/dist/assets/{Badge-D572l0uq.js → Badge-CYgTnIxj.js} +1 -1
  53. package/web-app/dist/assets/{Button-T4BnOZgl.js → Button-rYSyIu7X.js} +1 -1
  54. package/web-app/dist/assets/{CockpitPage-Cj_GFsNn.js → CockpitPage-9adANY4o.js} +1 -1
  55. package/web-app/dist/assets/{ComparePage-A8m4ZXak.js → ComparePage-DEG2oA-R.js} +1 -1
  56. package/web-app/dist/assets/{ErrorBoundary-hugCg5yg.js → ErrorBoundary-CwtvY4xs.js} +1 -1
  57. package/web-app/dist/assets/{EvidenceReceiptPanel-CuJKDC2G.js → EvidenceReceiptPanel-DTT73pPB.js} +1 -1
  58. package/web-app/dist/assets/{GitHubIssuesPanel-BYGKjarC.js → GitHubIssuesPanel-CpWZLz2x.js} +1 -1
  59. package/web-app/dist/assets/{GitHubPRsPanel-c7sFIJlf.js → GitHubPRsPanel-H293R7E2.js} +1 -1
  60. package/web-app/dist/assets/{HomePage-A1MIkG2P.js → HomePage-B11Imp9k.js} +2 -2
  61. package/web-app/dist/assets/{LoginPage-8KQMRhtR.js → LoginPage-BZBgx5Jr.js} +1 -1
  62. package/web-app/dist/assets/{MagicPage-C05QW2Lx.js → MagicPage-B27S4_X8.js} +1 -1
  63. package/web-app/dist/assets/{MetricsPage-Oukv5hme.js → MetricsPage-CfbJWNDG.js} +1 -1
  64. package/web-app/dist/assets/{NotFoundPage-DKIwsawz.js → NotFoundPage-Tp_4zMSm.js} +1 -1
  65. package/web-app/dist/assets/{ProjectPage-DwFRPLCG.js → ProjectPage-CM4fgMsV.js} +3 -3
  66. package/web-app/dist/assets/{ProjectsPage-CgY4YYDX.js → ProjectsPage-DP2Fvsrd.js} +1 -1
  67. package/web-app/dist/assets/{SettingsPage-BpfcSjUA.js → SettingsPage-C4G9-EAy.js} +1 -1
  68. package/web-app/dist/assets/{ShowcasePage-BqBakC4K.js → ShowcasePage-Dj-n4dwu.js} +1 -1
  69. package/web-app/dist/assets/{SystemSettingsPage-CZLu5VB0.js → SystemSettingsPage-BqMLpuGt.js} +1 -1
  70. package/web-app/dist/assets/{TeamsPage-D55S1jKz.js → TeamsPage-mIH8H96m.js} +1 -1
  71. package/web-app/dist/assets/{TemplatesPage-D3SydvxN.js → TemplatesPage-BagW-v4n.js} +1 -1
  72. package/web-app/dist/assets/{TerminalOutput-hNg8G1-e.js → TerminalOutput-CTQRHhnK.js} +1 -1
  73. package/web-app/dist/assets/{activity-D2C0VagO.js → activity-DNQiBDDL.js} +1 -1
  74. package/web-app/dist/assets/{bell-CMvYi36w.js → bell-Coiwdad1.js} +1 -1
  75. package/web-app/dist/assets/{bot-BvtQ6lmo.js → bot-Cou-rTgR.js} +1 -1
  76. package/web-app/dist/assets/{check-B13xkXed.js → check-CsF-XtQp.js} +1 -1
  77. package/web-app/dist/assets/{chevron-left-emu6r49E.js → chevron-left-BJiy55Ht.js} +1 -1
  78. package/web-app/dist/assets/{circle-alert-CExlwjuy.js → circle-alert-D6-pQQWq.js} +1 -1
  79. package/web-app/dist/assets/{clock-D7Uas3oL.js → clock-BOGqwgt9.js} +1 -1
  80. package/web-app/dist/assets/{cloud-CkB4S86C.js → cloud-DsxhTtf5.js} +1 -1
  81. package/web-app/dist/assets/{code-xml-SL9IIWIn.js → code-xml-CxJDHUlE.js} +1 -1
  82. package/web-app/dist/assets/{database-BQFkd7t1.js → database-BJePscl_.js} +1 -1
  83. package/web-app/dist/assets/{dollar-sign-qHmnNYsU.js → dollar-sign-6qWGAkZo.js} +1 -1
  84. package/web-app/dist/assets/{file-code-corner-C2YUDP0K.js → file-code-corner-DcOtYeDb.js} +1 -1
  85. package/web-app/dist/assets/{file-plus-C_ooIkDe.js → file-plus-WuRyLFo0.js} +1 -1
  86. package/web-app/dist/assets/{globe-CQ-GL485.js → globe-r-xCP4DE.js} +1 -1
  87. package/web-app/dist/assets/{hammer-U05L_D7V.js → hammer-DTt0SsCB.js} +1 -1
  88. package/web-app/dist/assets/{index-CooHd7I-.js → index-BkbXyH8y.js} +3 -3
  89. package/web-app/dist/assets/{layers-Buo17rjW.js → layers-BvZhvSMY.js} +1 -1
  90. package/web-app/dist/assets/{loader-circle-15vK3oV1.js → loader-circle-3gosTei9.js} +1 -1
  91. package/web-app/dist/assets/{lock-BeXLebuJ.js → lock-CZZMxP0U.js} +1 -1
  92. package/web-app/dist/assets/{package-MVh_6-6R.js → package-C5A8CkJr.js} +1 -1
  93. package/web-app/dist/assets/{plus-Dh_nd9vS.js → plus-Btv7tTIF.js} +1 -1
  94. package/web-app/dist/assets/{refresh-cw-C9cBJEAT.js → refresh-cw-DsWLXgs_.js} +1 -1
  95. package/web-app/dist/assets/{rotate-ccw-D3PAtzST.js → rotate-ccw-DOVDjway.js} +1 -1
  96. package/web-app/dist/assets/{scroll-text-DZCoXQjo.js → scroll-text-smySzlrX.js} +1 -1
  97. package/web-app/dist/assets/{server-OCOLI5J_.js → server-b5PHsqAU.js} +1 -1
  98. package/web-app/dist/assets/{shield-alert-oVhmf1_h.js → shield-alert-BD7FDlh-.js} +1 -1
  99. package/web-app/dist/assets/{thumbs-up-B-kbX4vN.js → thumbs-up-CAsFzbyE.js} +1 -1
  100. package/web-app/dist/assets/{trash-2-EL6moveW.js → trash-2-BJ35qHgl.js} +1 -1
  101. package/web-app/dist/assets/{trending-down-Cl3kjpsx.js → trending-down-Ozrd26cZ.js} +1 -1
  102. package/web-app/dist/assets/{trending-up-DST7I6M2.js → trending-up-BhnMcM32.js} +1 -1
  103. package/web-app/dist/assets/{upload-CUOT780G.js → upload-JVHfdwoA.js} +1 -1
  104. package/web-app/dist/assets/{usePolling-Djmt90eb.js → usePolling-CTzbDV-e.js} +1 -1
  105. package/web-app/dist/assets/{user-BRBohA6J.js → user-Bks3-GYv.js} +1 -1
  106. package/web-app/dist/index.html +1 -1
  107. package/packages/control-plane/ui/dist/assets/index-DcBJXjCJ.js +0 -190
@@ -43,6 +43,13 @@
43
43
  "when": 1791051000000,
44
44
  "tag": "0005_ask",
45
45
  "breakpoints": true
46
+ },
47
+ {
48
+ "idx": 6,
49
+ "version": "6",
50
+ "when": 1791052000000,
51
+ "tag": "0006_token_sessions",
52
+ "breakpoints": true
46
53
  }
47
54
  ]
48
55
  }
@@ -40,6 +40,7 @@ export const runs = sqliteTable("runs", {
40
40
  partialUsd: real("partial_usd").notNull(),
41
41
  measuredSessions: integer("measured_sessions").notNull(),
42
42
  totalSessions: integer("total_sessions").notNull(),
43
+ tokenSessions: integer("token_sessions"), // FC-44: cost events that carried usage; null on rows ingested before it existed
43
44
  inputTokens: integer("input_tokens").notNull(),
44
45
  outputTokens: integer("output_tokens").notNull(),
45
46
  wallS: real("wall_s"),
@@ -14,8 +14,8 @@ export const DEFAULT_API_KEY_CAP_USD = 100;
14
14
 
15
15
  const NONE = "unknown";
16
16
  type Run = typeof runs.$inferSelect;
17
- type Acc = { key: Record<string, string>; runs: number; measured_runs: number; partial_runs: number; unmeasured_runs: number; measured_usd: number; partial_usd: number; input_tokens: number; output_tokens: number };
18
- const mk = (key: Record<string, string>): Acc => ({ key, runs: 0, measured_runs: 0, partial_runs: 0, unmeasured_runs: 0, measured_usd: 0, partial_usd: 0, input_tokens: 0, output_tokens: 0 });
17
+ type Acc = { key: Record<string, string>; runs: number; measured_runs: number; partial_runs: number; unmeasured_runs: number; measured_usd: number; partial_usd: number; input_tokens: number; output_tokens: number; tk: number; tn: number };
18
+ const mk = (key: Record<string, string>): Acc => ({ key, runs: 0, measured_runs: 0, partial_runs: 0, unmeasured_runs: 0, measured_usd: 0, partial_usd: 0, input_tokens: 0, output_tokens: 0, tk: 0, tn: 0 });
19
19
  const add = (a: Acc, r: Run) => {
20
20
  a.runs++;
21
21
  if (r.costUsd !== null) { a.measured_runs++; a.measured_usd += r.costUsd; }
@@ -23,11 +23,12 @@ const add = (a: Acc, r: Run) => {
23
23
  else a.unmeasured_runs++;
24
24
  a.input_tokens += r.inputTokens;
25
25
  a.output_tokens += r.outputTokens;
26
+ if (r.tokenSessions !== null) { a.tk += r.tokenSessions; a.tn += r.totalSessions; } // FC-44: sessions that carried usage, of all cost events
26
27
  };
27
28
  const dimVal = (d: CostDim, r: Run): string =>
28
29
  d === "day" ? (r.startedAt ? r.startedAt.slice(0, 10) : NONE) : d === "model" ? (r.model ?? NONE) : d === "provider" ? (r.provider ?? NONE) : (r.originRepo ?? NONE);
29
30
  const round = (n: number) => Math.round(n * 1e6) / 1e6;
30
- const out = (a: Acc) => ({ ...a.key, runs: a.runs, measured_runs: a.measured_runs, partial_runs: a.partial_runs, unmeasured_runs: a.unmeasured_runs, measured_usd: round(a.measured_usd), partial_usd: round(a.partial_usd), input_tokens: a.input_tokens, output_tokens: a.output_tokens });
31
+ const out = (a: Acc) => ({ ...a.key, runs: a.runs, measured_runs: a.measured_runs, partial_runs: a.partial_runs, unmeasured_runs: a.unmeasured_runs, measured_usd: round(a.measured_usd), partial_usd: round(a.partial_usd), input_tokens: a.input_tokens, output_tokens: a.output_tokens, ...(a.tk < a.tn ? { token_sessions: a.tk, token_sessions_total: a.tn } : {}) });
31
32
 
32
33
  export function mount(ctx: RouteCtx): void {
33
34
  // B8: per-repo breakdown. total_usd sums measured runs only (never invents a zero); avg_usd is over measured runs; verified = plain attested success display verdict.
@@ -33,8 +33,8 @@ export function rebuildRun(db: Db, sourceId: string, runId: string): void {
33
33
  startedAt: f.run.started?.ts ?? evs[0]?.ts ?? null, endedAt: f.run.completed?.ts ?? null,
34
34
  verdict: f.run.verdict,
35
35
  prUrl: str(done.pr_url) ?? str(pr?.url), prDraft: typeof pr?.draft === "boolean" ? Number(pr.draft) : null,
36
- costUsd: f.cost.usd, partialUsd: pc.usd, measuredSessions: pc.measured, totalSessions: pc.total,
37
- inputTokens: f.cost.inputTokens, outputTokens: f.cost.outputTokens,
36
+ costUsd: f.cost.usd, partialUsd: pc.usd, measuredSessions: pc.measured, totalSessions: pc.total, tokenSessions: tampered ? null : evs.filter((e) => e.type === "cost" && typeof e.data.input_tokens === "number").length,
37
+ inputTokens: f.cost.inputTokens + f.cost.cacheReadTokens + f.cost.cacheCreationTokens, outputTokens: f.cost.outputTokens,
38
38
  wallS: typeof done.wall_s === "number" ? done.wall_s : null,
39
39
  lastSeq: f.lastSeq, lastEventAt: evs[evs.length - 1]?.ts ?? null, tampered: Number(tampered),
40
40
  attested: Number(integ.attested), sigChecked: Number(integ.sig_checked), integrityKeyFp: keys.fingerprint ?? "", integrityReasons: JSON.stringify(integ.reasons),
@@ -49,7 +49,7 @@ const parseRun = (r: typeof runs.$inferSelect) => ({
49
49
  source_id: r.sourceId, run_id: r.runId, origin_repo: r.originRepo, issue_ref: r.issueRef, task_source: r.taskSource,
50
50
  group_id: r.groupId, unit_id: r.unitId, provider: r.provider, model: r.model, started_at: r.startedAt, ended_at: r.endedAt, verdict: r.verdict,
51
51
  pr_url: r.prUrl, pr_draft: r.prDraft === null ? null : r.prDraft === 1,
52
- cost_usd: r.costUsd, partial_usd: r.partialUsd, measured_sessions: r.measuredSessions, total_sessions: r.totalSessions,
52
+ cost_usd: r.costUsd, partial_usd: r.partialUsd, measured_sessions: r.measuredSessions, total_sessions: r.totalSessions, token_sessions: r.tokenSessions,
53
53
  input_tokens: r.inputTokens, output_tokens: r.outputTokens, wall_s: r.wallS, last_seq: r.lastSeq,
54
54
  last_event_at: r.lastEventAt, tampered: r.tampered === 1, conflict: r.conflict === 1,
55
55
  attested: r.attested === 1, sig_checked: r.sigChecked === 1, integrity_reasons: reasonsOf(r.integrityReasons),