pi-agent-browser-native 0.9.2 → 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 (392) hide show
  1. package/CHANGELOG.md +91 -5
  2. package/README.md +120 -86
  3. package/dist/extensions/agent-browser/index.js +43065 -2016
  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 +113 -49
  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 -81
  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 +44 -9
  82. package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +107 -66
  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 +171 -57
  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 +204 -108
  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 -199
  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 -1114
  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 -910
  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 -753
  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 -816
  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 -139
  228. package/dist/extensions/agent-browser/lib/orchestration/operation-paths.js +124 -58
  229. package/dist/extensions/agent-browser/lib/orchestration/output-file.js +198 -98
  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 +59 -243
  236. package/dist/extensions/agent-browser/lib/parsing.js +13 -4
  237. package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +134 -68
  238. package/dist/extensions/agent-browser/lib/playbook.js +18 -14
  239. package/dist/extensions/agent-browser/lib/process-child.js +284 -0
  240. package/dist/extensions/agent-browser/lib/process-environment.js +22 -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 +146 -537
  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 +138 -35
  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 -10
  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 +93 -66
  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 -552
  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 -1019
  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 +117 -237
  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 -248
  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 +123 -123
  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 -1037
  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 +188 -324
  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 +22 -10
  360. package/docs/CODE_QUALITY.md +242 -0
  361. package/docs/COMMAND_REFERENCE.md +264 -229
  362. package/docs/ELECTRON.md +53 -44
  363. package/docs/RELEASE.md +21 -17
  364. package/docs/REQUIREMENTS.md +2 -0
  365. package/docs/SESSION_STORAGE.md +1 -1
  366. package/docs/SUPPORT_MATRIX.md +84 -77
  367. package/docs/TOOL_CONTRACT.md +165 -130
  368. package/docs/platform-smoke.md +5 -5
  369. package/package.json +143 -120
  370. package/scripts/agent-browser-capability-baseline.mjs +361 -957
  371. package/scripts/agent-browser-target.mjs +6 -2
  372. package/scripts/build.mjs +37 -8
  373. package/scripts/capability-core-commands.mjs +193 -0
  374. package/scripts/capability-options.mjs +283 -0
  375. package/scripts/capability-samples.mjs +133 -0
  376. package/scripts/capability-section.mjs +11 -0
  377. package/scripts/config.mjs +213 -114
  378. package/scripts/convert-browser-session.mjs +30 -9
  379. package/scripts/doctor-sources.mjs +195 -0
  380. package/scripts/doctor.mjs +92 -247
  381. package/scripts/platform-smoke/artifacts.mjs +38 -11
  382. package/scripts/platform-smoke/commands.mjs +104 -0
  383. package/scripts/platform-smoke/crabbox-runner.mjs +167 -80
  384. package/scripts/platform-smoke/doctor-support.mjs +157 -0
  385. package/scripts/platform-smoke/doctor-windows.mjs +230 -0
  386. package/scripts/platform-smoke/doctor.mjs +212 -320
  387. package/scripts/platform-smoke/lease-evidence.mjs +134 -0
  388. package/scripts/platform-smoke/suite-checks.mjs +98 -0
  389. package/scripts/platform-smoke/suite-evidence.mjs +281 -0
  390. package/scripts/platform-smoke/targets.mjs +158 -472
  391. package/scripts/platform-smoke.mjs +55 -40
  392. package/scripts/prepare.mjs +16 -7
@@ -1,285 +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
- const sessionKey = options.sessionName ? getAgentBrowserSessionIdentityKey(options.sessionName, options.namespace) : undefined;
225
- const previousRecording = options.artifactManifest?.entries.find((entry) => (entry.command === "record" &&
226
- (entry.subcommand === "start" || entry.subcommand === "restart") &&
227
- entry.kind === "video" &&
228
- (!sessionKey || (entry.session && getAgentBrowserSessionIdentityKey(entry.session, entry.namespace) === sessionKey))));
229
- if (!previousRecording)
70
+ const path = options.previousRecordingContactSheetPath;
71
+ if (path === undefined || path.length === 0) {
230
72
  return undefined;
231
- const absolutePath = previousRecording.absolutePath ?? resolve(options.cwd, previousRecording.path);
232
- const base = {
233
- absolutePath,
234
- artifactType: "video",
235
- command: "record",
236
- cwd: previousRecording.cwd ?? options.cwd,
237
- extension: previousRecording.extension ?? (extname(absolutePath).toLowerCase() || undefined),
238
- kind: "video",
239
- namespace: previousRecording.namespace ?? options.namespace,
240
- path: previousRecording.path,
241
- requestedPath: previousRecording.requestedPath,
242
- session: previousRecording.session ?? options.sessionName,
243
- subcommand: "restart-previous",
244
- };
245
- try {
246
- const fileStats = await stat(absolutePath);
247
- const stale = artifactMtimeIsOutsideCommandWindow(fileStats.mtimeMs, options.artifactMinUpdatedAtMs, options.artifactMaxUpdatedAtMs);
248
- return {
249
- ...base,
250
- exists: true,
251
- mediaType: fileStats.isFile() ? await getFileImageMimeType(absolutePath) : undefined,
252
- sizeBytes: fileStats.size,
253
- status: stale ? "stale" : "unverified",
254
- updatedAtMs: fileStats.mtimeMs,
255
- };
256
- }
257
- catch (error) {
258
- const missing = ["ENOENT", "ENOTDIR"].includes(error.code ?? "");
259
- return { ...base, exists: missing ? false : undefined, status: missing ? "missing" : "unverified" };
260
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;
261
86
  }
262
87
  export async function extractFileArtifacts(options) {
263
- 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) {
264
91
  return [];
265
- const candidates = extractPathStrings(options.data);
266
- const recording = options.commandInfo.command === "record" ? getRecordingReceipt(options.data, options.commandInfo.subcommand === "stop" ? options.recordingOutcome : undefined) : undefined;
267
- const recordingPending = options.recordingPending ?? (recording?.success === null && isRecord(options.data) && isRecord(options.data.capture) && recording.capture.endedAt === null);
268
- const currentArtifacts = (await Promise.all(candidates.map((path) => buildFileArtifactMetadata({ ...options, path, recording, recordingPending })))).filter((artifact) => artifact !== undefined);
269
- if (options.commandInfo.command === "record" && isRecord(options.data) && typeof options.data.contactSheetPath === "string" && options.data.contactSheetPath.trim() && !isNonFileArtifactPathCandidate(options.data.contactSheetPath)) {
270
- const sheet = await buildFileArtifactMetadata({ ...options, artifactRequest: undefined, kind: "image", path: options.data.contactSheetPath, recordingPending: recordingPending || ["start", "restart"].includes(options.commandInfo.subcommand ?? "") });
271
- if (sheet)
272
- currentArtifacts.push({ ...sheet, requestedPath: undefined });
273
92
  }
274
- if (options.commandInfo.command === "record" && options.commandInfo.subcommand === "restart" && options.recordingOutcome === true && options.previousRecordingContactSheetPath) {
275
- const previousSheet = await buildFileArtifactMetadata({ ...options, artifactRequest: undefined, commandInfo: { command: "record", subcommand: "restart-previous" }, kind: "image", path: options.previousRecordingContactSheetPath, recordingPending: false });
276
- // Native restart omits the previous sheet's terminal receipt. Retain the
277
- // known destination and disk evidence without inventing finalization proof.
278
- if (previousSheet)
279
- 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);
280
101
  }
281
- const previousRestartRecordingArtifact = await buildPreviousRestartRecordingArtifact(options);
282
- return previousRestartRecordingArtifact ? [previousRestartRecordingArtifact, ...currentArtifacts] : currentArtifacts;
102
+ const previousSheet = await extractPreviousContactSheet(options);
103
+ if (previousSheet) {
104
+ current.unshift(previousSheet);
105
+ }
106
+ const previous = await buildPreviousRestartRecordingArtifact(options);
107
+ return previous ? [previous, ...current] : current;
283
108
  }
284
109
  export function buildManifestEntriesForFileArtifacts(artifacts, nowMs = Date.now()) {
285
110
  return artifacts.map((artifact) => ({
@@ -306,313 +131,35 @@ export function buildManifestEntriesForFileArtifacts(artifacts, nowMs = Date.now
306
131
  }));
307
132
  }
308
133
  export function isManifestFileArtifact(artifact) {
309
- return artifact.kind === "video" && artifact.command === "record" ? true : artifact.status !== "stale" && !isPendingRecordingArtifact(artifact);
134
+ return artifact.kind === "video" && artifact.command === "record"
135
+ ? true
136
+ : artifact.status !== "stale" && !isPendingRecordingArtifact(artifact);
310
137
  }
311
- function getArtifactVerificationEntry(artifact) {
312
- if (isPendingRecordingArtifact(artifact)) {
313
- return {
314
- absolutePath: artifact.absolutePath,
315
- exists: artifact.exists,
316
- kind: artifact.kind,
317
- limitation: "Recording output is pending until native finalization succeeds and the file is verified.",
318
- recording: artifact.recording,
319
- recordingStartedAtMs: artifact.recordingStartedAtMs,
320
- mediaType: artifact.mediaType,
321
- path: artifact.path,
322
- recordingState: artifact.recordingState ?? "openRecording",
323
- requestedPath: artifact.requestedPath,
324
- retentionState: undefined,
325
- sizeBytes: artifact.sizeBytes,
326
- state: "pending",
327
- status: artifact.status ?? "pending",
328
- storageScope: undefined,
329
- willExistOnStop: artifact.willExistOnStop ?? true,
330
- };
138
+ function getSavedFileCommand(commandInfo) {
139
+ if (commandInfo.command === "wait" && isDownloadWaitSubcommand(commandInfo.subcommand)) {
140
+ return "wait";
331
141
  }
332
- const state = ["failed", "stale", "unverified"].includes(artifact.status ?? "")
333
- ? "unverified"
334
- : artifact.exists === true
335
- ? "verified"
336
- : artifact.exists === false
337
- ? "missing"
338
- : "unverified";
339
- return {
340
- absolutePath: artifact.absolutePath,
341
- exists: artifact.exists,
342
- kind: artifact.kind,
343
- recording: artifact.recording,
344
- recordingStartedAtMs: artifact.recordingStartedAtMs,
345
- limitation: artifact.status === "failed" || artifact.status === "unverified"
346
- ? "File presence does not prove successful native recording finalization or encoding. Inspect the receipt and original failure."
347
- : artifact.status === "stale"
348
- ? "The reported path's modification time fell outside this command's bounded artifact window. Treat the artifact as stale until regenerated."
349
- : state === "missing"
350
- ? "The wrapper did not find the reported artifact at absolutePath. Treat the path as unverified until recovered or regenerated."
351
- : state === "unverified"
352
- ? "The wrapper could not prove local filesystem existence for this artifact."
353
- : undefined,
354
- mediaType: artifact.mediaType,
355
- path: artifact.path,
356
- requestedPath: artifact.requestedPath,
357
- retentionState: artifact.exists === false ? "missing" : "live",
358
- sizeBytes: artifact.sizeBytes,
359
- state,
360
- status: artifact.status,
361
- storageScope: "explicit-path",
362
- updatedAtMs: artifact.updatedAtMs,
363
- };
364
- }
365
- function getManifestVerificationEntry(entry) {
366
- if (entry.storageScope === "explicit-path")
367
- return undefined;
368
- const state = entry.retentionState === "live"
369
- ? "verified"
370
- : entry.retentionState === "missing" || entry.retentionState === "evicted"
371
- ? "missing"
372
- : "unverified";
373
- return {
374
- absolutePath: entry.absolutePath,
375
- exists: entry.exists,
376
- kind: entry.kind,
377
- limitation: entry.retentionState === "ephemeral"
378
- ? "This spill file is process-temporary and may not survive reload or restart."
379
- : entry.retentionState === "evicted"
380
- ? "This persisted spill file was evicted from the bounded session artifact store."
381
- : undefined,
382
- mediaType: entry.mediaType,
383
- path: entry.path,
384
- requestedPath: entry.requestedPath,
385
- retentionState: entry.retentionState,
386
- sizeBytes: entry.sizeBytes,
387
- state,
388
- storageScope: entry.storageScope,
389
- };
390
- }
391
- export function buildArtifactVerificationSummary(artifacts, manifest, manifestPaths) {
392
- const entries = [
393
- ...artifacts.map(getArtifactVerificationEntry),
394
- ...(manifest?.entries.flatMap((entry) => {
395
- if (manifestPaths && !manifestPaths.has(entry.path))
396
- return [];
397
- const verificationEntry = getManifestVerificationEntry(entry);
398
- return verificationEntry ? [verificationEntry] : [];
399
- }) ?? []),
400
- ];
401
- if (entries.length === 0)
402
- return undefined;
403
- const verifiedCount = entries.filter((entry) => entry.state === "verified").length;
404
- const missingCount = entries.filter((entry) => entry.state === "missing").length;
405
- const pendingCount = entries.filter((entry) => entry.state === "pending").length;
406
- const unverifiedCount = entries.filter((entry) => entry.state === "unverified").length;
407
- return {
408
- artifacts: entries,
409
- missingCount,
410
- pendingCount,
411
- unverifiedCount,
412
- verified: entries.length > 0 && verifiedCount === entries.length,
413
- verifiedCount,
414
- };
415
- }
416
- export function hasMissingFileArtifact(artifacts) {
417
- return (artifacts ?? []).some((artifact) => !isPendingRecordingArtifact(artifact) && (artifact.exists === false || artifact.status === "stale"));
418
- }
419
- export function formatMissingArtifactFailureText(artifacts) {
420
- const failedArtifacts = (artifacts ?? []).filter((artifact) => !isPendingRecordingArtifact(artifact) && (artifact.exists === false || artifact.status === "stale"));
421
- if (failedArtifacts.length === 0)
422
- return undefined;
423
- if (failedArtifacts.length === 1) {
424
- const artifact = failedArtifacts[0];
425
- return artifact.status === "stale"
426
- ? `Artifact verification failed: requested ${artifact.kind} path ${artifact.absolutePath} has a modification time outside the current command window.`
427
- : `Artifact verification failed: requested ${artifact.kind} was not found at ${artifact.absolutePath}.`;
428
- }
429
- return `Artifact verification failed: ${failedArtifacts.length} requested artifacts were missing or stale.`;
430
- }
431
- export function classifyPresentationSuccessCategory(options) {
432
- if ((options.artifactVerification?.missingCount ?? 0) > 0 || (options.artifactVerification?.unverifiedCount ?? 0) > 0) {
433
- return "artifact-unverified";
434
- }
435
- return classifyAgentBrowserSuccessCategory(options);
436
- }
437
- function formatArtifactLabel(artifact) {
438
- switch (artifact.kind) {
439
- case "download":
440
- if (artifact.exists !== true) {
441
- return artifact.command === "wait" && isDownloadWaitSubcommand(artifact.subcommand) ? "Download event reported; file not verified" : "Download reported; file not verified";
442
- }
443
- return artifact.command === "wait" && isDownloadWaitSubcommand(artifact.subcommand) ? "Download saved and verified" : "Downloaded file verified";
444
- case "file":
445
- return artifact.command === "state" ? "State file" : "Saved file";
446
- case "har":
447
- return "Saved HAR";
448
- case "image":
449
- if (artifact.exists !== true)
450
- return artifact.command === "diff" && artifact.subcommand === "screenshot" ? "Diff image reported; file not verified" : "Image reported; file not verified";
451
- return artifact.command === "diff" && artifact.subcommand === "screenshot" ? "Saved diff image" : "Saved image";
452
- case "pdf":
453
- return "Saved PDF";
454
- case "profile":
455
- return "Saved profile";
456
- case "trace":
457
- return "Saved trace";
458
- case "video":
459
- if (artifact.status === "failed")
460
- return artifact.subcommand === "restart-previous" ? "Previous recording failed" : "Recording failed";
461
- if (artifact.status === "unverified")
462
- return artifact.subcommand === "restart-previous" ? "Previous recording unverified" : "Recording unverified";
463
- if (artifact.command === "record" && artifact.subcommand === "restart-previous") {
464
- if (artifact.status === "stale")
465
- return "Previous recording stale";
466
- if (artifact.exists === false)
467
- return "Previous recording missing";
468
- return "Previous recording saved";
469
- }
470
- if (!isPendingRecordingArtifact(artifact))
471
- return artifact.status === "saved" ? "Saved recording" : "Recording reported; file not verified";
472
- if (artifact.subcommand === "stop")
473
- return "Recording finalization pending";
474
- return artifact.subcommand === "restart" ? "Recording restarted; output will be written on stop" : "Recording started; output will be written on stop";
475
- }
476
- }
477
- export function formatArtifactSummary(artifacts) {
478
- if (artifacts.length === 0) {
479
- return undefined;
480
- }
481
- if (artifacts.length === 1) {
482
- const artifact = artifacts[0];
483
- return `${formatArtifactLabel(artifact)}: ${artifact.path}`;
484
- }
485
- const restartArtifact = artifacts.find((artifact) => isPendingRecordingArtifact(artifact) && artifact.subcommand === "restart");
486
- const previousRecordingArtifacts = artifacts.filter((artifact) => artifact.command === "record" && artifact.subcommand === "restart-previous");
487
- if (restartArtifact && previousRecordingArtifacts.length > 0) {
488
- return [...previousRecordingArtifacts, restartArtifact].map((artifact) => `${formatArtifactLabel(artifact)}: ${artifact.path}`).join("\n");
489
- }
490
- return `${artifacts.every((artifact) => artifact.status === "saved") ? "Saved" : "Reported"} ${artifacts.length} artifacts: ${artifacts.map((artifact) => `${artifact.kind} ${artifact.path}`).join(", ")}`;
491
- }
492
- export function formatArtifactMetadataLines(artifacts) {
493
- return artifacts.map((artifact, index) => {
494
- if (isPendingRecordingArtifact(artifact)) {
495
- return [
496
- `${formatArtifactLabel(artifact)}: ${artifact.path}`,
497
- `Artifact type: ${artifact.kind}`,
498
- artifact.requestedPath ? `Requested path: ${artifact.requestedPath}` : undefined,
499
- `Absolute path: ${artifact.absolutePath}`,
500
- `Exists: ${artifact.exists ?? "pending until record stop"}`,
501
- `Status: ${artifact.status ?? "pending"}`,
502
- `Recording state: ${artifact.recordingState ?? "openRecording"}`,
503
- `Will exist on stop: ${artifact.willExistOnStop !== false}`,
504
- artifact.session ? `Session: ${artifact.session}` : undefined,
505
- artifact.cwd ? `CWD: ${artifact.cwd}` : undefined,
506
- artifact.recording ? formatRecordingReceipt(artifact.recording) : undefined,
507
- `Machine data: details.artifacts[${index}]`,
508
- ].filter((item) => item !== undefined).join("\n");
509
- }
510
- return [
511
- `${formatArtifactLabel(artifact)}: ${artifact.path}`,
512
- `Artifact type: ${artifact.kind}`,
513
- artifact.requestedPath ? `Requested path: ${artifact.requestedPath}` : undefined,
514
- `Absolute path: ${artifact.absolutePath}`,
515
- `Exists: ${artifact.exists ?? "unknown"}`,
516
- artifact.exists === false ? "not found on disk" : undefined,
517
- typeof artifact.sizeBytes === "number" ? `Size: ${formatByteCount(artifact.sizeBytes)}` : undefined,
518
- typeof artifact.sizeBytes === "number" ? `Size bytes: ${artifact.sizeBytes}` : undefined,
519
- `Status: ${artifact.status ?? (artifact.exists === false ? "missing" : "saved")}`,
520
- artifact.tempPath ? `Reported path: ${artifact.tempPath}` : undefined,
521
- artifact.mediaType ? `Media type: ${artifact.mediaType}` : undefined,
522
- artifact.session ? `Session: ${artifact.session}` : undefined,
523
- artifact.cwd ? `CWD: ${artifact.cwd}` : undefined,
524
- artifact.recording ? formatRecordingReceipt(artifact.recording) : undefined,
525
- `Machine data: details.artifacts[${index}]`,
526
- ].filter((item) => item !== undefined).join("\n");
527
- });
528
- }
529
- function isDownloadWaitCommand(commandInfo) {
530
- return commandInfo.command === "wait" && isDownloadWaitSubcommand(commandInfo.subcommand);
531
- }
532
- function extractSavedFilePath(data) {
533
- 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;
534
145
  }
535
146
  export function getSavedFileDetails(commandInfo, data) {
536
- const path = extractSavedFilePath(data);
537
- 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)) {
538
149
  return undefined;
539
150
  }
540
- const savedFileCommand = isDownloadWaitCommand(commandInfo)
541
- ? "wait"
542
- : commandInfo.command === "download" || commandInfo.command === "pdf"
543
- ? commandInfo.command
544
- : undefined;
545
- if (!savedFileCommand) {
151
+ const command = getSavedFileCommand(commandInfo);
152
+ if (command === undefined) {
546
153
  return undefined;
547
154
  }
548
155
  const { path: _path, ...metadata } = data;
549
- const details = {
550
- command: savedFileCommand,
551
- kind: savedFileCommand === "pdf" ? "pdf" : "download",
156
+ return {
157
+ command,
158
+ kind: command === "pdf" ? "pdf" : "download",
552
159
  path,
160
+ ...(Object.keys(metadata).length > 0 ? { metadata } : {}),
161
+ ...(commandInfo.subcommand !== undefined && commandInfo.subcommand.length > 0
162
+ ? { subcommand: commandInfo.subcommand }
163
+ : {}),
553
164
  };
554
- if (Object.keys(metadata).length > 0) {
555
- details.metadata = metadata;
556
- }
557
- if (commandInfo.subcommand) {
558
- details.subcommand = commandInfo.subcommand;
559
- }
560
- return details;
561
- }
562
- function isTrustedScreenshotOutput(commandInfo) {
563
- return commandInfo.command === "screenshot";
564
- }
565
- export function extractImagePath(commandInfo, cwd, data) {
566
- if (!isTrustedScreenshotOutput(commandInfo)) {
567
- return undefined;
568
- }
569
- const path = typeof data === "string" ? data : isRecord(data) && typeof data.path === "string" ? data.path : undefined;
570
- return path?.trim() && !isNonFileArtifactPathCandidate(path) ? resolve(cwd, path) : undefined;
571
- }
572
- export async function attachInlineImage(presentation, imagePath, modelVisible = true) {
573
- try {
574
- const fileStats = await stat(imagePath);
575
- const handle = await open(imagePath, "r");
576
- let header;
577
- try {
578
- // Pi's dimension API accepts base64. Encode only a bounded header, never the whole code-mode image.
579
- const bytes = Buffer.alloc(64 * 1024);
580
- const { bytesRead } = await handle.read(bytes, 0, bytes.length, 0);
581
- header = bytes.subarray(0, bytesRead);
582
- }
583
- finally {
584
- await handle.close();
585
- }
586
- const mimeType = getImageMimeType(header);
587
- if (!mimeType)
588
- return presentation;
589
- const dimensions = getImageDimensions(header.toString("base64"), mimeType);
590
- presentation.imagePath = imagePath;
591
- const lifecycle = isRecord(presentation.data) && isRecord(presentation.data.lifecycle) ? presentation.data.lifecycle : undefined;
592
- const textRendered = isRecord(lifecycle?.effectiveLaunch) && lifecycle.effectiveLaunch.engine === "lightpanda";
593
- presentation.imageObservations = [{ path: imagePath, mimeType,
594
- ...(textRendered ? { rendering: "text" } : {}),
595
- pixels: dimensions ? { width: dimensions.widthPx, height: dimensions.heightPx } : undefined,
596
- 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." } }];
597
- if (!modelVisible)
598
- return presentation;
599
- if (textRendered)
600
- appendPresentationNotice(presentation, LIGHTPANDA_IMAGE_REASON);
601
- const inlineImageMaxBytes = getInlineImageMaxBytes();
602
- if (fileStats.size > inlineImageMaxBytes) {
603
- appendPresentationNotice(presentation, `Image attachment skipped: ${formatByteCount(fileStats.size)} exceeds the inline limit of ${formatByteCount(inlineImageMaxBytes)}.`);
604
- presentation.imagePath = imagePath;
605
- return presentation;
606
- }
607
- const file = await readFile(imagePath);
608
- presentation.content.push({ type: "image", data: file.toString("base64"), mimeType });
609
- presentation.imagePath = imagePath;
610
- return presentation;
611
- }
612
- catch (error) {
613
- const message = error instanceof Error ? error.message : String(error);
614
- appendPresentationNotice(presentation, `Image attachment failed: ${message}`);
615
- presentation.imagePath = imagePath;
616
- return presentation;
617
- }
618
165
  }