@tonyclaw/agent-inspector 3.0.45 → 3.0.46

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 (338) hide show
  1. package/.output/{nitro.json → backend/nitro.json} +3 -3
  2. package/.output/backend-public/assets/index-D4LX-sw-.js +11 -0
  3. package/.output/cli.js +2326 -516
  4. package/.output/server/_libs/extend.mjs +4 -8
  5. package/.output/server/_libs/jszip.mjs +9 -35
  6. package/.output/server/_libs/react-dom.mjs +2 -3
  7. package/.output/server/_libs/react.mjs +1 -27
  8. package/.output/server/_libs/tanstack__react-router.mjs +1 -329
  9. package/.output/server/_libs/tanstack__router-core.mjs +42 -100
  10. package/.output/server/_libs/use-sync-external-store.mjs +1 -64
  11. package/.output/server/_libs/ws.mjs +1 -1
  12. package/.output/server/_ssr/index.mjs +4 -4
  13. package/.output/server/_ssr/{publicBasePathContext-5264L3rX.mjs → publicBasePathContext-IH2ilOfu.mjs} +52 -24
  14. package/.output/server/_ssr/{router-BJ_ltLim.mjs → router-D18yUq36.mjs} +19770 -19447
  15. package/.output/server/_ssr/{start-C6MjPjxp.mjs → start-COQu_AgD.mjs} +1 -1
  16. package/.output/server/_tanstack-start-manifest_v-DnbdNeun.mjs +4 -0
  17. package/.output/server/index.mjs +5 -145
  18. package/.output/{public/assets/CompareDrawer-B3_TLTJh.js → ui/assets/CompareDrawer-DAUuIJ6G.js} +1 -1
  19. package/.output/{public/assets/InspectorPet-Cpn6hv4P.js → ui/assets/InspectorPet-BRBVjOWI.js} +1 -1
  20. package/.output/ui/assets/ProxyViewerContainer-D7Sq0ctc.js +59 -0
  21. package/.output/{public/assets/ReplayDialog-B3EKVdJk.js → ui/assets/ReplayDialog-nDLsjOhs.js} +1 -1
  22. package/.output/{public/assets/RequestAnatomy-COOQjyUC.js → ui/assets/RequestAnatomy-zd4BDgL0.js} +1 -1
  23. package/.output/ui/assets/ResponseView-AdIXGcSn.js +2 -0
  24. package/.output/ui/assets/StreamingChunkSequence-CesTz8He.js +1 -0
  25. package/.output/{public/assets/_sessionId-zbgYl7ZJ.js → ui/assets/_sessionId-BAfzrhSU.js} +1 -1
  26. package/.output/{public/assets/_sessionId-BJlM3nmt.js → ui/assets/_sessionId-QnBomgPD.js} +1 -1
  27. package/.output/ui/assets/favicon-DYEkHSNl.svg +21 -0
  28. package/.output/{public/assets/index-BIK4bPTv.js → ui/assets/index-BcsdxBAd.js} +1 -1
  29. package/.output/ui/assets/index-BvXp42al.css +1 -0
  30. package/.output/{public/assets/index-D2Qw6Ri2.js → ui/assets/index-D0rtCN9V.js} +1 -1
  31. package/.output/ui/assets/index-DHpwr08Z.js +73 -0
  32. package/.output/{public/assets/index-xF_NY8Yb.js → ui/assets/index-dNuk2dsU.js} +5 -5
  33. package/.output/ui/assets/json-viewer-BvFHglMb.js +1 -0
  34. package/.output/{public/assets/jszip.min-B_rfAUCe.js → ui/assets/jszip.min-B5Z7gNZB.js} +1 -1
  35. package/.output/ui/index.html +229 -0
  36. package/.output/ui/runtime-config.js +2 -0
  37. package/.output/workers/logFinalizer.worker.js +979 -414
  38. package/.output/workers/sessionWorkerEntry.js +979 -414
  39. package/README.md +175 -43
  40. package/docs/instance-control.openapi.yaml +59 -4
  41. package/package.json +25 -5
  42. package/scripts/generate-theme-scales.mjs +3 -3
  43. package/src/{router.tsx → backend/router.tsx} +3 -15
  44. package/src/backend/routes/$.ts +26 -0
  45. package/src/backend/routes/__root.ts +4 -0
  46. package/src/{routes → backend/routes}/api/-instances.ts +3 -3
  47. package/src/{routes → backend/routes}/api/alerts.summary.ts +3 -3
  48. package/src/{routes → backend/routes}/api/alerts.ts +4 -4
  49. package/src/{routes → backend/routes}/api/config.paths.ts +1 -1
  50. package/src/{routes → backend/routes}/api/config.ts +11 -2
  51. package/src/{routes → backend/routes}/api/ecosystem.packages.$packageId.help.ts +1 -1
  52. package/src/{routes → backend/routes}/api/ecosystem.packages.$packageId.install.ts +1 -1
  53. package/src/{routes → backend/routes}/api/ecosystem.packages.$packageId.runner-presets.ts +1 -1
  54. package/src/{routes → backend/routes}/api/ecosystem.packages.$packageId.upgrade.ts +1 -1
  55. package/src/{routes → backend/routes}/api/ecosystem.packages.ts +5 -1
  56. package/src/{routes → backend/routes}/api/ecosystem.recipes.$recipeId.run.ts +1 -1
  57. package/src/{routes → backend/routes}/api/ecosystem.tasks.$taskId.ts +1 -1
  58. package/src/{routes → backend/routes}/api/ecosystem.tasks.ts +1 -1
  59. package/src/{routes → backend/routes}/api/groups.$groupId.evidence.ts +2 -2
  60. package/src/{routes → backend/routes}/api/groups.$groupId.sessions.ts +2 -2
  61. package/src/{routes → backend/routes}/api/groups.$groupId.ts +2 -2
  62. package/src/{routes → backend/routes}/api/groups.ts +2 -2
  63. package/src/{routes → backend/routes}/api/health.ts +3 -3
  64. package/src/{routes → backend/routes}/api/instances.$name.connection.ts +1 -1
  65. package/src/{routes → backend/routes}/api/instances.$name.restart.ts +2 -2
  66. package/src/{routes → backend/routes}/api/instances.$name.start.ts +2 -2
  67. package/src/{routes → backend/routes}/api/instances.$name.stop.ts +2 -2
  68. package/src/{routes → backend/routes}/api/instances.$name.ts +1 -1
  69. package/src/{routes → backend/routes}/api/instances.ts +1 -1
  70. package/src/{routes → backend/routes}/api/knowledge.candidates.$candidateId.promote.ts +2 -2
  71. package/src/{routes → backend/routes}/api/knowledge.candidates.$candidateId.ts +2 -2
  72. package/src/{routes → backend/routes}/api/knowledge.candidates.ts +1 -1
  73. package/src/{routes → backend/routes}/api/knowledge.project-context.ts +2 -2
  74. package/src/{routes → backend/routes}/api/knowledge.search.ts +2 -2
  75. package/src/{routes → backend/routes}/api/knowledge.sessions.$sessionId.candidates.ts +3 -3
  76. package/src/{routes → backend/routes}/api/logs.$id.body.ts +6 -6
  77. package/src/{routes → backend/routes}/api/logs.$id.chunks.ts +5 -4
  78. package/src/{routes → backend/routes}/api/logs.$id.replay.ts +12 -11
  79. package/src/{routes → backend/routes}/api/logs.$id.ts +4 -3
  80. package/src/{routes → backend/routes}/api/logs.import.ts +3 -3
  81. package/src/{routes → backend/routes}/api/logs.stream.ts +11 -7
  82. package/src/{routes → backend/routes}/api/logs.ts +17 -9
  83. package/src/{routes → backend/routes}/api/mcp.ts +1 -1
  84. package/src/{routes → backend/routes}/api/models.ts +1 -1
  85. package/src/{routes → backend/routes}/api/pi-agent.ts +2 -2
  86. package/src/{routes → backend/routes}/api/providers.$providerId.model-metadata.ts +5 -5
  87. package/src/{routes → backend/routes}/api/providers.$providerId.test.log.ts +7 -7
  88. package/src/{routes → backend/routes}/api/providers.$providerId.ts +4 -4
  89. package/src/{routes → backend/routes}/api/providers.export.ts +1 -1
  90. package/src/{routes → backend/routes}/api/providers.import.ts +3 -3
  91. package/src/{routes → backend/routes}/api/providers.scan.ts +2 -2
  92. package/src/{routes → backend/routes}/api/providers.ts +9 -4
  93. package/src/{routes → backend/routes}/api/runs.$runId.evidence.ts +2 -2
  94. package/src/{routes → backend/routes}/api/runs.$runId.ts +2 -2
  95. package/src/{routes → backend/routes}/api/runs.ts +4 -4
  96. package/src/backend/routes/api/runtime.ts +46 -0
  97. package/src/{routes → backend/routes}/api/sessions.ts +3 -3
  98. package/src/{routes → backend/routes}/proxy/$.ts +1 -1
  99. package/src/{routes → backend/routes}/readyz.ts +1 -1
  100. package/src/{start.ts → backend/start.ts} +1 -1
  101. package/src/cli/alias.ts +2 -11
  102. package/src/cli/doctor.ts +32 -9
  103. package/src/cli/instance.ts +26 -13
  104. package/src/cli/instanceArgs.ts +30 -11
  105. package/src/cli/instanceControl.ts +0 -2
  106. package/src/cli/instanceModel.ts +9 -17
  107. package/src/cli/instanceRegistry.ts +0 -9
  108. package/src/cli/networkHints.ts +27 -14
  109. package/src/cli/onboard.ts +69 -2
  110. package/src/cli/onboardTarget.ts +89 -40
  111. package/src/cli/templates/codex-skill-onboard.ts +44 -14
  112. package/src/cli/templates/skill-onboard.ts +64 -28
  113. package/src/cli.ts +184 -61
  114. package/src/components/ProxyViewer.tsx +11 -9
  115. package/src/components/ProxyViewerContainer.tsx +12 -11
  116. package/src/components/pi-agent/PiAgentPanel.tsx +2 -2
  117. package/src/components/providers/ProviderCard.tsx +1 -1
  118. package/src/components/providers/ProviderTestResultsView.tsx +1 -1
  119. package/src/components/providers/SettingsDialog.tsx +159 -144
  120. package/src/components/proxy-viewer/ApplicationBar.tsx +2 -1
  121. package/src/components/proxy-viewer/LogEntry.tsx +1 -1
  122. package/src/components/proxy-viewer/log-formats/index.ts +1 -1
  123. package/src/contracts/index.ts +5 -0
  124. package/src/contracts/log.ts +33 -3
  125. package/src/knowledge/types.ts +3 -2
  126. package/src/lib/alertContract.ts +2 -2
  127. package/src/lib/apiClient.ts +30 -7
  128. package/src/lib/apiFormat.ts +29 -0
  129. package/src/lib/basePath.ts +29 -11
  130. package/src/lib/browserRuntimeContract.ts +124 -0
  131. package/src/lib/browserRuntimeResolver.ts +244 -0
  132. package/src/{proxy → lib}/claudeCodeStrip.ts +6 -7
  133. package/src/lib/codingAgentEndpoints.ts +38 -0
  134. package/src/lib/instanceContract.ts +27 -11
  135. package/src/lib/piAgentContract.ts +3 -2
  136. package/src/lib/publicBasePathContext.ts +40 -10
  137. package/src/lib/resourceLimits.ts +2 -0
  138. package/src/lib/runContract.ts +3 -3
  139. package/src/lib/sessionInfoContract.ts +3 -2
  140. package/src/mcp/instanceHandlers.ts +1 -0
  141. package/src/mcp/server.ts +19 -24
  142. package/src/proxy/config.ts +25 -30
  143. package/src/proxy/dataDir.ts +43 -7
  144. package/src/proxy/ecosystemTasks.ts +161 -70
  145. package/src/proxy/formats/registry.ts +6 -21
  146. package/src/proxy/handler.ts +129 -29
  147. package/src/proxy/identityProxy.ts +419 -39
  148. package/src/proxy/jsonlRecovery.ts +554 -0
  149. package/src/proxy/logFinalizer.ts +25 -10
  150. package/src/proxy/logImporter.ts +2 -1
  151. package/src/proxy/logIndex.ts +191 -95
  152. package/src/proxy/logger.ts +77 -14
  153. package/src/proxy/platformCommands.ts +41 -0
  154. package/src/proxy/privateDataPath.ts +310 -88
  155. package/src/proxy/rawStreamCapture.ts +194 -13
  156. package/src/proxy/runtimeAdmission.ts +5 -2
  157. package/src/proxy/runtimeHealth.ts +14 -1
  158. package/src/proxy/runtimeShutdown.ts +11 -1
  159. package/src/proxy/schemas.ts +7 -1
  160. package/src/proxy/sessionArchive.ts +78 -14
  161. package/src/proxy/sqliteLogIndex.ts +65 -2
  162. package/src/proxy/store.ts +141 -34
  163. package/src/proxy/uiAssetServer.ts +106 -0
  164. package/src/proxy/upstream.ts +29 -2
  165. package/src/ui/bootstrap.ts +167 -0
  166. package/src/ui/index.html +38 -0
  167. package/src/ui/logsStreamClient.ts +20 -0
  168. package/src/ui/main.tsx +13 -0
  169. package/src/ui/public/runtime-config.js +2 -0
  170. package/src/ui/router.tsx +13 -0
  171. package/src/ui/routes/__root.tsx +69 -0
  172. package/src/{routes → ui/routes}/index.tsx +2 -3
  173. package/src/{routes → ui/routes}/session/$sessionId.tsx +5 -11
  174. package/src/ui/runtimeDiscovery.ts +50 -0
  175. package/styles/globals.css +1 -0
  176. package/.output/public/assets/ProxyViewerContainer-BEAhuGOJ.js +0 -126
  177. package/.output/public/assets/ResponseView-DBCjkwye.js +0 -2
  178. package/.output/public/assets/StreamingChunkSequence-CuXhDgMo.js +0 -1
  179. package/.output/public/assets/index-BZo_8koU.js +0 -70
  180. package/.output/public/assets/index-ZWschkCh.css +0 -1
  181. package/.output/public/assets/json-viewer-B-Ao6pwW.js +0 -1
  182. package/.output/server/_libs/@radix-ui/react-accessible-icon+[...].mjs +0 -1
  183. package/.output/server/_libs/@radix-ui/react-dismissable-layer+[...].mjs +0 -344
  184. package/.output/server/_libs/@radix-ui/react-navigation-menu+[...].mjs +0 -2
  185. package/.output/server/_libs/@radix-ui/react-one-time-password-field+[...].mjs +0 -2
  186. package/.output/server/_libs/@radix-ui/react-password-toggle-field+[...].mjs +0 -2
  187. package/.output/server/_libs/@radix-ui/react-use-callback-ref+[...].mjs +0 -11
  188. package/.output/server/_libs/@radix-ui/react-use-controllable-state+[...].mjs +0 -69
  189. package/.output/server/_libs/@radix-ui/react-use-effect-event+[...].mjs +0 -1
  190. package/.output/server/_libs/@radix-ui/react-use-is-hydrated+[...].mjs +0 -28
  191. package/.output/server/_libs/@radix-ui/react-use-layout-effect+[...].mjs +0 -6
  192. package/.output/server/_libs/@radix-ui/react-visually-hidden+[...].mjs +0 -34
  193. package/.output/server/_libs/aria-hidden.mjs +0 -122
  194. package/.output/server/_libs/bail.mjs +0 -8
  195. package/.output/server/_libs/character-entities.mjs +0 -2130
  196. package/.output/server/_libs/class-variance-authority.mjs +0 -44
  197. package/.output/server/_libs/clsx.mjs +0 -16
  198. package/.output/server/_libs/comma-separated-tokens.mjs +0 -10
  199. package/.output/server/_libs/decode-named-character-reference+[...].mjs +0 -8
  200. package/.output/server/_libs/dequal.mjs +0 -27
  201. package/.output/server/_libs/detect-node-es.mjs +0 -1
  202. package/.output/server/_libs/devlop.mjs +0 -8
  203. package/.output/server/_libs/diff.mjs +0 -320
  204. package/.output/server/_libs/estree-util-is-identifier-name.mjs +0 -11
  205. package/.output/server/_libs/floating-ui__core.mjs +0 -725
  206. package/.output/server/_libs/floating-ui__dom.mjs +0 -622
  207. package/.output/server/_libs/floating-ui__react-dom.mjs +0 -292
  208. package/.output/server/_libs/floating-ui__utils.mjs +0 -320
  209. package/.output/server/_libs/get-nonce.mjs +0 -9
  210. package/.output/server/_libs/hast-util-to-jsx-runtime.mjs +0 -388
  211. package/.output/server/_libs/hast-util-whitespace.mjs +0 -10
  212. package/.output/server/_libs/html-url-attributes.mjs +0 -26
  213. package/.output/server/_libs/inline-style-parser.mjs +0 -142
  214. package/.output/server/_libs/is-plain-obj.mjs +0 -10
  215. package/.output/server/_libs/lucide-react.mjs +0 -1027
  216. package/.output/server/_libs/mdast-util-from-markdown.mjs +0 -717
  217. package/.output/server/_libs/mdast-util-to-hast.mjs +0 -710
  218. package/.output/server/_libs/mdast-util-to-string.mjs +0 -38
  219. package/.output/server/_libs/micromark-core-commonmark.mjs +0 -2259
  220. package/.output/server/_libs/micromark-factory-destination.mjs +0 -94
  221. package/.output/server/_libs/micromark-factory-label.mjs +0 -63
  222. package/.output/server/_libs/micromark-factory-space.mjs +0 -24
  223. package/.output/server/_libs/micromark-factory-title.mjs +0 -65
  224. package/.output/server/_libs/micromark-factory-whitespace.mjs +0 -22
  225. package/.output/server/_libs/micromark-util-character.mjs +0 -44
  226. package/.output/server/_libs/micromark-util-chunked.mjs +0 -36
  227. package/.output/server/_libs/micromark-util-classify-character+[...].mjs +0 -12
  228. package/.output/server/_libs/micromark-util-combine-extensions+[...].mjs +0 -41
  229. package/.output/server/_libs/micromark-util-decode-numeric-character-reference+[...].mjs +0 -19
  230. package/.output/server/_libs/micromark-util-decode-string.mjs +0 -21
  231. package/.output/server/_libs/micromark-util-encode.mjs +0 -1
  232. package/.output/server/_libs/micromark-util-html-tag-name.mjs +0 -69
  233. package/.output/server/_libs/micromark-util-normalize-identifier+[...].mjs +0 -6
  234. package/.output/server/_libs/micromark-util-resolve-all.mjs +0 -15
  235. package/.output/server/_libs/micromark-util-sanitize-uri.mjs +0 -41
  236. package/.output/server/_libs/micromark-util-subtokenize.mjs +0 -346
  237. package/.output/server/_libs/micromark.mjs +0 -906
  238. package/.output/server/_libs/property-information.mjs +0 -1209
  239. package/.output/server/_libs/radix-ui.mjs +0 -1
  240. package/.output/server/_libs/radix-ui__number.mjs +0 -6
  241. package/.output/server/_libs/radix-ui__primitive.mjs +0 -11
  242. package/.output/server/_libs/radix-ui__react-accordion.mjs +0 -1
  243. package/.output/server/_libs/radix-ui__react-alert-dialog.mjs +0 -1
  244. package/.output/server/_libs/radix-ui__react-arrow.mjs +0 -23
  245. package/.output/server/_libs/radix-ui__react-aspect-ratio.mjs +0 -1
  246. package/.output/server/_libs/radix-ui__react-avatar.mjs +0 -1
  247. package/.output/server/_libs/radix-ui__react-checkbox.mjs +0 -1
  248. package/.output/server/_libs/radix-ui__react-collapsible.mjs +0 -144
  249. package/.output/server/_libs/radix-ui__react-collection.mjs +0 -69
  250. package/.output/server/_libs/radix-ui__react-compose-refs.mjs +0 -38
  251. package/.output/server/_libs/radix-ui__react-context-menu.mjs +0 -1
  252. package/.output/server/_libs/radix-ui__react-context.mjs +0 -64
  253. package/.output/server/_libs/radix-ui__react-dialog.mjs +0 -280
  254. package/.output/server/_libs/radix-ui__react-direction.mjs +0 -9
  255. package/.output/server/_libs/radix-ui__react-dropdown-menu.mjs +0 -1
  256. package/.output/server/_libs/radix-ui__react-focus-guards.mjs +0 -39
  257. package/.output/server/_libs/radix-ui__react-focus-scope.mjs +0 -210
  258. package/.output/server/_libs/radix-ui__react-form.mjs +0 -1
  259. package/.output/server/_libs/radix-ui__react-hover-card.mjs +0 -1
  260. package/.output/server/_libs/radix-ui__react-id.mjs +0 -14
  261. package/.output/server/_libs/radix-ui__react-label.mjs +0 -1
  262. package/.output/server/_libs/radix-ui__react-menu.mjs +0 -1
  263. package/.output/server/_libs/radix-ui__react-menubar.mjs +0 -1
  264. package/.output/server/_libs/radix-ui__react-popover.mjs +0 -1
  265. package/.output/server/_libs/radix-ui__react-popper.mjs +0 -340
  266. package/.output/server/_libs/radix-ui__react-portal.mjs +0 -16
  267. package/.output/server/_libs/radix-ui__react-presence.mjs +0 -173
  268. package/.output/server/_libs/radix-ui__react-primitive.mjs +0 -42
  269. package/.output/server/_libs/radix-ui__react-progress.mjs +0 -1
  270. package/.output/server/_libs/radix-ui__react-radio-group.mjs +0 -1
  271. package/.output/server/_libs/radix-ui__react-roving-focus.mjs +0 -235
  272. package/.output/server/_libs/radix-ui__react-scroll-area.mjs +0 -731
  273. package/.output/server/_libs/radix-ui__react-select.mjs +0 -1207
  274. package/.output/server/_libs/radix-ui__react-separator.mjs +0 -28
  275. package/.output/server/_libs/radix-ui__react-slider.mjs +0 -1
  276. package/.output/server/_libs/radix-ui__react-slot.mjs +0 -132
  277. package/.output/server/_libs/radix-ui__react-switch.mjs +0 -1
  278. package/.output/server/_libs/radix-ui__react-tabs.mjs +0 -194
  279. package/.output/server/_libs/radix-ui__react-toast.mjs +0 -2
  280. package/.output/server/_libs/radix-ui__react-toggle-group.mjs +0 -1
  281. package/.output/server/_libs/radix-ui__react-toggle.mjs +0 -1
  282. package/.output/server/_libs/radix-ui__react-toolbar.mjs +0 -1
  283. package/.output/server/_libs/radix-ui__react-tooltip.mjs +0 -498
  284. package/.output/server/_libs/radix-ui__react-use-previous.mjs +0 -14
  285. package/.output/server/_libs/radix-ui__react-use-size.mjs +0 -39
  286. package/.output/server/_libs/react-markdown.mjs +0 -235
  287. package/.output/server/_libs/react-remove-scroll-bar.mjs +0 -82
  288. package/.output/server/_libs/react-remove-scroll.mjs +0 -328
  289. package/.output/server/_libs/react-style-singleton.mjs +0 -69
  290. package/.output/server/_libs/remark-parse.mjs +0 -19
  291. package/.output/server/_libs/remark-rehype.mjs +0 -21
  292. package/.output/server/_libs/space-separated-tokens.mjs +0 -6
  293. package/.output/server/_libs/style-to-js.mjs +0 -72
  294. package/.output/server/_libs/style-to-object.mjs +0 -38
  295. package/.output/server/_libs/swr.mjs +0 -947
  296. package/.output/server/_libs/tailwind-merge.mjs +0 -3255
  297. package/.output/server/_libs/tanstack__react-virtual.mjs +0 -130
  298. package/.output/server/_libs/tanstack__virtual-core.mjs +0 -1319
  299. package/.output/server/_libs/three.mjs +0 -26016
  300. package/.output/server/_libs/trim-lines.mjs +0 -41
  301. package/.output/server/_libs/trough.mjs +0 -85
  302. package/.output/server/_libs/tslib.mjs +0 -1
  303. package/.output/server/_libs/ungap__structured-clone.mjs +0 -212
  304. package/.output/server/_libs/unified.mjs +0 -661
  305. package/.output/server/_libs/unist-util-is.mjs +0 -100
  306. package/.output/server/_libs/unist-util-position.mjs +0 -27
  307. package/.output/server/_libs/unist-util-stringify-position.mjs +0 -27
  308. package/.output/server/_libs/unist-util-visit-parents.mjs +0 -82
  309. package/.output/server/_libs/unist-util-visit.mjs +0 -24
  310. package/.output/server/_libs/use-callback-ref.mjs +0 -66
  311. package/.output/server/_libs/use-sidecar.mjs +0 -106
  312. package/.output/server/_libs/vfile-message.mjs +0 -138
  313. package/.output/server/_libs/vfile.mjs +0 -467
  314. package/.output/server/_sessionId-CJ99gZFV.mjs +0 -84
  315. package/.output/server/_sessionId-DEjScBpK.mjs +0 -146
  316. package/.output/server/_ssr/CompareDrawer-DtOIMeQB.mjs +0 -1060
  317. package/.output/server/_ssr/InspectorPet-CXc4oCBQ.mjs +0 -938
  318. package/.output/server/_ssr/ProxyViewerContainer-DVPlwfkt.mjs +0 -17632
  319. package/.output/server/_ssr/ReplayDialog-BQEA95qC.mjs +0 -725
  320. package/.output/server/_ssr/RequestAnatomy-BMyd8B7Q.mjs +0 -837
  321. package/.output/server/_ssr/ResponseView-qrTaEIM8.mjs +0 -757
  322. package/.output/server/_ssr/StreamingChunkSequence-BFTL8mIy.mjs +0 -274
  323. package/.output/server/_ssr/index-Bcj1Hcy4.mjs +0 -135
  324. package/.output/server/_ssr/index-DW-M7XUG.mjs +0 -84
  325. package/.output/server/_ssr/json-viewer-DiI0Yjsn.mjs +0 -483
  326. package/.output/server/_tanstack-start-manifest_v-C6pXXX9R.mjs +0 -4
  327. package/.output/server/node_modules/tslib/modules/index.js +0 -70
  328. package/.output/server/node_modules/tslib/modules/package.json +0 -3
  329. package/.output/server/node_modules/tslib/package.json +0 -47
  330. package/.output/server/node_modules/tslib/tslib.js +0 -484
  331. package/.output/server/package.json +0 -9
  332. package/src/routes/__root.tsx +0 -170
  333. /package/.output/{public → ui}/assets/agent-inspector-58K1_MsC.ico +0 -0
  334. /package/.output/{public → ui}/assets/alibaba-TTwafVwX.svg +0 -0
  335. /package/.output/{public → ui}/assets/minimax-BPMzvuL-.jpeg +0 -0
  336. /package/.output/{public → ui}/assets/qwen-mMn3f5ul.webp +0 -0
  337. /package/.output/{public → ui}/assets/zhipuai-BPNAnxo-.svg +0 -0
  338. /package/src/{routes → backend/routes}/livez.ts +0 -0
@@ -12,8 +12,28 @@ import {
12
12
 
13
13
  const DEFAULT_MEMORY_LIMIT_BYTES = 1024 * 1024;
14
14
  const FILE_WRITE_BATCH_BYTES = 64 * 1024;
15
+ const DEFAULT_QUEUE_MAX_MESSAGES = 256;
16
+ const DEFAULT_QUEUE_MAX_BYTES = 8 * 1024 * 1024;
17
+ const DEFAULT_GLOBAL_QUEUE_MAX_MESSAGES = 4096;
18
+ const DEFAULT_GLOBAL_QUEUE_MAX_BYTES = 64 * 1024 * 1024;
15
19
  const activeCaptures = new Set<RawStreamCapture>();
16
20
 
21
+ export type RawStreamCaptureGapReason = "capacity-exceeded" | "pipeline-closed" | "write-failed";
22
+
23
+ export type RawStreamCaptureStatus = {
24
+ incomplete: boolean;
25
+ droppedChunks: number;
26
+ droppedBytes: number;
27
+ reason: RawStreamCaptureGapReason | null;
28
+ };
29
+
30
+ export type RawStreamCaptureOptions = {
31
+ memoryLimitBytes?: number;
32
+ queueMaxMessages?: number;
33
+ queueMaxBytes?: number;
34
+ globalBudget?: RawStreamObservationBudget;
35
+ };
36
+
17
37
  export type RawStreamSource =
18
38
  | {
19
39
  type: "memory";
@@ -32,6 +52,62 @@ function resolveMemoryLimitBytes(): number {
32
52
  return parsed;
33
53
  }
34
54
 
55
+ function resolvePositiveIntegerEnv(name: string, fallback: number): number {
56
+ const raw = process.env[name];
57
+ if (raw === undefined || raw === "") return fallback;
58
+ const parsed = Number(raw);
59
+ if (!Number.isSafeInteger(parsed) || parsed < 1) return fallback;
60
+ return parsed;
61
+ }
62
+
63
+ function defaultQueueMaxMessages(): number {
64
+ return resolvePositiveIntegerEnv(
65
+ "AGENT_INSPECTOR_OBSERVATION_QUEUE_MESSAGES",
66
+ DEFAULT_QUEUE_MAX_MESSAGES,
67
+ );
68
+ }
69
+
70
+ function defaultQueueMaxBytes(): number {
71
+ return resolvePositiveIntegerEnv(
72
+ "AGENT_INSPECTOR_OBSERVATION_QUEUE_BYTES",
73
+ DEFAULT_QUEUE_MAX_BYTES,
74
+ );
75
+ }
76
+
77
+ export class RawStreamObservationBudget {
78
+ private messages = 0;
79
+ private bytes = 0;
80
+
81
+ constructor(
82
+ private readonly maxMessages: number,
83
+ private readonly maxBytes: number,
84
+ ) {}
85
+
86
+ tryAcquire(bytes: number): (() => void) | null {
87
+ if (this.messages + 1 > this.maxMessages || this.bytes + bytes > this.maxBytes) return null;
88
+ this.messages += 1;
89
+ this.bytes += bytes;
90
+ let released = false;
91
+ return () => {
92
+ if (released) return;
93
+ released = true;
94
+ this.messages -= 1;
95
+ this.bytes -= bytes;
96
+ };
97
+ }
98
+ }
99
+
100
+ const globalObservationBudget = new RawStreamObservationBudget(
101
+ resolvePositiveIntegerEnv(
102
+ "AGENT_INSPECTOR_OBSERVATION_GLOBAL_QUEUE_MESSAGES",
103
+ DEFAULT_GLOBAL_QUEUE_MAX_MESSAGES,
104
+ ),
105
+ resolvePositiveIntegerEnv(
106
+ "AGENT_INSPECTOR_OBSERVATION_GLOBAL_QUEUE_BYTES",
107
+ DEFAULT_GLOBAL_QUEUE_MAX_BYTES,
108
+ ),
109
+ );
110
+
35
111
  function getRawStreamDir(): string {
36
112
  return join(getDataDir(), "raw-streams");
37
113
  }
@@ -42,6 +118,9 @@ function createRawStreamPath(): string {
42
118
 
43
119
  export class RawStreamCapture {
44
120
  private readonly memoryLimitBytes: number;
121
+ private readonly queueMaxMessages: number;
122
+ private readonly queueMaxBytes: number;
123
+ private readonly globalBudget: RawStreamObservationBudget;
45
124
  private chunks: string[] = [];
46
125
  private byteLength = 0;
47
126
  private filePath: string | null = null;
@@ -49,11 +128,22 @@ export class RawStreamCapture {
49
128
  private pendingFileChunks: string[] = [];
50
129
  private pendingFileBytes = 0;
51
130
  private operation = Promise.resolve();
131
+ private accepting = true;
52
132
  private closed = false;
53
133
  private sawChunk = false;
134
+ private queuedMessages = 0;
135
+ private queuedBytes = 0;
136
+ private incomplete = false;
137
+ private storageFailed = false;
138
+ private droppedChunks = 0;
139
+ private droppedBytes = 0;
140
+ private gapReason: RawStreamCaptureGapReason | null = null;
54
141
 
55
- constructor(memoryLimitBytes: number = resolveMemoryLimitBytes()) {
56
- this.memoryLimitBytes = memoryLimitBytes;
142
+ constructor(options: RawStreamCaptureOptions = {}) {
143
+ this.memoryLimitBytes = options.memoryLimitBytes ?? resolveMemoryLimitBytes();
144
+ this.queueMaxMessages = options.queueMaxMessages ?? defaultQueueMaxMessages();
145
+ this.queueMaxBytes = options.queueMaxBytes ?? defaultQueueMaxBytes();
146
+ this.globalBudget = options.globalBudget ?? globalObservationBudget;
57
147
  activeCaptures.add(this);
58
148
  }
59
149
 
@@ -61,6 +151,21 @@ export class RawStreamCapture {
61
151
  return this.sawChunk;
62
152
  }
63
153
 
154
+ get status(): RawStreamCaptureStatus {
155
+ return {
156
+ incomplete: this.incomplete,
157
+ droppedChunks: this.droppedChunks,
158
+ droppedBytes: this.droppedBytes,
159
+ reason: this.gapReason,
160
+ };
161
+ }
162
+
163
+ recordDroppedObservation(reason: RawStreamCaptureGapReason, observedBytes: number): void {
164
+ const safeObservedBytes =
165
+ Number.isSafeInteger(observedBytes) && observedBytes >= 0 ? observedBytes : 0;
166
+ this.recordGap(reason, safeObservedBytes, safeObservedBytes > 0);
167
+ }
168
+
64
169
  async append(text: string): Promise<void> {
65
170
  if (text === "") return;
66
171
  const next = this.operation.then(() => this.appendInternal(text));
@@ -68,7 +173,63 @@ export class RawStreamCapture {
68
173
  return next;
69
174
  }
70
175
 
176
+ /**
177
+ * Submit an observation without waiting for file I/O. Once capacity is exceeded, capture remains
178
+ * incomplete and all later chunks are counted as dropped so the persisted value is an honest
179
+ * prefix rather than a misleading stream with an unmarked hole.
180
+ */
181
+ tryAppend(text: string, observedBytes: number): boolean {
182
+ const safeObservedBytes =
183
+ Number.isSafeInteger(observedBytes) && observedBytes >= 0 ? observedBytes : 0;
184
+ const queuedBytes = Math.max(safeObservedBytes, Buffer.byteLength(text, "utf-8"));
185
+
186
+ if (!this.accepting || this.closed) {
187
+ this.recordGap("pipeline-closed", safeObservedBytes, safeObservedBytes > 0 || text !== "");
188
+ return false;
189
+ }
190
+ if (this.incomplete) {
191
+ this.recordGap("capacity-exceeded", safeObservedBytes, safeObservedBytes > 0 || text !== "");
192
+ return false;
193
+ }
194
+ if (text === "") return true;
195
+ if (
196
+ this.queuedMessages + 1 > this.queueMaxMessages ||
197
+ this.queuedBytes + queuedBytes > this.queueMaxBytes
198
+ ) {
199
+ this.recordGap("capacity-exceeded", safeObservedBytes, true);
200
+ return false;
201
+ }
202
+
203
+ const releaseGlobal = this.globalBudget.tryAcquire(queuedBytes);
204
+ if (releaseGlobal === null) {
205
+ this.recordGap("capacity-exceeded", safeObservedBytes, true);
206
+ return false;
207
+ }
208
+
209
+ this.queuedMessages += 1;
210
+ this.queuedBytes += queuedBytes;
211
+ this.operation = this.operation
212
+ .then(async () => {
213
+ if (this.storageFailed) {
214
+ this.recordGap("write-failed", safeObservedBytes, true);
215
+ return;
216
+ }
217
+ await this.appendInternal(text);
218
+ })
219
+ .catch(() => {
220
+ this.storageFailed = true;
221
+ this.recordGap("write-failed", safeObservedBytes, true);
222
+ })
223
+ .finally(() => {
224
+ this.queuedMessages -= 1;
225
+ this.queuedBytes -= queuedBytes;
226
+ releaseGlobal();
227
+ });
228
+ return true;
229
+ }
230
+
71
231
  async finalize(): Promise<RawStreamSource> {
232
+ this.accepting = false;
72
233
  const next = this.operation.then(() => this.finalizeInternal());
73
234
  this.operation = next.then(
74
235
  () => undefined,
@@ -100,14 +261,29 @@ export class RawStreamCapture {
100
261
  }
101
262
  }
102
263
 
264
+ private recordGap(
265
+ reason: RawStreamCaptureGapReason,
266
+ observedBytes: number,
267
+ countChunk: boolean,
268
+ ): void {
269
+ this.incomplete = true;
270
+ this.gapReason ??= reason;
271
+ if (countChunk) this.droppedChunks += 1;
272
+ this.droppedBytes += observedBytes;
273
+ }
274
+
103
275
  private async finalizeInternal(): Promise<RawStreamSource> {
104
276
  if (!this.closed) {
105
277
  this.closed = true;
106
278
  await this.flushFileBuffer();
107
279
  if (this.fileHandle !== null) {
108
- await this.fileHandle.sync();
109
- await this.fileHandle.close();
280
+ const handle = this.fileHandle;
110
281
  this.fileHandle = null;
282
+ try {
283
+ await handle.sync();
284
+ } finally {
285
+ await handle.close();
286
+ }
111
287
  }
112
288
  }
113
289
  if (this.filePath !== null) {
@@ -120,16 +296,21 @@ export class RawStreamCapture {
120
296
  const path = createRawStreamPath();
121
297
  assert(ensurePrivateDirectorySync(getRawStreamDir()), "Could not secure raw-stream directory");
122
298
  const handle = await open(path, "wx", PRIVATE_FILE_MODE);
123
- const memoryText = this.chunks.join("");
124
- if (memoryText.length > 0) await handle.write(memoryText, undefined, "utf-8");
125
- if (!securePrivateFileSync(path)) {
126
- await handle.close();
127
- await unlink(path);
128
- assert(false, "Could not secure raw-stream file");
299
+ let committed = false;
300
+ try {
301
+ const memoryText = this.chunks.join("");
302
+ if (memoryText.length > 0) await handle.write(memoryText, undefined, "utf-8");
303
+ assert(securePrivateFileSync(path), "Could not secure raw-stream file");
304
+ this.filePath = path;
305
+ this.fileHandle = handle;
306
+ this.chunks = [];
307
+ committed = true;
308
+ } finally {
309
+ if (!committed) {
310
+ await handle.close().catch(() => undefined);
311
+ await unlink(path).catch(() => undefined);
312
+ }
129
313
  }
130
- this.filePath = path;
131
- this.fileHandle = handle;
132
- this.chunks = [];
133
314
  }
134
315
 
135
316
  private async flushFileBuffer(): Promise<void> {
@@ -1,3 +1,5 @@
1
+ import { MAX_ACTIVE_PROXY_REQUESTS } from "../lib/resourceLimits";
2
+
1
3
  export type RuntimeRequestLease = {
2
4
  release: () => void;
3
5
  };
@@ -13,7 +15,7 @@ function notifyDrained(): void {
13
15
  }
14
16
 
15
17
  export function acquireRuntimeRequest(): RuntimeRequestLease | null {
16
- if (!acceptingRequests) return null;
18
+ if (!acceptingRequests || activeRequests >= MAX_ACTIVE_PROXY_REQUESTS) return null;
17
19
  activeRequests += 1;
18
20
  let released = false;
19
21
  return {
@@ -41,8 +43,9 @@ export async function waitForRuntimeTrafficDrain(): Promise<void> {
41
43
  export function getRuntimeAdmissionState(): {
42
44
  acceptingRequests: boolean;
43
45
  activeRequests: number;
46
+ capacity: number;
44
47
  } {
45
- return { acceptingRequests, activeRequests };
48
+ return { acceptingRequests, activeRequests, capacity: MAX_ACTIVE_PROXY_REQUESTS };
46
49
  }
47
50
 
48
51
  export function _resetRuntimeAdmissionForTests(): void {
@@ -5,6 +5,9 @@ import { getDataDir } from "./dataDir";
5
5
  import { getFinalizerRuntimeHealth } from "./logFinalizer";
6
6
  import { ensurePrivateDirectorySync, PRIVATE_FILE_MODE } from "./privateDataPath";
7
7
  import { isSqliteLogIndexReady } from "./sqliteLogIndex";
8
+ import { recoverCapturedLogStorage } from "./jsonlRecovery";
9
+ import { resolveLogDir } from "./logger";
10
+ import { loadIndex } from "./logIndex";
8
11
 
9
12
  const DEFAULT_CACHE_MS = 2_000;
10
13
  const DEFAULT_MIN_DISK_HEADROOM_BYTES = 256 * 1024 * 1024;
@@ -118,7 +121,17 @@ function checkQueue(): Promise<ReadinessCheckLevel> {
118
121
  }
119
122
 
120
123
  async function checkIndex(): Promise<ReadinessCheckLevel> {
121
- return (await isSqliteLogIndexReady()) ? "ok" : "degraded";
124
+ const recovery = await recoverCapturedLogStorage(resolveLogDir());
125
+ if (recovery.level === "unavailable") return "unavailable";
126
+
127
+ try {
128
+ await loadIndex();
129
+ } catch {
130
+ return "unavailable";
131
+ }
132
+
133
+ const sqliteReady = await isSqliteLogIndexReady();
134
+ return recovery.level === "degraded" || !sqliteReady ? "degraded" : "ok";
122
135
  }
123
136
 
124
137
  function checkShutdown(): Promise<ReadinessCheckLevel> {
@@ -15,6 +15,11 @@ import {
15
15
  type ShutdownResult,
16
16
  } from "./shutdownCoordinator";
17
17
  import { destroyAllSessionProcesses } from "./sessionProcess";
18
+ import {
19
+ beginEcosystemTaskShutdown,
20
+ forceCloseEcosystemTasks,
21
+ waitForEcosystemTasksToClose,
22
+ } from "./ecosystemTasks";
18
23
  import { flushSessionTasks } from "./sessionRuntime";
19
24
  import { closeSqliteLogIndex } from "./sqliteLogIndex";
20
25
  import { flushSessionArchiveWrites } from "./store";
@@ -45,6 +50,7 @@ async function flushPersistence(): Promise<void> {
45
50
  }
46
51
 
47
52
  async function closeResources(): Promise<void> {
53
+ await waitForEcosystemTasksToClose();
48
54
  await closeLogFinalizerWorkers();
49
55
  destroyAllSessionProcesses();
50
56
  closeSqliteLogIndex();
@@ -52,6 +58,7 @@ async function closeResources(): Promise<void> {
52
58
  }
53
59
 
54
60
  function forceCloseResources(): void {
61
+ forceCloseEcosystemTasks();
55
62
  forceCloseLogFinalizerWorkers();
56
63
  destroyAllSessionProcesses();
57
64
  closeSqliteLogIndex();
@@ -59,7 +66,10 @@ function forceCloseResources(): void {
59
66
 
60
67
  const runtimeShutdownCoordinator = createShutdownCoordinator(
61
68
  {
62
- markShuttingDown: () => setRuntimeShuttingDown(true),
69
+ markShuttingDown: () => {
70
+ setRuntimeShuttingDown(true);
71
+ beginEcosystemTaskShutdown();
72
+ },
63
73
  stopAdmission: stopRuntimeAdmission,
64
74
  drainTraffic: waitForRuntimeTrafficDrain,
65
75
  drainFinalizers,
@@ -1,9 +1,15 @@
1
1
  import { z } from "zod";
2
2
 
3
- export { CapturedLogSchema, JsonValueSchema, StreamingChunkSchema } from "../contracts";
3
+ export {
4
+ CaptureIncompleteReasonSchema,
5
+ CapturedLogSchema,
6
+ JsonValueSchema,
7
+ StreamingChunkSchema,
8
+ } from "../contracts";
4
9
  export type {
5
10
  CapturedLog,
6
11
  ApiFormat,
12
+ CaptureIncompleteReason,
7
13
  JsonValue,
8
14
  StreamingChunk,
9
15
  TokenUsage,
@@ -40,6 +40,7 @@ ON CONFLICT(id) DO UPDATE SET
40
40
  `;
41
41
 
42
42
  let didLogUnavailable = false;
43
+ let cachedArchiveMax: { root: string; maxId: number } | null = null;
43
44
 
44
45
  export function getSessionArchiveRoot(): string {
45
46
  return join(resolveLogDir(), SESSION_ARCHIVE_DIR);
@@ -236,23 +237,49 @@ async function openSessionArchiveDb(filePath: string, create: boolean): Promise<
236
237
  }
237
238
  }
238
239
 
239
- export async function archiveSessionLog(log: CapturedLog): Promise<boolean> {
240
- const sessionId = log.sessionId;
241
- if (sessionId === null || sessionId.trim().length === 0) return false;
240
+ export async function archiveSessionLogs(logs: readonly CapturedLog[]): Promise<number> {
241
+ const bySession = new Map<string, CapturedLog[]>();
242
+ for (const log of logs) {
243
+ const sessionId = log.sessionId;
244
+ if (sessionId === null || sessionId.trim().length === 0) continue;
245
+ const existing = bySession.get(sessionId);
246
+ if (existing === undefined) bySession.set(sessionId, [log]);
247
+ else existing.push(log);
248
+ }
242
249
 
243
- const db = await openSessionArchiveDb(getSessionArchivePath(sessionId), true);
244
- if (db === null) return false;
250
+ let archivedCount = 0;
251
+ for (const [sessionId, sessionLogs] of bySession) {
252
+ const db = await openSessionArchiveDb(getSessionArchivePath(sessionId), true);
253
+ if (db === null || !execSql(db, "BEGIN IMMEDIATE")) {
254
+ if (db !== null) closeDatabase(db);
255
+ continue;
256
+ }
245
257
 
246
- try {
247
- return runPrepared(db, UPSERT_SQL, [
248
- log.id,
249
- sessionId,
250
- JSON.stringify(log),
251
- new Date().toISOString(),
252
- ]);
253
- } finally {
254
- closeDatabase(db);
258
+ let committed = false;
259
+ try {
260
+ const updatedAt = new Date().toISOString();
261
+ const archived = sessionLogs.every((log) =>
262
+ runPrepared(db, UPSERT_SQL, [log.id, sessionId, JSON.stringify(log), updatedAt]),
263
+ );
264
+ if (archived && execSql(db, "COMMIT")) {
265
+ committed = true;
266
+ archivedCount += sessionLogs.length;
267
+ if (cachedArchiveMax?.root === getSessionArchiveRoot()) {
268
+ for (const log of sessionLogs) {
269
+ cachedArchiveMax.maxId = Math.max(cachedArchiveMax.maxId, log.id);
270
+ }
271
+ }
272
+ }
273
+ } finally {
274
+ if (!committed) void execSql(db, "ROLLBACK");
275
+ closeDatabase(db);
276
+ }
255
277
  }
278
+ return archivedCount;
279
+ }
280
+
281
+ export async function archiveSessionLog(log: CapturedLog): Promise<boolean> {
282
+ return (await archiveSessionLogs([log])) === 1;
256
283
  }
257
284
 
258
285
  function readString(row: unknown, name: string): string | null {
@@ -343,6 +370,36 @@ async function listArchiveDatabasePaths(): Promise<string[]> {
343
370
  }
344
371
  }
345
372
 
373
+ /**
374
+ * Return the highest ID retained by an authoritative session archive. The global SQLite index is a
375
+ * rebuildable projection and must never influence ID allocation, while archive IDs must remain
376
+ * reserved even after their corresponding global JSONL records have aged out.
377
+ */
378
+ export async function getSessionArchiveMaxLogId(): Promise<number> {
379
+ const root = getSessionArchiveRoot();
380
+ if (cachedArchiveMax?.root === root) return cachedArchiveMax.maxId;
381
+
382
+ let maxId = 0;
383
+ const archivePaths = await listArchiveDatabasePaths();
384
+ for (const archivePath of archivePaths) {
385
+ const db = await openSessionArchiveDb(archivePath, false);
386
+ if (db === null) continue;
387
+
388
+ try {
389
+ const rows = allPrepared(db, "SELECT MAX(id) AS max_id FROM session_logs");
390
+ const archiveMax = readNumber(rows[0], "max_id");
391
+ if (archiveMax !== null && Number.isSafeInteger(archiveMax) && archiveMax >= 0) {
392
+ maxId = Math.max(maxId, archiveMax);
393
+ }
394
+ } finally {
395
+ closeDatabase(db);
396
+ }
397
+ }
398
+
399
+ cachedArchiveMax = { root, maxId };
400
+ return maxId;
401
+ }
402
+
346
403
  export async function findArchivedLogById(id: number): Promise<CapturedLog | null> {
347
404
  const archivePaths = await listArchiveDatabasePaths();
348
405
  for (const archivePath of archivePaths) {
@@ -405,6 +462,8 @@ export async function deleteArchivedLogsByIds(ids: ReadonlySet<number>): Promise
405
462
  }
406
463
  }
407
464
 
465
+ if (removedIds.size > 0) cachedArchiveMax = null;
466
+
408
467
  return removedIds;
409
468
  }
410
469
 
@@ -415,9 +474,14 @@ export async function clearSessionArchives(): Promise<number> {
415
474
  const archivePaths = await listArchiveDatabasePaths();
416
475
  try {
417
476
  await rm(root, { recursive: true, force: true });
477
+ cachedArchiveMax = null;
418
478
  return archivePaths.length;
419
479
  } catch (err) {
420
480
  logger.warn("[sessionArchive] Failed to clear session archives:", String(err));
421
481
  return 0;
422
482
  }
423
483
  }
484
+
485
+ export function _resetSessionArchiveCacheForTests(): void {
486
+ cachedArchiveMax = null;
487
+ }
@@ -1,7 +1,7 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  import { logger, resolveLogDir } from "./logger";
4
- import type { ApiFormat } from "./schemas";
4
+ import type { ApiFormat, CaptureIncompleteReason } from "./schemas";
5
5
  import type { LogIndexEntry, LogIndexSummary } from "./logIndex";
6
6
  import { ensurePrivateDirectorySync, securePrivateFileSync } from "./privateDataPath";
7
7
 
@@ -47,6 +47,10 @@ CREATE TABLE IF NOT EXISTS log_index (
47
47
  streaming_chunks_path TEXT,
48
48
  raw_request_body_bytes INTEGER,
49
49
  response_text_bytes INTEGER,
50
+ capture_incomplete INTEGER NOT NULL DEFAULT 0,
51
+ dropped_chunks INTEGER NOT NULL DEFAULT 0,
52
+ dropped_bytes INTEGER NOT NULL DEFAULT 0,
53
+ capture_incomplete_reason TEXT,
50
54
  warnings_json TEXT,
51
55
  error TEXT
52
56
  );
@@ -89,10 +93,14 @@ INSERT INTO log_index (
89
93
  streaming_chunks_path,
90
94
  raw_request_body_bytes,
91
95
  response_text_bytes,
96
+ capture_incomplete,
97
+ dropped_chunks,
98
+ dropped_bytes,
99
+ capture_incomplete_reason,
92
100
  warnings_json,
93
101
  error
94
102
  ) VALUES (
95
- ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
103
+ ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
96
104
  )
97
105
  ON CONFLICT(id) DO UPDATE SET
98
106
  file = excluded.file,
@@ -126,6 +134,10 @@ ON CONFLICT(id) DO UPDATE SET
126
134
  streaming_chunks_path = excluded.streaming_chunks_path,
127
135
  raw_request_body_bytes = excluded.raw_request_body_bytes,
128
136
  response_text_bytes = excluded.response_text_bytes,
137
+ capture_incomplete = excluded.capture_incomplete,
138
+ dropped_chunks = excluded.dropped_chunks,
139
+ dropped_bytes = excluded.dropped_bytes,
140
+ capture_incomplete_reason = excluded.capture_incomplete_reason,
129
141
  warnings_json = excluded.warnings_json,
130
142
  error = excluded.error
131
143
  `;
@@ -215,6 +227,30 @@ function execSql(db: unknown, sql: string): boolean {
215
227
  return result !== undefined;
216
228
  }
217
229
 
230
+ const REQUIRED_SCHEMA_COLUMNS = [
231
+ { name: "capture_incomplete", definition: "INTEGER NOT NULL DEFAULT 0" },
232
+ { name: "dropped_chunks", definition: "INTEGER NOT NULL DEFAULT 0" },
233
+ { name: "dropped_bytes", definition: "INTEGER NOT NULL DEFAULT 0" },
234
+ { name: "capture_incomplete_reason", definition: "TEXT" },
235
+ ];
236
+
237
+ function ensureSchemaColumns(db: unknown): boolean {
238
+ const rows = allPrepared(db, "PRAGMA table_info(log_index)");
239
+ if (rows === null) return false;
240
+ const existing = new Set<string>();
241
+ for (const row of rows) {
242
+ const name = readProperty(row, "name");
243
+ if (typeof name === "string") existing.add(name);
244
+ }
245
+ for (const column of REQUIRED_SCHEMA_COLUMNS) {
246
+ if (existing.has(column.name)) continue;
247
+ if (!execSql(db, `ALTER TABLE log_index ADD COLUMN ${column.name} ${column.definition}`)) {
248
+ return false;
249
+ }
250
+ }
251
+ return true;
252
+ }
253
+
218
254
  function sqliteConstructorFromModule(
219
255
  moduleValue: unknown,
220
256
  exportName: "default" | "Database",
@@ -316,6 +352,9 @@ async function initializeSqliteState(): Promise<SqliteState> {
316
352
  if (!execSql(db, CREATE_SCHEMA_SQL)) {
317
353
  return { status: "unavailable", path, reason: "SQLite schema initialization failed" };
318
354
  }
355
+ if (!ensureSchemaColumns(db)) {
356
+ return { status: "unavailable", path, reason: "SQLite schema migration failed" };
357
+ }
319
358
  activeDb = db;
320
359
  return { status: "ready", db, path };
321
360
  } catch (err) {
@@ -394,6 +433,10 @@ function entryParams(entry: LogIndexEntry): readonly unknown[] {
394
433
  summary?.streamingChunksPath ?? null,
395
434
  summary?.rawRequestBodyBytes ?? null,
396
435
  summary?.responseTextBytes ?? null,
436
+ boolToInt(summary?.captureIncomplete ?? false),
437
+ summary?.droppedChunks ?? 0,
438
+ summary?.droppedBytes ?? 0,
439
+ summary?.captureIncompleteReason ?? null,
397
440
  warningJson(summary?.warnings),
398
441
  summary?.error ?? null,
399
442
  ];
@@ -428,6 +471,22 @@ function readApiFormat(row: unknown): ApiFormat {
428
471
  }
429
472
  }
430
473
 
474
+ function readCaptureIncompleteReason(row: unknown): CaptureIncompleteReason | null {
475
+ const value = readString(row, "capture_incomplete_reason");
476
+ switch (value) {
477
+ case "capacity-exceeded":
478
+ case "pipeline-closed":
479
+ case "write-failed":
480
+ case "finalize-failed":
481
+ case "upstream-stream-error":
482
+ case "shutdown":
483
+ return value;
484
+ case null:
485
+ default:
486
+ return null;
487
+ }
488
+ }
489
+
431
490
  function readWarnings(row: unknown): string[] | undefined {
432
491
  const value = readString(row, "warnings_json");
433
492
  if (value === null) return undefined;
@@ -481,6 +540,10 @@ function summaryFromRow(row: unknown, id: number): LogIndexSummary {
481
540
  streamingChunksPath: readString(row, "streaming_chunks_path"),
482
541
  rawRequestBodyBytes: readNumber(row, "raw_request_body_bytes"),
483
542
  responseTextBytes: readNumber(row, "response_text_bytes"),
543
+ captureIncomplete: readBoolean(row, "capture_incomplete"),
544
+ droppedChunks: readNumber(row, "dropped_chunks") ?? 0,
545
+ droppedBytes: readNumber(row, "dropped_bytes") ?? 0,
546
+ captureIncompleteReason: readCaptureIncompleteReason(row),
484
547
  warnings: readWarnings(row),
485
548
  error: readString(row, "error"),
486
549
  };