pi-agent-browser-native 0.9.3 → 0.9.4

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 (391) hide show
  1. package/CHANGELOG.md +77 -5
  2. package/README.md +103 -81
  3. package/dist/extensions/agent-browser/index.js +43057 -2031
  4. package/dist/extensions/agent-browser/lib/argv-descriptor.js +49 -26
  5. package/dist/extensions/agent-browser/lib/argv-grammar.js +82 -93
  6. package/dist/extensions/agent-browser/lib/bash-guard.js +129 -126
  7. package/dist/extensions/agent-browser/lib/batch-lifecycle.js +112 -51
  8. package/dist/extensions/agent-browser/lib/browser-execution-claim-codec.js +61 -0
  9. package/dist/extensions/agent-browser/lib/browser-execution-claim-storage.js +232 -0
  10. package/dist/extensions/agent-browser/lib/browser-execution-claims.js +202 -0
  11. package/dist/extensions/agent-browser/lib/browser-execution-identity.js +77 -0
  12. package/dist/extensions/agent-browser/lib/browser-journal-branch.js +98 -0
  13. package/dist/extensions/agent-browser/lib/browser-journal-contracts.js +1 -0
  14. package/dist/extensions/agent-browser/lib/browser-journal-projection.js +221 -0
  15. package/dist/extensions/agent-browser/lib/browser-journal-reader.js +89 -0
  16. package/dist/extensions/agent-browser/lib/browser-journal-replay.js +246 -0
  17. package/dist/extensions/agent-browser/lib/browser-journal.js +103 -394
  18. package/dist/extensions/agent-browser/lib/browser-legacy-pages.js +220 -0
  19. package/dist/extensions/agent-browser/lib/browser-legacy-projection.js +282 -0
  20. package/dist/extensions/agent-browser/lib/browser-legacy-types.js +1 -0
  21. package/dist/extensions/agent-browser/lib/browser-session-conversion-stream.js +217 -0
  22. package/dist/extensions/agent-browser/lib/browser-session-conversion.js +80 -335
  23. package/dist/extensions/agent-browser/lib/browser-transcript-contracts.js +35 -0
  24. package/dist/extensions/agent-browser/lib/browser-transcript-validation.js +166 -0
  25. package/dist/extensions/agent-browser/lib/browser-transcript.js +137 -82
  26. package/dist/extensions/agent-browser/lib/browser-value-parsing.js +15 -0
  27. package/dist/extensions/agent-browser/lib/command-capabilities.js +340 -0
  28. package/dist/extensions/agent-browser/lib/command-policy.js +107 -88
  29. package/dist/extensions/agent-browser/lib/command-taxonomy.js +49 -322
  30. package/dist/extensions/agent-browser/lib/config-policy.js +138 -343
  31. package/dist/extensions/agent-browser/lib/config-providers.js +71 -0
  32. package/dist/extensions/agent-browser/lib/config-validation.js +218 -0
  33. package/dist/extensions/agent-browser/lib/config.js +19 -7
  34. package/dist/extensions/agent-browser/lib/electron/cdp.js +15 -7
  35. package/dist/extensions/agent-browser/lib/electron/cleanup.js +134 -55
  36. package/dist/extensions/agent-browser/lib/electron/discovery-darwin.js +109 -0
  37. package/dist/extensions/agent-browser/lib/electron/discovery-desktop.js +136 -0
  38. package/dist/extensions/agent-browser/lib/electron/discovery-evidence.js +89 -0
  39. package/dist/extensions/agent-browser/lib/electron/discovery-linux.js +93 -0
  40. package/dist/extensions/agent-browser/lib/electron/discovery-packages.js +162 -0
  41. package/dist/extensions/agent-browser/lib/electron/discovery-types.js +2 -0
  42. package/dist/extensions/agent-browser/lib/electron/discovery.js +140 -549
  43. package/dist/extensions/agent-browser/lib/electron/launch-monitor.js +102 -0
  44. package/dist/extensions/agent-browser/lib/electron/launch-process.js +209 -0
  45. package/dist/extensions/agent-browser/lib/electron/launch-types.js +2 -0
  46. package/dist/extensions/agent-browser/lib/electron/launch.js +249 -354
  47. package/dist/extensions/agent-browser/lib/executable-path.js +21 -12
  48. package/dist/extensions/agent-browser/lib/execution-cwd.js +35 -18
  49. package/dist/extensions/agent-browser/lib/input-modes/electron.js +162 -121
  50. package/dist/extensions/agent-browser/lib/input-modes/job.js +116 -313
  51. package/dist/extensions/agent-browser/lib/input-modes/lookup-network-evidence.js +104 -0
  52. package/dist/extensions/agent-browser/lib/input-modes/lookup-plan.js +132 -0
  53. package/dist/extensions/agent-browser/lib/input-modes/lookup-redaction.js +57 -0
  54. package/dist/extensions/agent-browser/lib/input-modes/lookup-source-evidence.js +151 -0
  55. package/dist/extensions/agent-browser/lib/input-modes/lookup-workspace.js +142 -0
  56. package/dist/extensions/agent-browser/lib/input-modes/lookups.js +57 -412
  57. package/dist/extensions/agent-browser/lib/input-modes/params.js +63 -17
  58. package/dist/extensions/agent-browser/lib/input-modes/qa-analysis.js +268 -0
  59. package/dist/extensions/agent-browser/lib/input-modes/qa-presentation.js +117 -0
  60. package/dist/extensions/agent-browser/lib/input-modes/script-child.js +396 -0
  61. package/dist/extensions/agent-browser/lib/input-modes/script-protocol.js +86 -0
  62. package/dist/extensions/agent-browser/lib/input-modes/script-types.js +1 -0
  63. package/dist/extensions/agent-browser/lib/input-modes/script-validation.js +60 -0
  64. package/dist/extensions/agent-browser/lib/input-modes/script.js +60 -409
  65. package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +218 -128
  66. package/dist/extensions/agent-browser/lib/input-modes/shared.js +15 -4
  67. package/dist/extensions/agent-browser/lib/input-modes/types.js +56 -7
  68. package/dist/extensions/agent-browser/lib/json-schema.js +22 -10
  69. package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +17 -5
  70. package/dist/extensions/agent-browser/lib/managed-session-policy-lock.js +92 -425
  71. package/dist/extensions/agent-browser/lib/managed-session-posix-storage.js +58 -0
  72. package/dist/extensions/agent-browser/lib/managed-session-project-identity.js +244 -0
  73. package/dist/extensions/agent-browser/lib/managed-session-restore-context.js +84 -0
  74. package/dist/extensions/agent-browser/lib/managed-session-restore-policy.js +119 -0
  75. package/dist/extensions/agent-browser/lib/managed-session-restore-state.js +83 -0
  76. package/dist/extensions/agent-browser/lib/managed-session-restore.js +168 -300
  77. package/dist/extensions/agent-browser/lib/managed-session-snapshot-records.js +277 -0
  78. package/dist/extensions/agent-browser/lib/managed-session-snapshots.js +128 -305
  79. package/dist/extensions/agent-browser/lib/managed-session-storage.js +56 -253
  80. package/dist/extensions/agent-browser/lib/native-confirmation.js +140 -0
  81. package/dist/extensions/agent-browser/lib/native-output.js +43 -9
  82. package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +106 -59
  83. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-merge.js +14 -6
  84. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +109 -57
  85. package/dist/extensions/agent-browser/lib/orchestration/browser-run/browser-observation-result.js +82 -0
  86. package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +164 -60
  87. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostic-values.js +31 -0
  88. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +152 -781
  89. package/dist/extensions/agent-browser/lib/orchestration/browser-run/electron-observation.js +202 -0
  90. package/dist/extensions/agent-browser/lib/orchestration/browser-run/electron-text-diagnostics.js +109 -0
  91. package/dist/extensions/agent-browser/lib/orchestration/browser-run/fill-diagnostics.js +119 -0
  92. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-action-recovery.js +147 -0
  93. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-actions.js +144 -0
  94. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-content.js +123 -0
  95. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-contracts.js +1 -0
  96. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-details.js +156 -0
  97. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-electron.js +179 -0
  98. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-evidence.js +39 -0
  99. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-missing-binary.js +89 -0
  100. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-recovery.js +97 -0
  101. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-redaction.js +106 -0
  102. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-timeout.js +110 -0
  103. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +41 -538
  104. package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +199 -154
  105. package/dist/extensions/agent-browser/lib/orchestration/browser-run/interaction-diagnostics.js +290 -0
  106. package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-close.js +167 -0
  107. package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-inspection.js +108 -0
  108. package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-policy.js +127 -205
  109. package/dist/extensions/agent-browser/lib/orchestration/browser-run/native-helper-observation.js +65 -0
  110. package/dist/extensions/agent-browser/lib/orchestration/browser-run/observation-types.js +1 -0
  111. package/dist/extensions/agent-browser/lib/orchestration/browser-run/overlay-diagnostics.js +120 -0
  112. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.js +113 -30
  113. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js +109 -28
  114. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter-data.js +150 -0
  115. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +138 -253
  116. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-rendered-text.js +147 -0
  117. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.js +59 -24
  118. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-artifacts.js +159 -0
  119. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-command.js +131 -0
  120. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-contracts.js +1 -0
  121. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-daemon.js +93 -0
  122. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-failure.js +42 -0
  123. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-guards.js +242 -0
  124. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-input.js +75 -0
  125. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-observations.js +92 -0
  126. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-page-selection.js +254 -0
  127. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-page-state.js +121 -0
  128. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-refs.js +130 -0
  129. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-resources.js +114 -0
  130. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-semantic.js +121 -0
  131. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-session-plan.js +222 -0
  132. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-timeouts.js +68 -0
  133. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +176 -1123
  134. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-analysis.js +191 -0
  135. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-confirmation.js +152 -0
  136. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-diagnostics.js +182 -0
  137. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-electron.js +150 -0
  138. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle-contracts.js +1 -0
  139. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle-phase-contracts.js +1 -0
  140. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle-phase.js +115 -0
  141. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle.js +256 -0
  142. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-managed-contracts.js +1 -0
  143. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-managed.js +256 -0
  144. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-native-phase-contracts.js +1 -0
  145. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-native-phase.js +93 -0
  146. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-native.js +113 -0
  147. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-navigation-contracts.js +1 -0
  148. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-navigation.js +316 -0
  149. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-ownership.js +28 -0
  150. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-page-phase-contracts.js +1 -0
  151. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-page-phase.js +142 -0
  152. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-presentation-contracts.js +1 -0
  153. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-presentation.js +333 -0
  154. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-publication-phase-contracts.js +1 -0
  155. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-publication-phase.js +71 -0
  156. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-publication.js +201 -0
  157. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-receipts.js +183 -0
  158. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-refs.js +200 -0
  159. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-tabs.js +142 -0
  160. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +18 -968
  161. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.js +23 -13
  162. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-receipt-reconciliation.js +198 -0
  163. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery-contracts.js +1 -0
  164. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery-presentation.js +154 -0
  165. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery.js +68 -151
  166. package/dist/extensions/agent-browser/lib/orchestration/browser-run/screenshot-capture.js +14 -0
  167. package/dist/extensions/agent-browser/lib/orchestration/browser-run/screenshot-observation.js +169 -46
  168. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-commands.js +130 -0
  169. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-electron.js +210 -0
  170. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-observations.js +61 -0
  171. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-outcomes.js +187 -0
  172. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-refs.js +171 -0
  173. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-tabs.js +228 -0
  174. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +77 -765
  175. package/dist/extensions/agent-browser/lib/orchestration/browser-run/text-visibility-diagnostics.js +182 -0
  176. package/dist/extensions/agent-browser/lib/orchestration/browser-run/timeout-diagnostics.js +256 -0
  177. package/dist/extensions/agent-browser/lib/orchestration/browser-run/timeout-progress.js +108 -0
  178. package/dist/extensions/agent-browser/lib/orchestration/code-artifact-observation.js +39 -0
  179. package/dist/extensions/agent-browser/lib/orchestration/code-image-observation.js +119 -0
  180. package/dist/extensions/agent-browser/lib/orchestration/electron-host/branch.js +92 -0
  181. package/dist/extensions/agent-browser/lib/orchestration/electron-host/cleanup-result.js +58 -0
  182. package/dist/extensions/agent-browser/lib/orchestration/electron-host/cleanup.js +78 -0
  183. package/dist/extensions/agent-browser/lib/orchestration/electron-host/contracts.js +1 -0
  184. package/dist/extensions/agent-browser/lib/orchestration/electron-host/discovery.js +106 -0
  185. package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +48 -821
  186. package/dist/extensions/agent-browser/lib/orchestration/electron-host/policy.js +86 -0
  187. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-collection.js +69 -0
  188. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-data.js +167 -0
  189. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-presentation.js +164 -0
  190. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe.js +161 -0
  191. package/dist/extensions/agent-browser/lib/orchestration/electron-host/status.js +165 -0
  192. package/dist/extensions/agent-browser/lib/orchestration/execution-queue.js +21 -9
  193. package/dist/extensions/agent-browser/lib/orchestration/extension-artifact-preflight.js +211 -0
  194. package/dist/extensions/agent-browser/lib/orchestration/extension-artifacts.js +23 -0
  195. package/dist/extensions/agent-browser/lib/orchestration/extension-attachment-replay.js +99 -0
  196. package/dist/extensions/agent-browser/lib/orchestration/extension-branch-restore.js +275 -0
  197. package/dist/extensions/agent-browser/lib/orchestration/extension-code.js +280 -0
  198. package/dist/extensions/agent-browser/lib/orchestration/extension-command-admission.js +303 -0
  199. package/dist/extensions/agent-browser/lib/orchestration/extension-command-output.js +36 -0
  200. package/dist/extensions/agent-browser/lib/orchestration/extension-command-result.js +335 -0
  201. package/dist/extensions/agent-browser/lib/orchestration/extension-command-run.js +227 -0
  202. package/dist/extensions/agent-browser/lib/orchestration/extension-command-state.js +1 -0
  203. package/dist/extensions/agent-browser/lib/orchestration/extension-electron-ownership.js +204 -0
  204. package/dist/extensions/agent-browser/lib/orchestration/extension-execution-locks.js +139 -0
  205. package/dist/extensions/agent-browser/lib/orchestration/extension-execution-queue.js +24 -0
  206. package/dist/extensions/agent-browser/lib/orchestration/extension-host-coordination.js +98 -0
  207. package/dist/extensions/agent-browser/lib/orchestration/extension-host-run.js +295 -0
  208. package/dist/extensions/agent-browser/lib/orchestration/extension-intent-replay.js +41 -0
  209. package/dist/extensions/agent-browser/lib/orchestration/extension-invocation.js +7 -0
  210. package/dist/extensions/agent-browser/lib/orchestration/extension-lifecycle.js +102 -0
  211. package/dist/extensions/agent-browser/lib/orchestration/extension-managed-ownership.js +133 -0
  212. package/dist/extensions/agent-browser/lib/orchestration/extension-observation.js +120 -0
  213. package/dist/extensions/agent-browser/lib/orchestration/extension-prompt.js +180 -0
  214. package/dist/extensions/agent-browser/lib/orchestration/extension-recording.js +290 -0
  215. package/dist/extensions/agent-browser/lib/orchestration/extension-resource-contracts.js +1 -0
  216. package/dist/extensions/agent-browser/lib/orchestration/extension-resource-replay.js +269 -0
  217. package/dist/extensions/agent-browser/lib/orchestration/extension-result-state.js +113 -0
  218. package/dist/extensions/agent-browser/lib/orchestration/extension-runtime.js +146 -0
  219. package/dist/extensions/agent-browser/lib/orchestration/extension-script-leases.js +58 -0
  220. package/dist/extensions/agent-browser/lib/orchestration/extension-tool-boundary.js +62 -0
  221. package/dist/extensions/agent-browser/lib/orchestration/extension-version-check.js +54 -0
  222. package/dist/extensions/agent-browser/lib/orchestration/input-plan-types.js +1 -0
  223. package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +261 -185
  224. package/dist/extensions/agent-browser/lib/orchestration/input-redaction.js +62 -0
  225. package/dist/extensions/agent-browser/lib/orchestration/native-config.js +144 -0
  226. package/dist/extensions/agent-browser/lib/orchestration/native-root-launch.js +77 -0
  227. package/dist/extensions/agent-browser/lib/orchestration/native-session-defaults.js +210 -157
  228. package/dist/extensions/agent-browser/lib/orchestration/operation-paths.js +124 -58
  229. package/dist/extensions/agent-browser/lib/orchestration/output-file.js +197 -99
  230. package/dist/extensions/agent-browser/lib/orchestration/script-mode.js +199 -96
  231. package/dist/extensions/agent-browser/lib/owned-managed-session-context.js +55 -0
  232. package/dist/extensions/agent-browser/lib/page-target-batch.js +118 -0
  233. package/dist/extensions/agent-browser/lib/page-target-guards.js +50 -0
  234. package/dist/extensions/agent-browser/lib/page-target-navigation.js +104 -0
  235. package/dist/extensions/agent-browser/lib/page-target-validation.js +55 -246
  236. package/dist/extensions/agent-browser/lib/parsing.js +13 -4
  237. package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +133 -68
  238. package/dist/extensions/agent-browser/lib/playbook.js +16 -12
  239. package/dist/extensions/agent-browser/lib/process-child.js +284 -0
  240. package/dist/extensions/agent-browser/lib/process-environment.js +13 -6
  241. package/dist/extensions/agent-browser/lib/process-errors.js +23 -0
  242. package/dist/extensions/agent-browser/lib/process-identity.js +47 -15
  243. package/dist/extensions/agent-browser/lib/process-socket-storage.js +256 -0
  244. package/dist/extensions/agent-browser/lib/process-stdout.js +74 -0
  245. package/dist/extensions/agent-browser/lib/process.js +145 -536
  246. package/dist/extensions/agent-browser/lib/prompt-artifacts.js +287 -0
  247. package/dist/extensions/agent-browser/lib/prompt-policy.js +15 -194
  248. package/dist/extensions/agent-browser/lib/read-command.js +41 -0
  249. package/dist/extensions/agent-browser/lib/read-confirmation.js +131 -68
  250. package/dist/extensions/agent-browser/lib/recording-reservations.js +118 -45
  251. package/dist/extensions/agent-browser/lib/redaction-fields.js +75 -0
  252. package/dist/extensions/agent-browser/lib/redaction-json.js +149 -0
  253. package/dist/extensions/agent-browser/lib/redaction-url.js +88 -0
  254. package/dist/extensions/agent-browser/lib/results/action-contracts.js +1 -0
  255. package/dist/extensions/agent-browser/lib/results/action-recommendations.js +28 -271
  256. package/dist/extensions/agent-browser/lib/results/artifact-contracts.js +1 -0
  257. package/dist/extensions/agent-browser/lib/results/artifact-manifest-validation.js +133 -0
  258. package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +96 -94
  259. package/dist/extensions/agent-browser/lib/results/artifact-recommendations.js +73 -0
  260. package/dist/extensions/agent-browser/lib/results/categories.js +111 -54
  261. package/dist/extensions/agent-browser/lib/results/confirmation.js +29 -13
  262. package/dist/extensions/agent-browser/lib/results/editable-ref-evidence.js +62 -27
  263. package/dist/extensions/agent-browser/lib/results/electron-recommendations.js +83 -0
  264. package/dist/extensions/agent-browser/lib/results/envelope-decoding.js +48 -0
  265. package/dist/extensions/agent-browser/lib/results/envelope.js +90 -67
  266. package/dist/extensions/agent-browser/lib/results/evidence-contracts.js +1 -0
  267. package/dist/extensions/agent-browser/lib/results/failure-recommendations.js +180 -0
  268. package/dist/extensions/agent-browser/lib/results/network-routes.js +86 -45
  269. package/dist/extensions/agent-browser/lib/results/network.js +35 -12
  270. package/dist/extensions/agent-browser/lib/results/next-actions.js +49 -19
  271. package/dist/extensions/agent-browser/lib/results/presentation/artifact-files.js +320 -0
  272. package/dist/extensions/agent-browser/lib/results/presentation/artifact-format.js +138 -0
  273. package/dist/extensions/agent-browser/lib/results/presentation/artifact-images.js +113 -0
  274. package/dist/extensions/agent-browser/lib/results/presentation/artifact-verification.js +145 -0
  275. package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +99 -555
  276. package/dist/extensions/agent-browser/lib/results/presentation/batch-contracts.js +1 -0
  277. package/dist/extensions/agent-browser/lib/results/presentation/batch-recording.js +118 -0
  278. package/dist/extensions/agent-browser/lib/results/presentation/batch-redaction.js +68 -0
  279. package/dist/extensions/agent-browser/lib/results/presentation/batch-rendering.js +135 -0
  280. package/dist/extensions/agent-browser/lib/results/presentation/batch-step.js +227 -0
  281. package/dist/extensions/agent-browser/lib/results/presentation/batch-summary.js +91 -0
  282. package/dist/extensions/agent-browser/lib/results/presentation/batch.js +91 -460
  283. package/dist/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.js +9 -5
  284. package/dist/extensions/agent-browser/lib/results/presentation/command-presenters.js +216 -0
  285. package/dist/extensions/agent-browser/lib/results/presentation/common.js +26 -9
  286. package/dist/extensions/agent-browser/lib/results/presentation/content.js +86 -29
  287. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-a11y.js +67 -0
  288. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-health.js +79 -0
  289. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-identity.js +199 -0
  290. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-logs.js +75 -0
  291. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-network-actions.js +216 -0
  292. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-network.js +124 -0
  293. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-redaction.js +64 -0
  294. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-storage.js +209 -0
  295. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-stream.js +69 -0
  296. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-summary.js +222 -0
  297. package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +103 -1052
  298. package/dist/extensions/agent-browser/lib/results/presentation/early-result.js +70 -0
  299. package/dist/extensions/agent-browser/lib/results/presentation/errors.js +130 -60
  300. package/dist/extensions/agent-browser/lib/results/presentation/input-contracts.js +1 -0
  301. package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +60 -145
  302. package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +147 -88
  303. package/dist/extensions/agent-browser/lib/results/presentation/notices.js +75 -0
  304. package/dist/extensions/agent-browser/lib/results/presentation/observation-contracts.js +1 -0
  305. package/dist/extensions/agent-browser/lib/results/presentation/observation-rendering.js +127 -0
  306. package/dist/extensions/agent-browser/lib/results/presentation/outcomes.js +120 -0
  307. package/dist/extensions/agent-browser/lib/results/presentation/output-completion.js +77 -0
  308. package/dist/extensions/agent-browser/lib/results/presentation/output-spill.js +51 -0
  309. package/dist/extensions/agent-browser/lib/results/presentation/registry.js +116 -240
  310. package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +35 -21
  311. package/dist/extensions/agent-browser/lib/results/presentation/skills.js +104 -73
  312. package/dist/extensions/agent-browser/lib/results/presentation/source.js +109 -0
  313. package/dist/extensions/agent-browser/lib/results/presentation.js +17 -261
  314. package/dist/extensions/agent-browser/lib/results/recommendation-contracts.js +1 -0
  315. package/dist/extensions/agent-browser/lib/results/recording.js +52 -14
  316. package/dist/extensions/agent-browser/lib/results/recovery-actions.js +14 -5
  317. package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +30 -22
  318. package/dist/extensions/agent-browser/lib/results/selector-recovery-target.js +83 -0
  319. package/dist/extensions/agent-browser/lib/results/selector-recovery.js +119 -119
  320. package/dist/extensions/agent-browser/lib/results/snapshot-compact.js +266 -0
  321. package/dist/extensions/agent-browser/lib/results/snapshot-content.js +32 -0
  322. package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +104 -71
  323. package/dist/extensions/agent-browser/lib/results/snapshot-refs.js +31 -11
  324. package/dist/extensions/agent-browser/lib/results/snapshot-segments.js +125 -66
  325. package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +26 -7
  326. package/dist/extensions/agent-browser/lib/results/snapshot.js +28 -248
  327. package/dist/extensions/agent-browser/lib/results/text.js +16 -5
  328. package/dist/extensions/agent-browser/lib/runtime-args-validation.js +133 -0
  329. package/dist/extensions/agent-browser/lib/runtime-compatibility.js +81 -0
  330. package/dist/extensions/agent-browser/lib/runtime-contracts.js +1 -0
  331. package/dist/extensions/agent-browser/lib/runtime-redaction.js +118 -0
  332. package/dist/extensions/agent-browser/lib/runtime-replay-events.js +144 -0
  333. package/dist/extensions/agent-browser/lib/runtime-session-identity.js +76 -0
  334. package/dist/extensions/agent-browser/lib/runtime-session-plan.js +114 -0
  335. package/dist/extensions/agent-browser/lib/runtime-session-replay.js +123 -0
  336. package/dist/extensions/agent-browser/lib/runtime-tab-correction.js +65 -0
  337. package/dist/extensions/agent-browser/lib/runtime-timeouts.js +28 -0
  338. package/dist/extensions/agent-browser/lib/runtime.js +137 -1041
  339. package/dist/extensions/agent-browser/lib/session-identity.js +51 -0
  340. package/dist/extensions/agent-browser/lib/session-page-observation.js +357 -0
  341. package/dist/extensions/agent-browser/lib/session-page-state.js +178 -333
  342. package/dist/extensions/agent-browser/lib/session-page-types.js +1 -0
  343. package/dist/extensions/agent-browser/lib/temp-artifact-budget.js +78 -0
  344. package/dist/extensions/agent-browser/lib/temp-mutation-queue.js +7 -0
  345. package/dist/extensions/agent-browser/lib/temp-root-ownership.js +234 -0
  346. package/dist/extensions/agent-browser/lib/temp-root.js +207 -0
  347. package/dist/extensions/agent-browser/lib/temp.js +33 -446
  348. package/dist/extensions/agent-browser/lib/tool-surface.js +94 -24
  349. package/dist/extensions/agent-browser/lib/upstream-version.js +3 -2
  350. package/dist/extensions/agent-browser/lib/web-search-providers.js +229 -0
  351. package/dist/extensions/agent-browser/lib/web-search-request.js +108 -0
  352. package/dist/extensions/agent-browser/lib/web-search-results.js +281 -0
  353. package/dist/extensions/agent-browser/lib/web-search-schema.js +82 -0
  354. package/dist/extensions/agent-browser/lib/web-search.js +109 -617
  355. package/dist/extensions/agent-browser/lib/webmcp-observation.js +13 -6
  356. package/dist/extensions/agent-browser/lib/windows-stock-launcher.js +63 -37
  357. package/dist/extensions/agent-browser/script-worker.js +80 -43
  358. package/dist/scripts/agent-browser-target.mjs +4 -2
  359. package/docs/ARCHITECTURE.md +17 -5
  360. package/docs/CODE_QUALITY.md +242 -0
  361. package/docs/COMMAND_REFERENCE.md +251 -220
  362. package/docs/ELECTRON.md +53 -44
  363. package/docs/RELEASE.md +18 -15
  364. package/docs/REQUIREMENTS.md +1 -0
  365. package/docs/SUPPORT_MATRIX.md +76 -75
  366. package/docs/TOOL_CONTRACT.md +145 -116
  367. package/docs/platform-smoke.md +5 -5
  368. package/package.json +143 -120
  369. package/scripts/agent-browser-capability-baseline.mjs +361 -957
  370. package/scripts/agent-browser-target.mjs +6 -2
  371. package/scripts/build.mjs +37 -8
  372. package/scripts/capability-core-commands.mjs +193 -0
  373. package/scripts/capability-options.mjs +283 -0
  374. package/scripts/capability-samples.mjs +133 -0
  375. package/scripts/capability-section.mjs +11 -0
  376. package/scripts/config.mjs +213 -114
  377. package/scripts/convert-browser-session.mjs +30 -9
  378. package/scripts/doctor-sources.mjs +195 -0
  379. package/scripts/doctor.mjs +92 -247
  380. package/scripts/platform-smoke/artifacts.mjs +38 -11
  381. package/scripts/platform-smoke/commands.mjs +104 -0
  382. package/scripts/platform-smoke/crabbox-runner.mjs +167 -80
  383. package/scripts/platform-smoke/doctor-support.mjs +157 -0
  384. package/scripts/platform-smoke/doctor-windows.mjs +230 -0
  385. package/scripts/platform-smoke/doctor.mjs +212 -320
  386. package/scripts/platform-smoke/lease-evidence.mjs +134 -0
  387. package/scripts/platform-smoke/suite-checks.mjs +98 -0
  388. package/scripts/platform-smoke/suite-evidence.mjs +281 -0
  389. package/scripts/platform-smoke/targets.mjs +158 -472
  390. package/scripts/platform-smoke.mjs +55 -40
  391. package/scripts/prepare.mjs +16 -7
@@ -1,288 +1,110 @@
1
- import { open, readFile, stat } from "node:fs/promises";
2
- import { extname, resolve } from "node:path";
3
- import { getImageDimensions } from "@earendil-works/pi-tui";
4
- import { getAgentBrowserSessionIdentityKey } from "../../argv-grammar.js";
5
- import { getExplicitArtifactDestination } from "../../orchestration/browser-run/artifact-paths.js";
6
- import { isRecord, parsePositiveInteger } from "../../parsing.js";
7
- import { formatSessionArtifactRetentionSummary, getSessionArtifactManifestEntryKey, isPendingRecordingArtifact, isPendingRecordingCommand, mergeSessionArtifactManifest, } from "../artifact-manifest.js";
8
- import { classifyAgentBrowserSuccessCategory } from "../categories.js";
9
- import { LIGHTPANDA_IMAGE_REASON } from "./common.js";
10
- import { formatRecordingReceipt, getRecordingReceipt } from "../recording.js";
11
- const PNG_HEADER = Buffer.from("89504e470d0a1a0a0000000d49484452", "hex");
12
- const INLINE_IMAGE_MAX_BYTES_ENV = "PI_AGENT_BROWSER_INLINE_IMAGE_MAX_BYTES";
13
- const DEFAULT_INLINE_IMAGE_MAX_BYTES = 5 * 1_024 * 1_024;
14
- const ARTIFACT_MTIME_TOLERANCE_MS = 2_000;
15
- function getImageMimeType(bytes) {
16
- if (bytes.length < 16)
17
- return undefined;
18
- if (bytes.subarray(0, 16).equals(PNG_HEADER))
19
- return "image/png";
20
- if (bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff && bytes[3] !== 0xf7)
21
- return "image/jpeg";
22
- if (["GIF87a", "GIF89a"].includes(bytes.toString("utf8", 0, 6)))
23
- return "image/gif";
24
- if (bytes.toString("utf8", 0, 4) === "RIFF" && bytes.toString("utf8", 8, 12) === "WEBP")
25
- return "image/webp";
26
- return undefined;
27
- }
28
- async function getFileImageMimeType(path) {
29
- try {
30
- const file = await open(path, "r");
31
- try {
32
- const bytes = Buffer.alloc(16);
33
- const { bytesRead } = await file.read(bytes, 0, bytes.length, 0);
34
- return getImageMimeType(bytes.subarray(0, bytesRead));
35
- }
36
- finally {
37
- await file.close();
38
- }
39
- }
40
- catch {
41
- return undefined;
42
- }
43
- }
44
- function getInlineImageMaxBytes(env = process.env) {
45
- return parsePositiveInteger(env[INLINE_IMAGE_MAX_BYTES_ENV]) ?? DEFAULT_INLINE_IMAGE_MAX_BYTES;
46
- }
47
- function formatByteCount(bytes) {
48
- if (bytes < 1_024)
49
- return `${bytes} B`;
50
- if (bytes < 1_024 * 1_024)
51
- return `${(bytes / 1_024).toFixed(1)} KiB`;
52
- return `${(bytes / (1_024 * 1_024)).toFixed(1)} MiB`;
53
- }
54
- function appendPresentationNotice(presentation, message) {
55
- const existingText = presentation.content[0]?.type === "text" ? presentation.content[0].text : "";
56
- presentation.content[0] = {
57
- type: "text",
58
- text: existingText.length > 0 ? `${existingText}\n\n${message}` : message,
59
- };
60
- }
61
- function shouldAppendArtifactRetentionNotice(entries) {
62
- return entries.some((entry) => entry.retentionState === "evicted" || entry.storageScope !== "explicit-path");
1
+ import { isRecord } from "../../parsing.js";
2
+ import { formatSessionArtifactRetentionSummary, getSessionArtifactManifestEntryKey, isPendingRecordingArtifact, mergeSessionArtifactManifest, } from "../artifact-manifest.js";
3
+ import { getRecordingReceipt } from "../recording.js";
4
+ import { buildFileArtifactMetadata, buildPreviousRestartRecordingArtifact, extractPathStrings, isDownloadWaitSubcommand, isNonFileArtifactPathCandidate, } from "./artifact-files.js";
5
+ import { appendPresentationNotice } from "./artifact-images.js";
6
+ export { attachInlineImage, extractImagePath, getScreenshotSummary } from "./artifact-images.js";
7
+ export { formatArtifactMetadataLines, formatArtifactSummary } from "./artifact-format.js";
8
+ export { buildArtifactVerificationSummary, classifyPresentationSuccessCategory, formatMissingArtifactFailureText, hasMissingFileArtifact, } from "./artifact-verification.js";
9
+ function noticeWorthy(entry) {
10
+ return entry.retentionState === "evicted" || entry.storageScope !== "explicit-path";
63
11
  }
64
12
  export function manifestHasNewNoticeWorthyEntries(base, current) {
65
- if (!current)
13
+ if (!current) {
66
14
  return false;
15
+ }
67
16
  const baseKeys = new Set((base?.entries ?? []).map(getSessionArtifactManifestEntryKey));
68
- return current.entries.some((entry) => !baseKeys.has(getSessionArtifactManifestEntryKey(entry)) && (entry.retentionState === "evicted" || entry.storageScope !== "explicit-path"));
17
+ return current.entries.some((entry) => !baseKeys.has(getSessionArtifactManifestEntryKey(entry)) && noticeWorthy(entry));
69
18
  }
70
19
  export function applyArtifactManifest(presentation, baseManifest, entries) {
71
- if (entries.length === 0)
20
+ if (entries.length === 0) {
72
21
  return presentation;
73
- const artifactManifest = mergeSessionArtifactManifest({ base: baseManifest, entries });
74
- if (!artifactManifest)
22
+ }
23
+ const artifactManifest = mergeSessionArtifactManifest({
24
+ base: baseManifest,
25
+ entries: [...entries],
26
+ });
27
+ if (!artifactManifest) {
75
28
  return presentation;
29
+ }
76
30
  presentation.artifactManifest = artifactManifest;
77
31
  presentation.artifactRetentionSummary = formatSessionArtifactRetentionSummary(artifactManifest);
78
- if (shouldAppendArtifactRetentionNotice(entries)) {
32
+ if (entries.some(noticeWorthy)) {
79
33
  appendPresentationNotice(presentation, presentation.artifactRetentionSummary);
80
34
  }
81
35
  return presentation;
82
36
  }
83
- export function getScreenshotSummary(data) {
84
- if (data.changed === false)
85
- return "Screenshot unchanged; no image saved.";
86
- return typeof data.path === "string" ? `Saved image: ${data.path}` : undefined;
87
- }
88
- const PATH_FIELD_CANDIDATES = [
89
- "path",
90
- "file",
91
- "filePath",
92
- "outputPath",
93
- "downloadPath",
94
- "diffPath",
95
- "harPath",
96
- "savedPath",
97
- "statePath",
98
- "tracePath",
99
- "profilePath",
100
- "videoPath",
101
- ];
102
- function isDownloadWaitSubcommand(subcommand) {
103
- return subcommand === "--download" || subcommand === "-d";
104
- }
105
- function getArtifactKind(commandInfo) {
106
- if (commandInfo.command === "screenshot")
107
- return "image";
108
- if (commandInfo.command === "diff" && commandInfo.subcommand === "screenshot")
109
- return "image";
110
- if (commandInfo.command === "pdf")
111
- return "pdf";
112
- if (commandInfo.command === "download")
113
- return "download";
114
- if (commandInfo.command === "wait" && isDownloadWaitSubcommand(commandInfo.subcommand))
115
- return "download";
116
- if (commandInfo.command === "state" && commandInfo.subcommand === "save")
117
- return "file";
118
- if (commandInfo.command === "trace")
119
- return "trace";
120
- if (commandInfo.command === "profiler")
121
- return "profile";
122
- if (commandInfo.command === "record")
123
- return "video";
124
- if (commandInfo.command === "network" && commandInfo.subcommand === "har")
125
- return "har";
126
- return undefined;
127
- }
128
- function isNonFileArtifactPathCandidate(path) {
129
- return /^(?:data|blob|https?|javascript|mailto):/i.test(path.trim());
130
- }
131
- function extractPathStrings(data) {
132
- if (typeof data === "string") {
133
- return data.trim().length > 0 && !isNonFileArtifactPathCandidate(data) ? [data] : [];
134
- }
135
- if (!isRecord(data)) {
136
- return [];
137
- }
138
- const paths = [];
139
- for (const key of PATH_FIELD_CANDIDATES) {
140
- const value = data[key];
141
- if (typeof value === "string" && value.trim().length > 0 && !isNonFileArtifactPathCandidate(value)) {
142
- paths.push(value);
143
- }
144
- if (Array.isArray(value)) {
145
- for (const item of value) {
146
- if (typeof item === "string" && item.trim().length > 0 && !isNonFileArtifactPathCandidate(item)) {
147
- paths.push(item);
148
- }
149
- }
150
- }
151
- }
152
- return [...new Set(paths)];
153
- }
154
- function artifactMtimeIsOutsideCommandWindow(updatedAtMs, minUpdatedAtMs, maxUpdatedAtMs) {
155
- return minUpdatedAtMs !== undefined
156
- && (updatedAtMs < minUpdatedAtMs - ARTIFACT_MTIME_TOLERANCE_MS
157
- || (maxUpdatedAtMs !== undefined && updatedAtMs > maxUpdatedAtMs + ARTIFACT_MTIME_TOLERANCE_MS));
37
+ function getRecordingPending(options, recording) {
38
+ return (options.recordingPending ??
39
+ (recording?.success === null &&
40
+ isRecord(options.data) &&
41
+ isRecord(options.data.capture) &&
42
+ recording.capture.endedAt === null));
158
43
  }
159
- async function buildFileArtifactMetadata(options) {
160
- const kind = options.kind ?? getArtifactKind(options.commandInfo);
161
- if (!kind) {
44
+ async function extractContactSheet(options, recordingPending) {
45
+ if (options.commandInfo.command !== "record" || !isRecord(options.data)) {
162
46
  return undefined;
163
47
  }
164
- const absolutePath = options.artifactRequest?.absolutePath ?? resolve(options.cwd, options.path);
165
- const displayPath = options.artifactRequest?.path ?? options.path;
166
- const extension = extname(absolutePath || options.path).toLowerCase() || undefined;
167
- const pendingRecording = options.recordingPending === true || (isPendingRecordingCommand(options.commandInfo.command, options.commandInfo.subcommand, kind) && options.recordingOutcome !== false && options.recording?.success !== false);
168
- const captureStartedAtMs = options.recording?.capture.startedAt ? Date.parse(options.recording.capture.startedAt) : NaN;
169
- const recordingStartedAtMs = Number.isFinite(captureStartedAtMs) ? captureStartedAtMs : options.artifactMinUpdatedAtMs;
170
- let exists;
171
- let sizeBytes;
172
- let mediaType;
173
- let stale = false;
174
- let updatedAtMs;
175
- if (!pendingRecording || options.commandInfo.subcommand === "stop") {
176
- try {
177
- const fileStats = await stat(absolutePath);
178
- exists = fileStats.isFile();
179
- sizeBytes = fileStats.size;
180
- updatedAtMs = fileStats.mtimeMs;
181
- mediaType = fileStats.isFile() ? await getFileImageMimeType(absolutePath) : undefined;
182
- const commandCreatesArtifact = !(options.commandInfo.command === "wait" && isDownloadWaitSubcommand(options.commandInfo.subcommand));
183
- stale = commandCreatesArtifact && artifactMtimeIsOutsideCommandWindow(updatedAtMs, kind === "video" ? recordingStartedAtMs : options.artifactMinUpdatedAtMs, options.artifactMaxUpdatedAtMs);
184
- }
185
- catch (error) {
186
- exists = ["ENOENT", "ENOTDIR"].includes(error.code ?? "") ? false : undefined;
187
- }
48
+ const path = options.data.contactSheetPath;
49
+ if (typeof path !== "string" ||
50
+ path.trim().length === 0 ||
51
+ isNonFileArtifactPathCandidate(path)) {
52
+ return undefined;
188
53
  }
189
- return {
190
- absolutePath,
191
- artifactType: kind,
192
- command: options.commandInfo.command,
193
- cwd: options.cwd,
194
- exists,
195
- extension,
196
- kind,
197
- mediaType,
198
- namespace: options.namespace,
199
- path: displayPath,
200
- recording: options.recording,
201
- recordingStartedAtMs: kind === "video" ? recordingStartedAtMs : undefined,
202
- recordingState: pendingRecording ? "openRecording" : undefined,
203
- requestedPath: options.artifactRequest?.path ?? getExplicitArtifactDestination(options.commandInfo.commandTokens ?? []),
204
- session: options.sessionName,
205
- sizeBytes,
206
- status: pendingRecording ? "pending" : exists !== true ? exists === false ? "missing" : "unverified" : stale ? "stale"
207
- : kind === "video" && (options.recording?.success === false || options.recording?.output.encoderSucceeded === false || (options.recordingOutcome === false && options.recording?.success !== null)) ? "failed"
208
- : kind === "video" && ((options.recording?.success !== true && options.recordingOutcome !== true)
209
- || (options.recording?.file.sizeBytes != null && options.recording.file.sizeBytes !== sizeBytes)) ? "unverified"
210
- : options.artifactRequest?.status ?? "saved",
211
- subcommand: options.commandInfo.subcommand,
212
- tempPath: options.artifactRequest?.tempPath,
213
- updatedAtMs,
214
- willExistOnStop: pendingRecording ? true : undefined,
215
- };
54
+ const sheet = await buildFileArtifactMetadata({
55
+ ...options,
56
+ artifactRequest: undefined,
57
+ kind: "image",
58
+ path,
59
+ recordingPending: recordingPending === true ||
60
+ ["start", "restart"].includes(options.commandInfo.subcommand ?? ""),
61
+ });
62
+ return sheet ? { ...sheet, requestedPath: undefined } : undefined;
216
63
  }
217
- async function buildPreviousRestartRecordingArtifact(options) {
218
- if (options.commandInfo.command !== "record" || options.commandInfo.subcommand !== "restart")
64
+ async function extractPreviousContactSheet(options) {
65
+ if (options.commandInfo.command !== "record" ||
66
+ options.commandInfo.subcommand !== "restart" ||
67
+ options.recordingOutcome !== true) {
219
68
  return undefined;
220
- if (isRecord(options.data) && "previousRecording" in options.data) {
221
- const recording = getRecordingReceipt(options.data.previousRecording);
222
- return recording ? buildFileArtifactMetadata({ ...options, commandInfo: { command: "record", subcommand: "restart-previous" }, path: recording.path, recording }) : undefined;
223
69
  }
224
- // A rejected or pending restart has not acknowledged replacement of the active take.
225
- if (!isRecord(options.data) || options.data.restarted !== true)
226
- return undefined;
227
- const sessionKey = options.sessionName ? getAgentBrowserSessionIdentityKey(options.sessionName, options.namespace) : undefined;
228
- const previousRecording = options.artifactManifest?.entries.find((entry) => (entry.command === "record" &&
229
- (entry.subcommand === "start" || entry.subcommand === "restart") &&
230
- entry.kind === "video" &&
231
- (!sessionKey || (entry.session && getAgentBrowserSessionIdentityKey(entry.session, entry.namespace) === sessionKey))));
232
- if (!previousRecording)
70
+ const path = options.previousRecordingContactSheetPath;
71
+ if (path === undefined || path.length === 0) {
233
72
  return undefined;
234
- const absolutePath = previousRecording.absolutePath ?? resolve(options.cwd, previousRecording.path);
235
- const base = {
236
- absolutePath,
237
- artifactType: "video",
238
- command: "record",
239
- cwd: previousRecording.cwd ?? options.cwd,
240
- extension: previousRecording.extension ?? (extname(absolutePath).toLowerCase() || undefined),
241
- kind: "video",
242
- namespace: previousRecording.namespace ?? options.namespace,
243
- path: previousRecording.path,
244
- requestedPath: previousRecording.requestedPath,
245
- session: previousRecording.session ?? options.sessionName,
246
- subcommand: "restart-previous",
247
- };
248
- try {
249
- const fileStats = await stat(absolutePath);
250
- const stale = artifactMtimeIsOutsideCommandWindow(fileStats.mtimeMs, options.artifactMinUpdatedAtMs, options.artifactMaxUpdatedAtMs);
251
- return {
252
- ...base,
253
- exists: true,
254
- mediaType: fileStats.isFile() ? await getFileImageMimeType(absolutePath) : undefined,
255
- sizeBytes: fileStats.size,
256
- status: stale ? "stale" : "unverified",
257
- updatedAtMs: fileStats.mtimeMs,
258
- };
259
- }
260
- catch (error) {
261
- const missing = ["ENOENT", "ENOTDIR"].includes(error.code ?? "");
262
- return { ...base, exists: missing ? false : undefined, status: missing ? "missing" : "unverified" };
263
73
  }
74
+ const sheet = await buildFileArtifactMetadata({
75
+ ...options,
76
+ artifactRequest: undefined,
77
+ commandInfo: { command: "record", subcommand: "restart-previous" },
78
+ kind: "image",
79
+ path,
80
+ recordingPending: false,
81
+ });
82
+ // Native restart omits the previous sheet's terminal receipt. Disk presence isn't finalization proof.
83
+ return sheet
84
+ ? { ...sheet, status: sheet.status === "saved" ? "unverified" : sheet.status }
85
+ : undefined;
264
86
  }
265
87
  export async function extractFileArtifacts(options) {
266
- if (options.commandInfo.command === "screenshot" && isRecord(options.data) && options.data.changed === false)
88
+ if (options.commandInfo.command === "screenshot" &&
89
+ isRecord(options.data) &&
90
+ options.data.changed === false) {
267
91
  return [];
268
- const candidates = extractPathStrings(options.data);
269
- const recording = options.commandInfo.command === "record" ? getRecordingReceipt(options.data, options.commandInfo.subcommand === "stop" ? options.recordingOutcome : undefined) : undefined;
270
- const recordingPending = options.recordingPending ?? (recording?.success === null && isRecord(options.data) && isRecord(options.data.capture) && recording.capture.endedAt === null);
271
- const currentArtifacts = (await Promise.all(candidates.map((path) => buildFileArtifactMetadata({ ...options, path, recording, recordingPending })))).filter((artifact) => artifact !== undefined);
272
- if (options.commandInfo.command === "record" && isRecord(options.data) && typeof options.data.contactSheetPath === "string" && options.data.contactSheetPath.trim() && !isNonFileArtifactPathCandidate(options.data.contactSheetPath)) {
273
- const sheet = await buildFileArtifactMetadata({ ...options, artifactRequest: undefined, kind: "image", path: options.data.contactSheetPath, recordingPending: recordingPending || ["start", "restart"].includes(options.commandInfo.subcommand ?? "") });
274
- if (sheet)
275
- currentArtifacts.push({ ...sheet, requestedPath: undefined });
276
92
  }
277
- if (options.commandInfo.command === "record" && options.commandInfo.subcommand === "restart" && options.recordingOutcome === true && options.previousRecordingContactSheetPath) {
278
- const previousSheet = await buildFileArtifactMetadata({ ...options, artifactRequest: undefined, commandInfo: { command: "record", subcommand: "restart-previous" }, kind: "image", path: options.previousRecordingContactSheetPath, recordingPending: false });
279
- // Native restart omits the previous sheet's terminal receipt. Retain the
280
- // known destination and disk evidence without inventing finalization proof.
281
- if (previousSheet)
282
- currentArtifacts.unshift({ ...previousSheet, status: previousSheet.status === "saved" ? "unverified" : previousSheet.status });
93
+ const recording = options.commandInfo.command === "record"
94
+ ? getRecordingReceipt(options.data, options.commandInfo.subcommand === "stop" ? options.recordingOutcome : undefined)
95
+ : undefined;
96
+ const recordingPending = getRecordingPending(options, recording);
97
+ const current = (await Promise.all(extractPathStrings(options.data).map((path) => buildFileArtifactMetadata({ ...options, path, recording, recordingPending })))).filter((artifact) => artifact !== undefined);
98
+ const sheet = await extractContactSheet(options, recordingPending);
99
+ if (sheet) {
100
+ current.push(sheet);
101
+ }
102
+ const previousSheet = await extractPreviousContactSheet(options);
103
+ if (previousSheet) {
104
+ current.unshift(previousSheet);
283
105
  }
284
- const previousRestartRecordingArtifact = await buildPreviousRestartRecordingArtifact(options);
285
- return previousRestartRecordingArtifact ? [previousRestartRecordingArtifact, ...currentArtifacts] : currentArtifacts;
106
+ const previous = await buildPreviousRestartRecordingArtifact(options);
107
+ return previous ? [previous, ...current] : current;
286
108
  }
287
109
  export function buildManifestEntriesForFileArtifacts(artifacts, nowMs = Date.now()) {
288
110
  return artifacts.map((artifact) => ({
@@ -309,313 +131,35 @@ export function buildManifestEntriesForFileArtifacts(artifacts, nowMs = Date.now
309
131
  }));
310
132
  }
311
133
  export function isManifestFileArtifact(artifact) {
312
- return artifact.kind === "video" && artifact.command === "record" ? true : artifact.status !== "stale" && !isPendingRecordingArtifact(artifact);
313
- }
314
- function getArtifactVerificationEntry(artifact) {
315
- if (isPendingRecordingArtifact(artifact)) {
316
- return {
317
- absolutePath: artifact.absolutePath,
318
- exists: artifact.exists,
319
- kind: artifact.kind,
320
- limitation: "Recording output is pending until native finalization succeeds and the file is verified.",
321
- recording: artifact.recording,
322
- recordingStartedAtMs: artifact.recordingStartedAtMs,
323
- mediaType: artifact.mediaType,
324
- path: artifact.path,
325
- recordingState: artifact.recordingState ?? "openRecording",
326
- requestedPath: artifact.requestedPath,
327
- retentionState: undefined,
328
- sizeBytes: artifact.sizeBytes,
329
- state: "pending",
330
- status: artifact.status ?? "pending",
331
- storageScope: undefined,
332
- willExistOnStop: artifact.willExistOnStop ?? true,
333
- };
334
- }
335
- const state = ["failed", "stale", "unverified"].includes(artifact.status ?? "")
336
- ? "unverified"
337
- : artifact.exists === true
338
- ? "verified"
339
- : artifact.exists === false
340
- ? "missing"
341
- : "unverified";
342
- return {
343
- absolutePath: artifact.absolutePath,
344
- exists: artifact.exists,
345
- kind: artifact.kind,
346
- recording: artifact.recording,
347
- recordingStartedAtMs: artifact.recordingStartedAtMs,
348
- limitation: artifact.status === "failed" || artifact.status === "unverified"
349
- ? "File presence does not prove successful native recording finalization or encoding. Inspect the receipt and original failure."
350
- : artifact.status === "stale"
351
- ? "The reported path's modification time fell outside this command's bounded artifact window. Treat the artifact as stale until regenerated."
352
- : state === "missing"
353
- ? "The wrapper did not find the reported artifact at absolutePath. Treat the path as unverified until recovered or regenerated."
354
- : state === "unverified"
355
- ? "The wrapper could not prove local filesystem existence for this artifact."
356
- : undefined,
357
- mediaType: artifact.mediaType,
358
- path: artifact.path,
359
- requestedPath: artifact.requestedPath,
360
- retentionState: artifact.exists === false ? "missing" : "live",
361
- sizeBytes: artifact.sizeBytes,
362
- state,
363
- status: artifact.status,
364
- storageScope: "explicit-path",
365
- updatedAtMs: artifact.updatedAtMs,
366
- };
367
- }
368
- function getManifestVerificationEntry(entry) {
369
- if (entry.storageScope === "explicit-path")
370
- return undefined;
371
- const state = entry.retentionState === "live"
372
- ? "verified"
373
- : entry.retentionState === "missing" || entry.retentionState === "evicted"
374
- ? "missing"
375
- : "unverified";
376
- return {
377
- absolutePath: entry.absolutePath,
378
- exists: entry.exists,
379
- kind: entry.kind,
380
- limitation: entry.retentionState === "ephemeral"
381
- ? "This spill file is process-temporary and may not survive reload or restart."
382
- : entry.retentionState === "evicted"
383
- ? "This persisted spill file was evicted from the bounded session artifact store."
384
- : undefined,
385
- mediaType: entry.mediaType,
386
- path: entry.path,
387
- requestedPath: entry.requestedPath,
388
- retentionState: entry.retentionState,
389
- sizeBytes: entry.sizeBytes,
390
- state,
391
- storageScope: entry.storageScope,
392
- };
393
- }
394
- export function buildArtifactVerificationSummary(artifacts, manifest, manifestPaths) {
395
- const entries = [
396
- ...artifacts.map(getArtifactVerificationEntry),
397
- ...(manifest?.entries.flatMap((entry) => {
398
- if (manifestPaths && !manifestPaths.has(entry.path))
399
- return [];
400
- const verificationEntry = getManifestVerificationEntry(entry);
401
- return verificationEntry ? [verificationEntry] : [];
402
- }) ?? []),
403
- ];
404
- if (entries.length === 0)
405
- return undefined;
406
- const verifiedCount = entries.filter((entry) => entry.state === "verified").length;
407
- const missingCount = entries.filter((entry) => entry.state === "missing").length;
408
- const pendingCount = entries.filter((entry) => entry.state === "pending").length;
409
- const unverifiedCount = entries.filter((entry) => entry.state === "unverified").length;
410
- return {
411
- artifacts: entries,
412
- missingCount,
413
- pendingCount,
414
- unverifiedCount,
415
- verified: entries.length > 0 && verifiedCount === entries.length,
416
- verifiedCount,
417
- };
418
- }
419
- export function hasMissingFileArtifact(artifacts) {
420
- return (artifacts ?? []).some((artifact) => !isPendingRecordingArtifact(artifact) && (artifact.exists === false || artifact.status === "stale"));
421
- }
422
- export function formatMissingArtifactFailureText(artifacts) {
423
- const failedArtifacts = (artifacts ?? []).filter((artifact) => !isPendingRecordingArtifact(artifact) && (artifact.exists === false || artifact.status === "stale"));
424
- if (failedArtifacts.length === 0)
425
- return undefined;
426
- if (failedArtifacts.length === 1) {
427
- const artifact = failedArtifacts[0];
428
- return artifact.status === "stale"
429
- ? `Artifact verification failed: requested ${artifact.kind} path ${artifact.absolutePath} has a modification time outside the current command window.`
430
- : `Artifact verification failed: requested ${artifact.kind} was not found at ${artifact.absolutePath}.`;
431
- }
432
- return `Artifact verification failed: ${failedArtifacts.length} requested artifacts were missing or stale.`;
433
- }
434
- export function classifyPresentationSuccessCategory(options) {
435
- if ((options.artifactVerification?.missingCount ?? 0) > 0 || (options.artifactVerification?.unverifiedCount ?? 0) > 0) {
436
- return "artifact-unverified";
437
- }
438
- return classifyAgentBrowserSuccessCategory(options);
134
+ return artifact.kind === "video" && artifact.command === "record"
135
+ ? true
136
+ : artifact.status !== "stale" && !isPendingRecordingArtifact(artifact);
439
137
  }
440
- function formatArtifactLabel(artifact) {
441
- switch (artifact.kind) {
442
- case "download":
443
- if (artifact.exists !== true) {
444
- return artifact.command === "wait" && isDownloadWaitSubcommand(artifact.subcommand) ? "Download event reported; file not verified" : "Download reported; file not verified";
445
- }
446
- return artifact.command === "wait" && isDownloadWaitSubcommand(artifact.subcommand) ? "Download saved and verified" : "Downloaded file verified";
447
- case "file":
448
- return artifact.command === "state" ? "State file" : "Saved file";
449
- case "har":
450
- return "Saved HAR";
451
- case "image":
452
- if (artifact.exists !== true)
453
- return artifact.command === "diff" && artifact.subcommand === "screenshot" ? "Diff image reported; file not verified" : "Image reported; file not verified";
454
- return artifact.command === "diff" && artifact.subcommand === "screenshot" ? "Saved diff image" : "Saved image";
455
- case "pdf":
456
- return "Saved PDF";
457
- case "profile":
458
- return "Saved profile";
459
- case "trace":
460
- return "Saved trace";
461
- case "video":
462
- if (artifact.status === "failed")
463
- return artifact.subcommand === "restart-previous" ? "Previous recording failed" : "Recording failed";
464
- if (artifact.status === "unverified")
465
- return artifact.subcommand === "restart-previous" ? "Previous recording unverified" : "Recording unverified";
466
- if (artifact.command === "record" && artifact.subcommand === "restart-previous") {
467
- if (artifact.status === "stale")
468
- return "Previous recording stale";
469
- if (artifact.exists === false)
470
- return "Previous recording missing";
471
- return "Previous recording saved";
472
- }
473
- if (!isPendingRecordingArtifact(artifact))
474
- return artifact.status === "saved" ? "Saved recording" : "Recording reported; file not verified";
475
- if (artifact.subcommand === "stop")
476
- return "Recording finalization pending";
477
- return artifact.subcommand === "restart" ? "Recording restarted; output will be written on stop" : "Recording started; output will be written on stop";
138
+ function getSavedFileCommand(commandInfo) {
139
+ if (commandInfo.command === "wait" && isDownloadWaitSubcommand(commandInfo.subcommand)) {
140
+ return "wait";
478
141
  }
479
- }
480
- export function formatArtifactSummary(artifacts) {
481
- if (artifacts.length === 0) {
482
- return undefined;
483
- }
484
- if (artifacts.length === 1) {
485
- const artifact = artifacts[0];
486
- return `${formatArtifactLabel(artifact)}: ${artifact.path}`;
487
- }
488
- const restartArtifact = artifacts.find((artifact) => isPendingRecordingArtifact(artifact) && artifact.subcommand === "restart");
489
- const previousRecordingArtifacts = artifacts.filter((artifact) => artifact.command === "record" && artifact.subcommand === "restart-previous");
490
- if (restartArtifact && previousRecordingArtifacts.length > 0) {
491
- return [...previousRecordingArtifacts, restartArtifact].map((artifact) => `${formatArtifactLabel(artifact)}: ${artifact.path}`).join("\n");
492
- }
493
- return `${artifacts.every((artifact) => artifact.status === "saved") ? "Saved" : "Reported"} ${artifacts.length} artifacts: ${artifacts.map((artifact) => `${artifact.kind} ${artifact.path}`).join(", ")}`;
494
- }
495
- export function formatArtifactMetadataLines(artifacts) {
496
- return artifacts.map((artifact, index) => {
497
- if (isPendingRecordingArtifact(artifact)) {
498
- return [
499
- `${formatArtifactLabel(artifact)}: ${artifact.path}`,
500
- `Artifact type: ${artifact.kind}`,
501
- artifact.requestedPath ? `Requested path: ${artifact.requestedPath}` : undefined,
502
- `Absolute path: ${artifact.absolutePath}`,
503
- `Exists: ${artifact.exists ?? "pending until record stop"}`,
504
- `Status: ${artifact.status ?? "pending"}`,
505
- `Recording state: ${artifact.recordingState ?? "openRecording"}`,
506
- `Will exist on stop: ${artifact.willExistOnStop !== false}`,
507
- artifact.session ? `Session: ${artifact.session}` : undefined,
508
- artifact.cwd ? `CWD: ${artifact.cwd}` : undefined,
509
- artifact.recording ? formatRecordingReceipt(artifact.recording) : undefined,
510
- `Machine data: details.artifacts[${index}]`,
511
- ].filter((item) => item !== undefined).join("\n");
512
- }
513
- return [
514
- `${formatArtifactLabel(artifact)}: ${artifact.path}`,
515
- `Artifact type: ${artifact.kind}`,
516
- artifact.requestedPath ? `Requested path: ${artifact.requestedPath}` : undefined,
517
- `Absolute path: ${artifact.absolutePath}`,
518
- `Exists: ${artifact.exists ?? "unknown"}`,
519
- artifact.exists === false ? "not found on disk" : undefined,
520
- typeof artifact.sizeBytes === "number" ? `Size: ${formatByteCount(artifact.sizeBytes)}` : undefined,
521
- typeof artifact.sizeBytes === "number" ? `Size bytes: ${artifact.sizeBytes}` : undefined,
522
- `Status: ${artifact.status ?? (artifact.exists === false ? "missing" : "saved")}`,
523
- artifact.tempPath ? `Reported path: ${artifact.tempPath}` : undefined,
524
- artifact.mediaType ? `Media type: ${artifact.mediaType}` : undefined,
525
- artifact.session ? `Session: ${artifact.session}` : undefined,
526
- artifact.cwd ? `CWD: ${artifact.cwd}` : undefined,
527
- artifact.recording ? formatRecordingReceipt(artifact.recording) : undefined,
528
- `Machine data: details.artifacts[${index}]`,
529
- ].filter((item) => item !== undefined).join("\n");
530
- });
531
- }
532
- function isDownloadWaitCommand(commandInfo) {
533
- return commandInfo.command === "wait" && isDownloadWaitSubcommand(commandInfo.subcommand);
534
- }
535
- function extractSavedFilePath(data) {
536
- return typeof data.path === "string" && data.path.trim().length > 0 ? data.path : undefined;
142
+ return commandInfo.command === "download" || commandInfo.command === "pdf"
143
+ ? commandInfo.command
144
+ : undefined;
537
145
  }
538
146
  export function getSavedFileDetails(commandInfo, data) {
539
- const path = extractSavedFilePath(data);
540
- if (!path || isNonFileArtifactPathCandidate(path)) {
147
+ const path = typeof data.path === "string" && data.path.trim().length > 0 ? data.path : undefined;
148
+ if (path === undefined || isNonFileArtifactPathCandidate(path)) {
541
149
  return undefined;
542
150
  }
543
- const savedFileCommand = isDownloadWaitCommand(commandInfo)
544
- ? "wait"
545
- : commandInfo.command === "download" || commandInfo.command === "pdf"
546
- ? commandInfo.command
547
- : undefined;
548
- if (!savedFileCommand) {
151
+ const command = getSavedFileCommand(commandInfo);
152
+ if (command === undefined) {
549
153
  return undefined;
550
154
  }
551
155
  const { path: _path, ...metadata } = data;
552
- const details = {
553
- command: savedFileCommand,
554
- kind: savedFileCommand === "pdf" ? "pdf" : "download",
156
+ return {
157
+ command,
158
+ kind: command === "pdf" ? "pdf" : "download",
555
159
  path,
160
+ ...(Object.keys(metadata).length > 0 ? { metadata } : {}),
161
+ ...(commandInfo.subcommand !== undefined && commandInfo.subcommand.length > 0
162
+ ? { subcommand: commandInfo.subcommand }
163
+ : {}),
556
164
  };
557
- if (Object.keys(metadata).length > 0) {
558
- details.metadata = metadata;
559
- }
560
- if (commandInfo.subcommand) {
561
- details.subcommand = commandInfo.subcommand;
562
- }
563
- return details;
564
- }
565
- function isTrustedScreenshotOutput(commandInfo) {
566
- return commandInfo.command === "screenshot";
567
- }
568
- export function extractImagePath(commandInfo, cwd, data) {
569
- if (!isTrustedScreenshotOutput(commandInfo)) {
570
- return undefined;
571
- }
572
- const path = typeof data === "string" ? data : isRecord(data) && typeof data.path === "string" ? data.path : undefined;
573
- return path?.trim() && !isNonFileArtifactPathCandidate(path) ? resolve(cwd, path) : undefined;
574
- }
575
- export async function attachInlineImage(presentation, imagePath, modelVisible = true) {
576
- try {
577
- const fileStats = await stat(imagePath);
578
- const handle = await open(imagePath, "r");
579
- let header;
580
- try {
581
- // Pi's dimension API accepts base64. Encode only a bounded header, never the whole code-mode image.
582
- const bytes = Buffer.alloc(64 * 1024);
583
- const { bytesRead } = await handle.read(bytes, 0, bytes.length, 0);
584
- header = bytes.subarray(0, bytesRead);
585
- }
586
- finally {
587
- await handle.close();
588
- }
589
- const mimeType = getImageMimeType(header);
590
- if (!mimeType)
591
- return presentation;
592
- const dimensions = getImageDimensions(header.toString("base64"), mimeType);
593
- presentation.imagePath = imagePath;
594
- const lifecycle = isRecord(presentation.data) && isRecord(presentation.data.lifecycle) ? presentation.data.lifecycle : undefined;
595
- const textRendered = isRecord(lifecycle?.effectiveLaunch) && lifecycle.effectiveLaunch.engine === "lightpanda";
596
- presentation.imageObservations = [{ path: imagePath, mimeType,
597
- ...(textRendered ? { rendering: "text" } : {}),
598
- pixels: dimensions ? { width: dimensions.widthPx, height: dimensions.heightPx } : undefined,
599
- capture: "unknown", geometry: { status: "unknown", reason: textRendered ? LIGHTPANDA_IMAGE_REASON : dimensions ? "Capture geometry was not observed." : "Image dimensions could not be read from the bounded header." } }];
600
- if (!modelVisible)
601
- return presentation;
602
- if (textRendered)
603
- appendPresentationNotice(presentation, LIGHTPANDA_IMAGE_REASON);
604
- const inlineImageMaxBytes = getInlineImageMaxBytes();
605
- if (fileStats.size > inlineImageMaxBytes) {
606
- appendPresentationNotice(presentation, `Image attachment skipped: ${formatByteCount(fileStats.size)} exceeds the inline limit of ${formatByteCount(inlineImageMaxBytes)}.`);
607
- presentation.imagePath = imagePath;
608
- return presentation;
609
- }
610
- const file = await readFile(imagePath);
611
- presentation.content.push({ type: "image", data: file.toString("base64"), mimeType });
612
- presentation.imagePath = imagePath;
613
- return presentation;
614
- }
615
- catch (error) {
616
- const message = error instanceof Error ? error.message : String(error);
617
- appendPresentationNotice(presentation, `Image attachment failed: ${message}`);
618
- presentation.imagePath = imagePath;
619
- return presentation;
620
- }
621
165
  }