@songsid/agend 2.3.4-beta.6 → 2.3.5-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (386) hide show
  1. package/README.md +2 -0
  2. package/README.zh-TW.md +2 -0
  3. package/THIRD_PARTY_NOTICES.md +53 -0
  4. package/dist/agent-endpoint.d.ts +5 -1
  5. package/dist/agent-endpoint.js +12 -2
  6. package/dist/agent-endpoint.js.map +1 -1
  7. package/dist/backend/claude-code.d.ts +15 -12
  8. package/dist/backend/claude-code.js +137 -133
  9. package/dist/backend/claude-code.js.map +1 -1
  10. package/dist/backend/codex-package.d.ts +5 -2
  11. package/dist/backend/codex-package.js +1 -5
  12. package/dist/backend/codex-package.js.map +1 -1
  13. package/dist/backend/codex.d.ts +136 -113
  14. package/dist/backend/codex.js +1271 -1219
  15. package/dist/backend/codex.js.map +1 -1
  16. package/dist/backend/grok-model-cache.d.ts +7 -0
  17. package/dist/backend/grok-model-cache.js +65 -0
  18. package/dist/backend/grok-model-cache.js.map +1 -0
  19. package/dist/backend/grok.d.ts +2 -0
  20. package/dist/backend/grok.js +22 -0
  21. package/dist/backend/grok.js.map +1 -1
  22. package/dist/backend/native-pane.d.ts +9 -0
  23. package/dist/backend/native-pane.js +59 -0
  24. package/dist/backend/native-pane.js.map +1 -0
  25. package/dist/backend/types.d.ts +7 -0
  26. package/dist/backend/types.js.map +1 -1
  27. package/dist/channel/ipc-bridge.d.ts +2 -0
  28. package/dist/channel/mcp-tools.js +1 -1
  29. package/dist/channel/mcp-tools.js.map +1 -1
  30. package/dist/cli.js +6 -2
  31. package/dist/cli.js.map +1 -1
  32. package/dist/config-validator.js +59 -0
  33. package/dist/config-validator.js.map +1 -1
  34. package/dist/config.js +16 -0
  35. package/dist/config.js.map +1 -1
  36. package/dist/daemon.d.ts +62 -5
  37. package/dist/daemon.js +749 -267
  38. package/dist/daemon.js.map +1 -1
  39. package/dist/delivery-consumed-watch.d.ts +15 -3
  40. package/dist/delivery-consumed-watch.js +23 -1
  41. package/dist/delivery-consumed-watch.js.map +1 -1
  42. package/dist/delivery-outbox.d.ts +5 -0
  43. package/dist/delivery-outbox.js +32 -4
  44. package/dist/delivery-outbox.js.map +1 -1
  45. package/dist/delivery-reconciliation.d.ts +2 -35
  46. package/dist/delivery-reconciliation.js +2 -156
  47. package/dist/delivery-reconciliation.js.map +1 -1
  48. package/dist/fleet-context.d.ts +2 -2
  49. package/dist/fleet-level-config.d.ts +1 -1
  50. package/dist/fleet-level-config.js +2 -0
  51. package/dist/fleet-level-config.js.map +1 -1
  52. package/dist/fleet-manager.d.ts +125 -2
  53. package/dist/fleet-manager.js +1157 -27
  54. package/dist/fleet-manager.js.map +1 -1
  55. package/dist/fleet-windows-runtime.d.ts +92 -0
  56. package/dist/fleet-windows-runtime.js +373 -0
  57. package/dist/fleet-windows-runtime.js.map +1 -0
  58. package/dist/instance-config-impact.js +4 -0
  59. package/dist/instance-config-impact.js.map +1 -1
  60. package/dist/instance-lifecycle.d.ts +20 -3
  61. package/dist/instance-lifecycle.js +358 -156
  62. package/dist/instance-lifecycle.js.map +1 -1
  63. package/dist/local-pane-endpoint.d.ts +46 -0
  64. package/dist/local-pane-endpoint.js +189 -0
  65. package/dist/local-pane-endpoint.js.map +1 -0
  66. package/dist/local-pane-launcher.d.ts +2 -0
  67. package/dist/local-pane-launcher.js +38 -0
  68. package/dist/local-pane-launcher.js.map +1 -0
  69. package/dist/local-pane-stage.ps1 +101 -0
  70. package/dist/locale.js +34 -0
  71. package/dist/locale.js.map +1 -1
  72. package/dist/model-catalog-defaults.d.ts +14 -0
  73. package/dist/model-catalog-defaults.js +20 -0
  74. package/dist/model-catalog-defaults.js.map +1 -0
  75. package/dist/native-agent-admission.d.ts +7 -0
  76. package/dist/native-agent-admission.js +26 -0
  77. package/dist/native-agent-admission.js.map +1 -0
  78. package/dist/native-daemon-client.d.ts +13 -0
  79. package/dist/native-daemon-client.js +28 -0
  80. package/dist/native-daemon-client.js.map +1 -0
  81. package/dist/native-instance-api.d.ts +14 -0
  82. package/dist/native-instance-api.js +205 -0
  83. package/dist/native-instance-api.js.map +1 -0
  84. package/dist/native-instance-input.d.ts +84 -0
  85. package/dist/native-instance-input.js +54 -0
  86. package/dist/native-instance-input.js.map +1 -0
  87. package/dist/native-instance-registry.d.ts +32 -0
  88. package/dist/native-instance-registry.js +105 -0
  89. package/dist/native-instance-registry.js.map +1 -0
  90. package/dist/native-mcp.d.ts +40 -0
  91. package/dist/native-mcp.js +278 -0
  92. package/dist/native-mcp.js.map +1 -0
  93. package/dist/native-model-catalog.d.ts +5 -0
  94. package/dist/native-model-catalog.js +76 -0
  95. package/dist/native-model-catalog.js.map +1 -0
  96. package/dist/native-pane-crash-budget.d.ts +20 -0
  97. package/dist/native-pane-crash-budget.js +60 -0
  98. package/dist/native-pane-crash-budget.js.map +1 -0
  99. package/dist/native-pane-create.d.ts +26 -0
  100. package/dist/native-pane-create.js +53 -0
  101. package/dist/native-pane-create.js.map +1 -0
  102. package/dist/native-pane-lifecycle.d.ts +65 -0
  103. package/dist/native-pane-lifecycle.js +227 -0
  104. package/dist/native-pane-lifecycle.js.map +1 -0
  105. package/dist/native-pane-manager.d.ts +58 -0
  106. package/dist/native-pane-manager.js +563 -0
  107. package/dist/native-pane-manager.js.map +1 -0
  108. package/dist/native-pane-output-log.d.ts +15 -0
  109. package/dist/native-pane-output-log.js +108 -0
  110. package/dist/native-pane-output-log.js.map +1 -0
  111. package/dist/native-pane-reconciliation.d.ts +4 -0
  112. package/dist/native-pane-reconciliation.js +40 -0
  113. package/dist/native-pane-reconciliation.js.map +1 -0
  114. package/dist/native-pane-recovery.d.ts +12 -0
  115. package/dist/native-pane-recovery.js +10 -0
  116. package/dist/native-pane-recovery.js.map +1 -0
  117. package/dist/native-pane-tools.d.ts +2 -0
  118. package/dist/native-pane-tools.js +14 -0
  119. package/dist/native-pane-tools.js.map +1 -0
  120. package/dist/needs-you-hub.d.ts +2 -0
  121. package/dist/needs-you-hub.js +1 -0
  122. package/dist/needs-you-hub.js.map +1 -1
  123. package/dist/needs-you.d.ts +12 -1
  124. package/dist/needs-you.js +8 -1
  125. package/dist/needs-you.js.map +1 -1
  126. package/dist/outbound-handlers.d.ts +16 -2
  127. package/dist/outbound-handlers.js +67 -3
  128. package/dist/outbound-handlers.js.map +1 -1
  129. package/dist/outbound-schemas.d.ts +38 -0
  130. package/dist/outbound-schemas.js +12 -0
  131. package/dist/outbound-schemas.js.map +1 -1
  132. package/dist/pane-port.d.ts +107 -0
  133. package/dist/pane-port.js +2 -0
  134. package/dist/pane-port.js.map +1 -0
  135. package/dist/runtime-api.d.ts +8 -0
  136. package/dist/runtime-api.js +96 -0
  137. package/dist/runtime-api.js.map +1 -0
  138. package/dist/runtime-assets/@xterm/addon-serialize/LICENSE +21 -0
  139. package/dist/runtime-assets/@xterm/addon-serialize/lib/addon-serialize.js +2 -0
  140. package/dist/runtime-assets/@xterm/addon-serialize/lib/addon-serialize.mjs +19 -0
  141. package/dist/runtime-assets/@xterm/addon-serialize/package.json +29 -0
  142. package/dist/runtime-assets/@xterm/headless/LICENSE +21 -0
  143. package/dist/runtime-assets/@xterm/headless/lib-headless/xterm-headless.js +2 -0
  144. package/dist/runtime-assets/@xterm/headless/lib-headless/xterm-headless.mjs +46 -0
  145. package/dist/runtime-assets/@xterm/headless/package.json +29 -0
  146. package/dist/runtime-assets/node-pty/CONPTY-LICENSE +21 -0
  147. package/dist/runtime-assets/node-pty/CONPTY-NOTICE.md +503 -0
  148. package/dist/runtime-assets/node-pty/LICENSE +69 -0
  149. package/dist/runtime-assets/node-pty/lib/conpty_console_list_agent.js +16 -0
  150. package/dist/runtime-assets/node-pty/lib/eventEmitter2.js +47 -0
  151. package/dist/runtime-assets/node-pty/lib/index.js +52 -0
  152. package/dist/runtime-assets/node-pty/lib/interfaces.js +7 -0
  153. package/dist/runtime-assets/node-pty/lib/shared/conout.js +11 -0
  154. package/dist/runtime-assets/node-pty/lib/terminal.js +190 -0
  155. package/dist/runtime-assets/node-pty/lib/types.js +7 -0
  156. package/dist/runtime-assets/node-pty/lib/unixTerminal.js +346 -0
  157. package/dist/runtime-assets/node-pty/lib/utils.js +39 -0
  158. package/dist/runtime-assets/node-pty/lib/windowsConoutConnection.js +125 -0
  159. package/dist/runtime-assets/node-pty/lib/windowsPtyAgent.js +320 -0
  160. package/dist/runtime-assets/node-pty/lib/windowsTerminal.js +199 -0
  161. package/dist/runtime-assets/node-pty/lib/worker/conoutSocketWorker.js +22 -0
  162. package/dist/runtime-assets/node-pty/package.json +64 -0
  163. package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
  164. package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
  165. package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty.node +0 -0
  166. package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty_console_list.node +0 -0
  167. package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
  168. package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty/conpty.dll +0 -0
  169. package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty.node +0 -0
  170. package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty_console_list.node +0 -0
  171. package/dist/runtime-bundle.d.ts +17 -0
  172. package/dist/runtime-bundle.js +147 -0
  173. package/dist/runtime-bundle.js.map +1 -0
  174. package/dist/runtime-cli.d.ts +2 -0
  175. package/dist/runtime-cli.js +117 -0
  176. package/dist/runtime-cli.js.map +1 -0
  177. package/dist/runtime-client-store.d.ts +49 -0
  178. package/dist/runtime-client-store.js +292 -0
  179. package/dist/runtime-client-store.js.map +1 -0
  180. package/dist/runtime-client.d.ts +100 -0
  181. package/dist/runtime-client.js +700 -0
  182. package/dist/runtime-client.js.map +1 -0
  183. package/dist/runtime-coordinator.d.ts +82 -0
  184. package/dist/runtime-coordinator.js +864 -0
  185. package/dist/runtime-coordinator.js.map +1 -0
  186. package/dist/runtime-pane-assets.d.ts +17 -0
  187. package/dist/runtime-pane-assets.js +23 -0
  188. package/dist/runtime-pane-assets.js.map +1 -0
  189. package/dist/runtime-pane-boot.d.ts +2 -0
  190. package/dist/runtime-pane-boot.js +24 -0
  191. package/dist/runtime-pane-boot.js.map +1 -0
  192. package/dist/runtime-pane-codex-index.d.ts +1 -0
  193. package/dist/runtime-pane-codex-index.js +47 -0
  194. package/dist/runtime-pane-codex-index.js.map +1 -0
  195. package/dist/runtime-pane-config.d.ts +16 -0
  196. package/dist/runtime-pane-config.js +54 -0
  197. package/dist/runtime-pane-config.js.map +1 -0
  198. package/dist/runtime-pane-host.d.ts +43 -0
  199. package/dist/runtime-pane-host.js +403 -0
  200. package/dist/runtime-pane-host.js.map +1 -0
  201. package/dist/runtime-pane-job-owner.d.ts +1 -0
  202. package/dist/runtime-pane-job-owner.js +29 -0
  203. package/dist/runtime-pane-job-owner.js.map +1 -0
  204. package/dist/runtime-pane-job.ps1 +116 -0
  205. package/dist/runtime-pane-link.d.ts +40 -0
  206. package/dist/runtime-pane-link.js +246 -0
  207. package/dist/runtime-pane-link.js.map +1 -0
  208. package/dist/runtime-pane-mcp-protocol.d.ts +32 -0
  209. package/dist/runtime-pane-mcp-protocol.js +39 -0
  210. package/dist/runtime-pane-mcp-protocol.js.map +1 -0
  211. package/dist/runtime-pane-mcp-relay.d.ts +17 -0
  212. package/dist/runtime-pane-mcp-relay.js +70 -0
  213. package/dist/runtime-pane-mcp-relay.js.map +1 -0
  214. package/dist/runtime-pane-mcp.d.ts +43 -0
  215. package/dist/runtime-pane-mcp.js +137 -0
  216. package/dist/runtime-pane-mcp.js.map +1 -0
  217. package/dist/runtime-pane-native.d.ts +45 -0
  218. package/dist/runtime-pane-native.js +65 -0
  219. package/dist/runtime-pane-native.js.map +1 -0
  220. package/dist/runtime-pane-output.d.ts +19 -0
  221. package/dist/runtime-pane-output.js +53 -0
  222. package/dist/runtime-pane-output.js.map +1 -0
  223. package/dist/runtime-pane-port.d.ts +134 -0
  224. package/dist/runtime-pane-port.js +537 -0
  225. package/dist/runtime-pane-port.js.map +1 -0
  226. package/dist/runtime-pane-private.d.ts +14 -0
  227. package/dist/runtime-pane-private.js +51 -0
  228. package/dist/runtime-pane-private.js.map +1 -0
  229. package/dist/runtime-pane-private.ps1 +14 -0
  230. package/dist/runtime-pane-process.d.ts +4 -0
  231. package/dist/runtime-pane-process.js +108 -0
  232. package/dist/runtime-pane-process.js.map +1 -0
  233. package/dist/runtime-pane-protocol.d.ts +169 -0
  234. package/dist/runtime-pane-protocol.js +189 -0
  235. package/dist/runtime-pane-protocol.js.map +1 -0
  236. package/dist/runtime-pane-screen.d.ts +19 -0
  237. package/dist/runtime-pane-screen.js +76 -0
  238. package/dist/runtime-pane-screen.js.map +1 -0
  239. package/dist/runtime-pane-service.d.ts +11 -0
  240. package/dist/runtime-pane-service.js +221 -0
  241. package/dist/runtime-pane-service.js.map +1 -0
  242. package/dist/runtime-pane-stdio-protocol.d.ts +54 -0
  243. package/dist/runtime-pane-stdio-protocol.js +94 -0
  244. package/dist/runtime-pane-stdio-protocol.js.map +1 -0
  245. package/dist/runtime-pane-stdio.d.ts +3 -0
  246. package/dist/runtime-pane-stdio.js +123 -0
  247. package/dist/runtime-pane-stdio.js.map +1 -0
  248. package/dist/runtime-pane-store.d.ts +33 -0
  249. package/dist/runtime-pane-store.js +164 -0
  250. package/dist/runtime-pane-store.js.map +1 -0
  251. package/dist/runtime-pane-transcript-protocol.d.ts +43 -0
  252. package/dist/runtime-pane-transcript-protocol.js +58 -0
  253. package/dist/runtime-pane-transcript-protocol.js.map +1 -0
  254. package/dist/runtime-pane-transcript.d.ts +45 -0
  255. package/dist/runtime-pane-transcript.js +605 -0
  256. package/dist/runtime-pane-transcript.js.map +1 -0
  257. package/dist/runtime-pane-worker.d.ts +1 -0
  258. package/dist/runtime-pane-worker.js +154 -0
  259. package/dist/runtime-pane-worker.js.map +1 -0
  260. package/dist/runtime-protocol.d.ts +149 -0
  261. package/dist/runtime-protocol.js +19 -0
  262. package/dist/runtime-protocol.js.map +1 -0
  263. package/dist/runtime-switches.d.ts +79 -0
  264. package/dist/runtime-switches.js +90 -0
  265. package/dist/runtime-switches.js.map +1 -0
  266. package/dist/runtime-transcript-delta-reader.d.ts +23 -0
  267. package/dist/runtime-transcript-delta-reader.js +74 -0
  268. package/dist/runtime-transcript-delta-reader.js.map +1 -0
  269. package/dist/runtime-transcript-source.d.ts +36 -0
  270. package/dist/runtime-transcript-source.js +189 -0
  271. package/dist/runtime-transcript-source.js.map +1 -0
  272. package/dist/runtime-windows-bridge.d.ts +41 -0
  273. package/dist/runtime-windows-bridge.js +157 -0
  274. package/dist/runtime-windows-bridge.js.map +1 -0
  275. package/dist/settings-api.js +58 -0
  276. package/dist/settings-api.js.map +1 -1
  277. package/dist/settings-change.js +28 -0
  278. package/dist/settings-change.js.map +1 -1
  279. package/dist/settings-confirmation.d.ts +15 -1
  280. package/dist/settings-confirmation.js +46 -9
  281. package/dist/settings-confirmation.js.map +1 -1
  282. package/dist/settings-effect.js +23 -1
  283. package/dist/settings-effect.js.map +1 -1
  284. package/dist/settings-http-confirmation.js +11 -2
  285. package/dist/settings-http-confirmation.js.map +1 -1
  286. package/dist/tmux-control.d.ts +2 -1
  287. package/dist/tmux-control.js.map +1 -1
  288. package/dist/tmux-manager.d.ts +2 -1
  289. package/dist/tmux-manager.js.map +1 -1
  290. package/dist/tmux-pane-host.d.ts +26 -0
  291. package/dist/tmux-pane-host.js +25 -0
  292. package/dist/tmux-pane-host.js.map +1 -0
  293. package/dist/topic-commands.js +3 -0
  294. package/dist/topic-commands.js.map +1 -1
  295. package/dist/transcript-delta-reader.d.ts +1 -1
  296. package/dist/transcript-delta-reader.js +1 -1
  297. package/dist/transcript-delta-reader.js.map +1 -1
  298. package/dist/transcript-monitor.d.ts +3 -0
  299. package/dist/transcript-monitor.js +22 -46
  300. package/dist/transcript-monitor.js.map +1 -1
  301. package/dist/transcript-needles.d.ts +35 -0
  302. package/dist/transcript-needles.js +158 -0
  303. package/dist/transcript-needles.js.map +1 -0
  304. package/dist/transcript-records.d.ts +21 -0
  305. package/dist/transcript-records.js +140 -0
  306. package/dist/transcript-records.js.map +1 -0
  307. package/dist/transcript-sources.d.ts +5 -0
  308. package/dist/transcript-sources.js +8 -79
  309. package/dist/transcript-sources.js.map +1 -1
  310. package/dist/types.d.ts +21 -0
  311. package/dist/ui/agent-proposals.js +90 -0
  312. package/dist/ui/agent-runtime.js +106 -0
  313. package/dist/ui/chat-store.js +13 -2
  314. package/dist/ui/chat-strings.js +48 -0
  315. package/dist/ui/cli-picker.js +42 -0
  316. package/dist/ui/native-instance-settings.js +47 -0
  317. package/dist/ui/native-pane-recovery.js +45 -0
  318. package/dist/ui/panel-chat.js +61 -32
  319. package/dist/ui/panel-details.js +2 -1
  320. package/dist/ui/panel-fleet.js +99 -18
  321. package/dist/ui/panel-needs.js +152 -3
  322. package/dist/ui/panel-runtimes.js +231 -0
  323. package/dist/ui/panel-settings.js +14 -8
  324. package/dist/ui/panel-windows-agent.js +86 -0
  325. package/dist/ui/panel-windows-cli.js +143 -0
  326. package/dist/ui/provider-marks.js +83 -0
  327. package/dist/ui/runtime-catalog.js +55 -0
  328. package/dist/ui/settings-catalog.js +37 -10
  329. package/dist/ui/settings-confirm.js +3 -1
  330. package/dist/ui/settings-dialogs.js +14 -5
  331. package/dist/ui/settings-registry.js +5 -0
  332. package/dist/ui/settings-strings.js +14 -0
  333. package/dist/ui/shared/app-i18n.js +2 -2
  334. package/dist/ui/shared/app-route.js +6 -2
  335. package/dist/ui/shared/app-shell.js +3 -2
  336. package/dist/ui/shared/app-store.js +1 -0
  337. package/dist/ui/shared/app-stream.js +3 -1
  338. package/dist/ui/shared/app.css +301 -0
  339. package/dist/ui/shared/app.js +4 -0
  340. package/dist/ui/shared/header-tools.js +6 -4
  341. package/dist/ui/shared/instance-nav.js +20 -4
  342. package/dist/ui/shared/instance-switch.js +4 -3
  343. package/dist/ui/shared/ui-menu.js +28 -8
  344. package/dist/ui/shared/view-strings.js +6 -0
  345. package/dist/ui/windows-agents-nav.js +2 -0
  346. package/dist/ui/windows-cli-catalog.js +79 -0
  347. package/dist/update-check.d.ts +8 -2
  348. package/dist/update-check.js +5 -2
  349. package/dist/update-check.js.map +1 -1
  350. package/dist/web-api.d.ts +25 -0
  351. package/dist/web-api.js +171 -6
  352. package/dist/web-api.js.map +1 -1
  353. package/dist/web-chat-history.d.ts +19 -2
  354. package/dist/web-chat-history.js +72 -3
  355. package/dist/web-chat-history.js.map +1 -1
  356. package/dist/web-shell-routes.d.ts +4 -1
  357. package/dist/web-shell-routes.js +7 -2
  358. package/dist/web-shell-routes.js.map +1 -1
  359. package/dist/windows-agents.d.ts +112 -0
  360. package/dist/windows-agents.js +463 -0
  361. package/dist/windows-agents.js.map +1 -0
  362. package/dist/windows-cli-api.d.ts +23 -0
  363. package/dist/windows-cli-api.js +158 -0
  364. package/dist/windows-cli-api.js.map +1 -0
  365. package/dist/windows-cli-providers.d.ts +115 -0
  366. package/dist/windows-cli-providers.js +429 -0
  367. package/dist/windows-cli-providers.js.map +1 -0
  368. package/dist/windows-cli-worker.d.ts +58 -0
  369. package/dist/windows-cli-worker.js +479 -0
  370. package/dist/windows-cli-worker.js.map +1 -0
  371. package/dist/windows-cli.d.ts +115 -0
  372. package/dist/windows-cli.js +402 -0
  373. package/dist/windows-cli.js.map +1 -0
  374. package/dist/windows-native-mcp.d.ts +19 -0
  375. package/dist/windows-native-mcp.js +143 -0
  376. package/dist/windows-native-mcp.js.map +1 -0
  377. package/dist/windows-pane-mcp.d.ts +26 -0
  378. package/dist/windows-pane-mcp.js +187 -0
  379. package/dist/windows-pane-mcp.js.map +1 -0
  380. package/package.json +9 -3
  381. package/templates/runtime-assets/conpty-LICENSE +21 -0
  382. package/templates/runtime-assets/conpty-NOTICE.md +503 -0
  383. package/templates/runtime-assets/local-pane-stage.ps1 +101 -0
  384. package/templates/runtime-assets/runtime-pane-job.ps1 +116 -0
  385. package/templates/runtime-assets/runtime-pane-private.ps1 +14 -0
  386. package/templates/runtime-assets/xterm-LICENSE +21 -0
@@ -0,0 +1,605 @@
1
+ /** Exact-session reads on the runner. No caller-supplied path and no newest-by-cwd discovery. */
2
+ import { codexTurnRecord } from "./transcript-records.js";
3
+ import { constants } from "node:fs";
4
+ import { codexIndexHasNoThread } from "./runtime-pane-codex-index.js";
5
+ import { lstat, open, opendir, realpath } from "node:fs/promises";
6
+ import { homedir } from "node:os";
7
+ import { dirname, join, normalize, parse, resolve, win32 } from "node:path";
8
+ import { createHash } from "node:crypto";
9
+ import { validNativeSessionId } from "./windows-cli-providers.js";
10
+ import { nativeCliEnvironment } from "./windows-cli-worker.js";
11
+ import { PANE_TRANSCRIPT_EMPTY_ANCHOR as EMPTY, PANE_TRANSCRIPT_MAX_FILE_BYTES as MAX_FILE, validatePaneTranscriptCursor } from "./runtime-pane-transcript-protocol.js";
12
+ export { validatePaneTranscriptCursor } from "./runtime-pane-transcript-protocol.js";
13
+ const CHUNK = 160 * 1024, META = 1024 * 1024, ANCHOR = 4096;
14
+ const hash = (value) => createHash("sha256").update(value).digest("hex");
15
+ const missing = (error) => error.code === "ENOENT";
16
+ const comparable = (path) => /^[a-z]:[\\/]/i.test(path)
17
+ ? win32.normalize(path).replace(/[\\/]+$/, "").toLowerCase() : normalize(path).replace(/\/+$/, "");
18
+ function owned(stat) { return typeof process.getuid !== "function" || stat.uid === process.getuid(); }
19
+ function sameFile(a, b) { return a.dev === b.dev && a.ino === b.ino && a.birthtimeMs === b.birthtimeMs; }
20
+ function regular(stat) {
21
+ if (!stat.isFile() || stat.isSymbolicLink() || !owned(stat) || stat.size > MAX_FILE)
22
+ throw Error("Owned pane transcript is not a bounded regular file");
23
+ }
24
+ /** Root configuration comes only from the runner's allowed provider environment, never a pane RPC. */
25
+ export function nativePaneTranscriptRoots(env = nativeCliEnvironment(), home = homedir()) {
26
+ const find = (key) => Object.entries(env).find(([name]) => name.toUpperCase() === key)?.[1];
27
+ return { codex: find("CODEX_HOME") ?? join(home, ".codex"), claude: find("CLAUDE_CONFIG_DIR") ?? join(home, ".claude") };
28
+ }
29
+ /** Same algorithm as Claude's project directory, evaluated on the runner's canonical native cwd. */
30
+ export function nativeClaudeProjectKey(cwd) {
31
+ const safe = cwd.replace(/[^a-zA-Z0-9]/g, "-");
32
+ if (safe.length <= 200)
33
+ return safe;
34
+ let n = 0;
35
+ for (let i = 0; i < cwd.length; i++)
36
+ n = (Math.imul(31, n) + cwd.charCodeAt(i)) | 0;
37
+ return `${safe.slice(0, 200)}-${Math.abs(n).toString(36)}`;
38
+ }
39
+ /** Positive absence is a read-only runner proof, never inferred from a failed resume or pending transcript read.
40
+ * Key derivation is tied to the audited Claude launch version; re-check it with each Claude version audit. */
41
+ export async function nativeClaudeSessionState(cwd, sessionId, current = () => true, roots = nativePaneTranscriptRoots()) {
42
+ if (!validNativeSessionId("claude-code", sessionId))
43
+ return "unknown";
44
+ let reader;
45
+ try {
46
+ const canonical = await realpath(cwd);
47
+ if (!current() || comparable(canonical) !== comparable(cwd))
48
+ return "unknown";
49
+ await realDirectory(roots.claude);
50
+ let parent = roots.claude;
51
+ // Check every existing directory; a junction/link/access error never becomes ENOENT evidence.
52
+ for (const name of ["projects", nativeClaudeProjectKey(canonical), `${sessionId}.jsonl`]) {
53
+ const path = join(parent, name);
54
+ let stat;
55
+ try {
56
+ stat = await lstat(path);
57
+ }
58
+ catch (error) {
59
+ if (!missing(error))
60
+ return "unknown";
61
+ await realDirectory(parent);
62
+ try {
63
+ await lstat(path);
64
+ return "unknown";
65
+ }
66
+ catch (again) {
67
+ return missing(again) && current() ? "absent" : "unknown";
68
+ }
69
+ }
70
+ if (name.endsWith(".jsonl")) {
71
+ regular(stat);
72
+ if (stat.size === 0)
73
+ return "unknown";
74
+ }
75
+ else
76
+ await realDirectory(path);
77
+ parent = path;
78
+ }
79
+ reader = new NativePaneTranscriptReader("claude-code", cwd, sessionId, roots);
80
+ const proof = await reader.baseline(undefined, current);
81
+ return current() && proof.state === "ready" ? "saved" : "unknown";
82
+ }
83
+ catch {
84
+ return "unknown";
85
+ }
86
+ finally {
87
+ await reader?.close();
88
+ }
89
+ }
90
+ /** Complete, bounded absence proof, distinct from the transcript reader's incremental "pending" result.
91
+ * A matching archive, stale metadata, incomplete walk, WAL, unsafe file or lost lease is unknown, never absence. */
92
+ export async function nativeCodexSessionState(cwd, sessionId, current = () => true, roots = nativePaneTranscriptRoots()) {
93
+ if (!validNativeSessionId("codex", sessionId) || sessionId !== sessionId.toLowerCase())
94
+ return "unknown";
95
+ const deadline = performance.now() + 1250, live = () => current() && performance.now() < deadline;
96
+ const observed = new Map(), matches = [];
97
+ const same = (a, b) => sameFile(a, b) && a.size === b.size && a.mtimeMs === b.mtimeMs && a.ctimeMs === b.ctimeMs;
98
+ const inspect = async (path) => { if (!live())
99
+ throw Error("Expired proof"); try {
100
+ const st = await lstat(path);
101
+ observed.set(path, st);
102
+ return st;
103
+ }
104
+ catch (error) {
105
+ if (!missing(error))
106
+ throw error;
107
+ observed.set(path, null);
108
+ return null;
109
+ } };
110
+ const unchanged = async () => { for (const [path, before] of observed) {
111
+ if (!live())
112
+ return false;
113
+ let after;
114
+ try {
115
+ after = await lstat(path);
116
+ }
117
+ catch (error) {
118
+ if (!missing(error))
119
+ return false;
120
+ after = null;
121
+ }
122
+ if (before ? (!after || !same(before, after)) : after)
123
+ return false;
124
+ } return live(); };
125
+ let entries = 0, dirs = 0;
126
+ try {
127
+ const canonical = await realpath(cwd);
128
+ if (!live() || comparable(canonical) !== comparable(cwd))
129
+ return "unknown";
130
+ await realDirectory(roots.codex);
131
+ await inspect(roots.codex);
132
+ const walk = async (folder, depth, archive) => {
133
+ if (++dirs > 1024)
134
+ throw Error("Proof scan bound");
135
+ const stat = await inspect(folder);
136
+ if (!stat)
137
+ return;
138
+ await realDirectory(folder);
139
+ const dir = await opendir(folder);
140
+ for await (const entry of dir) {
141
+ if (!live() || ++entries > 16384)
142
+ throw Error("Proof scan bound");
143
+ const path = join(folder, entry.name);
144
+ if (entry.isSymbolicLink())
145
+ throw Error("Unsafe proof entry");
146
+ if (entry.name.toLowerCase().includes(sessionId) && !entry.name.endsWith(`-${sessionId}.jsonl`))
147
+ throw Error("Unknown exact-ID filename");
148
+ if (entry.name.endsWith(`-${sessionId}.jsonl`)) {
149
+ if (archive || !entry.isFile() || entry.isSymbolicLink())
150
+ throw Error("Archived or unsafe exact match");
151
+ const st = await inspect(path);
152
+ if (!st)
153
+ throw Error("Match changed");
154
+ regular(st);
155
+ if (!st.size)
156
+ throw Error("Incomplete match");
157
+ matches.push(path);
158
+ }
159
+ else if (depth < 3 && /^\d{2,4}$/.test(entry.name)) {
160
+ if (!entry.isDirectory() || entry.isSymbolicLink())
161
+ throw Error("Unsafe date directory");
162
+ await walk(path, depth + 1, archive);
163
+ }
164
+ else if (entry.isDirectory())
165
+ throw Error("Unknown proof layout");
166
+ }
167
+ };
168
+ await walk(join(roots.codex, "sessions"), 0, false);
169
+ await walk(join(roots.codex, "archived_sessions"), 0, true);
170
+ if (matches.length > 1)
171
+ return "unknown";
172
+ if (matches.length === 1) {
173
+ const reader = new NativePaneTranscriptReader("codex", canonical, sessionId, roots);
174
+ try {
175
+ let proof;
176
+ do {
177
+ proof = await reader.baseline(undefined, live);
178
+ } while (live() && proof.state === "pending");
179
+ return proof.state === "ready" && proof.complete && await unchanged() ? "saved" : "unknown";
180
+ }
181
+ finally {
182
+ await reader.close();
183
+ }
184
+ }
185
+ // No rollouts is not sufficient if Codex retains metadata for that ID. Never open its DB in normal WAL mode.
186
+ const index = join(roots.codex, "session_index.jsonl"), indexStat = await inspect(index);
187
+ if (indexStat) {
188
+ regular(indexStat);
189
+ if (indexStat.size > 16 * 1024 * 1024)
190
+ return "unknown";
191
+ const handle = await open(index, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
192
+ try {
193
+ if (!same(indexStat, await handle.stat()))
194
+ return "unknown";
195
+ const text = decode(await bytes(handle, 0, indexStat.size));
196
+ for (const line of text.split(/\r?\n/)) {
197
+ if (!live())
198
+ return "unknown";
199
+ if (line) {
200
+ const entry = record(line);
201
+ if (typeof entry.id !== "string" || !validNativeSessionId("codex", entry.id) || entry.id.toLowerCase() === sessionId)
202
+ return "unknown";
203
+ }
204
+ }
205
+ }
206
+ finally {
207
+ await handle.close();
208
+ }
209
+ }
210
+ const profile = await opendir(roots.codex);
211
+ for await (const entry of profile) {
212
+ if (!live() || ++entries > 16384)
213
+ return "unknown";
214
+ if (/^state_.*\.sqlite(?:-wal|-shm)?$/.test(entry.name) && !/^state_5\.sqlite(?:-wal|-shm)?$/.test(entry.name))
215
+ return "unknown";
216
+ }
217
+ const dbPath = join(roots.codex, "state_5.sqlite"), db = await inspect(dbPath), wal = await inspect(dbPath + "-wal");
218
+ if (wal) {
219
+ regular(wal);
220
+ if (wal.size)
221
+ return "unknown";
222
+ }
223
+ if (db) {
224
+ regular(db);
225
+ if (!db.size || db.size > 128 * 1024 * 1024)
226
+ return "unknown";
227
+ if (!await codexIndexHasNoThread(dbPath, sessionId, live))
228
+ return "unknown";
229
+ }
230
+ await realDirectory(roots.codex);
231
+ return await unchanged() ? "absent" : "unknown";
232
+ }
233
+ catch {
234
+ return "unknown";
235
+ }
236
+ }
237
+ /** Reject directory links/junctions, including an ancestor swapped outside a configured provider root. */
238
+ async function realDirectory(path) {
239
+ const absolute = resolve(path), root = parse(absolute).root;
240
+ let current = root;
241
+ for (const segment of absolute.slice(root.length).split(/[\\/]/).filter(Boolean)) {
242
+ current = join(current, segment);
243
+ const stat = await lstat(current);
244
+ if (!stat.isDirectory() || stat.isSymbolicLink())
245
+ throw Error("Pane transcript directory is not a real directory");
246
+ }
247
+ if (comparable(await realpath(absolute)) !== comparable(absolute))
248
+ throw Error("Pane transcript directory escaped its configured root");
249
+ }
250
+ async function bytes(file, offset, length) {
251
+ const buffer = Buffer.alloc(length);
252
+ let count = 0;
253
+ while (count < length) {
254
+ const read = await file.read(buffer, count, length - count, offset + count);
255
+ if (!read.bytesRead)
256
+ break;
257
+ count += read.bytesRead;
258
+ }
259
+ return buffer.subarray(0, count);
260
+ }
261
+ function decode(value) { return new TextDecoder("utf-8", { fatal: true }).decode(value); }
262
+ function record(line) {
263
+ try {
264
+ const value = JSON.parse(line);
265
+ if (!value || typeof value !== "object" || Array.isArray(value))
266
+ throw Error();
267
+ return value;
268
+ }
269
+ catch {
270
+ throw Error("Pane transcript contains an invalid JSON record");
271
+ }
272
+ }
273
+ function metadata(lines, provider, sessionId, cwd) {
274
+ if (provider === "codex") {
275
+ const first = record(lines[0] ?? "null");
276
+ if (first?.type !== "session_meta" || first.payload?.id !== sessionId || comparable(String(first.payload?.cwd ?? "")) !== comparable(cwd))
277
+ throw Error("Pane transcript session metadata differs from its pinned conversation");
278
+ return;
279
+ }
280
+ let proved = false;
281
+ for (const line of lines) {
282
+ const entry = record(line);
283
+ if (entry.sessionId !== undefined && entry.sessionId !== sessionId || entry.cwd !== undefined && comparable(String(entry.cwd)) !== comparable(cwd)
284
+ || entry.isSidechain === true)
285
+ throw Error("Pane transcript session metadata differs from its pinned conversation");
286
+ if (entry.sessionId === sessionId && typeof entry.cwd === "string" && comparable(entry.cwd) === comparable(cwd))
287
+ proved = true;
288
+ }
289
+ if (!proved)
290
+ throw Error("Pane transcript has no exact session and workspace proof yet");
291
+ }
292
+ function ownedHeader(head, provider, sessionId, cwd) {
293
+ const lines = [];
294
+ for (let start = 0; start < head.length;) {
295
+ const end = head.indexOf(10, start);
296
+ if (end < 0)
297
+ break;
298
+ const line = decode(head.subarray(start, end)).replace(/\r$/, "");
299
+ start = end + 1;
300
+ if (!line)
301
+ continue;
302
+ const entry = record(line);
303
+ lines.push(line);
304
+ if (provider === "codex" || entry.sessionId === sessionId && typeof entry.cwd === "string") {
305
+ metadata(lines, provider, sessionId, cwd);
306
+ return head.subarray(0, start);
307
+ }
308
+ if (entry.sessionId !== undefined && entry.sessionId !== sessionId || entry.cwd !== undefined && comparable(String(entry.cwd)) !== comparable(cwd)
309
+ || entry.isSidechain === true)
310
+ throw Error("Pane transcript session metadata differs from its pinned conversation");
311
+ }
312
+ if (!lines.length)
313
+ throw Error("Pane transcript metadata is incomplete");
314
+ throw Error("Pane transcript has no exact session and workspace proof yet");
315
+ }
316
+ export class NativePaneTranscriptReader {
317
+ provider;
318
+ cwd;
319
+ sessionId;
320
+ roots;
321
+ busy = false;
322
+ pinnedFile;
323
+ metadataBytes = 0;
324
+ discovery;
325
+ discoveryMatches = [];
326
+ canonicalCwd;
327
+ stopped = false;
328
+ initial;
329
+ constructor(provider, cwd, sessionId, roots = nativePaneTranscriptRoots()) {
330
+ this.provider = provider;
331
+ this.cwd = cwd;
332
+ this.sessionId = sessionId;
333
+ this.roots = roots;
334
+ if (!validNativeSessionId(provider, sessionId))
335
+ throw Error("Invalid pane transcript session identity");
336
+ this.initial = { sessionId, offset: 0, fileId: null, anchor: EMPTY };
337
+ }
338
+ /** At most one filesystem operation remains in flight even if a transport deadline abandons its result. */
339
+ async read(cursor = this.initial, current = () => true) {
340
+ validatePaneTranscriptCursor(cursor, this.sessionId);
341
+ if (this.stopped)
342
+ throw Error("Pane transcript reader is closed");
343
+ if (this.busy)
344
+ throw Error("Pane transcript read is already pending");
345
+ this.busy = true;
346
+ try {
347
+ return await this.readOwned(cursor, current);
348
+ }
349
+ finally {
350
+ this.busy = false;
351
+ }
352
+ }
353
+ /** At most 4 MiB of tail content, independent of history size; no historical text leaves the runner. */
354
+ async baseline(cursor = this.initial, current = () => true) {
355
+ validatePaneTranscriptCursor(cursor, this.sessionId);
356
+ if (cursor.offset !== 0 || this.busy || this.stopped)
357
+ throw Error("Native transcript baseline is not available");
358
+ this.busy = true;
359
+ const check = () => { if (this.stopped || !current())
360
+ throw Error("Pane baseline lease expired"); };
361
+ const pending = () => ({ state: "pending", cursor, complete: false, turnKnown: false, openTurn: null });
362
+ try {
363
+ check();
364
+ const found = this.pinnedFile ? { path: this.pinnedFile } : await this.locate(current), path = found.path;
365
+ check();
366
+ if (!path)
367
+ return pending();
368
+ await realDirectory(dirname(path));
369
+ const before = await lstat(path);
370
+ regular(before);
371
+ const file = await open(path, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
372
+ try {
373
+ const stat = await file.stat();
374
+ regular(stat);
375
+ if (!sameFile(before, stat) || comparable(await realpath(path)) !== comparable(path))
376
+ throw Error("Pane baseline changed while opening");
377
+ const header = ownedHeader(await bytes(file, 0, Math.min(stat.size, this.metadataBytes || META)), this.provider, this.sessionId, this.cwd);
378
+ const fileId = hash(`${stat.dev}:${stat.ino}:${stat.birthtimeMs}:${hash(header.subarray(0, header.indexOf(10) + 1))}`);
379
+ if (cursor.fileId && cursor.fileId !== fileId)
380
+ throw Error("Pane baseline file identity changed");
381
+ const start = Math.max(0, stat.size - 4 * 1024 * 1024), tail = await bytes(file, start, stat.size - start), last = tail.lastIndexOf(10);
382
+ if (last < 0)
383
+ return pending();
384
+ const first = start ? tail.indexOf(10) + 1 : 0, offset = start + last + 1;
385
+ const state = { openTurnId: "", openTurn: null, turnKnown: start === 0 || this.provider !== "codex" };
386
+ for (const line of decode(tail.subarray(first, last + 1)).split(/\r?\n/))
387
+ if (line) {
388
+ const entry = record(line);
389
+ if (this.provider === "codex") {
390
+ if (entry.type === "session_meta")
391
+ metadata([line], this.provider, this.sessionId, this.cwd);
392
+ const orphanEnd = !state.turnKnown && entry.type === "event_msg" && ["task_complete", "turn_aborted"].includes(entry.payload?.type);
393
+ if (!orphanEnd)
394
+ codexTurnRecord(entry, state, []);
395
+ }
396
+ else if (entry.sessionId !== undefined && entry.sessionId !== this.sessionId || entry.cwd !== undefined && comparable(String(entry.cwd)) !== comparable(this.cwd) || entry.isSidechain === true)
397
+ throw Error("Pane baseline belongs to another conversation");
398
+ }
399
+ const anchor = await bytes(file, Math.max(0, offset - ANCHOR), Math.min(offset, ANCHOR));
400
+ if (hash(await bytes(file, start, tail.length)) !== hash(tail) || hash(await bytes(file, 0, header.length)) !== hash(header))
401
+ throw Error("Pane baseline bytes changed during read");
402
+ const after = await file.stat(), named = await lstat(path);
403
+ regular(named);
404
+ if (!sameFile(stat, after) || !sameFile(stat, named) || after.size < stat.size || after.size !== named.size || after.mtimeMs !== named.mtimeMs || after.ctimeMs !== named.ctimeMs
405
+ || after.size === stat.size && (after.mtimeMs !== stat.mtimeMs || after.ctimeMs !== stat.ctimeMs))
406
+ throw Error("Pane baseline changed during read");
407
+ check();
408
+ this.pinnedFile = path;
409
+ this.metadataBytes = header.length;
410
+ return { state: "ready", cursor: { sessionId: this.sessionId, offset, fileId, anchor: hash(anchor) }, complete: offset === stat.size && after.size === stat.size,
411
+ turnKnown: state.turnKnown, openTurn: state.turnKnown ? state.openTurn : null };
412
+ }
413
+ finally {
414
+ await file.close();
415
+ }
416
+ }
417
+ catch (error) {
418
+ if (!missing(error))
419
+ throw error;
420
+ if (cursor.fileId || this.pinnedFile)
421
+ throw Error("Pinned pane baseline disappeared");
422
+ return pending();
423
+ }
424
+ finally {
425
+ this.busy = false;
426
+ }
427
+ }
428
+ async close() { this.stopped = true; await this.discovery?.return(undefined); this.discovery = undefined; }
429
+ async *candidates() {
430
+ const root = this.roots[this.provider === "codex" ? "codex" : "claude"];
431
+ if (this.provider === "claude-code") {
432
+ this.canonicalCwd ??= await realpath(this.cwd);
433
+ if (comparable(this.canonicalCwd) !== comparable(this.cwd))
434
+ throw Error("Pane transcript workspace is not canonical");
435
+ const folder = join(root, "projects", nativeClaudeProjectKey(this.canonicalCwd));
436
+ try {
437
+ await realDirectory(folder);
438
+ yield join(folder, `${this.sessionId}.jsonl`);
439
+ return;
440
+ }
441
+ catch (error) {
442
+ if (missing(error))
443
+ return;
444
+ throw error;
445
+ }
446
+ }
447
+ let entries = 0, directories = 0;
448
+ const sessionId = this.sessionId;
449
+ const walk = async function* (folder, depth) {
450
+ if (++directories > 1024)
451
+ throw Error("Pane transcript discovery exceeded its bound");
452
+ let dir;
453
+ try {
454
+ await realDirectory(folder);
455
+ dir = await opendir(folder);
456
+ }
457
+ catch (error) {
458
+ if (missing(error))
459
+ return;
460
+ throw error;
461
+ }
462
+ for await (const entry of dir) {
463
+ if (++entries > 16_384)
464
+ throw Error("Pane transcript discovery exceeded its bound");
465
+ if (entry.name.endsWith(`-${sessionId}.jsonl`)) {
466
+ if (!entry.isFile() || entry.isSymbolicLink())
467
+ throw Error("Pinned pane transcript is not a regular file");
468
+ yield join(folder, entry.name);
469
+ }
470
+ else if (depth < 3 && /^\d{2,4}$/.test(entry.name)) {
471
+ if (!entry.isDirectory() || entry.isSymbolicLink())
472
+ throw Error("Pane transcript date directory is unsafe");
473
+ yield null;
474
+ yield* walk(join(folder, entry.name), depth + 1);
475
+ }
476
+ else
477
+ yield null;
478
+ }
479
+ };
480
+ yield* walk(join(root, "sessions"), 0);
481
+ yield* walk(join(root, "archived_sessions"), 0);
482
+ }
483
+ async locate(current) {
484
+ if (!this.discovery) {
485
+ this.discovery = this.candidates();
486
+ this.discoveryMatches = [];
487
+ }
488
+ const started = performance.now();
489
+ try {
490
+ for (let step = 0; step < 128; step++) {
491
+ if (!current() || this.stopped)
492
+ throw Error("Pane transcript lease expired");
493
+ const next = await this.discovery.next();
494
+ if (next.done) {
495
+ this.discovery = undefined;
496
+ if (this.discoveryMatches.length > 1)
497
+ throw Error("Pinned pane transcript has ambiguous matching files");
498
+ return { path: this.discoveryMatches[0], pending: false };
499
+ }
500
+ if (next.value)
501
+ this.discoveryMatches.push(next.value);
502
+ if (performance.now() - started >= 250)
503
+ break;
504
+ }
505
+ // Keep a bounded iterator across looks: a cold disk/AV scan must not restart discovery forever.
506
+ return { pending: true };
507
+ }
508
+ catch (error) {
509
+ await this.discovery?.return(undefined);
510
+ this.discovery = undefined;
511
+ throw error;
512
+ }
513
+ }
514
+ async readOwned(cursor, current) {
515
+ const check = () => { if (!current() || this.stopped)
516
+ throw Error("Pane transcript lease expired"); };
517
+ check();
518
+ const found = this.pinnedFile ? { path: this.pinnedFile, pending: false } : await this.locate(current), path = found.path;
519
+ check();
520
+ if (!path) {
521
+ if (cursor.fileId && !found.pending)
522
+ throw Error("Pinned pane transcript disappeared");
523
+ return { state: "pending", cursor, lines: [], data: "", complete: false, gap: false };
524
+ }
525
+ let file;
526
+ try {
527
+ await realDirectory(dirname(path));
528
+ const before = await lstat(path);
529
+ regular(before);
530
+ file = await open(path, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
531
+ try {
532
+ const stat = await file.stat();
533
+ regular(stat);
534
+ if (!sameFile(before, stat) || comparable(await realpath(path)) !== comparable(path))
535
+ throw Error("Pane transcript changed while opening");
536
+ const head = await bytes(file, 0, Math.min(stat.size, this.metadataBytes || META));
537
+ const header = ownedHeader(head, this.provider, this.sessionId, this.cwd);
538
+ // File identity excludes append-sensitive mtime/size; its first record is immutable session metadata.
539
+ const firstEnd = header.indexOf(10) + 1;
540
+ const fileId = hash(`${stat.dev}:${stat.ino}:${stat.birthtimeMs}:${hash(header.subarray(0, firstEnd))}`);
541
+ if (cursor.fileId !== null && cursor.fileId !== fileId || stat.size < cursor.offset)
542
+ throw Error("Pane transcript identity changed or was truncated");
543
+ const anchor = await bytes(file, Math.max(0, cursor.offset - ANCHOR), Math.min(cursor.offset, ANCHOR));
544
+ if (hash(anchor) !== cursor.anchor)
545
+ throw Error("Pane transcript checkpoint bytes changed");
546
+ const chunk = await bytes(file, cursor.offset, Math.min(CHUNK, stat.size - cursor.offset));
547
+ let start = 0, consumed = 0, skipping = cursor.skipping === true, gap = skipping;
548
+ if (skipping) {
549
+ const next = chunk.indexOf(10);
550
+ if (next < 0)
551
+ start = consumed = chunk.length;
552
+ else {
553
+ start = consumed = next + 1;
554
+ skipping = false;
555
+ }
556
+ }
557
+ const last = chunk.lastIndexOf(10);
558
+ const completeBytes = last < start ? Buffer.alloc(0) : chunk.subarray(start, last + 1);
559
+ consumed = Math.max(consumed, start + completeBytes.length);
560
+ if (!skipping && !consumed && chunk.length === CHUNK) {
561
+ consumed = chunk.length;
562
+ skipping = true;
563
+ gap = true;
564
+ }
565
+ const lines = decode(completeBytes).split(/\r?\n/).filter(Boolean);
566
+ // Reject corrupted JSON instead of dropping a possible user or turn-boundary record.
567
+ for (const line of lines) {
568
+ const entry = record(line);
569
+ if (this.provider === "claude-code" && (entry.sessionId !== undefined && entry.sessionId !== this.sessionId
570
+ || entry.cwd !== undefined && comparable(String(entry.cwd)) !== comparable(this.cwd) || entry.isSidechain === true))
571
+ throw Error("Pane transcript record belongs to another conversation");
572
+ if (this.provider === "codex" && entry.type === "session_meta")
573
+ metadata([line], this.provider, this.sessionId, this.cwd);
574
+ }
575
+ const offset = cursor.offset + consumed;
576
+ const nextAnchor = await bytes(file, Math.max(0, offset - ANCHOR), Math.min(offset, ANCHOR));
577
+ if (hash(await bytes(file, cursor.offset, consumed)) !== hash(chunk.subarray(0, consumed))
578
+ || hash(await bytes(file, Math.max(0, cursor.offset - ANCHOR), Math.min(cursor.offset, ANCHOR))) !== cursor.anchor)
579
+ throw Error("Pane transcript checkpoint bytes changed during its read");
580
+ const after = await file.stat(), named = await lstat(path);
581
+ regular(named);
582
+ if (!sameFile(stat, after) || !sameFile(stat, named) || after.size < stat.size
583
+ || after.size !== named.size || after.mtimeMs !== named.mtimeMs || after.ctimeMs !== named.ctimeMs
584
+ || after.size === stat.size && (after.mtimeMs !== stat.mtimeMs || after.ctimeMs !== stat.ctimeMs))
585
+ throw Error("Pane transcript changed during its read");
586
+ check();
587
+ this.pinnedFile = path;
588
+ this.metadataBytes = header.length;
589
+ return { state: "ready", cursor: { sessionId: this.sessionId, fileId, offset, anchor: hash(nextAnchor), ...(skipping ? { skipping: true } : {}) }, lines,
590
+ data: completeBytes.toString("base64"), gap, complete: !skipping && offset === stat.size && after.size === stat.size };
591
+ }
592
+ finally {
593
+ await file.close();
594
+ }
595
+ }
596
+ catch (error) {
597
+ if (!missing(error))
598
+ throw error;
599
+ if (cursor.fileId || this.pinnedFile)
600
+ throw Error("Pinned pane transcript disappeared");
601
+ return { state: "pending", cursor, lines: [], data: "", gap: false, complete: false };
602
+ }
603
+ }
604
+ }
605
+ //# sourceMappingURL=runtime-pane-transcript.js.map