agent-nuvira 3.5.5 → 3.5.7

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 (229) hide show
  1. package/.agents/skills/index.json +16 -0
  2. package/.agents/skills/motion/SKILL.md +27 -0
  3. package/README.md +122 -1
  4. package/dist/cli/chat.d.ts +76 -17
  5. package/dist/cli/chat.d.ts.map +1 -1
  6. package/dist/cli/chat.js +330 -137
  7. package/dist/cli/chat.js.map +1 -1
  8. package/dist/cli/config.d.ts.map +1 -1
  9. package/dist/cli/config.js +17 -3
  10. package/dist/cli/config.js.map +1 -1
  11. package/dist/cli/doctor.d.ts +31 -2
  12. package/dist/cli/doctor.d.ts.map +1 -1
  13. package/dist/cli/doctor.js +143 -7
  14. package/dist/cli/doctor.js.map +1 -1
  15. package/dist/cli/execute.d.ts.map +1 -1
  16. package/dist/cli/execute.js +63 -22
  17. package/dist/cli/execute.js.map +1 -1
  18. package/dist/cli/failover-runner.js +4 -4
  19. package/dist/cli/failover-runner.js.map +1 -1
  20. package/dist/cli/gateway.js +13 -13
  21. package/dist/cli/gateway.js.map +1 -1
  22. package/dist/cli/loop-executor.d.ts +22 -0
  23. package/dist/cli/loop-executor.d.ts.map +1 -1
  24. package/dist/cli/loop-executor.js +60 -13
  25. package/dist/cli/loop-executor.js.map +1 -1
  26. package/dist/cli/parity.d.ts +12 -0
  27. package/dist/cli/parity.d.ts.map +1 -1
  28. package/dist/cli/parity.js +46 -1
  29. package/dist/cli/parity.js.map +1 -1
  30. package/dist/cli/stats.d.ts +62 -4
  31. package/dist/cli/stats.d.ts.map +1 -1
  32. package/dist/cli/stats.js +282 -5
  33. package/dist/cli/stats.js.map +1 -1
  34. package/dist/cli/tool-install-prompt.d.ts +2 -7
  35. package/dist/cli/tool-install-prompt.d.ts.map +1 -1
  36. package/dist/cli/tool-install-prompt.js +11 -28
  37. package/dist/cli/tool-install-prompt.js.map +1 -1
  38. package/dist/cli/ui/index.d.ts +2 -2
  39. package/dist/cli/ui/index.d.ts.map +1 -1
  40. package/dist/cli/ui/index.js +1 -1
  41. package/dist/cli/ui/index.js.map +1 -1
  42. package/dist/cli/ui/presenter.d.ts +43 -0
  43. package/dist/cli/ui/presenter.d.ts.map +1 -1
  44. package/dist/cli/ui/presenter.js +88 -1
  45. package/dist/cli/ui/presenter.js.map +1 -1
  46. package/dist/config/manager.d.ts +29 -1
  47. package/dist/config/manager.d.ts.map +1 -1
  48. package/dist/config/manager.js +178 -143
  49. package/dist/config/manager.js.map +1 -1
  50. package/dist/config/paths.d.ts +48 -1
  51. package/dist/config/paths.d.ts.map +1 -1
  52. package/dist/config/paths.js +59 -9
  53. package/dist/config/paths.js.map +1 -1
  54. package/dist/config/scratch-workspace.d.ts +134 -0
  55. package/dist/config/scratch-workspace.d.ts.map +1 -0
  56. package/dist/config/scratch-workspace.js +213 -0
  57. package/dist/config/scratch-workspace.js.map +1 -0
  58. package/dist/config/service-catalog.js +1 -1
  59. package/dist/config/service-catalog.js.map +1 -1
  60. package/dist/config/service-probe.js +1 -1
  61. package/dist/config/service-probe.js.map +1 -1
  62. package/dist/config/types.d.ts +22 -0
  63. package/dist/config/types.d.ts.map +1 -1
  64. package/dist/gateway/adapters.d.ts +24 -0
  65. package/dist/gateway/adapters.d.ts.map +1 -1
  66. package/dist/gateway/adapters.js +20 -8
  67. package/dist/gateway/adapters.js.map +1 -1
  68. package/dist/gateway/oversized-reply.d.ts +39 -0
  69. package/dist/gateway/oversized-reply.d.ts.map +1 -0
  70. package/dist/gateway/oversized-reply.js +54 -0
  71. package/dist/gateway/oversized-reply.js.map +1 -0
  72. package/dist/gateway/registry.d.ts +0 -10
  73. package/dist/gateway/registry.d.ts.map +1 -1
  74. package/dist/gateway/registry.js +149 -5
  75. package/dist/gateway/registry.js.map +1 -1
  76. package/dist/learning/auto-router.d.ts +30 -4
  77. package/dist/learning/auto-router.d.ts.map +1 -1
  78. package/dist/learning/auto-router.js +54 -38
  79. package/dist/learning/auto-router.js.map +1 -1
  80. package/dist/learning/cost-classification.d.ts +188 -0
  81. package/dist/learning/cost-classification.d.ts.map +1 -0
  82. package/dist/learning/cost-classification.js +294 -0
  83. package/dist/learning/cost-classification.js.map +1 -0
  84. package/dist/learning/cost-ledger-maintenance.d.ts +122 -0
  85. package/dist/learning/cost-ledger-maintenance.d.ts.map +1 -0
  86. package/dist/learning/cost-ledger-maintenance.js +289 -0
  87. package/dist/learning/cost-ledger-maintenance.js.map +1 -0
  88. package/dist/learning/cost-reconcile.d.ts +160 -0
  89. package/dist/learning/cost-reconcile.d.ts.map +1 -0
  90. package/dist/learning/cost-reconcile.js +238 -0
  91. package/dist/learning/cost-reconcile.js.map +1 -0
  92. package/dist/learning/cost-tracker.d.ts +134 -13
  93. package/dist/learning/cost-tracker.d.ts.map +1 -1
  94. package/dist/learning/cost-tracker.js +190 -68
  95. package/dist/learning/cost-tracker.js.map +1 -1
  96. package/dist/learning/model-pricing.d.ts +240 -0
  97. package/dist/learning/model-pricing.d.ts.map +1 -0
  98. package/dist/learning/model-pricing.js +309 -0
  99. package/dist/learning/model-pricing.js.map +1 -0
  100. package/dist/learning/model-selection.d.ts +15 -0
  101. package/dist/learning/model-selection.d.ts.map +1 -1
  102. package/dist/learning/model-selection.js +22 -2
  103. package/dist/learning/model-selection.js.map +1 -1
  104. package/dist/learning/model-warmup.d.ts.map +1 -1
  105. package/dist/learning/model-warmup.js +4 -1
  106. package/dist/learning/model-warmup.js.map +1 -1
  107. package/dist/learning/quota-ledger.d.ts +24 -0
  108. package/dist/learning/quota-ledger.d.ts.map +1 -1
  109. package/dist/learning/quota-ledger.js +40 -0
  110. package/dist/learning/quota-ledger.js.map +1 -1
  111. package/dist/learning/runtime-dependencies.d.ts +183 -0
  112. package/dist/learning/runtime-dependencies.d.ts.map +1 -0
  113. package/dist/learning/runtime-dependencies.js +349 -0
  114. package/dist/learning/runtime-dependencies.js.map +1 -0
  115. package/dist/learning/session-store.d.ts +1 -5
  116. package/dist/learning/session-store.d.ts.map +1 -1
  117. package/dist/learning/session-store.js +10 -1
  118. package/dist/learning/session-store.js.map +1 -1
  119. package/dist/learning/skill-store.d.ts.map +1 -1
  120. package/dist/learning/skill-store.js +6 -5
  121. package/dist/learning/skill-store.js.map +1 -1
  122. package/dist/learning/step-checkpoint.d.ts +32 -3
  123. package/dist/learning/step-checkpoint.d.ts.map +1 -1
  124. package/dist/learning/step-checkpoint.js +33 -4
  125. package/dist/learning/step-checkpoint.js.map +1 -1
  126. package/dist/mcp/settings.d.ts +15 -3
  127. package/dist/mcp/settings.d.ts.map +1 -1
  128. package/dist/mcp/settings.js +30 -15
  129. package/dist/mcp/settings.js.map +1 -1
  130. package/dist/parity/drivers.d.ts.map +1 -1
  131. package/dist/parity/drivers.js +31 -5
  132. package/dist/parity/drivers.js.map +1 -1
  133. package/dist/skills/bundled-skills-phase3.d.ts +14 -0
  134. package/dist/skills/bundled-skills-phase3.d.ts.map +1 -1
  135. package/dist/skills/bundled-skills-phase3.js +50 -0
  136. package/dist/skills/bundled-skills-phase3.js.map +1 -1
  137. package/dist/tools/child-agent-runtime.d.ts.map +1 -1
  138. package/dist/tools/child-agent-runtime.js +13 -7
  139. package/dist/tools/child-agent-runtime.js.map +1 -1
  140. package/dist/tools/followup-utils.d.ts +36 -0
  141. package/dist/tools/followup-utils.d.ts.map +1 -1
  142. package/dist/tools/followup-utils.js +66 -0
  143. package/dist/tools/followup-utils.js.map +1 -1
  144. package/dist/tools/modality/browser.js +2 -2
  145. package/dist/tools/modality/browser.js.map +1 -1
  146. package/dist/tools/modality/image-gen.d.ts +1 -1
  147. package/dist/tools/modality/image-gen.js +1 -1
  148. package/dist/tools/modality/image-providers.js +1 -1
  149. package/dist/tools/modality/image-providers.js.map +1 -1
  150. package/dist/tools/modality/motion-presets.d.ts +62 -0
  151. package/dist/tools/modality/motion-presets.d.ts.map +1 -0
  152. package/dist/tools/modality/motion-presets.js +399 -0
  153. package/dist/tools/modality/motion-presets.js.map +1 -0
  154. package/dist/tools/modality/motion-tool.d.ts +62 -0
  155. package/dist/tools/modality/motion-tool.d.ts.map +1 -0
  156. package/dist/tools/modality/motion-tool.js +220 -0
  157. package/dist/tools/modality/motion-tool.js.map +1 -0
  158. package/dist/tools/modality/motion.d.ts +298 -0
  159. package/dist/tools/modality/motion.d.ts.map +1 -0
  160. package/dist/tools/modality/motion.js +514 -0
  161. package/dist/tools/modality/motion.js.map +1 -0
  162. package/dist/tools/modality/vision.d.ts +1 -1
  163. package/dist/tools/modality/vision.js +1 -1
  164. package/dist/tools/modality/voice.js +2 -2
  165. package/dist/tools/modality/voice.js.map +1 -1
  166. package/dist/tools/neutts-synth.d.ts +3 -3
  167. package/dist/tools/neutts-synth.js +3 -3
  168. package/dist/tools/neutts-synth.js.map +1 -1
  169. package/dist/tools/process-liveness.d.ts +50 -0
  170. package/dist/tools/process-liveness.d.ts.map +1 -1
  171. package/dist/tools/process-liveness.js +82 -9
  172. package/dist/tools/process-liveness.js.map +1 -1
  173. package/dist/tools/registry.d.ts +1 -1
  174. package/dist/tools/registry.d.ts.map +1 -1
  175. package/dist/tools/registry.js +102 -4
  176. package/dist/tools/registry.js.map +1 -1
  177. package/dist/tools/run-terminal.d.ts.map +1 -1
  178. package/dist/tools/run-terminal.js +18 -1
  179. package/dist/tools/run-terminal.js.map +1 -1
  180. package/dist/tools/tool-loop.d.ts.map +1 -1
  181. package/dist/tools/tool-loop.js +71 -19
  182. package/dist/tools/tool-loop.js.map +1 -1
  183. package/dist/tools/toolsets.js +2 -2
  184. package/dist/tools/toolsets.js.map +1 -1
  185. package/dist/tools/web-research.d.ts +1 -1
  186. package/dist/tools/web-research.js +3 -3
  187. package/dist/tools/web-research.js.map +1 -1
  188. package/dist/utils/workspace-need.d.ts +84 -0
  189. package/dist/utils/workspace-need.d.ts.map +1 -0
  190. package/dist/utils/workspace-need.js +227 -0
  191. package/dist/utils/workspace-need.js.map +1 -0
  192. package/dist/web-dashboard/chat-console.d.ts +78 -0
  193. package/dist/web-dashboard/chat-console.d.ts.map +1 -1
  194. package/dist/web-dashboard/chat-console.js +122 -12
  195. package/dist/web-dashboard/chat-console.js.map +1 -1
  196. package/dist/web-dashboard/hub-data.d.ts +9 -1
  197. package/dist/web-dashboard/hub-data.d.ts.map +1 -1
  198. package/dist/web-dashboard/hub-data.js +2 -0
  199. package/dist/web-dashboard/hub-data.js.map +1 -1
  200. package/dist/web-dashboard/project-context.d.ts +1 -1
  201. package/dist/web-dashboard/project-context.d.ts.map +1 -1
  202. package/dist/web-dashboard/project-context.js +7 -1
  203. package/dist/web-dashboard/project-context.js.map +1 -1
  204. package/dist/web-dashboard/server.d.ts +33 -0
  205. package/dist/web-dashboard/server.d.ts.map +1 -1
  206. package/dist/web-dashboard/server.js +326 -23
  207. package/dist/web-dashboard/server.js.map +1 -1
  208. package/dist/web-dashboard/src/types.d.ts +109 -0
  209. package/dist/web-dashboard/src/types.d.ts.map +1 -1
  210. package/dist/web-dashboard/task-runner.d.ts +17 -1
  211. package/dist/web-dashboard/task-runner.d.ts.map +1 -1
  212. package/dist/web-dashboard/task-runner.js +40 -4
  213. package/dist/web-dashboard/task-runner.js.map +1 -1
  214. package/dist/web-dashboard/workspace-guard.d.ts +20 -21
  215. package/dist/web-dashboard/workspace-guard.d.ts.map +1 -1
  216. package/dist/web-dashboard/workspace-guard.js +20 -153
  217. package/dist/web-dashboard/workspace-guard.js.map +1 -1
  218. package/dist/web-dashboard/workspace-resolution.d.ts +23 -5
  219. package/dist/web-dashboard/workspace-resolution.d.ts.map +1 -1
  220. package/dist/web-dashboard/workspace-resolution.js +22 -4
  221. package/dist/web-dashboard/workspace-resolution.js.map +1 -1
  222. package/package.json +1 -1
  223. package/src/web-dashboard/public/assets/index-CzRU84ET.css +1 -0
  224. package/src/web-dashboard/public/assets/index-V0rIqVbg.js +236 -0
  225. package/src/web-dashboard/public/assets/index-V0rIqVbg.js.map +1 -0
  226. package/src/web-dashboard/public/index.html +2 -2
  227. package/src/web-dashboard/public/assets/index-DycGBWwy.js +0 -236
  228. package/src/web-dashboard/public/assets/index-DycGBWwy.js.map +0 -1
  229. package/src/web-dashboard/public/assets/index-aO3aG7ex.css +0 -1
@@ -10,6 +10,7 @@
10
10
  * Opens at: http://localhost:3030
11
11
  */
12
12
  import { createServer } from 'node:http';
13
+ import { type DependencyStatus } from '../learning/runtime-dependencies.js';
13
14
  import type { WireFinding } from '../findings/verdicts.js';
14
15
  import { WhatsAppPairingManager } from './whatsapp-pairing.js';
15
16
  import { ChatConsole } from './chat-console.js';
@@ -304,6 +305,38 @@ export declare function readTracesData(): {
304
305
  };
305
306
  /** Full trace detail (steps included) for the replay view. */
306
307
  export declare function readTraceDetail(id: string): DashboardTrace | null;
308
+ /**
309
+ * One runtime tool the agent uses but does not ship, as the System page's panel
310
+ * needs it. Mirrored by `RuntimeTool` in the dashboard's `types.ts` — the same
311
+ * split `AdminProviderSummary` uses, so the wire shape is stated where it is
312
+ * produced and where it is rendered, not imported across the boundary.
313
+ *
314
+ * The server maps the DECLARATION into this DTO rather than shipping the whole
315
+ * dependency object: the panel renders, it does not decide, and the internal
316
+ * probe list has no business on the wire.
317
+ */
318
+ interface RuntimeTool {
319
+ id: string;
320
+ label: string;
321
+ need: 'recommended' | 'optional';
322
+ /** Whether the server found it on THIS machine. */
323
+ present: boolean;
324
+ /** What installing it buys, one sentence. */
325
+ enables: string;
326
+ /** The tools that need it (cited under the row). */
327
+ neededBy: string[];
328
+ /** The command for this OS, or null when no one-liner applies here. */
329
+ installCommand: string | null;
330
+ /** The caveat that bites, shown with the command. */
331
+ note?: string;
332
+ /** True when running it needs a human (sudo, a GUI installer). */
333
+ needsHumanInput: boolean;
334
+ }
335
+ /**
336
+ * One runtime tool as the panel's payload. Exported for the server test, which
337
+ * asserts the panel is fed the same list `nuvira doctor` prints.
338
+ */
339
+ export declare function runtimeToolSummary(status: DependencyStatus): RuntimeTool;
307
340
  /** Test hook: swap the chat console (e.g. a fake engine) — routes read the
308
341
  * module variable at request time, so this works anytime. The Phase 4
309
342
  * DAG-telemetry hook is re-attached to the replacement. */
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/web-dashboard/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/web-dashboard/server.ts"],"names":[],"mappings":"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"}
@@ -25,7 +25,9 @@ import { loadEnv } from '../utils/env.js';
25
25
  import { ConfigManager } from '../config/manager.js';
26
26
  import { parseRuntimeSpec } from '../mcp/runtime.js';
27
27
  import { runAllChecks } from '../cli/doctor.js';
28
+ import { dependencySummary, probeRuntimeDependencies, } from '../learning/runtime-dependencies.js';
28
29
  import { getAutoRouter } from '../learning/auto-router.js';
30
+ import { classifyEntries, } from '../learning/cost-classification.js';
29
31
  import { acceptanceSummary, collectLabelledTurns, serializeLabelledTurns, parseCorpusText, detectCorpusFormat, mergeImportedLabels, } from '../learning/acceptance-model.js';
30
32
  import { readDecisions, recallDecisions, reviseDecision } from '../learning/decision-log.js';
31
33
  import { degradedCallsFromTraces } from '../learning/reasoning-trace.js';
@@ -54,6 +56,7 @@ import { isCuratedProcessEnvVar, normalizeProcessEnvValue, } from '../config/pro
54
56
  import { FRESH_DAYS, FRESHNESS_COPY, REACHABILITY_COPY, classifyFreshness, classifyReachability, } from '../learning/model-reachability.js';
55
57
  import { VERIFY_BACKLOG_DEFAULT_PER_RUN, VERIFY_BACKLOG_MAX_PER_RUN, getVerifyBacklogState, startVerifyBacklogRun, } from '../learning/model-verify-job.js';
56
58
  import { setToolsetEnabled } from '../tools/toolsets.js';
59
+ import { ArtifactStore } from '../tools/artifact-store.js';
57
60
  import { setSkillEnabled } from '../learning/hub-skill-catalog.js';
58
61
  // I11 — dashboard channel send-test: the same registry/adapters `nuvira gateway
59
62
  // send` uses, so a Channels-tab test message behaves identically to the CLI.
@@ -67,6 +70,7 @@ import { ChannelDirectory, PLATFORM_ENV_VARS, platformConfigVars } from '../gate
67
70
  import { applyEnvToProcess, configurablePlatforms, envVarState, platformConfigStatus, platformEnvVarMeta, redactValue, writeEnvFile, } from '../gateway/platform-config.js';
68
71
  import { SERVICE_CATALOG, getServiceDefinition, } from '../config/service-catalog.js';
69
72
  import { probeService } from '../config/service-probe.js';
73
+ import { pruneScratchWorkspaces } from '../config/scratch-workspace.js';
70
74
  // ─── Constants ──────────────────────────────────────────────────────────────
71
75
  const PORT = parseInt(envBuff('DASHBOARD_PORT') || '3030', 10);
72
76
  const HOST = envBuff('DASHBOARD_HOST') || '127.0.0.1';
@@ -118,6 +122,40 @@ let alwaysWatchQuota = false;
118
122
  * loadApiKeysFromConfig uses). Best-effort — a missing/corrupt config just
119
123
  * keeps the default (false = arm-on-connect only).
120
124
  */
125
+ /**
126
+ * The content type for an artifact file: the recorded mime when there is one,
127
+ * otherwise the extension. Video and image types are the ones the panel renders
128
+ * inline, so a wrong type is a blank frame rather than a failed download.
129
+ */
130
+ function artifactFileMime(file, recorded) {
131
+ if (recorded && /^[a-z]+\/[a-z0-9.+-]+$/i.test(recorded))
132
+ return recorded;
133
+ const ext = (file.split('.').pop() ?? '').toLowerCase();
134
+ const byExt = {
135
+ mp4: 'video/mp4',
136
+ webm: 'video/webm',
137
+ mov: 'video/quicktime',
138
+ mkv: 'video/x-matroska',
139
+ gif: 'image/gif',
140
+ png: 'image/png',
141
+ jpg: 'image/jpeg',
142
+ jpeg: 'image/jpeg',
143
+ webp: 'image/webp',
144
+ svg: 'image/svg+xml',
145
+ mp3: 'audio/mpeg',
146
+ wav: 'audio/wav',
147
+ m4a: 'audio/mp4',
148
+ srt: 'application/x-subrip',
149
+ vtt: 'text/vtt',
150
+ json: 'application/json',
151
+ md: 'text/markdown',
152
+ txt: 'text/plain',
153
+ log: 'text/plain',
154
+ csv: 'text/csv',
155
+ pdf: 'application/pdf',
156
+ };
157
+ return byExt[ext] ?? 'application/octet-stream';
158
+ }
121
159
  function loadAlwaysWatchQuotaFlag() {
122
160
  try {
123
161
  const configPath = resolveBuffConfigPath();
@@ -1513,9 +1551,52 @@ function readCostData() {
1513
1551
  if (!data?.entries) {
1514
1552
  // The empty state deliberately omits `recent` entirely (the dashboard reads
1515
1553
  // a missing list as "nothing recorded"), matching the other zero counters.
1516
- return { totalRequests: 0, totalCost: 0, byProvider: {}, byModel: {} };
1554
+ return {
1555
+ totalRequests: 0,
1556
+ totalCost: 0,
1557
+ byProvider: {},
1558
+ byModel: {},
1559
+ billedUsd: 0,
1560
+ billedReportedUsd: 0,
1561
+ billedListedUsd: 0,
1562
+ unverifiedListedUsd: 0,
1563
+ notBilledValueUsd: 0,
1564
+ unpricedCalls: 0,
1565
+ unpricedTokens: 0,
1566
+ recomputedCalls: 0,
1567
+ testOriginCalls: 0,
1568
+ // No invoice has been checked yet — stated, not implied.
1569
+ reconciliations: [],
1570
+ };
1517
1571
  }
1518
1572
  const entries = data.entries;
1573
+ // ── The classified view (ONE judgement for every surface) ────────────────
1574
+ // The Cost page's headline used to be `totalCost` — the sum of a column the
1575
+ // ledger had priced from its own hardcoded table — printed under the words
1576
+ // "Total Spent". It is now split by EVIDENCE: what was billed (provider-reported
1577
+ // exact + list-priced with a declared paid account), the value a free tier
1578
+ // absorbed, the list-priced rows whose tier is undeclared, and the calls with no
1579
+ // price at all. Test-origin rows are excluded here: a row written by a test run
1580
+ // is not the user's usage (the model registry takes the same posture).
1581
+ const classified = classifyEntries(entries, {
1582
+ excludeTestOrigin: true,
1583
+ });
1584
+ const byProviderBilled = {};
1585
+ const byProviderUnverified = {};
1586
+ const byProviderValue = {};
1587
+ const byProviderUnpricedCalls = {};
1588
+ const byModelBilled = {};
1589
+ const byModelValue = {};
1590
+ for (const [provider, t] of Object.entries(classified.byProvider)) {
1591
+ byProviderBilled[provider] = t.billedUsd;
1592
+ byProviderUnverified[provider] = t.unverifiedListedUsd;
1593
+ byProviderValue[provider] = t.notBilledValueUsd;
1594
+ byProviderUnpricedCalls[provider] = t.unpricedCalls;
1595
+ }
1596
+ for (const [model, t] of Object.entries(classified.byModel)) {
1597
+ byModelBilled[model] = t.billedUsd;
1598
+ byModelValue[model] = t.notBilledValueUsd;
1599
+ }
1519
1600
  const totalCost = entries.reduce((s, e) => s + (typeof e.costUsd === 'number' ? e.costUsd : 0), 0);
1520
1601
  const totalTokens = entries.reduce((s, e) => s + (typeof e.totalTokens === 'number' ? e.totalTokens : 0), 0);
1521
1602
  const byProvider = {};
@@ -1567,9 +1648,53 @@ function readCostData() {
1567
1648
  measured: e.measured === true,
1568
1649
  reported: e.costReported === true,
1569
1650
  }));
1651
+ // ── Invoice checks: the only EXTERNAL figures on this page ───────────────
1652
+ // Written by `nuvira stats cost reconcile` when the operator enters the
1653
+ // provider's own charge for a window. Everything else here is an estimate of
1654
+ // money owed; this is the one place the page can be compared against what was
1655
+ // ACTUALLY charged. Read straight from the file (no module import) so the
1656
+ // dashboard keeps resolving its own memory dir, and capped like `recent`.
1657
+ const reconciliationFile = readJSON(join(MEMORY_DIR, 'cost-reconciliations.json'));
1658
+ const reconciliations = (Array.isArray(reconciliationFile?.reconciliations) ? reconciliationFile.reconciliations : [])
1659
+ .filter((r) => r && typeof r.provider === 'string' && typeof r.invoiceUsd === 'number')
1660
+ .slice(0, 20)
1661
+ .map((r) => ({
1662
+ provider: r.provider,
1663
+ invoiceUsd: r.invoiceUsd,
1664
+ billedUsd: r.billedUsd,
1665
+ deltaUsd: r.deltaUsd,
1666
+ verdict: r.verdict,
1667
+ since: r.since,
1668
+ until: r.until,
1669
+ recordedAt: r.recordedAt,
1670
+ ...(r.note ? { note: r.note } : {}),
1671
+ ...(r.tierEvidence ? { tier: r.tierEvidence.tier } : {}),
1672
+ }));
1570
1673
  return {
1571
1674
  totalRequests: entries.length,
1572
1675
  totalCost: Math.round(totalCost * 100000) / 100000,
1676
+ // The evidence-backed figures. `totalCost` above is kept for compatibility
1677
+ // (it is the ledger total as recorded, including rows priced by the retired
1678
+ // hardcoded table); these are what the page headlines.
1679
+ billedUsd: classified.billedUsd,
1680
+ billedReportedUsd: classified.billedReportedUsd,
1681
+ billedListedUsd: classified.billedListedUsd,
1682
+ billedReportedCalls: classified.billedReportedCalls,
1683
+ billedListedCalls: classified.billedListedCalls,
1684
+ unverifiedListedUsd: classified.unverifiedListedUsd,
1685
+ unverifiedListedCalls: classified.unverifiedListedCalls,
1686
+ notBilledValueUsd: classified.notBilledValueUsd,
1687
+ notBilledValueCalls: classified.notBilledValueCalls,
1688
+ unpricedCalls: classified.unpricedCalls,
1689
+ unpricedTokens: classified.unpricedTokens,
1690
+ recomputedCalls: classified.recomputedCalls,
1691
+ testOriginCalls: classified.testOriginCalls,
1692
+ byProviderBilled,
1693
+ byProviderUnverified,
1694
+ byProviderValue,
1695
+ byProviderUnpricedCalls,
1696
+ byModelBilled,
1697
+ byModelValue,
1573
1698
  totalTokens,
1574
1699
  byProvider,
1575
1700
  byModel,
@@ -1581,6 +1706,7 @@ function readCostData() {
1581
1706
  estimatedCost: Math.round(estimatedCost * 100000) / 100000,
1582
1707
  reportedCalls,
1583
1708
  reportedCost: Math.round(reportedCost * 100000) / 100000,
1709
+ reconciliations,
1584
1710
  recent,
1585
1711
  };
1586
1712
  }
@@ -2718,14 +2844,42 @@ function buildServiceRow(def, canReadValues) {
2718
2844
  envVars,
2719
2845
  };
2720
2846
  }
2847
+ /**
2848
+ * One runtime tool as the panel's payload. Exported for the server test, which
2849
+ * asserts the panel is fed the same list `nuvira doctor` prints.
2850
+ */
2851
+ export function runtimeToolSummary(status) {
2852
+ return {
2853
+ id: status.dependency.id,
2854
+ label: status.dependency.label,
2855
+ need: status.dependency.need,
2856
+ present: status.present,
2857
+ enables: status.dependency.enables,
2858
+ neededBy: status.dependency.neededBy,
2859
+ // A tool the machine ALREADY has gets no command on the wire, the same way
2860
+ // `nuvira doctor` prints a fix only for what is missing: sending one anyway
2861
+ // invites a user to reinstall something that is working.
2862
+ installCommand: status.present ? null : status.installCommand,
2863
+ note: status.dependency.note,
2864
+ needsHumanInput: status.needsHumanInput,
2865
+ };
2866
+ }
2721
2867
  /** Run ALL state checks — the dashboard command-runner payload. */
2722
2868
  async function runAdminChecks() {
2723
2869
  const configManager = new ConfigManager();
2724
2870
  const { system, enterprise } = await runAllChecks(configManager);
2871
+ // The SAME declaration the CLI's `nuvira doctor`, the `--fix` installer and the
2872
+ // setup scripts read, probed once for this payload. The rows are also in
2873
+ // `system` (one check each) because a pass/warn verdict is what a check list
2874
+ // is for; this is the actionable half — the command to copy, the
2875
+ // recommended/optional split, and the caveat.
2876
+ const statuses = probeRuntimeDependencies();
2725
2877
  return {
2726
2878
  system,
2727
2879
  enterprise,
2728
2880
  providers: buildAdminProviderSummary(configManager),
2881
+ runtimeTools: statuses.map(runtimeToolSummary),
2882
+ runtimeToolsSummary: dependencySummary(statuses),
2729
2883
  serverTime: Date.now(),
2730
2884
  };
2731
2885
  }
@@ -3223,6 +3377,52 @@ function handleRequest(req, res) {
3223
3377
  })();
3224
3378
  return;
3225
3379
  }
3380
+ // ── An artifact's BYTES — how the Artifacts tab shows a rendered video rather
3381
+ // than a filename. The path is looked up in OUR OWN artifact store by (session,
3382
+ // artifact id) and is never taken from the query string, so a caller cannot ask
3383
+ // this endpoint for an arbitrary file; a bad pair is a 404, not a read.
3384
+ if (pathname === '/api/artifact-file') {
3385
+ const sessionId = url.searchParams.get('session') ?? '';
3386
+ const artifactId = url.searchParams.get('artifact') ?? '';
3387
+ const artifact = artifactId
3388
+ ? new ArtifactStore().read(sessionId).find((a) => a.id === artifactId)
3389
+ : undefined;
3390
+ if (!artifact || !artifact.path || !existsSync(artifact.path) || !statSync(artifact.path).isFile()) {
3391
+ writeJson(res, 404, { ok: false, error: 'No such artifact file.' });
3392
+ return;
3393
+ }
3394
+ const size = statSync(artifact.path).size;
3395
+ const type = artifactFileMime(artifact.path, artifact.mime);
3396
+ // Range support, because a <video> that cannot seek cannot be reviewed: a
3397
+ // player asks for byte ranges the moment the user drags the scrubber.
3398
+ const range = /^bytes=(\d*)-(\d*)$/.exec(req.headers.range ?? '');
3399
+ if (range) {
3400
+ const start = range[1] ? Number(range[1]) : 0;
3401
+ const end = range[2] ? Math.min(Number(range[2]), size - 1) : size - 1;
3402
+ if (start >= size || end < start) {
3403
+ res.writeHead(416, { 'Content-Range': `bytes */${size}` });
3404
+ res.end();
3405
+ return;
3406
+ }
3407
+ res.writeHead(206, {
3408
+ 'Content-Type': type,
3409
+ 'Content-Length': String(end - start + 1),
3410
+ 'Content-Range': `bytes ${start}-${end}/${size}`,
3411
+ 'Accept-Ranges': 'bytes',
3412
+ 'Cache-Control': 'no-store',
3413
+ });
3414
+ createReadStream(artifact.path, { start, end }).pipe(res);
3415
+ return;
3416
+ }
3417
+ res.writeHead(200, {
3418
+ 'Content-Type': type,
3419
+ 'Content-Length': String(size),
3420
+ 'Accept-Ranges': 'bytes',
3421
+ 'Cache-Control': 'no-store',
3422
+ });
3423
+ createReadStream(artifact.path).pipe(res);
3424
+ return;
3425
+ }
3226
3426
  if (pathname === '/api/benchmarks') {
3227
3427
  res.writeHead(200, { 'Content-Type': 'application/json' });
3228
3428
  res.end(JSON.stringify(readBenchmarkData()));
@@ -3302,7 +3502,17 @@ function handleRequest(req, res) {
3302
3502
  res.end(JSON.stringify(payload));
3303
3503
  }).catch((err) => {
3304
3504
  res.writeHead(500, { 'Content-Type': 'application/json' });
3305
- res.end(JSON.stringify({ error: String(err), system: [], enterprise: [], providers: [], serverTime: Date.now() }));
3505
+ res.end(JSON.stringify({
3506
+ error: String(err),
3507
+ system: [],
3508
+ enterprise: [],
3509
+ providers: [],
3510
+ // An empty list, not a missing one: the panel must be able to say
3511
+ // "nothing reported" on a failed run rather than crash on undefined.
3512
+ runtimeTools: [],
3513
+ runtimeToolsSummary: 'unavailable — the checks run failed',
3514
+ serverTime: Date.now(),
3515
+ }));
3306
3516
  });
3307
3517
  return;
3308
3518
  }
@@ -7216,7 +7426,27 @@ function handleRequest(req, res) {
7216
7426
  // `busy` lets a client that reloaded mid-turn know the answer is still being
7217
7427
  // produced, so it can keep the bubble alive and poll instead of showing a
7218
7428
  // finished-looking thread.
7219
- writeJson(res, 200, { ok: true, session: { id, ...rec, busy: chatConsole.isBusy(id) } });
7429
+ // `pendingQuestion` rides with the transcript because a reload has to be
7430
+ // able to SEE an open question, not just guess at it from `busy`. The turn
7431
+ // holding for an answer reports `busy: true` exactly like one that is
7432
+ // working, so without this the resumed page showed "⏳ Still working on the
7433
+ // server" for a turn that was waiting on the user (measured 2026-10-14:
7434
+ // trace-1791996357488-wpm352 sat in `ask_user` for 5m02s and was cancelled
7435
+ // with the question never on screen).
7436
+ // `busySince` is when the RUNNING turn started, so a client that gave up on
7437
+ // its own POST (a 5-minute ceiling) or reloaded mid-turn reports how long
7438
+ // the wait really is rather than counting from whenever it attached
7439
+ // (measured 2026-10-14: a 664s turn shown as "1m 25s elapsed").
7440
+ writeJson(res, 200, {
7441
+ ok: true,
7442
+ session: {
7443
+ id,
7444
+ ...rec,
7445
+ busy: chatConsole.isBusy(id),
7446
+ ...(chatConsole.busySince(id) !== null ? { busySince: chatConsole.busySince(id) } : {}),
7447
+ ...(chatConsole.pendingQuestionFor(id) ? { pendingQuestion: chatConsole.pendingQuestionFor(id) } : {}),
7448
+ },
7449
+ });
7220
7450
  return;
7221
7451
  }
7222
7452
  // GET /api/continuity — the stored session snapshots + the semantic recall
@@ -7489,13 +7719,51 @@ function handleRequest(req, res) {
7489
7719
  */
7490
7720
  const configuredCwd = resolveDashboardCwd();
7491
7721
  const { resolveTurnWorkspace, formatWorkspaceNoticeText } = await import('./workspace-resolution.js');
7722
+ const { workspaceNeedForMissingFolder } = await import('./workspace-guard.js');
7492
7723
  const sessionProjectPath = chatConsole.get(sessionId)?.projectPath;
7493
- const workspace = resolveTurnWorkspace({
7724
+ /**
7725
+ * The same ladder, asked twice when the last rung is needed.
7726
+ *
7727
+ * WHY TWO PASSES. The scratch folder is a real directory on disk, so it is
7728
+ * only created when the ladder has actually RUN OUT (nothing attached,
7729
+ * nothing named in the message, no configured default) AND the ask needs
7730
+ * somewhere to PUT new work. Creating it eagerly would leave an empty
7731
+ * temporary folder behind on every turn that already had a folder, and
7732
+ * handing it to a READ ask would be the kuttaaddon defect again — an empty
7733
+ * folder cannot answer "assess this project".
7734
+ */
7735
+ const resolveWorkspaceNow = (scratchPath) => resolveTurnWorkspace({
7494
7736
  ...(attachedPath ? { attachedPath } : {}),
7495
7737
  ...(sessionProjectPath ? { sessionPath: sessionProjectPath } : {}),
7496
7738
  ...(configuredCwd ? { configuredCwd } : {}),
7497
7739
  message,
7740
+ ...(scratchPath ? { scratchPath } : {}),
7498
7741
  });
7742
+ let workspace = resolveWorkspaceNow();
7743
+ /**
7744
+ * What this ask needs a folder FOR — `'produce'` is the case a temporary
7745
+ * folder can serve, `'read'` is the case it cannot (and keeps the folder
7746
+ * prompt), `null` is plain chat, which needs none.
7747
+ */
7748
+ const missingWorkspaceNeed = workspace.path ? null : workspaceNeedForMissingFolder(message);
7749
+ if (missingWorkspaceNeed === 'produce') {
7750
+ // The scratch folder is offered through the SAME rule the gateway uses
7751
+ // (`scratchWorkspaceForTurn`), so the two surfaces cannot disagree about
7752
+ // when a temporary folder is the right answer — in particular about an
7753
+ // ISOLATED turn, which a scratch folder can never serve: it has no base
7754
+ // commit to diff against. There, this turn has no folder at all, so it
7755
+ // falls through to the folder request below rather than isolating a
7756
+ // directory the user never chose.
7757
+ const { scratchWorkspaceForTurn } = await import('../config/scratch-workspace.js');
7758
+ const { resolveIsolationRequest } = await import('../tools/worktree.js');
7759
+ const scratch = scratchWorkspaceForTurn({
7760
+ key: sessionId,
7761
+ need: missingWorkspaceNeed,
7762
+ isolationAsked: resolveIsolationRequest({ worktree }).asked,
7763
+ });
7764
+ if (scratch)
7765
+ workspace = resolveWorkspaceNow(scratch);
7766
+ }
7499
7767
  if (workspace.path) {
7500
7768
  projectPath = workspace.path;
7501
7769
  const bundle = getProjectBundle(workspace.path);
@@ -7513,24 +7781,23 @@ function handleRequest(req, res) {
7513
7781
  * needs no caption.
7514
7782
  */
7515
7783
  const workspaceNotice = formatWorkspaceNoticeText(workspace);
7516
- // No workspace and no configured default: an ask that names a project, or
7517
- // that produces/consumes files, gets a folder request instead of an answer
7518
- // about the wrong tree. General chat is unaffected.
7519
- if (!workspace.path) {
7520
- const { needsProjectAttachment, projectAttachmentPrompt, projectAttachmentFollowups } = await import('./workspace-guard.js');
7521
- if (needsProjectAttachment(message)) {
7522
- writeJson(res, 200, {
7523
- ok: true,
7524
- sessionId,
7525
- content: projectAttachmentPrompt(),
7526
- followups: projectAttachmentFollowups(),
7527
- provider: null,
7528
- model: null,
7529
- generationFailed: false,
7530
- needsProject: true,
7531
- });
7532
- return;
7533
- }
7784
+ // Still no workspace: either the ask must READ or CHANGE work that already
7785
+ // exists (a temporary folder holds none of it), or the scratch folder could
7786
+ // not be created. Both are the case for a folder request rather than an
7787
+ // answer about the wrong tree. General chat — `null` — is unaffected.
7788
+ if (!workspace.path && missingWorkspaceNeed !== null) {
7789
+ const { projectAttachmentPrompt, projectAttachmentFollowups } = await import('./workspace-guard.js');
7790
+ writeJson(res, 200, {
7791
+ ok: true,
7792
+ sessionId,
7793
+ content: projectAttachmentPrompt(),
7794
+ followups: projectAttachmentFollowups(),
7795
+ provider: null,
7796
+ model: null,
7797
+ generationFailed: false,
7798
+ needsProject: true,
7799
+ });
7800
+ return;
7534
7801
  }
7535
7802
  // P4 (revised) — a client DISCONNECT no longer cancels the turn. It used
7536
7803
  // to: the server treated `res` close as an abort, which meant a page
@@ -7568,6 +7835,14 @@ function handleRequest(req, res) {
7568
7835
  const result = await withStrictModel(strict, () => chatConsole.answer(sessionId, message, {
7569
7836
  provider,
7570
7837
  model,
7838
+ // P8b — the STRICT half of the pin rides into the console so the
7839
+ // CONVERSATION can remember it. `withStrictModel` above scopes it to
7840
+ // this turn, but a conversation whose lock is forgotten between turns
7841
+ // is a pin the user cannot actually rely on: measured live
7842
+ // (trace-1792068695325-42wb1j) the pin survived a reload and the lock
7843
+ // did not, so the engine handed the turn to another model with the
7844
+ // user's "this model only" instruction never in force.
7845
+ strict,
7571
7846
  projectContext,
7572
7847
  projectPath,
7573
7848
  // Cluster G — carry the "no folder attached" state into the turn so a
@@ -7636,7 +7911,12 @@ function handleRequest(req, res) {
7636
7911
  routingNotice = `Auto routing took over: this turn ran on ${served} because your pinned ${requested} was not available. To work with ${requested} only, enable strict model mode.`;
7637
7912
  }
7638
7913
  else if (result.generationFailed === true) {
7639
- routingNotice = `Your pinned ${requested} could not complete this turn, so auto routing may hand the work to another model. To stay on this model only, enable strict model mode.`;
7914
+ // The turn ran on the pair the user pinned and stopped there. Saying
7915
+ // "auto routing may hand the work to another model" described the old
7916
+ // behaviour (a pinned turn followed the health ranking the moment its
7917
+ // pair returned an error) and would now be a lie: a pin waits on itself
7918
+ // and then asks. See `pinnedEscalation`.
7919
+ routingNotice = `Your pinned ${requested} did not answer, and nothing was sent to another model — the turn stopped instead of substituting. Retry it, or switch models.`;
7640
7920
  }
7641
7921
  }
7642
7922
  // Did the offer we are about to send get a mechanism behind it? The client
@@ -7949,6 +8229,17 @@ function handleRequest(req, res) {
7949
8229
  'X-Accel-Buffering': 'no',
7950
8230
  });
7951
8231
  res.write(`event: init\ndata: ${JSON.stringify({ sessionId })}\n\n`);
8232
+ // A question asked BEFORE this client attached is still waiting for an
8233
+ // answer, and the turn will hold until one arrives. Replaying it here is
8234
+ // what makes a reload (or a second tab) able to ANSWER it: without this the
8235
+ // new page shows a "still working" notice and no choice card at all, while
8236
+ // the turn waits on a reply the page has no way to send — the exact
8237
+ // "the model asked something but nothing appeared on screen" report
8238
+ // (2026-10-14, trace-1791996357488-wpm352, 5m02s in `ask_user`).
8239
+ const pendingQuestion = chatConsole.pendingQuestionFor(sessionId);
8240
+ if (pendingQuestion) {
8241
+ res.write(`event: question\ndata: ${JSON.stringify(pendingQuestion)}\n\n`);
8242
+ }
7952
8243
  const heartbeat = setInterval(() => {
7953
8244
  try {
7954
8245
  res.write(': heartbeat\n\n');
@@ -8228,6 +8519,18 @@ export function createDashboardServer(opts) {
8228
8519
  handle.ipv6Twin = undefined;
8229
8520
  }
8230
8521
  }
8522
+ // Scratch workspaces are temporary BY DEFINITION, so the ones nobody came back
8523
+ // to are cleaned on boot rather than accumulating in the user's home for the
8524
+ // life of the install (see `pruneScratchWorkspaces`). Best-effort: a failed
8525
+ // prune must never stop the server from coming up.
8526
+ try {
8527
+ const removed = pruneScratchWorkspaces();
8528
+ if (removed > 0)
8529
+ console.log(` 🧹 Removed ${removed} expired scratch workspace(s)`);
8530
+ }
8531
+ catch {
8532
+ /* best-effort */
8533
+ }
8231
8534
  server.listen(bindPort, bindHost, () => {
8232
8535
  console.log(`\n 🌐 Agent-Nuvira Dashboard`);
8233
8536
  console.log(` ─────────────────────────`);