pi-agent-browser-native 0.9.3 → 0.9.5

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 (394) hide show
  1. package/CHANGELOG.md +106 -5
  2. package/README.md +58 -791
  3. package/dist/extensions/agent-browser/index.js +43101 -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 +231 -0
  33. package/dist/extensions/agent-browser/lib/config.js +20 -8
  34. package/dist/extensions/agent-browser/lib/electron/cdp.js +20 -8
  35. package/dist/extensions/agent-browser/lib/electron/cleanup.js +128 -83
  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 +90 -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 +261 -355
  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/fs-utils.js +1 -9
  50. package/dist/extensions/agent-browser/lib/input-modes/electron.js +162 -121
  51. package/dist/extensions/agent-browser/lib/input-modes/job.js +123 -317
  52. package/dist/extensions/agent-browser/lib/input-modes/lookup-network-evidence.js +116 -0
  53. package/dist/extensions/agent-browser/lib/input-modes/lookup-plan.js +132 -0
  54. package/dist/extensions/agent-browser/lib/input-modes/lookup-redaction.js +57 -0
  55. package/dist/extensions/agent-browser/lib/input-modes/lookup-source-evidence.js +151 -0
  56. package/dist/extensions/agent-browser/lib/input-modes/lookup-workspace.js +142 -0
  57. package/dist/extensions/agent-browser/lib/input-modes/lookups.js +58 -412
  58. package/dist/extensions/agent-browser/lib/input-modes/params.js +86 -40
  59. package/dist/extensions/agent-browser/lib/input-modes/qa-analysis.js +268 -0
  60. package/dist/extensions/agent-browser/lib/input-modes/qa-presentation.js +117 -0
  61. package/dist/extensions/agent-browser/lib/input-modes/script-child.js +396 -0
  62. package/dist/extensions/agent-browser/lib/input-modes/script-protocol.js +86 -0
  63. package/dist/extensions/agent-browser/lib/input-modes/script-types.js +1 -0
  64. package/dist/extensions/agent-browser/lib/input-modes/script-validation.js +60 -0
  65. package/dist/extensions/agent-browser/lib/input-modes/script.js +60 -409
  66. package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +218 -128
  67. package/dist/extensions/agent-browser/lib/input-modes/shared.js +15 -4
  68. package/dist/extensions/agent-browser/lib/input-modes/types.js +56 -7
  69. package/dist/extensions/agent-browser/lib/json-schema.js +22 -10
  70. package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +17 -5
  71. package/dist/extensions/agent-browser/lib/managed-session-policy-lock.js +92 -425
  72. package/dist/extensions/agent-browser/lib/managed-session-posix-storage.js +58 -0
  73. package/dist/extensions/agent-browser/lib/managed-session-project-identity.js +244 -0
  74. package/dist/extensions/agent-browser/lib/managed-session-restore-context.js +84 -0
  75. package/dist/extensions/agent-browser/lib/managed-session-restore-policy.js +119 -0
  76. package/dist/extensions/agent-browser/lib/managed-session-restore-state.js +83 -0
  77. package/dist/extensions/agent-browser/lib/managed-session-restore.js +168 -300
  78. package/dist/extensions/agent-browser/lib/managed-session-snapshot-records.js +277 -0
  79. package/dist/extensions/agent-browser/lib/managed-session-snapshots.js +128 -305
  80. package/dist/extensions/agent-browser/lib/managed-session-storage.js +56 -253
  81. package/dist/extensions/agent-browser/lib/native-confirmation.js +140 -0
  82. package/dist/extensions/agent-browser/lib/native-output.js +43 -9
  83. package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +106 -59
  84. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-merge.js +14 -6
  85. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +109 -57
  86. package/dist/extensions/agent-browser/lib/orchestration/browser-run/browser-observation-result.js +82 -0
  87. package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +164 -60
  88. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostic-values.js +31 -0
  89. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +152 -781
  90. package/dist/extensions/agent-browser/lib/orchestration/browser-run/electron-observation.js +203 -0
  91. package/dist/extensions/agent-browser/lib/orchestration/browser-run/electron-text-diagnostics.js +109 -0
  92. package/dist/extensions/agent-browser/lib/orchestration/browser-run/fill-diagnostics.js +119 -0
  93. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-action-recovery.js +147 -0
  94. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-actions.js +144 -0
  95. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-content.js +123 -0
  96. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-contracts.js +1 -0
  97. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-details.js +156 -0
  98. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-electron.js +187 -0
  99. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-evidence.js +39 -0
  100. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-missing-binary.js +89 -0
  101. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-recovery.js +97 -0
  102. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-redaction.js +106 -0
  103. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-timeout.js +110 -0
  104. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +41 -538
  105. package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +199 -154
  106. package/dist/extensions/agent-browser/lib/orchestration/browser-run/interaction-diagnostics.js +290 -0
  107. package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-close.js +167 -0
  108. package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-inspection.js +108 -0
  109. package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-policy.js +127 -205
  110. package/dist/extensions/agent-browser/lib/orchestration/browser-run/native-helper-observation.js +65 -0
  111. package/dist/extensions/agent-browser/lib/orchestration/browser-run/observation-types.js +1 -0
  112. package/dist/extensions/agent-browser/lib/orchestration/browser-run/overlay-diagnostics.js +120 -0
  113. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.js +113 -30
  114. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js +109 -28
  115. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter-data.js +150 -0
  116. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +147 -253
  117. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-rendered-text.js +147 -0
  118. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.js +59 -24
  119. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-artifacts.js +159 -0
  120. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-command.js +131 -0
  121. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-contracts.js +1 -0
  122. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-daemon.js +93 -0
  123. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-failure.js +42 -0
  124. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-guards.js +242 -0
  125. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-input.js +75 -0
  126. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-observations.js +92 -0
  127. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-page-selection.js +254 -0
  128. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-page-state.js +121 -0
  129. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-refs.js +130 -0
  130. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-resources.js +114 -0
  131. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-semantic.js +121 -0
  132. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-session-plan.js +222 -0
  133. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-timeouts.js +68 -0
  134. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +176 -1123
  135. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-analysis.js +191 -0
  136. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-confirmation.js +152 -0
  137. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-diagnostics.js +182 -0
  138. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-electron.js +150 -0
  139. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle-contracts.js +1 -0
  140. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle-phase-contracts.js +1 -0
  141. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle-phase.js +115 -0
  142. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle.js +256 -0
  143. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-managed-contracts.js +1 -0
  144. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-managed.js +256 -0
  145. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-native-phase-contracts.js +1 -0
  146. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-native-phase.js +93 -0
  147. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-native.js +113 -0
  148. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-navigation-contracts.js +1 -0
  149. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-navigation.js +316 -0
  150. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-ownership.js +28 -0
  151. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-page-phase-contracts.js +1 -0
  152. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-page-phase.js +142 -0
  153. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-presentation-contracts.js +1 -0
  154. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-presentation.js +333 -0
  155. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-publication-phase-contracts.js +1 -0
  156. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-publication-phase.js +71 -0
  157. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-publication.js +201 -0
  158. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-receipts.js +183 -0
  159. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-refs.js +200 -0
  160. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-tabs.js +142 -0
  161. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +18 -968
  162. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.js +23 -13
  163. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-receipt-reconciliation.js +198 -0
  164. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery-contracts.js +1 -0
  165. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery-presentation.js +154 -0
  166. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery.js +68 -151
  167. package/dist/extensions/agent-browser/lib/orchestration/browser-run/screenshot-capture.js +14 -0
  168. package/dist/extensions/agent-browser/lib/orchestration/browser-run/screenshot-observation.js +169 -46
  169. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-commands.js +130 -0
  170. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-electron.js +212 -0
  171. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-observations.js +61 -0
  172. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-outcomes.js +187 -0
  173. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-refs.js +169 -0
  174. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-tabs.js +228 -0
  175. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +77 -765
  176. package/dist/extensions/agent-browser/lib/orchestration/browser-run/text-visibility-diagnostics.js +182 -0
  177. package/dist/extensions/agent-browser/lib/orchestration/browser-run/timeout-diagnostics.js +256 -0
  178. package/dist/extensions/agent-browser/lib/orchestration/browser-run/timeout-progress.js +108 -0
  179. package/dist/extensions/agent-browser/lib/orchestration/code-artifact-observation.js +39 -0
  180. package/dist/extensions/agent-browser/lib/orchestration/code-image-observation.js +119 -0
  181. package/dist/extensions/agent-browser/lib/orchestration/electron-host/branch.js +93 -0
  182. package/dist/extensions/agent-browser/lib/orchestration/electron-host/cleanup-result.js +58 -0
  183. package/dist/extensions/agent-browser/lib/orchestration/electron-host/cleanup.js +78 -0
  184. package/dist/extensions/agent-browser/lib/orchestration/electron-host/contracts.js +1 -0
  185. package/dist/extensions/agent-browser/lib/orchestration/electron-host/discovery.js +106 -0
  186. package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +48 -821
  187. package/dist/extensions/agent-browser/lib/orchestration/electron-host/policy.js +86 -0
  188. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-collection.js +68 -0
  189. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-data.js +169 -0
  190. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-presentation.js +182 -0
  191. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe.js +161 -0
  192. package/dist/extensions/agent-browser/lib/orchestration/electron-host/status.js +167 -0
  193. package/dist/extensions/agent-browser/lib/orchestration/execution-queue.js +22 -10
  194. package/dist/extensions/agent-browser/lib/orchestration/extension-artifact-preflight.js +211 -0
  195. package/dist/extensions/agent-browser/lib/orchestration/extension-artifacts.js +23 -0
  196. package/dist/extensions/agent-browser/lib/orchestration/extension-attachment-replay.js +99 -0
  197. package/dist/extensions/agent-browser/lib/orchestration/extension-branch-restore.js +275 -0
  198. package/dist/extensions/agent-browser/lib/orchestration/extension-code.js +280 -0
  199. package/dist/extensions/agent-browser/lib/orchestration/extension-command-admission.js +303 -0
  200. package/dist/extensions/agent-browser/lib/orchestration/extension-command-output.js +36 -0
  201. package/dist/extensions/agent-browser/lib/orchestration/extension-command-result.js +335 -0
  202. package/dist/extensions/agent-browser/lib/orchestration/extension-command-run.js +227 -0
  203. package/dist/extensions/agent-browser/lib/orchestration/extension-command-state.js +1 -0
  204. package/dist/extensions/agent-browser/lib/orchestration/extension-electron-ownership.js +204 -0
  205. package/dist/extensions/agent-browser/lib/orchestration/extension-execution-locks.js +139 -0
  206. package/dist/extensions/agent-browser/lib/orchestration/extension-execution-queue.js +24 -0
  207. package/dist/extensions/agent-browser/lib/orchestration/extension-host-coordination.js +98 -0
  208. package/dist/extensions/agent-browser/lib/orchestration/extension-host-run.js +295 -0
  209. package/dist/extensions/agent-browser/lib/orchestration/extension-intent-replay.js +41 -0
  210. package/dist/extensions/agent-browser/lib/orchestration/extension-invocation.js +7 -0
  211. package/dist/extensions/agent-browser/lib/orchestration/extension-lifecycle.js +102 -0
  212. package/dist/extensions/agent-browser/lib/orchestration/extension-managed-ownership.js +133 -0
  213. package/dist/extensions/agent-browser/lib/orchestration/extension-observation.js +120 -0
  214. package/dist/extensions/agent-browser/lib/orchestration/extension-prompt.js +180 -0
  215. package/dist/extensions/agent-browser/lib/orchestration/extension-recording.js +290 -0
  216. package/dist/extensions/agent-browser/lib/orchestration/extension-resource-contracts.js +1 -0
  217. package/dist/extensions/agent-browser/lib/orchestration/extension-resource-replay.js +269 -0
  218. package/dist/extensions/agent-browser/lib/orchestration/extension-result-state.js +113 -0
  219. package/dist/extensions/agent-browser/lib/orchestration/extension-runtime.js +146 -0
  220. package/dist/extensions/agent-browser/lib/orchestration/extension-script-leases.js +58 -0
  221. package/dist/extensions/agent-browser/lib/orchestration/extension-tool-boundary.js +62 -0
  222. package/dist/extensions/agent-browser/lib/orchestration/extension-version-check.js +54 -0
  223. package/dist/extensions/agent-browser/lib/orchestration/input-plan-types.js +1 -0
  224. package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +261 -185
  225. package/dist/extensions/agent-browser/lib/orchestration/input-redaction.js +62 -0
  226. package/dist/extensions/agent-browser/lib/orchestration/native-config.js +144 -0
  227. package/dist/extensions/agent-browser/lib/orchestration/native-root-launch.js +77 -0
  228. package/dist/extensions/agent-browser/lib/orchestration/native-session-defaults.js +210 -157
  229. package/dist/extensions/agent-browser/lib/orchestration/operation-paths.js +124 -58
  230. package/dist/extensions/agent-browser/lib/orchestration/output-file.js +197 -99
  231. package/dist/extensions/agent-browser/lib/orchestration/script-mode.js +199 -96
  232. package/dist/extensions/agent-browser/lib/owned-managed-session-context.js +55 -0
  233. package/dist/extensions/agent-browser/lib/page-target-batch.js +118 -0
  234. package/dist/extensions/agent-browser/lib/page-target-guards.js +50 -0
  235. package/dist/extensions/agent-browser/lib/page-target-navigation.js +104 -0
  236. package/dist/extensions/agent-browser/lib/page-target-validation.js +55 -246
  237. package/dist/extensions/agent-browser/lib/parsing.js +13 -4
  238. package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +133 -68
  239. package/dist/extensions/agent-browser/lib/playbook.js +16 -12
  240. package/dist/extensions/agent-browser/lib/process-child.js +284 -0
  241. package/dist/extensions/agent-browser/lib/process-environment.js +13 -6
  242. package/dist/extensions/agent-browser/lib/process-errors.js +23 -0
  243. package/dist/extensions/agent-browser/lib/process-identity.js +47 -15
  244. package/dist/extensions/agent-browser/lib/process-socket-storage.js +256 -0
  245. package/dist/extensions/agent-browser/lib/process-stdout.js +74 -0
  246. package/dist/extensions/agent-browser/lib/process.js +145 -536
  247. package/dist/extensions/agent-browser/lib/prompt-artifacts.js +287 -0
  248. package/dist/extensions/agent-browser/lib/prompt-policy.js +15 -194
  249. package/dist/extensions/agent-browser/lib/read-command.js +41 -0
  250. package/dist/extensions/agent-browser/lib/read-confirmation.js +131 -68
  251. package/dist/extensions/agent-browser/lib/recording-reservations.js +118 -45
  252. package/dist/extensions/agent-browser/lib/redaction-fields.js +75 -0
  253. package/dist/extensions/agent-browser/lib/redaction-json.js +149 -0
  254. package/dist/extensions/agent-browser/lib/redaction-url.js +88 -0
  255. package/dist/extensions/agent-browser/lib/results/action-contracts.js +1 -0
  256. package/dist/extensions/agent-browser/lib/results/action-recommendations.js +28 -271
  257. package/dist/extensions/agent-browser/lib/results/artifact-contracts.js +1 -0
  258. package/dist/extensions/agent-browser/lib/results/artifact-manifest-validation.js +133 -0
  259. package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +96 -94
  260. package/dist/extensions/agent-browser/lib/results/artifact-recommendations.js +73 -0
  261. package/dist/extensions/agent-browser/lib/results/categories.js +111 -54
  262. package/dist/extensions/agent-browser/lib/results/confirmation.js +29 -13
  263. package/dist/extensions/agent-browser/lib/results/editable-ref-evidence.js +62 -27
  264. package/dist/extensions/agent-browser/lib/results/electron-recommendations.js +83 -0
  265. package/dist/extensions/agent-browser/lib/results/envelope-decoding.js +48 -0
  266. package/dist/extensions/agent-browser/lib/results/envelope.js +90 -67
  267. package/dist/extensions/agent-browser/lib/results/evidence-contracts.js +1 -0
  268. package/dist/extensions/agent-browser/lib/results/failure-recommendations.js +180 -0
  269. package/dist/extensions/agent-browser/lib/results/network-routes.js +86 -45
  270. package/dist/extensions/agent-browser/lib/results/network.js +35 -12
  271. package/dist/extensions/agent-browser/lib/results/next-actions.js +49 -19
  272. package/dist/extensions/agent-browser/lib/results/presentation/artifact-files.js +320 -0
  273. package/dist/extensions/agent-browser/lib/results/presentation/artifact-format.js +138 -0
  274. package/dist/extensions/agent-browser/lib/results/presentation/artifact-images.js +113 -0
  275. package/dist/extensions/agent-browser/lib/results/presentation/artifact-verification.js +145 -0
  276. package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +99 -555
  277. package/dist/extensions/agent-browser/lib/results/presentation/batch-contracts.js +1 -0
  278. package/dist/extensions/agent-browser/lib/results/presentation/batch-recording.js +118 -0
  279. package/dist/extensions/agent-browser/lib/results/presentation/batch-redaction.js +68 -0
  280. package/dist/extensions/agent-browser/lib/results/presentation/batch-rendering.js +135 -0
  281. package/dist/extensions/agent-browser/lib/results/presentation/batch-step.js +227 -0
  282. package/dist/extensions/agent-browser/lib/results/presentation/batch-summary.js +91 -0
  283. package/dist/extensions/agent-browser/lib/results/presentation/batch.js +91 -460
  284. package/dist/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.js +9 -5
  285. package/dist/extensions/agent-browser/lib/results/presentation/command-presenters.js +216 -0
  286. package/dist/extensions/agent-browser/lib/results/presentation/common.js +26 -9
  287. package/dist/extensions/agent-browser/lib/results/presentation/content.js +86 -29
  288. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-a11y.js +67 -0
  289. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-health.js +79 -0
  290. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-identity.js +199 -0
  291. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-logs.js +75 -0
  292. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-network-actions.js +216 -0
  293. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-network.js +124 -0
  294. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-redaction.js +64 -0
  295. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-storage.js +209 -0
  296. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-stream.js +69 -0
  297. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-summary.js +222 -0
  298. package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +103 -1052
  299. package/dist/extensions/agent-browser/lib/results/presentation/early-result.js +70 -0
  300. package/dist/extensions/agent-browser/lib/results/presentation/errors.js +130 -60
  301. package/dist/extensions/agent-browser/lib/results/presentation/input-contracts.js +1 -0
  302. package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +60 -145
  303. package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +147 -88
  304. package/dist/extensions/agent-browser/lib/results/presentation/notices.js +75 -0
  305. package/dist/extensions/agent-browser/lib/results/presentation/observation-contracts.js +1 -0
  306. package/dist/extensions/agent-browser/lib/results/presentation/observation-rendering.js +127 -0
  307. package/dist/extensions/agent-browser/lib/results/presentation/outcomes.js +120 -0
  308. package/dist/extensions/agent-browser/lib/results/presentation/output-completion.js +77 -0
  309. package/dist/extensions/agent-browser/lib/results/presentation/output-spill.js +51 -0
  310. package/dist/extensions/agent-browser/lib/results/presentation/registry.js +116 -240
  311. package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +35 -21
  312. package/dist/extensions/agent-browser/lib/results/presentation/skills.js +109 -73
  313. package/dist/extensions/agent-browser/lib/results/presentation/source.js +109 -0
  314. package/dist/extensions/agent-browser/lib/results/presentation.js +17 -261
  315. package/dist/extensions/agent-browser/lib/results/recommendation-contracts.js +1 -0
  316. package/dist/extensions/agent-browser/lib/results/recording.js +52 -14
  317. package/dist/extensions/agent-browser/lib/results/recovery-actions.js +14 -5
  318. package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +30 -22
  319. package/dist/extensions/agent-browser/lib/results/selector-recovery-target.js +83 -0
  320. package/dist/extensions/agent-browser/lib/results/selector-recovery.js +119 -119
  321. package/dist/extensions/agent-browser/lib/results/snapshot-compact.js +266 -0
  322. package/dist/extensions/agent-browser/lib/results/snapshot-content.js +32 -0
  323. package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +104 -71
  324. package/dist/extensions/agent-browser/lib/results/snapshot-refs.js +31 -11
  325. package/dist/extensions/agent-browser/lib/results/snapshot-segments.js +125 -66
  326. package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +26 -7
  327. package/dist/extensions/agent-browser/lib/results/snapshot.js +28 -248
  328. package/dist/extensions/agent-browser/lib/results/text.js +16 -5
  329. package/dist/extensions/agent-browser/lib/runtime-args-validation.js +133 -0
  330. package/dist/extensions/agent-browser/lib/runtime-compatibility.js +81 -0
  331. package/dist/extensions/agent-browser/lib/runtime-contracts.js +1 -0
  332. package/dist/extensions/agent-browser/lib/runtime-redaction.js +118 -0
  333. package/dist/extensions/agent-browser/lib/runtime-replay-events.js +144 -0
  334. package/dist/extensions/agent-browser/lib/runtime-session-identity.js +76 -0
  335. package/dist/extensions/agent-browser/lib/runtime-session-plan.js +114 -0
  336. package/dist/extensions/agent-browser/lib/runtime-session-replay.js +123 -0
  337. package/dist/extensions/agent-browser/lib/runtime-tab-correction.js +65 -0
  338. package/dist/extensions/agent-browser/lib/runtime-timeouts.js +28 -0
  339. package/dist/extensions/agent-browser/lib/runtime.js +137 -1041
  340. package/dist/extensions/agent-browser/lib/session-identity.js +51 -0
  341. package/dist/extensions/agent-browser/lib/session-page-observation.js +357 -0
  342. package/dist/extensions/agent-browser/lib/session-page-state.js +178 -333
  343. package/dist/extensions/agent-browser/lib/session-page-types.js +1 -0
  344. package/dist/extensions/agent-browser/lib/temp-artifact-budget.js +81 -0
  345. package/dist/extensions/agent-browser/lib/temp-mutation-queue.js +7 -0
  346. package/dist/extensions/agent-browser/lib/temp-root-ownership.js +234 -0
  347. package/dist/extensions/agent-browser/lib/temp-root.js +211 -0
  348. package/dist/extensions/agent-browser/lib/temp.js +33 -446
  349. package/dist/extensions/agent-browser/lib/tool-surface.js +94 -24
  350. package/dist/extensions/agent-browser/lib/upstream-version.js +3 -2
  351. package/dist/extensions/agent-browser/lib/web-search-providers.js +193 -0
  352. package/dist/extensions/agent-browser/lib/web-search-request.js +102 -0
  353. package/dist/extensions/agent-browser/lib/web-search-results.js +281 -0
  354. package/dist/extensions/agent-browser/lib/web-search-schema.js +82 -0
  355. package/dist/extensions/agent-browser/lib/web-search.js +124 -614
  356. package/dist/extensions/agent-browser/lib/webmcp-observation.js +13 -6
  357. package/dist/extensions/agent-browser/lib/windows-stock-launcher.js +63 -37
  358. package/dist/extensions/agent-browser/script-worker.js +80 -43
  359. package/dist/scripts/agent-browser-target.mjs +4 -2
  360. package/docs/ARCHITECTURE.md +19 -6
  361. package/docs/CODE_QUALITY.md +267 -0
  362. package/docs/COMMAND_REFERENCE.md +272 -241
  363. package/docs/ELECTRON.md +77 -46
  364. package/docs/REFERENCE.md +869 -0
  365. package/docs/RELEASE.md +25 -22
  366. package/docs/REQUIREMENTS.md +2 -1
  367. package/docs/SUPPORT_MATRIX.md +81 -79
  368. package/docs/TOOL_CONTRACT.md +158 -125
  369. package/docs/platform-smoke.md +8 -8
  370. package/package.json +144 -120
  371. package/scripts/agent-browser-capability-baseline.mjs +361 -957
  372. package/scripts/agent-browser-target.mjs +6 -2
  373. package/scripts/build.mjs +37 -8
  374. package/scripts/capability-core-commands.mjs +193 -0
  375. package/scripts/capability-options.mjs +283 -0
  376. package/scripts/capability-samples.mjs +133 -0
  377. package/scripts/capability-section.mjs +11 -0
  378. package/scripts/config.mjs +235 -132
  379. package/scripts/convert-browser-session.mjs +30 -9
  380. package/scripts/doctor-sources.mjs +195 -0
  381. package/scripts/doctor.mjs +94 -249
  382. package/scripts/platform-smoke/artifacts.mjs +38 -11
  383. package/scripts/platform-smoke/commands.mjs +104 -0
  384. package/scripts/platform-smoke/crabbox-runner.mjs +167 -80
  385. package/scripts/platform-smoke/doctor-support.mjs +157 -0
  386. package/scripts/platform-smoke/doctor-windows.mjs +230 -0
  387. package/scripts/platform-smoke/doctor.mjs +212 -320
  388. package/scripts/platform-smoke/lease-evidence.mjs +132 -0
  389. package/scripts/platform-smoke/linux-image/Dockerfile +8 -2
  390. package/scripts/platform-smoke/suite-checks.mjs +98 -0
  391. package/scripts/platform-smoke/suite-evidence.mjs +281 -0
  392. package/scripts/platform-smoke/targets.mjs +154 -472
  393. package/scripts/platform-smoke.mjs +55 -40
  394. package/scripts/prepare.mjs +16 -7
@@ -1,34 +1,35 @@
1
- import { execFile } from "node:child_process";
2
1
  import { lstat, rm } from "node:fs/promises";
3
- import { win32 } from "node:path";
4
- import { promisify } from "node:util";
5
- import { fetchCdpJson, parseCdpTargets, parseCdpVersion } from "./cdp.js";
6
- import { ELECTRON_PROFILE_DIR_PREFIX } from "./launch.js";
2
+ import { fetchCdpJson, parseCdpTargets, parseCdpVersion, } from "./cdp.js";
3
+ import { ELECTRON_PROFILE_DIR_PREFIX } from "./launch-types.js";
7
4
  import { pathExists } from "../fs-utils.js";
5
+ import { isRecord } from "../parsing.js";
6
+ import { readProcessStartIdentity, processStartIdentitiesMatch } from "../process-identity.js";
7
+ import { stringifyUnknown } from "../results/text.js";
8
8
  import { getSecureTempChildDirectoryValidationError } from "../temp.js";
9
9
  const ELECTRON_CLEANUP_DEFAULT_TIMEOUT_MS = 5_000;
10
10
  const ELECTRON_CLEANUP_POLL_INTERVAL_MS = 100;
11
- const RESTORED_PROCESS_COMMAND_TIMEOUT_MS = 1_000;
12
- const execFileAsync = promisify(execFile);
13
11
  function sleep(ms) {
14
- return new Promise((resolve) => setTimeout(resolve, ms));
12
+ return new Promise((resolve) => {
13
+ setTimeout(resolve, ms);
14
+ });
15
15
  }
16
16
  function isPidAlive(pid) {
17
- if (!pid || !Number.isSafeInteger(pid) || pid <= 0)
17
+ if (pid === undefined || !Number.isSafeInteger(pid) || pid <= 0) {
18
18
  return undefined;
19
+ }
19
20
  try {
20
21
  process.kill(pid, 0);
21
22
  return true;
22
23
  }
23
24
  catch (error) {
24
- const code = error.code;
25
- return code === "EPERM" ? true : false;
25
+ return isRecord(error) && error.code === "EPERM";
26
26
  }
27
27
  }
28
28
  async function isPortAlive(port, signal) {
29
29
  const version = parseCdpVersion(await fetchCdpJson(`http://127.0.0.1:${port}/json/version`, signal));
30
- if (!version)
30
+ if (!version) {
31
31
  return { targets: [] };
32
+ }
32
33
  const targets = parseCdpTargets(await fetchCdpJson(`http://127.0.0.1:${port}/json/list`, signal));
33
34
  return { targets, version };
34
35
  }
@@ -40,7 +41,7 @@ export async function inspectElectronLaunchStatus(record, signal) {
40
41
  userDataDirState = "present";
41
42
  }
42
43
  catch (error) {
43
- userDataDirState = error.code === "ENOENT" ? "absent" : "unknown";
44
+ userDataDirState = isRecord(error) && error.code === "ENOENT" ? "absent" : "unknown";
44
45
  }
45
46
  return {
46
47
  cleanupState: record.cleanupState,
@@ -61,52 +62,32 @@ function hasProcessExited(child, pid) {
61
62
  }
62
63
  async function waitForProcessExit(child, pid, deadlineMs) {
63
64
  while (Date.now() <= deadlineMs) {
64
- if (hasProcessExited(child, pid))
65
+ if (hasProcessExited(child, pid)) {
65
66
  return true;
67
+ }
68
+ // Polling observes exit between sleeps; parallel waits cannot preserve the deadline.
69
+ // oxlint-disable-next-line no-await-in-loop
66
70
  await sleep(ELECTRON_CLEANUP_POLL_INTERVAL_MS);
67
71
  }
68
72
  return hasProcessExited(child, pid);
69
73
  }
70
- async function readPidCommandLine(pid) {
71
- if (!pid || !Number.isSafeInteger(pid) || pid <= 0)
72
- return undefined;
73
- try {
74
- // Win32_Process.CommandLine is the native ownership evidence; process
75
- // start time (used by daemon-policy locks) cannot prove profile ownership.
76
- const systemRoot = process.env.SystemRoot;
77
- const windowsRoot = systemRoot && win32.isAbsolute(systemRoot) ? systemRoot : "C:\\Windows";
78
- const file = process.platform === "win32"
79
- ? win32.join(windowsRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe")
80
- : "ps";
81
- const args = process.platform === "win32"
82
- ? ["-NoProfile", "-NonInteractive", "-Command",
83
- `[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new(); $p = [wmi]"Win32_Process.Handle='${pid}'"; [Console]::WriteLine($p.CommandLine)`]
84
- : ["-ww", "-p", String(pid), "-o", "command="];
85
- const { stdout } = await execFileAsync(file, args, {
86
- timeout: RESTORED_PROCESS_COMMAND_TIMEOUT_MS,
87
- });
88
- return stdout.trim() || undefined;
89
- }
90
- catch {
91
- return undefined;
92
- }
93
- }
94
- function restoredLaunchCommandMatchesRecord(record, commandLine) {
95
- return commandLine?.includes(`--user-data-dir=${record.userDataDir}`) === true;
96
- }
97
74
  async function getRestoredProcessVerificationError(record) {
98
- const commandLine = await readPidCommandLine(record.pid);
99
- if (!commandLine) {
100
- return `PID ${record.pid} is alive, but this session has no tracked child handle and its command line could not be inspected; refusing to signal a restored PID that may have been reused.`;
75
+ if (record.startIdentity === undefined || record.startIdentity.length === 0) {
76
+ return `PID ${String(record.pid)} is alive, but this session has no tracked child handle or recorded start identity; refusing to signal a restored PID that may have been reused.`;
101
77
  }
102
- if (!restoredLaunchCommandMatchesRecord(record, commandLine)) {
103
- return `PID ${record.pid} is alive, but this session has no tracked child handle and its command line does not include wrapper-owned user data dir ${record.userDataDir}; refusing to signal a restored PID that may have been reused.`;
78
+ const currentIdentity = record.pid === undefined ? undefined : await readProcessStartIdentity(record.pid);
79
+ if (currentIdentity === undefined) {
80
+ return `PID ${String(record.pid)} is alive, but its current start identity could not be inspected; refusing to signal a restored PID that may have been reused.`;
81
+ }
82
+ if (!processStartIdentitiesMatch(record.startIdentity, currentIdentity)) {
83
+ return `PID ${String(record.pid)} is alive, but its start identity does not match the wrapper launch record; refusing to signal a restored PID that may have been reused.`;
104
84
  }
105
85
  return undefined;
106
86
  }
107
87
  function killPid(pid, signal) {
108
- if (!pid || !Number.isSafeInteger(pid) || pid <= 0)
88
+ if (pid === undefined || !Number.isSafeInteger(pid) || pid <= 0) {
109
89
  return false;
90
+ }
110
91
  try {
111
92
  process.kill(pid, signal);
112
93
  return true;
@@ -116,8 +97,12 @@ function killPid(pid, signal) {
116
97
  }
117
98
  }
118
99
  function killProcessGroup(processGroupId, signal) {
119
- if (process.platform === "win32" || !processGroupId || !Number.isSafeInteger(processGroupId) || processGroupId <= 0)
100
+ if (process.platform === "win32" ||
101
+ processGroupId === undefined ||
102
+ !Number.isSafeInteger(processGroupId) ||
103
+ processGroupId <= 0) {
120
104
  return false;
105
+ }
121
106
  try {
122
107
  process.kill(-processGroupId, signal);
123
108
  return true;
@@ -130,68 +115,122 @@ function signalRestoredLaunchProcess(record, signal) {
130
115
  return killProcessGroup(record.processGroupId, signal) || killPid(record.pid, signal);
131
116
  }
132
117
  async function cleanupProcess(record, child, deadlineMs) {
133
- if (!record.pid)
118
+ if (record.pid === undefined || record.pid === 0 || Number.isNaN(record.pid)) {
134
119
  return { resource: "process", state: "skipped" };
135
- if (hasProcessExited(child, record.pid))
120
+ }
121
+ if (hasProcessExited(child, record.pid)) {
136
122
  return { resource: "process", state: "already-gone" };
137
- if (!child) {
138
- const verificationError = await getRestoredProcessVerificationError(record);
139
- if (verificationError)
140
- return { error: verificationError, resource: "process", state: "failed" };
141
- if (!signalRestoredLaunchProcess(record, "SIGTERM")) {
142
- return { error: `PID ${record.pid} matched wrapper launch metadata but could not be signaled.`, resource: "process", state: "failed" };
143
- }
144
- if (await waitForProcessExit(undefined, record.pid, deadlineMs))
145
- return { resource: "process", state: "removed" };
146
- signalRestoredLaunchProcess(record, "SIGKILL");
147
- if (await waitForProcessExit(undefined, record.pid, Date.now() + 1_000))
148
- return { resource: "process", state: "removed" };
149
- return { error: `PID ${record.pid} remained alive after SIGTERM/SIGKILL.`, resource: "process", state: "failed" };
150
- }
151
- if (child.exitCode === null && child.signalCode === null)
123
+ }
124
+ return child === undefined
125
+ ? cleanupRestoredProcess(record, deadlineMs)
126
+ : cleanupTrackedProcess(record, child, deadlineMs);
127
+ }
128
+ async function cleanupRestoredProcess(record, deadlineMs) {
129
+ const verificationError = await getRestoredProcessVerificationError(record);
130
+ if (verificationError !== undefined) {
131
+ return { error: verificationError, resource: "process", state: "failed" };
132
+ }
133
+ if (!signalRestoredLaunchProcess(record, "SIGTERM")) {
134
+ return {
135
+ error: `PID ${String(record.pid)} matched wrapper launch metadata but could not be signaled.`,
136
+ resource: "process",
137
+ state: "failed",
138
+ };
139
+ }
140
+ if (await waitForProcessExit(undefined, record.pid, deadlineMs)) {
141
+ return { resource: "process", state: "removed" };
142
+ }
143
+ const killVerificationError = await getRestoredProcessVerificationError(record);
144
+ if (killVerificationError !== undefined) {
145
+ return { error: killVerificationError, resource: "process", state: "failed" };
146
+ }
147
+ signalRestoredLaunchProcess(record, "SIGKILL");
148
+ if (await waitForProcessExit(undefined, record.pid, Date.now() + 1_000)) {
149
+ return { resource: "process", state: "removed" };
150
+ }
151
+ return {
152
+ error: `PID ${String(record.pid)} remained alive after SIGTERM/SIGKILL.`,
153
+ resource: "process",
154
+ state: "failed",
155
+ };
156
+ }
157
+ async function cleanupTrackedProcess(record, child, deadlineMs) {
158
+ if (child.exitCode === null && child.signalCode === null) {
152
159
  child.kill("SIGTERM");
153
- else
160
+ }
161
+ else {
154
162
  killPid(record.pid, "SIGTERM");
155
- if (await waitForProcessExit(child, record.pid, deadlineMs))
163
+ }
164
+ if (await waitForProcessExit(child, record.pid, deadlineMs)) {
156
165
  return { resource: "process", state: "removed" };
157
- if (child.exitCode === null && child.signalCode === null)
166
+ }
167
+ if (child.exitCode === null && child.signalCode === null) {
158
168
  child.kill("SIGKILL");
159
- else
169
+ }
170
+ else {
160
171
  killPid(record.pid, "SIGKILL");
161
- if (await waitForProcessExit(child, record.pid, Date.now() + 1_000))
172
+ }
173
+ if (await waitForProcessExit(child, record.pid, Date.now() + 1_000)) {
162
174
  return { resource: "process", state: "removed" };
163
- return { error: `PID ${record.pid} remained alive after SIGTERM/SIGKILL.`, resource: "process", state: "failed" };
175
+ }
176
+ return {
177
+ error: `PID ${String(record.pid)} remained alive after SIGTERM/SIGKILL.`,
178
+ resource: "process",
179
+ state: "failed",
180
+ };
164
181
  }
165
182
  async function cleanupUserDataDir(record) {
166
- if (!record.userDataDir)
183
+ if (record.userDataDir.length === 0) {
167
184
  return { resource: "user-data-dir", state: "skipped" };
168
- if (!await pathExists(record.userDataDir))
185
+ }
186
+ if (!(await pathExists(record.userDataDir))) {
169
187
  return { resource: "user-data-dir", state: "already-gone" };
188
+ }
170
189
  const validationError = await getSecureTempChildDirectoryValidationError(record.userDataDir, ELECTRON_PROFILE_DIR_PREFIX);
171
- if (validationError)
190
+ if (validationError !== undefined) {
172
191
  return { error: validationError, resource: "user-data-dir", state: "failed" };
192
+ }
173
193
  try {
174
194
  await rm(record.userDataDir, { force: true, recursive: true });
175
- return { resource: "user-data-dir", state: await pathExists(record.userDataDir) ? "failed" : "removed" };
195
+ return {
196
+ resource: "user-data-dir",
197
+ state: (await pathExists(record.userDataDir)) ? "failed" : "removed",
198
+ };
176
199
  }
177
200
  catch (error) {
178
- return { error: error instanceof Error ? error.message : String(error), resource: "user-data-dir", state: "failed" };
201
+ return {
202
+ error: error instanceof Error ? error.message : stringifyUnknown(error),
203
+ resource: "user-data-dir",
204
+ state: "failed",
205
+ };
179
206
  }
180
207
  }
181
208
  function shouldSkipUserDataDirCleanup(processStep, debugPortStep) {
182
- if (processStep.state === "failed")
209
+ if (processStep.state === "failed") {
183
210
  return `Skipped because process cleanup failed: ${processStep.error ?? "process state could not be verified"}.`;
184
- if (debugPortStep.state === "failed")
211
+ }
212
+ if (debugPortStep.state === "failed") {
185
213
  return `Skipped because debug port cleanup is incomplete: ${debugPortStep.error ?? "debug port still responds"}.`;
214
+ }
186
215
  return undefined;
187
216
  }
188
217
  async function cleanupDebugPort(record) {
189
218
  const cdp = await isPortAlive(record.port);
190
- return cdp.version ? { resource: "debug-port", state: "failed", error: `/json/version still responds on port ${record.port}.` } : { resource: "debug-port", state: "already-gone" };
219
+ return cdp.version
220
+ ? {
221
+ resource: "debug-port",
222
+ state: "failed",
223
+ error: `/json/version still responds on port ${record.port}.`,
224
+ }
225
+ : { resource: "debug-port", state: "already-gone" };
191
226
  }
192
227
  function summarizeCleanup(launchId, steps) {
193
228
  const remainingResources = steps
194
- .filter((step) => step.state === "failed" || (step.resource === "user-data-dir" && step.state === "skipped" && step.error))
229
+ .filter((step) => step.state === "failed" ||
230
+ (step.resource === "user-data-dir" &&
231
+ step.state === "skipped" &&
232
+ step.error !== undefined &&
233
+ step.error.length > 0))
195
234
  .map((step) => step.resource);
196
235
  const partial = remainingResources.length > 0;
197
236
  return {
@@ -203,15 +242,21 @@ function summarizeCleanup(launchId, steps) {
203
242
  };
204
243
  }
205
244
  export async function cleanupElectronLaunchResources(options) {
206
- const timeoutMs = Number.isSafeInteger(options.timeoutMs) && (options.timeoutMs ?? 0) > 0
245
+ const timeoutMs = typeof options.timeoutMs === "number" &&
246
+ Number.isSafeInteger(options.timeoutMs) &&
247
+ options.timeoutMs > 0
207
248
  ? options.timeoutMs
208
249
  : ELECTRON_CLEANUP_DEFAULT_TIMEOUT_MS;
209
250
  const deadlineMs = Date.now() + timeoutMs;
210
251
  const processStep = await cleanupProcess(options.record, options.child, deadlineMs);
211
252
  const debugPortStep = await cleanupDebugPort(options.record);
212
253
  const userDataDirSkipReason = shouldSkipUserDataDirCleanup(processStep, debugPortStep);
213
- const userDataDirStep = userDataDirSkipReason
214
- ? { error: userDataDirSkipReason, resource: "user-data-dir", state: "skipped" }
254
+ const userDataDirStep = userDataDirSkipReason !== undefined
255
+ ? {
256
+ error: userDataDirSkipReason,
257
+ resource: "user-data-dir",
258
+ state: "skipped",
259
+ }
215
260
  : await cleanupUserDataDir(options.record);
216
261
  const steps = [processStep, debugPortStep, userDataDirStep];
217
262
  const summary = summarizeCleanup(options.record.launchId, steps);
@@ -0,0 +1,109 @@
1
+ import { readdir, readFile } from "node:fs/promises";
2
+ import { basename, join } from "node:path";
3
+ import { pathExists } from "../fs-utils.js";
4
+ import { hasElectronAppPayload, isDirectory } from "./discovery-evidence.js";
5
+ function readPlistString(plist, key) {
6
+ const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7
+ const match = new RegExp(`<key>\\s*${escapedKey}\\s*</key>\\s*<string>([\\s\\S]*?)</string>`, "i").exec(plist);
8
+ return match?.[1]
9
+ ?.trim()
10
+ .replaceAll("&amp;", "&")
11
+ .replaceAll("&lt;", "<")
12
+ .replaceAll("&gt;", ">")
13
+ .replaceAll("&quot;", '"')
14
+ .replaceAll("&apos;", "'");
15
+ }
16
+ async function readMacInfoPlist(appPath) {
17
+ try {
18
+ const plist = await readFile(join(appPath, "Contents", "Info.plist"), "utf8");
19
+ return {
20
+ CFBundleDisplayName: readPlistString(plist, "CFBundleDisplayName") ?? "",
21
+ CFBundleExecutable: readPlistString(plist, "CFBundleExecutable") ?? "",
22
+ CFBundleIdentifier: readPlistString(plist, "CFBundleIdentifier") ?? "",
23
+ CFBundleName: readPlistString(plist, "CFBundleName") ?? "",
24
+ };
25
+ }
26
+ catch {
27
+ return {};
28
+ }
29
+ }
30
+ async function resolveMacExecutablePath(appPath, executableName, fallbackName) {
31
+ const directory = join(appPath, "Contents", "MacOS");
32
+ if (executableName !== undefined && executableName.trim().length > 0) {
33
+ const path = join(directory, executableName);
34
+ return (await pathExists(path)) ? path : undefined;
35
+ }
36
+ try {
37
+ const entries = await readdir(directory, { withFileTypes: true });
38
+ const candidate = entries.find((entry) => entry.isFile() && entry.name === fallbackName) ??
39
+ entries.find((entry) => entry.isFile());
40
+ return candidate ? join(directory, candidate.name) : undefined;
41
+ }
42
+ catch {
43
+ return undefined;
44
+ }
45
+ }
46
+ function firstNonempty(values) {
47
+ return values.find((value) => value !== undefined && value.length > 0);
48
+ }
49
+ export async function inspectDarwinApp(appPath) {
50
+ const framework = join(appPath, "Contents", "Frameworks", "Electron Framework.framework");
51
+ const hasFramework = await isDirectory(framework);
52
+ const hasPayload = await hasElectronAppPayload(join(appPath, "Contents", "Resources"));
53
+ if (!hasFramework || !hasPayload) {
54
+ return undefined;
55
+ }
56
+ const info = await readMacInfoPlist(appPath);
57
+ const directoryName = basename(appPath, ".app");
58
+ const executablePath = await resolveMacExecutablePath(appPath, info.CFBundleExecutable, directoryName);
59
+ if (executablePath === undefined) {
60
+ return undefined;
61
+ }
62
+ return {
63
+ appPath,
64
+ bundleId: firstNonempty([info.CFBundleIdentifier]),
65
+ executablePath,
66
+ name: firstNonempty([info.CFBundleDisplayName, info.CFBundleName]) ?? directoryName,
67
+ platform: "darwin",
68
+ };
69
+ }
70
+ async function inspectDirectory(directory) {
71
+ let entries;
72
+ try {
73
+ entries = await readdir(directory, { withFileTypes: true });
74
+ }
75
+ catch {
76
+ return { apps: [], skippedCount: 0 };
77
+ }
78
+ const apps = [];
79
+ let skippedCount = 0;
80
+ for (const entry of entries) {
81
+ if (!entry.name.endsWith(".app")) {
82
+ continue;
83
+ }
84
+ try {
85
+ // Inspect in filesystem order and count failures without overlapping app reads.
86
+ // oxlint-disable-next-line no-await-in-loop
87
+ const app = await inspectDarwinApp(join(directory, entry.name));
88
+ if (app) {
89
+ apps.push(app);
90
+ }
91
+ }
92
+ catch {
93
+ skippedCount += 1;
94
+ }
95
+ }
96
+ return { apps, skippedCount };
97
+ }
98
+ export async function discoverDarwinApps(directories) {
99
+ const apps = [];
100
+ let skippedCount = 0;
101
+ for (const directory of directories) {
102
+ // Location priority is observable when duplicate bundles are discovered.
103
+ // oxlint-disable-next-line no-await-in-loop
104
+ const scan = await inspectDirectory(directory);
105
+ apps.push(...scan.apps);
106
+ skippedCount += scan.skippedCount;
107
+ }
108
+ return { apps, skippedCount };
109
+ }
@@ -0,0 +1,136 @@
1
+ import { basename } from "node:path";
2
+ function unescapeDesktopValue(value) {
3
+ return value
4
+ .replace(/\\s/g, " ")
5
+ .replace(/\\n/g, "\n")
6
+ .replace(/\\r/g, "\r")
7
+ .replace(/\\t/g, "\t")
8
+ .replace(/\\\\/g, "\\");
9
+ }
10
+ function parseDesktopFields(text) {
11
+ const fields = new Map();
12
+ let inDesktopEntry = false;
13
+ for (const rawLine of text.split(/\r?\n/)) {
14
+ const line = rawLine.trim();
15
+ if (line.length === 0 || line.startsWith("#")) {
16
+ continue;
17
+ }
18
+ if (line.startsWith("[") && line.endsWith("]")) {
19
+ inDesktopEntry = line === "[Desktop Entry]";
20
+ continue;
21
+ }
22
+ const separator = line.indexOf("=");
23
+ if (inDesktopEntry && separator > 0) {
24
+ fields.set(line.slice(0, separator), unescapeDesktopValue(line.slice(separator + 1)));
25
+ }
26
+ }
27
+ return fields;
28
+ }
29
+ function nonempty(value) {
30
+ return value !== undefined && value.length > 0 ? value : undefined;
31
+ }
32
+ export function parseDesktopFile(text, filePath) {
33
+ const fields = parseDesktopFields(text);
34
+ if (fields.get("Type") !== "Application") {
35
+ return undefined;
36
+ }
37
+ if (["NoDisplay", "Hidden"].some((key) => fields.get(key)?.trim().toLowerCase() === "true")) {
38
+ return undefined;
39
+ }
40
+ const exec = nonempty(fields.get("Exec")?.trim());
41
+ if (exec === undefined) {
42
+ return undefined;
43
+ }
44
+ const desktopId = basename(filePath, ".desktop");
45
+ return {
46
+ comment: nonempty(fields.get("Comment")),
47
+ desktopId,
48
+ exec,
49
+ filePath,
50
+ icon: nonempty(fields.get("Icon")),
51
+ name: nonempty(fields.get("Name")) ?? desktopId,
52
+ };
53
+ }
54
+ function stripDesktopExecFieldCodes(exec) {
55
+ const placeholder = "\u0000PERCENT\u0000";
56
+ return exec
57
+ .replaceAll("%%", placeholder)
58
+ .replace(/%[A-Za-z]/g, "")
59
+ .replaceAll(placeholder, "%");
60
+ }
61
+ class DesktopExecWords {
62
+ tokens = [];
63
+ current = "";
64
+ quote;
65
+ escaped = false;
66
+ parse(exec) {
67
+ for (const char of stripDesktopExecFieldCodes(exec)) {
68
+ this.accept(char);
69
+ }
70
+ if (this.escaped) {
71
+ this.current += "\\";
72
+ }
73
+ this.flush();
74
+ return this.tokens;
75
+ }
76
+ flush() {
77
+ if (this.current.length > 0) {
78
+ this.tokens.push(this.current);
79
+ this.current = "";
80
+ }
81
+ }
82
+ accept(char) {
83
+ if (this.escaped) {
84
+ this.current += char;
85
+ this.escaped = false;
86
+ return;
87
+ }
88
+ if (char === "\\") {
89
+ this.escaped = true;
90
+ return;
91
+ }
92
+ if (this.quote !== undefined) {
93
+ if (char === this.quote) {
94
+ this.quote = undefined;
95
+ }
96
+ else {
97
+ this.current += char;
98
+ }
99
+ return;
100
+ }
101
+ if (char === '"' || char === "'") {
102
+ this.quote = char;
103
+ return;
104
+ }
105
+ if (/\s/.test(char)) {
106
+ this.flush();
107
+ return;
108
+ }
109
+ this.current += char;
110
+ }
111
+ }
112
+ export function tokenizeDesktopExec(exec) {
113
+ return new DesktopExecWords().parse(exec);
114
+ }
115
+ function envOptionWidth(token) {
116
+ return ["-u", "--unset", "--chdir"].includes(token) ? 2 : 1;
117
+ }
118
+ export function stripEnvLauncher(tokens) {
119
+ if (tokens.length === 0 || basename(tokens[0] ?? "") !== "env") {
120
+ return tokens;
121
+ }
122
+ let index = 1;
123
+ while (index < tokens.length) {
124
+ const token = tokens[index] ?? "";
125
+ if (token.startsWith("-")) {
126
+ index += envOptionWidth(token);
127
+ continue;
128
+ }
129
+ if (/^[A-Za-z_][A-Za-z0-9_]*=.*/.test(token)) {
130
+ index += 1;
131
+ continue;
132
+ }
133
+ break;
134
+ }
135
+ return tokens.slice(index);
136
+ }
@@ -0,0 +1,90 @@
1
+ import { constants as fsConstants } from "node:fs";
2
+ import { access, readdir, realpath, stat } from "node:fs/promises";
3
+ import { basename, dirname, extname, join } from "node:path";
4
+ import { pathExists } from "../fs-utils.js";
5
+ export async function isDirectory(path) {
6
+ try {
7
+ return (await stat(path)).isDirectory();
8
+ }
9
+ catch {
10
+ return false;
11
+ }
12
+ }
13
+ export async function isFile(path) {
14
+ try {
15
+ return (await stat(path)).isFile();
16
+ }
17
+ catch {
18
+ return false;
19
+ }
20
+ }
21
+ export async function isExecutableFile(path) {
22
+ try {
23
+ if (!(await stat(path)).isFile()) {
24
+ return false;
25
+ }
26
+ await access(path, fsConstants.X_OK);
27
+ return true;
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ }
33
+ export async function resolveRealPath(path) {
34
+ try {
35
+ return await realpath(path);
36
+ }
37
+ catch {
38
+ return path;
39
+ }
40
+ }
41
+ export async function directoryContainsChromePak(directory) {
42
+ try {
43
+ const entries = await readdir(directory, { withFileTypes: true });
44
+ return entries.some((entry) => entry.isFile() && /^chrome_.*\.pak$/i.test(entry.name));
45
+ }
46
+ catch {
47
+ return false;
48
+ }
49
+ }
50
+ export async function hasElectronAppPayload(resourcesDirectory) {
51
+ return ((await pathExists(join(resourcesDirectory, "app.asar"))) ||
52
+ (await pathExists(join(resourcesDirectory, "default_app.asar"))) ||
53
+ (await isDirectory(join(resourcesDirectory, "app"))));
54
+ }
55
+ export async function hasLinuxElectronEvidence(executablePath) {
56
+ const resolved = await resolveRealPath(executablePath);
57
+ if (!(await isExecutableFile(resolved))) {
58
+ return false;
59
+ }
60
+ const directory = dirname(resolved);
61
+ if (!(await directoryContainsChromePak(directory))) {
62
+ return false;
63
+ }
64
+ for (const base of [directory, dirname(directory)]) {
65
+ // Ordered evidence checks avoid unnecessary filesystem work after the first match.
66
+ // oxlint-disable-next-line no-await-in-loop
67
+ if (await hasElectronAppPayload(join(base, "resources"))) {
68
+ return true;
69
+ }
70
+ }
71
+ return false;
72
+ }
73
+ export async function inspectWin32Executable(executablePath) {
74
+ const resolved = await resolveRealPath(executablePath);
75
+ if (!(await isExecutableFile(resolved))) {
76
+ return undefined;
77
+ }
78
+ const directory = dirname(resolved);
79
+ const hasAppPayload = await hasElectronAppPayload(join(directory, "resources"));
80
+ const hasPak = (await directoryContainsChromePak(directory)) ||
81
+ (await pathExists(join(directory, "resources.pak")));
82
+ if (!hasAppPayload || !hasPak) {
83
+ return undefined;
84
+ }
85
+ return {
86
+ executablePath: resolved,
87
+ name: basename(resolved, extname(resolved)),
88
+ platform: "win32",
89
+ };
90
+ }