muonroi-cli 1.4.1 → 1.6.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 (194) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +122 -122
  3. package/dist/packages/agent-harness-core/src/predicate.d.ts +1 -1
  4. package/dist/src/agent-harness/__tests__/mock-model.spec.js +48 -1
  5. package/dist/src/agent-harness/mock-model.d.ts +11 -0
  6. package/dist/src/agent-harness/mock-model.js +21 -0
  7. package/dist/src/cli/cost-forensics.js +12 -12
  8. package/dist/src/council/__tests__/clarification-prompt.test.js +51 -0
  9. package/dist/src/council/__tests__/clarifier-ready-gate.test.js +32 -0
  10. package/dist/src/council/__tests__/decisions-lock.test.js +17 -1
  11. package/dist/src/council/__tests__/oauth-reachable.test.d.ts +1 -0
  12. package/dist/src/council/__tests__/oauth-reachable.test.js +31 -0
  13. package/dist/src/council/__tests__/parse-outcome-fallback.test.js +11 -0
  14. package/dist/src/council/clarifier.js +9 -1
  15. package/dist/src/council/debate.js +5 -1
  16. package/dist/src/council/decisions-lock.js +3 -3
  17. package/dist/src/council/index.js +12 -5
  18. package/dist/src/council/leader.d.ts +0 -17
  19. package/dist/src/council/leader.js +22 -15
  20. package/dist/src/council/planner.js +1 -1
  21. package/dist/src/council/prompts.js +63 -57
  22. package/dist/src/council/types.d.ts +7 -0
  23. package/dist/src/ee/__tests__/ee-onboarding.test.d.ts +1 -0
  24. package/dist/src/ee/__tests__/ee-onboarding.test.js +32 -0
  25. package/dist/src/ee/artifact-cache.d.ts +56 -0
  26. package/dist/src/ee/artifact-cache.js +155 -0
  27. package/dist/src/ee/artifact-cache.test.d.ts +1 -0
  28. package/dist/src/ee/artifact-cache.test.js +69 -0
  29. package/dist/src/ee/auth.d.ts +9 -0
  30. package/dist/src/ee/auth.js +19 -0
  31. package/dist/src/ee/ee-onboarding.d.ts +5 -0
  32. package/dist/src/ee/ee-onboarding.js +76 -0
  33. package/dist/src/ee/search.js +7 -5
  34. package/dist/src/ee/search.test.d.ts +1 -0
  35. package/dist/src/ee/search.test.js +23 -0
  36. package/dist/src/generated/version.d.ts +1 -1
  37. package/dist/src/generated/version.js +1 -1
  38. package/dist/src/headless/output.js +6 -4
  39. package/dist/src/headless/output.test.js +4 -3
  40. package/dist/src/index.js +20 -1
  41. package/dist/src/mcp/__tests__/auto-setup.test.js +74 -0
  42. package/dist/src/mcp/__tests__/client-pool.spec.d.ts +1 -0
  43. package/dist/src/mcp/__tests__/client-pool.spec.js +98 -0
  44. package/dist/src/mcp/__tests__/parallel-build.spec.d.ts +1 -0
  45. package/dist/src/mcp/__tests__/parallel-build.spec.js +67 -0
  46. package/dist/src/mcp/__tests__/smart-filter.test.js +56 -0
  47. package/dist/src/mcp/auto-setup.js +56 -2
  48. package/dist/src/mcp/client-pool.d.ts +46 -0
  49. package/dist/src/mcp/client-pool.js +212 -0
  50. package/dist/src/mcp/oauth-callback.js +2 -2
  51. package/dist/src/mcp/parse-headers.test.js +14 -14
  52. package/dist/src/mcp/runtime.d.ts +28 -0
  53. package/dist/src/mcp/runtime.js +117 -51
  54. package/dist/src/mcp/self-verify-runner.d.ts +14 -0
  55. package/dist/src/mcp/self-verify-runner.js +38 -0
  56. package/dist/src/mcp/setup-guide-text.d.ts +9 -0
  57. package/dist/src/mcp/setup-guide-text.js +84 -0
  58. package/dist/src/mcp/smart-filter.js +49 -0
  59. package/dist/src/mcp/smoke.test.js +43 -43
  60. package/dist/src/mcp/tools-server.d.ts +7 -0
  61. package/dist/src/mcp/tools-server.js +19 -22
  62. package/dist/src/models/catalog.json +349 -349
  63. package/dist/src/ops/__tests__/doctor-ee-health.test.js +21 -0
  64. package/dist/src/ops/doctor.d.ts +3 -2
  65. package/dist/src/ops/doctor.js +47 -11
  66. package/dist/src/ops/doctor.test.js +4 -3
  67. package/dist/src/orchestrator/__tests__/mcp-capability-block.test.d.ts +1 -0
  68. package/dist/src/orchestrator/__tests__/mcp-capability-block.test.js +39 -0
  69. package/dist/src/orchestrator/__tests__/project-stack.test.d.ts +1 -0
  70. package/dist/src/orchestrator/__tests__/project-stack.test.js +65 -0
  71. package/dist/src/orchestrator/batch-turn-runner.js +7 -11
  72. package/dist/src/orchestrator/compaction.d.ts +2 -0
  73. package/dist/src/orchestrator/compaction.js +14 -1
  74. package/dist/src/orchestrator/compaction.test.js +25 -1
  75. package/dist/src/orchestrator/message-processor.js +72 -32
  76. package/dist/src/orchestrator/orchestrator.js +26 -0
  77. package/dist/src/orchestrator/prompts.d.ts +51 -0
  78. package/dist/src/orchestrator/prompts.js +257 -134
  79. package/dist/src/orchestrator/scope-ceiling.js +6 -1
  80. package/dist/src/orchestrator/scope-reminder.d.ts +12 -0
  81. package/dist/src/orchestrator/scope-reminder.js +16 -0
  82. package/dist/src/orchestrator/scope-reminder.test.js +22 -1
  83. package/dist/src/orchestrator/stream-runner.js +23 -15
  84. package/dist/src/orchestrator/subagent-compactor.d.ts +14 -5
  85. package/dist/src/orchestrator/subagent-compactor.js +30 -8
  86. package/dist/src/orchestrator/subagent-compactor.spec.js +18 -0
  87. package/dist/src/orchestrator/text-tool-call-detector.test.js +13 -13
  88. package/dist/src/pil/__tests__/clarity-gate.test.js +24 -215
  89. package/dist/src/pil/__tests__/config.test.js +1 -17
  90. package/dist/src/pil/__tests__/discovery.test.js +144 -11
  91. package/dist/src/pil/__tests__/layer1-intent-trace.test.js +7 -2
  92. package/dist/src/pil/__tests__/layer1-intent.test.js +3 -0
  93. package/dist/src/pil/__tests__/layer16-clarity.test.js +32 -116
  94. package/dist/src/pil/__tests__/layer4-gsd.test.js +37 -0
  95. package/dist/src/pil/__tests__/layer6-output.test.js +158 -18
  96. package/dist/src/pil/__tests__/llm-classify.test.js +49 -2
  97. package/dist/src/pil/__tests__/surface-compaction-artifacts.test.d.ts +1 -0
  98. package/dist/src/pil/__tests__/surface-compaction-artifacts.test.js +112 -0
  99. package/dist/src/pil/agent-operating-contract.d.ts +1 -1
  100. package/dist/src/pil/agent-operating-contract.js +2 -0
  101. package/dist/src/pil/agent-operating-contract.test.js +7 -2
  102. package/dist/src/pil/cheap-model-playbook.js +35 -35
  103. package/dist/src/pil/cheap-model-workbooks.js +16 -13
  104. package/dist/src/pil/clarity-gate.d.ts +21 -19
  105. package/dist/src/pil/clarity-gate.js +26 -153
  106. package/dist/src/pil/config.d.ts +9 -1
  107. package/dist/src/pil/config.js +15 -4
  108. package/dist/src/pil/discovery.js +211 -136
  109. package/dist/src/pil/layer1-intent.d.ts +12 -0
  110. package/dist/src/pil/layer1-intent.js +283 -38
  111. package/dist/src/pil/layer1-intent.test.js +210 -4
  112. package/dist/src/pil/layer16-clarity.d.ts +25 -11
  113. package/dist/src/pil/layer16-clarity.js +19 -306
  114. package/dist/src/pil/layer3-ee-injection.d.ts +19 -0
  115. package/dist/src/pil/layer3-ee-injection.js +96 -4
  116. package/dist/src/pil/layer4-gsd.js +18 -6
  117. package/dist/src/pil/layer6-output.d.ts +2 -0
  118. package/dist/src/pil/layer6-output.js +151 -25
  119. package/dist/src/pil/llm-classify.d.ts +26 -0
  120. package/dist/src/pil/llm-classify.js +34 -5
  121. package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
  122. package/dist/src/pil/native-capabilities-workbook.js +82 -76
  123. package/dist/src/pil/pipeline.js +15 -9
  124. package/dist/src/pil/schema.d.ts +8 -0
  125. package/dist/src/pil/schema.js +12 -1
  126. package/dist/src/pil/task-tier-map.js +4 -0
  127. package/dist/src/pil/types.d.ts +11 -1
  128. package/dist/src/product-loop/done-gate.js +3 -3
  129. package/dist/src/product-loop/loop-driver.js +18 -18
  130. package/dist/src/product-loop/progress-snapshot.js +4 -4
  131. package/dist/src/providers/auth/gemini-oauth.js +6 -15
  132. package/dist/src/providers/auth/grok-oauth.js +6 -15
  133. package/dist/src/providers/auth/openai-oauth.js +6 -15
  134. package/dist/src/providers/mcp-vision-bridge.js +48 -48
  135. package/dist/src/reporter/index.js +1 -1
  136. package/dist/src/scaffold/bb-ecosystem-apply.js +47 -47
  137. package/dist/src/scaffold/bb-quality-gate.js +5 -5
  138. package/dist/src/scaffold/continuation-prompt.js +60 -60
  139. package/dist/src/scaffold/init-new.js +453 -453
  140. package/dist/src/self-qa/__tests__/scenario-planner.test.js +3 -3
  141. package/dist/src/self-qa/agentic-loop.js +24 -19
  142. package/dist/src/self-qa/spec-emitter.js +26 -23
  143. package/dist/src/storage/__tests__/migrations.test.js +2 -2
  144. package/dist/src/storage/interaction-log.js +5 -5
  145. package/dist/src/storage/migrations.js +122 -122
  146. package/dist/src/storage/sessions.js +42 -42
  147. package/dist/src/storage/transcript.js +91 -84
  148. package/dist/src/storage/usage.js +14 -14
  149. package/dist/src/storage/workspaces.js +12 -12
  150. package/dist/src/tools/__tests__/native-tools.test.d.ts +1 -0
  151. package/dist/src/tools/__tests__/native-tools.test.js +53 -0
  152. package/dist/src/tools/git-safety.d.ts +61 -0
  153. package/dist/src/tools/git-safety.js +141 -0
  154. package/dist/src/tools/git-safety.test.d.ts +1 -0
  155. package/dist/src/tools/git-safety.test.js +111 -0
  156. package/dist/src/tools/native-tools.d.ts +31 -0
  157. package/dist/src/tools/native-tools.js +273 -0
  158. package/dist/src/tools/registry-ee-query.test.js +18 -1
  159. package/dist/src/tools/registry-git-safety.test.d.ts +7 -0
  160. package/dist/src/tools/registry-git-safety.test.js +92 -0
  161. package/dist/src/tools/registry.js +52 -6
  162. package/dist/src/ui/__tests__/markdown-render.test.d.ts +1 -0
  163. package/dist/src/ui/__tests__/markdown-render.test.js +48 -0
  164. package/dist/src/ui/app.js +0 -0
  165. package/dist/src/ui/components/message-view.js +4 -1
  166. package/dist/src/ui/components/structured-response-view.js +7 -3
  167. package/dist/src/ui/components/tool-group.js +7 -1
  168. package/dist/src/ui/markdown-render.d.ts +41 -0
  169. package/dist/src/ui/markdown-render.js +223 -0
  170. package/dist/src/ui/markdown.d.ts +10 -0
  171. package/dist/src/ui/markdown.js +12 -35
  172. package/dist/src/ui/slash/council-inspect.js +4 -4
  173. package/dist/src/ui/slash/export.js +4 -4
  174. package/dist/src/ui/utils/text.d.ts +8 -0
  175. package/dist/src/ui/utils/text.js +16 -0
  176. package/dist/src/ui/utils/text.test.d.ts +1 -0
  177. package/dist/src/ui/utils/text.test.js +23 -0
  178. package/dist/src/usage/ledger.js +48 -15
  179. package/dist/src/utils/__tests__/footprint-gitignore.test.d.ts +1 -0
  180. package/dist/src/utils/__tests__/footprint-gitignore.test.js +50 -0
  181. package/dist/src/utils/clipboard-image.js +23 -23
  182. package/dist/src/utils/open-url.d.ts +56 -0
  183. package/dist/src/utils/open-url.js +58 -0
  184. package/dist/src/utils/open-url.test.d.ts +1 -0
  185. package/dist/src/utils/open-url.test.js +86 -0
  186. package/dist/src/utils/settings.d.ts +12 -0
  187. package/dist/src/utils/settings.js +48 -0
  188. package/dist/src/utils/side-question.js +2 -2
  189. package/dist/src/utils/skills.js +3 -3
  190. package/dist/src/verify/__tests__/coverage-parsers.test.js +30 -30
  191. package/dist/src/verify/environment.js +2 -1
  192. package/package.json +1 -1
  193. package/dist/src/pil/layer16-clarity.test.js +0 -31
  194. /package/dist/src/{pil/layer16-clarity.test.d.ts → council/__tests__/clarification-prompt.test.d.ts} +0 -0
@@ -29,9 +29,9 @@ describe("scenario-planner", () => {
29
29
  expect(hits[0]?.line).toBe(3);
30
30
  });
31
31
  it("handles multiple hits in one file", () => {
32
- const src = `
33
- <Semantic id="one" role="textbox">
34
- <Semantic id="two" role="button">
32
+ const src = `
33
+ <Semantic id="one" role="textbox">
34
+ <Semantic id="two" role="button">
35
35
  `;
36
36
  const hits = extractSemanticHits(src, "f.tsx");
37
37
  expect(hits.map((h) => h.id)).toEqual(["one", "two"]);
@@ -23,6 +23,7 @@ import { createLineSplitter } from "@muonroi/agent-harness-core/transports/sidec
23
23
  import { generateObject, generateText } from "ai";
24
24
  import { z } from "zod";
25
25
  import { spawnAgentTui } from "../agent-harness/test-spawn.js";
26
+ import { loadCatalog } from "../models/registry.js";
26
27
  import { loadKeyForProvider } from "../providers/keychain.js";
27
28
  import { createProviderFactory, detectProviderForModel, resolveModelRuntime } from "../providers/runtime.js";
28
29
  import { buildAgenticContext } from "./agentic-context.js";
@@ -64,25 +65,25 @@ export function createMockBrain(script) {
64
65
  // ---------------------------------------------------------------------------
65
66
  // LLM brain — uses the configured provider stack
66
67
  // ---------------------------------------------------------------------------
67
- const DEFAULT_SYSTEM_PROMPT = `You are a QA agent driving a TUI via an agent-harness.
68
- Your job: given a free-form goal and the current TUI state (semantic tree + recent events),
69
- decide the SINGLE next action.
70
-
71
- Reply with a strict JSON object — no prose, no markdown fences:
72
-
73
- {"action":"type","text":"...","reason":"short"}
74
- {"action":"press","key":"Enter|Escape|Down|Up|Tab","reason":"short"}
75
- {"action":"wait_for","idle":true,"timeoutMs":5000,"reason":"..."}
76
- {"action":"wait_for","selector":"id=askcard","timeoutMs":5000,"reason":"..."}
77
- {"action":"wait_for","event":"askcard-open","timeoutMs":5000,"reason":"..."}
78
- {"action":"done","verdict":"pass","reason":"goal achieved"}
79
- {"action":"done","verdict":"fail","reason":"goal cannot be achieved"}
80
-
81
- Rules:
82
- - One action per turn. Do not batch.
83
- - Prefer wait_for after type/press to let the TUI settle.
84
- - If the goal looks satisfied, return done(pass).
85
- - If an error toast appears or the TUI is stuck, return done(fail).
68
+ const DEFAULT_SYSTEM_PROMPT = `You are a QA agent driving a TUI via an agent-harness.
69
+ Your job: given a free-form goal and the current TUI state (semantic tree + recent events),
70
+ decide the SINGLE next action.
71
+
72
+ Reply with a strict JSON object — no prose, no markdown fences:
73
+
74
+ {"action":"type","text":"...","reason":"short"}
75
+ {"action":"press","key":"Enter|Escape|Down|Up|Tab","reason":"short"}
76
+ {"action":"wait_for","idle":true,"timeoutMs":5000,"reason":"..."}
77
+ {"action":"wait_for","selector":"id=askcard","timeoutMs":5000,"reason":"..."}
78
+ {"action":"wait_for","event":"askcard-open","timeoutMs":5000,"reason":"..."}
79
+ {"action":"done","verdict":"pass","reason":"goal achieved"}
80
+ {"action":"done","verdict":"fail","reason":"goal cannot be achieved"}
81
+
82
+ Rules:
83
+ - One action per turn. Do not batch.
84
+ - Prefer wait_for after type/press to let the TUI settle.
85
+ - If the goal looks satisfied, return done(pass).
86
+ - If an error toast appears or the TUI is stuck, return done(fail).
86
87
  - Stay within ${"${maxTurns}"} turns. Be concise.`;
87
88
  /**
88
89
  * Pull a usable text body out of an AI SDK generateText result.
@@ -130,6 +131,10 @@ export async function createLLMBrain(opts) {
130
131
  if (process.env["MUONROI_DEEPSEEK_DISABLE_THINKING"] === undefined) {
131
132
  process.env["MUONROI_DEEPSEEK_DISABLE_THINKING"] = "1";
132
133
  }
134
+ // Resolve the catalog before any model lookup — resolveModelRuntime needs it
135
+ // loaded or it throws "not found in catalog". self-verify --agentic is a
136
+ // standalone entrypoint that never ran the main boot's loadCatalog(). F13.
137
+ await loadCatalog();
133
138
  const provider = detectProviderForModel(opts.modelId);
134
139
  if (!provider)
135
140
  throw new Error(`No provider detected for model '${opts.modelId}'`);
@@ -54,29 +54,32 @@ function buildTestBody(scenario) {
54
54
  const expectLines = scenario.expectations.flatMap(expectationToCode);
55
55
  const body = [...stepLines, "", ...expectLines].join("\n ");
56
56
  const safeDesc = escapeForString(scenario.description);
57
- return `import { afterAll, beforeAll, describe, expect, it } from "vitest";
58
- import { spawnHarness, type HarnessContext } from "../helpers.js";
59
-
60
- describe.skipIf(process.platform === "win32" && process.env["MUONROI_SKIP_NAMED_PIPE"] === "1")(
61
- "self-qa auto: ${escapeForString(scenario.id)}",
62
- () => {
63
- let ctx: HarnessContext;
64
-
65
- beforeAll(async () => {
66
- ctx = await spawnHarness();
67
- await ctx.driver.wait_for({ idle: true, timeoutMs: 15_000 });
68
- }, 20_000);
69
-
70
- afterAll(() => {
71
- ctx?.cleanup();
72
- });
73
-
74
- it("${safeDesc}", async () => {
75
- const { driver } = ctx;
76
- ${body}
77
- }, ${scenario.budgetMs + 5_000});
78
- },
79
- );
57
+ return `import { afterAll, beforeAll, describe, expect, it } from "vitest";
58
+ import { spawnHarness, type HarnessContext } from "../helpers.js";
59
+
60
+ describe.skipIf(process.platform === "win32" && process.env["MUONROI_SKIP_NAMED_PIPE"] === "1")(
61
+ "self-qa auto: ${escapeForString(scenario.id)}",
62
+ () => {
63
+ let ctx: HarnessContext;
64
+
65
+ beforeAll(async () => {
66
+ ctx = await spawnHarness();
67
+ await ctx.driver.wait_for({ idle: true, timeoutMs: 15_000 });
68
+ // 120s: cold agent-mode TUI boot under CPU contention can take 25-46s+
69
+ // (the named-pipe handshake budget alone is 90s). A tighter hook timeout
70
+ // is the wrong constraint and surfaces as a flaky "Hook timed out".
71
+ }, 120_000);
72
+
73
+ afterAll(() => {
74
+ ctx?.cleanup();
75
+ });
76
+
77
+ it("${safeDesc}", async () => {
78
+ const { driver } = ctx;
79
+ ${body}
80
+ }, ${scenario.budgetMs + 5_000});
81
+ },
82
+ );
80
83
  `;
81
84
  }
82
85
  function stepToCode(step) {
@@ -313,7 +313,7 @@ describe("DB migrations", () => {
313
313
  ]);
314
314
  raw.rows.set("usage_events", []);
315
315
  // Insert without pil_active/enrichment_delta — should default to 0
316
- db.prepare(`INSERT INTO usage_events (session_id, message_seq, source, model, input_tokens, output_tokens, total_tokens, cost_micros, created_at)
316
+ db.prepare(`INSERT INTO usage_events (session_id, message_seq, source, model, input_tokens, output_tokens, total_tokens, cost_micros, created_at)
317
317
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run("sess1", null, "orchestrator", "claude", 100, 50, 150, 0, new Date().toISOString());
318
318
  const usageRows = raw.rows.get("usage_events");
319
319
  expect(usageRows).toHaveLength(1);
@@ -346,7 +346,7 @@ describe("DB migrations", () => {
346
346
  },
347
347
  ]);
348
348
  raw.rows.set("usage_events", []);
349
- db.prepare(`INSERT INTO usage_events (session_id, message_seq, source, model, input_tokens, output_tokens, total_tokens, cost_micros, created_at, pil_active, enrichment_delta)
349
+ db.prepare(`INSERT INTO usage_events (session_id, message_seq, source, model, input_tokens, output_tokens, total_tokens, cost_micros, created_at, pil_active, enrichment_delta)
350
350
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run("sess2", null, "orchestrator", "claude", 100, 50, 150, 0, new Date().toISOString(), 1, -120);
351
351
  const usageRows = raw.rows.get("usage_events");
352
352
  expect(usageRows).toHaveLength(1);
@@ -43,10 +43,10 @@ export function selectEEInjectionsForRun(runId, limit = 20) {
43
43
  try {
44
44
  const db = getDatabase();
45
45
  return db
46
- .prepare(`SELECT session_id, event_subtype, duration_ms, metadata_json, created_at
47
- FROM interaction_logs
48
- WHERE session_id = ? AND event_type = 'ee_injection'
49
- ORDER BY created_at DESC
46
+ .prepare(`SELECT session_id, event_subtype, duration_ms, metadata_json, created_at
47
+ FROM interaction_logs
48
+ WHERE session_id = ? AND event_type = 'ee_injection'
49
+ ORDER BY created_at DESC
50
50
  LIMIT ?`)
51
51
  .all(runId, limit);
52
52
  }
@@ -62,7 +62,7 @@ export function logInteraction(sessionId, eventType, metadata) {
62
62
  try {
63
63
  const db = getDatabase();
64
64
  const metadataJson = metadata?.data ? JSON.stringify(metadata.data) : null;
65
- db.prepare(`INSERT INTO interaction_logs (session_id, event_type, event_subtype, model, duration_ms, input_tokens, output_tokens, metadata_json, created_at)
65
+ db.prepare(`INSERT INTO interaction_logs (session_id, event_type, event_subtype, model, duration_ms, input_tokens, output_tokens, metadata_json, created_at)
66
66
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(sessionId, eventType, metadata?.eventSubtype ?? null, metadata?.model ?? null, metadata?.durationMs ?? null, metadata?.inputTokens ?? null, metadata?.outputTokens ?? null, metadataJson, new Date().toISOString());
67
67
  maybePruneOld();
68
68
  }
@@ -13,9 +13,9 @@ export function applyMigrations(db) {
13
13
  db.pragma("user_version = 2");
14
14
  }
15
15
  if (version < 3) {
16
- db.exec(`
17
- ALTER TABLE usage_events ADD COLUMN pil_active INTEGER NOT NULL DEFAULT 0;
18
- ALTER TABLE usage_events ADD COLUMN enrichment_delta INTEGER NOT NULL DEFAULT 0;
16
+ db.exec(`
17
+ ALTER TABLE usage_events ADD COLUMN pil_active INTEGER NOT NULL DEFAULT 0;
18
+ ALTER TABLE usage_events ADD COLUMN enrichment_delta INTEGER NOT NULL DEFAULT 0;
19
19
  `);
20
20
  db.pragma("user_version = 3");
21
21
  }
@@ -34,24 +34,24 @@ export function applyMigrations(db) {
34
34
  db.pragma("user_version = 4");
35
35
  }
36
36
  if (version < 5) {
37
- db.exec(`
38
- CREATE TABLE IF NOT EXISTS interaction_logs (
39
- id INTEGER PRIMARY KEY AUTOINCREMENT,
40
- session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
41
- event_type TEXT NOT NULL,
42
- event_subtype TEXT,
43
- model TEXT,
44
- duration_ms INTEGER,
45
- input_tokens INTEGER,
46
- output_tokens INTEGER,
47
- metadata_json TEXT,
48
- created_at TEXT NOT NULL
49
- ) STRICT;
50
-
51
- CREATE INDEX IF NOT EXISTS idx_interaction_logs_session
52
- ON interaction_logs(session_id, created_at DESC);
53
- CREATE INDEX IF NOT EXISTS idx_interaction_logs_event_type
54
- ON interaction_logs(event_type, created_at DESC);
37
+ db.exec(`
38
+ CREATE TABLE IF NOT EXISTS interaction_logs (
39
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
40
+ session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
41
+ event_type TEXT NOT NULL,
42
+ event_subtype TEXT,
43
+ model TEXT,
44
+ duration_ms INTEGER,
45
+ input_tokens INTEGER,
46
+ output_tokens INTEGER,
47
+ metadata_json TEXT,
48
+ created_at TEXT NOT NULL
49
+ ) STRICT;
50
+
51
+ CREATE INDEX IF NOT EXISTS idx_interaction_logs_session
52
+ ON interaction_logs(session_id, created_at DESC);
53
+ CREATE INDEX IF NOT EXISTS idx_interaction_logs_event_type
54
+ ON interaction_logs(event_type, created_at DESC);
55
55
  `);
56
56
  db.pragma("user_version = 5");
57
57
  }
@@ -91,110 +91,110 @@ export function applyMigrations(db) {
91
91
  migrate();
92
92
  }
93
93
  function createInitialSchema(db) {
94
- db.exec(`
95
- CREATE TABLE IF NOT EXISTS workspaces (
96
- id TEXT PRIMARY KEY,
97
- scope_key TEXT NOT NULL UNIQUE,
98
- canonical_path TEXT NOT NULL,
99
- git_root TEXT,
100
- display_name TEXT NOT NULL,
101
- last_seen_at TEXT NOT NULL
102
- ) STRICT;
103
-
104
- CREATE TABLE IF NOT EXISTS sessions (
105
- id TEXT PRIMARY KEY,
106
- workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
107
- title TEXT,
108
- model TEXT NOT NULL,
109
- mode TEXT NOT NULL,
110
- cwd_at_start TEXT NOT NULL,
111
- cwd_last TEXT NOT NULL,
112
- status TEXT NOT NULL,
113
- created_at TEXT NOT NULL,
114
- updated_at TEXT NOT NULL
115
- ) STRICT;
116
-
117
- CREATE TABLE IF NOT EXISTS messages (
118
- session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
119
- seq INTEGER NOT NULL,
120
- role TEXT NOT NULL,
121
- message_json TEXT NOT NULL,
122
- created_at TEXT NOT NULL,
123
- status TEXT,
124
- PRIMARY KEY (session_id, seq)
125
- ) STRICT;
126
-
127
- CREATE TABLE IF NOT EXISTS tool_calls (
128
- id INTEGER PRIMARY KEY AUTOINCREMENT,
129
- session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
130
- message_seq INTEGER NOT NULL,
131
- tool_call_id TEXT NOT NULL,
132
- tool_name TEXT NOT NULL,
133
- args_json TEXT NOT NULL,
134
- status TEXT NOT NULL,
135
- started_at TEXT NOT NULL,
136
- completed_at TEXT,
137
- UNIQUE(session_id, tool_call_id)
138
- ) STRICT;
139
-
140
- CREATE TABLE IF NOT EXISTS tool_results (
141
- id INTEGER PRIMARY KEY AUTOINCREMENT,
142
- tool_call_row_id INTEGER NOT NULL REFERENCES tool_calls(id) ON DELETE CASCADE,
143
- output_kind TEXT NOT NULL,
144
- output_json TEXT NOT NULL,
145
- success INTEGER NOT NULL,
146
- created_at TEXT NOT NULL
147
- ) STRICT;
148
-
149
- CREATE TABLE IF NOT EXISTS usage_events (
150
- id INTEGER PRIMARY KEY AUTOINCREMENT,
151
- session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
152
- message_seq INTEGER,
153
- source TEXT NOT NULL,
154
- model TEXT NOT NULL,
155
- input_tokens INTEGER NOT NULL DEFAULT 0,
156
- output_tokens INTEGER NOT NULL DEFAULT 0,
157
- total_tokens INTEGER NOT NULL DEFAULT 0,
158
- cost_micros INTEGER NOT NULL DEFAULT 0,
159
- created_at TEXT NOT NULL,
160
- cache_read_tokens INTEGER NOT NULL DEFAULT 0,
161
- cache_creation_tokens INTEGER NOT NULL DEFAULT 0
162
- ) STRICT;
163
-
164
- CREATE TABLE IF NOT EXISTS compactions (
165
- id INTEGER PRIMARY KEY AUTOINCREMENT,
166
- session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
167
- first_kept_seq INTEGER NOT NULL,
168
- summary TEXT NOT NULL,
169
- tokens_before INTEGER NOT NULL DEFAULT 0,
170
- created_at TEXT NOT NULL
171
- ) STRICT;
172
-
173
- CREATE INDEX IF NOT EXISTS idx_sessions_workspace_updated
174
- ON sessions(workspace_id, updated_at DESC);
175
- CREATE INDEX IF NOT EXISTS idx_messages_session_seq
176
- ON messages(session_id, seq);
177
- CREATE INDEX IF NOT EXISTS idx_tool_calls_session_seq
178
- ON tool_calls(session_id, message_seq);
179
- CREATE INDEX IF NOT EXISTS idx_usage_events_session_created
180
- ON usage_events(session_id, created_at DESC);
181
- CREATE INDEX IF NOT EXISTS idx_compactions_session_created
182
- ON compactions(session_id, created_at DESC);
94
+ db.exec(`
95
+ CREATE TABLE IF NOT EXISTS workspaces (
96
+ id TEXT PRIMARY KEY,
97
+ scope_key TEXT NOT NULL UNIQUE,
98
+ canonical_path TEXT NOT NULL,
99
+ git_root TEXT,
100
+ display_name TEXT NOT NULL,
101
+ last_seen_at TEXT NOT NULL
102
+ ) STRICT;
103
+
104
+ CREATE TABLE IF NOT EXISTS sessions (
105
+ id TEXT PRIMARY KEY,
106
+ workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
107
+ title TEXT,
108
+ model TEXT NOT NULL,
109
+ mode TEXT NOT NULL,
110
+ cwd_at_start TEXT NOT NULL,
111
+ cwd_last TEXT NOT NULL,
112
+ status TEXT NOT NULL,
113
+ created_at TEXT NOT NULL,
114
+ updated_at TEXT NOT NULL
115
+ ) STRICT;
116
+
117
+ CREATE TABLE IF NOT EXISTS messages (
118
+ session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
119
+ seq INTEGER NOT NULL,
120
+ role TEXT NOT NULL,
121
+ message_json TEXT NOT NULL,
122
+ created_at TEXT NOT NULL,
123
+ status TEXT,
124
+ PRIMARY KEY (session_id, seq)
125
+ ) STRICT;
126
+
127
+ CREATE TABLE IF NOT EXISTS tool_calls (
128
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
129
+ session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
130
+ message_seq INTEGER NOT NULL,
131
+ tool_call_id TEXT NOT NULL,
132
+ tool_name TEXT NOT NULL,
133
+ args_json TEXT NOT NULL,
134
+ status TEXT NOT NULL,
135
+ started_at TEXT NOT NULL,
136
+ completed_at TEXT,
137
+ UNIQUE(session_id, tool_call_id)
138
+ ) STRICT;
139
+
140
+ CREATE TABLE IF NOT EXISTS tool_results (
141
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
142
+ tool_call_row_id INTEGER NOT NULL REFERENCES tool_calls(id) ON DELETE CASCADE,
143
+ output_kind TEXT NOT NULL,
144
+ output_json TEXT NOT NULL,
145
+ success INTEGER NOT NULL,
146
+ created_at TEXT NOT NULL
147
+ ) STRICT;
148
+
149
+ CREATE TABLE IF NOT EXISTS usage_events (
150
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
151
+ session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
152
+ message_seq INTEGER,
153
+ source TEXT NOT NULL,
154
+ model TEXT NOT NULL,
155
+ input_tokens INTEGER NOT NULL DEFAULT 0,
156
+ output_tokens INTEGER NOT NULL DEFAULT 0,
157
+ total_tokens INTEGER NOT NULL DEFAULT 0,
158
+ cost_micros INTEGER NOT NULL DEFAULT 0,
159
+ created_at TEXT NOT NULL,
160
+ cache_read_tokens INTEGER NOT NULL DEFAULT 0,
161
+ cache_creation_tokens INTEGER NOT NULL DEFAULT 0
162
+ ) STRICT;
163
+
164
+ CREATE TABLE IF NOT EXISTS compactions (
165
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
166
+ session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
167
+ first_kept_seq INTEGER NOT NULL,
168
+ summary TEXT NOT NULL,
169
+ tokens_before INTEGER NOT NULL DEFAULT 0,
170
+ created_at TEXT NOT NULL
171
+ ) STRICT;
172
+
173
+ CREATE INDEX IF NOT EXISTS idx_sessions_workspace_updated
174
+ ON sessions(workspace_id, updated_at DESC);
175
+ CREATE INDEX IF NOT EXISTS idx_messages_session_seq
176
+ ON messages(session_id, seq);
177
+ CREATE INDEX IF NOT EXISTS idx_tool_calls_session_seq
178
+ ON tool_calls(session_id, message_seq);
179
+ CREATE INDEX IF NOT EXISTS idx_usage_events_session_created
180
+ ON usage_events(session_id, created_at DESC);
181
+ CREATE INDEX IF NOT EXISTS idx_compactions_session_created
182
+ ON compactions(session_id, created_at DESC);
183
183
  `);
184
184
  }
185
185
  function createCompactionSchema(db) {
186
- db.exec(`
187
- CREATE TABLE IF NOT EXISTS compactions (
188
- id INTEGER PRIMARY KEY AUTOINCREMENT,
189
- session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
190
- first_kept_seq INTEGER NOT NULL,
191
- summary TEXT NOT NULL,
192
- tokens_before INTEGER NOT NULL DEFAULT 0,
193
- created_at TEXT NOT NULL
194
- ) STRICT;
195
-
196
- CREATE INDEX IF NOT EXISTS idx_compactions_session_created
197
- ON compactions(session_id, created_at DESC);
186
+ db.exec(`
187
+ CREATE TABLE IF NOT EXISTS compactions (
188
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
189
+ session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
190
+ first_kept_seq INTEGER NOT NULL,
191
+ summary TEXT NOT NULL,
192
+ tokens_before INTEGER NOT NULL DEFAULT 0,
193
+ created_at TEXT NOT NULL
194
+ ) STRICT;
195
+
196
+ CREATE INDEX IF NOT EXISTS idx_compactions_session_created
197
+ ON compactions(session_id, created_at DESC);
198
198
  `);
199
199
  }
200
200
  //# sourceMappingURL=migrations.js.map
@@ -43,12 +43,12 @@ export class SessionStore {
43
43
  const now = new Date().toISOString();
44
44
  const id = createSessionId();
45
45
  const db = getDatabase();
46
- db.prepare(`
47
- INSERT INTO sessions (
48
- id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
49
- ) VALUES (
50
- @id, @workspace_id, NULL, @model, @mode, @cwd_at_start, @cwd_last, 'active', @created_at, @updated_at
51
- )
46
+ db.prepare(`
47
+ INSERT INTO sessions (
48
+ id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
49
+ ) VALUES (
50
+ @id, @workspace_id, NULL, @model, @mode, @cwd_at_start, @cwd_last, 'active', @created_at, @updated_at
51
+ )
52
52
  `).run({
53
53
  id,
54
54
  workspace_id: this.workspace.id,
@@ -67,34 +67,34 @@ export class SessionStore {
67
67
  */
68
68
  listRecentSessions(limit = 20) {
69
69
  const rows = getDatabase()
70
- .prepare(`
71
- SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
72
- FROM sessions
73
- WHERE workspace_id = ?
74
- ORDER BY updated_at DESC
75
- LIMIT ?
70
+ .prepare(`
71
+ SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
72
+ FROM sessions
73
+ WHERE workspace_id = ?
74
+ ORDER BY updated_at DESC
75
+ LIMIT ?
76
76
  `)
77
77
  .all(this.workspace.id, limit);
78
78
  return rows.map(toSessionInfo);
79
79
  }
80
80
  getLatestSession() {
81
81
  const row = getDatabase()
82
- .prepare(`
83
- SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
84
- FROM sessions
85
- WHERE workspace_id = ?
86
- ORDER BY updated_at DESC
87
- LIMIT 1
82
+ .prepare(`
83
+ SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
84
+ FROM sessions
85
+ WHERE workspace_id = ?
86
+ ORDER BY updated_at DESC
87
+ LIMIT 1
88
88
  `)
89
89
  .get(this.workspace.id);
90
90
  return row ? toSessionInfo(row) : null;
91
91
  }
92
92
  getSessionById(id) {
93
93
  const row = getDatabase()
94
- .prepare(`
95
- SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
96
- FROM sessions
97
- WHERE id = ?
94
+ .prepare(`
95
+ SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
96
+ FROM sessions
97
+ WHERE id = ?
98
98
  `)
99
99
  .get(id);
100
100
  return row ? toSessionInfo(row) : null;
@@ -109,49 +109,49 @@ export class SessionStore {
109
109
  setStatus(id, status) {
110
110
  const now = new Date().toISOString();
111
111
  getDatabase()
112
- .prepare(`
113
- UPDATE sessions
114
- SET status = ?, updated_at = ?
115
- WHERE id = ?
112
+ .prepare(`
113
+ UPDATE sessions
114
+ SET status = ?, updated_at = ?
115
+ WHERE id = ?
116
116
  `)
117
117
  .run(status, now, id);
118
118
  }
119
119
  setTitle(id, title) {
120
120
  const now = new Date().toISOString();
121
121
  getDatabase()
122
- .prepare(`
123
- UPDATE sessions
124
- SET title = ?, updated_at = ?
125
- WHERE id = ?
122
+ .prepare(`
123
+ UPDATE sessions
124
+ SET title = ?, updated_at = ?
125
+ WHERE id = ?
126
126
  `)
127
127
  .run(title, now, id);
128
128
  }
129
129
  setModel(id, model) {
130
130
  const now = new Date().toISOString();
131
131
  getDatabase()
132
- .prepare(`
133
- UPDATE sessions
134
- SET model = ?, updated_at = ?
135
- WHERE id = ?
132
+ .prepare(`
133
+ UPDATE sessions
134
+ SET model = ?, updated_at = ?
135
+ WHERE id = ?
136
136
  `)
137
137
  .run(model, now, id);
138
138
  }
139
139
  setMode(id, mode) {
140
140
  const now = new Date().toISOString();
141
141
  getDatabase()
142
- .prepare(`
143
- UPDATE sessions
144
- SET mode = ?, updated_at = ?
145
- WHERE id = ?
142
+ .prepare(`
143
+ UPDATE sessions
144
+ SET mode = ?, updated_at = ?
145
+ WHERE id = ?
146
146
  `)
147
147
  .run(mode, now, id);
148
148
  }
149
149
  touchSession(id, cwd) {
150
150
  getDatabase()
151
- .prepare(`
152
- UPDATE sessions
153
- SET cwd_last = ?, updated_at = ?
154
- WHERE id = ?
151
+ .prepare(`
152
+ UPDATE sessions
153
+ SET cwd_last = ?, updated_at = ?
154
+ WHERE id = ?
155
155
  `)
156
156
  .run(cwd, new Date().toISOString(), id);
157
157
  }